mirror of
https://github.com/alkimake/paperclip.git
synced 2026-06-16 02:40:39 +09:00
Merge branch 'master' into feature/change-reports-to
This commit is contained in:
commit
dfb83295de
191 changed files with 46471 additions and 1103 deletions
|
|
@ -45,6 +45,7 @@ import { MarkdownEditor } from "./MarkdownEditor";
|
|||
import { ChoosePathButton } from "./PathInstructionsModal";
|
||||
import { OpenCodeLogoIcon } from "./OpenCodeLogoIcon";
|
||||
import { ReportsToPicker } from "./ReportsToPicker";
|
||||
import { shouldShowLegacyWorkingDirectoryField } from "../lib/legacy-agent-config";
|
||||
|
||||
/* ---- Create mode values ---- */
|
||||
|
||||
|
|
@ -61,6 +62,12 @@ type AgentConfigFormProps = {
|
|||
onSaveActionChange?: (save: (() => void) | null) => void;
|
||||
onCancelActionChange?: (cancel: (() => void) | null) => void;
|
||||
hideInlineSave?: boolean;
|
||||
showAdapterTypeField?: boolean;
|
||||
showAdapterTestEnvironmentButton?: boolean;
|
||||
showCreateRunPolicySection?: boolean;
|
||||
hideInstructionsFile?: boolean;
|
||||
/** Hide the prompt template field from the Identity section (used when it's shown in a separate Prompts tab). */
|
||||
hidePromptTemplate?: boolean;
|
||||
/** "cards" renders each section as heading + bordered card (for settings pages). Default: "inline" (border-b dividers). */
|
||||
sectionLayout?: "inline" | "cards";
|
||||
} & (
|
||||
|
|
@ -164,6 +171,10 @@ export function AgentConfigForm(props: AgentConfigFormProps) {
|
|||
const { mode, adapterModels: externalModels } = props;
|
||||
const isCreate = mode === "create";
|
||||
const cards = props.sectionLayout === "cards";
|
||||
const showAdapterTypeField = props.showAdapterTypeField ?? true;
|
||||
const showAdapterTestEnvironmentButton = props.showAdapterTestEnvironmentButton ?? true;
|
||||
const showCreateRunPolicySection = props.showCreateRunPolicySection ?? true;
|
||||
const hideInstructionsFile = props.hideInstructionsFile ?? false;
|
||||
const { selectedCompanyId } = useCompany();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
|
|
@ -286,7 +297,10 @@ export function AgentConfigForm(props: AgentConfigFormProps) {
|
|||
adapterType === "codex_local" ||
|
||||
adapterType === "gemini_local" ||
|
||||
adapterType === "opencode_local" ||
|
||||
adapterType === "pi_local" ||
|
||||
adapterType === "cursor";
|
||||
const showLegacyWorkingDirectoryField =
|
||||
isLocal && shouldShowLegacyWorkingDirectoryField({ isCreate, adapterConfig: config });
|
||||
const uiAdapter = useMemo(() => getUIAdapter(adapterType), [adapterType]);
|
||||
|
||||
// Fetch adapter models for the effective adapter type
|
||||
|
|
@ -319,6 +333,7 @@ export function AgentConfigForm(props: AgentConfigFormProps) {
|
|||
eff: eff as <T>(group: "adapterConfig", field: string, original: T) => T,
|
||||
mark: mark as (group: "adapterConfig", field: string, value: unknown) => void,
|
||||
models,
|
||||
hideInstructionsFile,
|
||||
};
|
||||
|
||||
// Section toggle state — advanced always starts collapsed
|
||||
|
|
@ -478,7 +493,7 @@ export function AgentConfigForm(props: AgentConfigFormProps) {
|
|||
}}
|
||||
/>
|
||||
</Field>
|
||||
{isLocal && (
|
||||
{isLocal && !props.hidePromptTemplate && (
|
||||
<>
|
||||
<Field label="Prompt Template" hint={help.promptTemplate}>
|
||||
<MarkdownEditor
|
||||
|
|
@ -513,69 +528,73 @@ export function AgentConfigForm(props: AgentConfigFormProps) {
|
|||
? <h3 className="text-sm font-medium">Adapter</h3>
|
||||
: <span className="text-xs font-medium text-muted-foreground">Adapter</span>
|
||||
}
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="h-7 px-2.5 text-xs"
|
||||
onClick={() => testEnvironment.mutate()}
|
||||
disabled={testEnvironment.isPending || !selectedCompanyId}
|
||||
>
|
||||
{testEnvironment.isPending ? "Testing..." : "Test environment"}
|
||||
</Button>
|
||||
{showAdapterTestEnvironmentButton && (
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="h-7 px-2.5 text-xs"
|
||||
onClick={() => testEnvironment.mutate()}
|
||||
disabled={testEnvironment.isPending || !selectedCompanyId}
|
||||
>
|
||||
{testEnvironment.isPending ? "Testing..." : "Test environment"}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
<div className={cn(cards ? "border border-border rounded-lg p-4 space-y-3" : "px-4 pb-3 space-y-3")}>
|
||||
<Field label="Adapter type" hint={help.adapterType}>
|
||||
<AdapterTypeDropdown
|
||||
value={adapterType}
|
||||
onChange={(t) => {
|
||||
if (isCreate) {
|
||||
// Reset all adapter-specific fields to defaults when switching adapter type
|
||||
const { adapterType: _at, ...defaults } = defaultCreateValues;
|
||||
const nextValues: CreateConfigValues = { ...defaults, adapterType: t };
|
||||
if (t === "codex_local") {
|
||||
nextValues.model = DEFAULT_CODEX_LOCAL_MODEL;
|
||||
nextValues.dangerouslyBypassSandbox =
|
||||
DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX;
|
||||
} else if (t === "gemini_local") {
|
||||
nextValues.model = DEFAULT_GEMINI_LOCAL_MODEL;
|
||||
} else if (t === "cursor") {
|
||||
nextValues.model = DEFAULT_CURSOR_LOCAL_MODEL;
|
||||
} else if (t === "opencode_local") {
|
||||
nextValues.model = "";
|
||||
{showAdapterTypeField && (
|
||||
<Field label="Adapter type" hint={help.adapterType}>
|
||||
<AdapterTypeDropdown
|
||||
value={adapterType}
|
||||
onChange={(t) => {
|
||||
if (isCreate) {
|
||||
// Reset all adapter-specific fields to defaults when switching adapter type
|
||||
const { adapterType: _at, ...defaults } = defaultCreateValues;
|
||||
const nextValues: CreateConfigValues = { ...defaults, adapterType: t };
|
||||
if (t === "codex_local") {
|
||||
nextValues.model = DEFAULT_CODEX_LOCAL_MODEL;
|
||||
nextValues.dangerouslyBypassSandbox =
|
||||
DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX;
|
||||
} else if (t === "gemini_local") {
|
||||
nextValues.model = DEFAULT_GEMINI_LOCAL_MODEL;
|
||||
} else if (t === "cursor") {
|
||||
nextValues.model = DEFAULT_CURSOR_LOCAL_MODEL;
|
||||
} else if (t === "opencode_local") {
|
||||
nextValues.model = "";
|
||||
}
|
||||
set!(nextValues);
|
||||
} else {
|
||||
// Clear all adapter config and explicitly blank out model + effort/mode keys
|
||||
// so the old adapter's values don't bleed through via eff()
|
||||
setOverlay((prev) => ({
|
||||
...prev,
|
||||
adapterType: t,
|
||||
adapterConfig: {
|
||||
model:
|
||||
t === "codex_local"
|
||||
? DEFAULT_CODEX_LOCAL_MODEL
|
||||
: t === "gemini_local"
|
||||
? DEFAULT_GEMINI_LOCAL_MODEL
|
||||
: t === "cursor"
|
||||
? DEFAULT_CURSOR_LOCAL_MODEL
|
||||
: "",
|
||||
effort: "",
|
||||
modelReasoningEffort: "",
|
||||
variant: "",
|
||||
mode: "",
|
||||
...(t === "codex_local"
|
||||
? {
|
||||
dangerouslyBypassApprovalsAndSandbox:
|
||||
DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX,
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
}));
|
||||
}
|
||||
set!(nextValues);
|
||||
} else {
|
||||
// Clear all adapter config and explicitly blank out model + effort/mode keys
|
||||
// so the old adapter's values don't bleed through via eff()
|
||||
setOverlay((prev) => ({
|
||||
...prev,
|
||||
adapterType: t,
|
||||
adapterConfig: {
|
||||
model:
|
||||
t === "codex_local"
|
||||
? DEFAULT_CODEX_LOCAL_MODEL
|
||||
: t === "gemini_local"
|
||||
? DEFAULT_GEMINI_LOCAL_MODEL
|
||||
: t === "cursor"
|
||||
? DEFAULT_CURSOR_LOCAL_MODEL
|
||||
: "",
|
||||
effort: "",
|
||||
modelReasoningEffort: "",
|
||||
variant: "",
|
||||
mode: "",
|
||||
...(t === "codex_local"
|
||||
? {
|
||||
dangerouslyBypassApprovalsAndSandbox:
|
||||
DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX,
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
}));
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Field>
|
||||
}}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
|
||||
{testEnvironment.error && (
|
||||
<div className="rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-xs text-destructive">
|
||||
|
|
@ -590,8 +609,8 @@ export function AgentConfigForm(props: AgentConfigFormProps) {
|
|||
)}
|
||||
|
||||
{/* Working directory */}
|
||||
{isLocal && (
|
||||
<Field label="Working directory" hint={help.cwd}>
|
||||
{showLegacyWorkingDirectoryField && (
|
||||
<Field label="Working directory (deprecated)" hint={help.cwd}>
|
||||
<div className="flex items-center gap-2 rounded-md border border-border px-2.5 py-1.5">
|
||||
<FolderOpen className="h-3.5 w-3.5 text-muted-foreground shrink-0" />
|
||||
<DraftInput
|
||||
|
|
@ -669,8 +688,10 @@ export function AgentConfigForm(props: AgentConfigFormProps) {
|
|||
? "codex"
|
||||
: adapterType === "gemini_local"
|
||||
? "gemini"
|
||||
: adapterType === "cursor"
|
||||
? "agent"
|
||||
: adapterType === "pi_local"
|
||||
? "pi"
|
||||
: adapterType === "cursor"
|
||||
? "agent"
|
||||
: adapterType === "opencode_local"
|
||||
? "opencode"
|
||||
: "claude"
|
||||
|
|
@ -825,7 +846,7 @@ export function AgentConfigForm(props: AgentConfigFormProps) {
|
|||
)}
|
||||
|
||||
{/* ---- Run Policy ---- */}
|
||||
{isCreate ? (
|
||||
{isCreate && showCreateRunPolicySection ? (
|
||||
<div className={cn(!cards && "border-b border-border")}>
|
||||
{cards
|
||||
? <h3 className="text-sm font-medium flex items-center gap-2 mb-3"><Heart className="h-3 w-3" /> Run Policy</h3>
|
||||
|
|
@ -846,7 +867,7 @@ export function AgentConfigForm(props: AgentConfigFormProps) {
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
) : !isCreate ? (
|
||||
<div className={cn(!cards && "border-b border-border")}>
|
||||
{cards
|
||||
? <h3 className="text-sm font-medium flex items-center gap-2 mb-3"><Heart className="h-3 w-3" /> Run Policy</h3>
|
||||
|
|
@ -912,7 +933,7 @@ export function AgentConfigForm(props: AgentConfigFormProps) {
|
|||
</CollapsibleSection>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
) : null}
|
||||
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue