@zihanw/pi-forge 0.4.0-beta.1 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -1
- package/PUBLIC_API.md +3 -26
- package/README.md +90 -601
- package/README.zh-CN.md +86 -585
- package/SUBAGENT_ADAPTER_CONTRACT.md +3 -197
- package/dist/agent-profile.d.ts +24 -1
- package/dist/agent-profile.d.ts.map +1 -1
- package/dist/agent-profile.js +146 -36
- package/dist/agent-profile.js.map +1 -1
- package/dist/catalog.d.ts +27 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +59 -0
- package/dist/catalog.js.map +1 -0
- package/dist/forge-config.d.ts +106 -0
- package/dist/forge-config.d.ts.map +1 -1
- package/dist/forge-config.js +305 -18
- package/dist/forge-config.js.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +55 -8
- package/dist/index.js.map +1 -1
- package/dist/lifecycle.d.ts +2 -1
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/lifecycle.js +7 -4
- package/dist/lifecycle.js.map +1 -1
- package/dist/loader.d.ts +17 -1
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +84 -25
- package/dist/loader.js.map +1 -1
- package/dist/preset-command.d.ts +1 -1
- package/dist/preset-command.d.ts.map +1 -1
- package/dist/preset-command.js +38 -10
- package/dist/preset-command.js.map +1 -1
- package/dist/profile-command.d.ts.map +1 -1
- package/dist/profile-command.js +46 -21
- package/dist/profile-command.js.map +1 -1
- package/dist/profile-service.d.ts +6 -3
- package/dist/profile-service.d.ts.map +1 -1
- package/dist/profile-service.js +55 -13
- package/dist/profile-service.js.map +1 -1
- package/dist/resource-identity.d.ts +33 -0
- package/dist/resource-identity.d.ts.map +1 -0
- package/dist/resource-identity.js +56 -0
- package/dist/resource-identity.js.map +1 -0
- package/dist/runtime/profile-runtime.d.ts.map +1 -1
- package/dist/runtime/profile-runtime.js +7 -2
- package/dist/runtime/profile-runtime.js.map +1 -1
- package/dist/runtime/prompt-stack-runtime.d.ts +1 -1
- package/dist/runtime/prompt-stack-runtime.d.ts.map +1 -1
- package/dist/runtime/prompt-stack-runtime.js +22 -12
- package/dist/runtime/prompt-stack-runtime.js.map +1 -1
- package/dist/runtime/subagent-runtime.d.ts +23 -8
- package/dist/runtime/subagent-runtime.d.ts.map +1 -1
- package/dist/runtime/subagent-runtime.js +296 -67
- package/dist/runtime/subagent-runtime.js.map +1 -1
- package/dist/storage.d.ts +11 -0
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +51 -2
- package/dist/storage.js.map +1 -1
- package/dist/subagent/canonical.d.ts +19 -7
- package/dist/subagent/canonical.d.ts.map +1 -1
- package/dist/subagent/canonical.js +19 -47
- package/dist/subagent/canonical.js.map +1 -1
- package/dist/subagent/contract.d.ts +1 -2
- package/dist/subagent/contract.d.ts.map +1 -1
- package/dist/subagent/contract.js +1 -2
- package/dist/subagent/contract.js.map +1 -1
- package/dist/subagent/index.d.ts +4 -3
- package/dist/subagent/index.d.ts.map +1 -1
- package/dist/subagent/index.js +4 -3
- package/dist/subagent/index.js.map +1 -1
- package/dist/subagent/plan.d.ts +5 -1
- package/dist/subagent/plan.d.ts.map +1 -1
- package/dist/subagent/plan.js +29 -32
- package/dist/subagent/plan.js.map +1 -1
- package/dist/subagent/request.d.ts.map +1 -1
- package/dist/subagent/request.js +36 -4
- package/dist/subagent/request.js.map +1 -1
- package/dist/subagent/types.d.ts +66 -178
- package/dist/subagent/types.d.ts.map +1 -1
- package/dist/subagent/types.js +1 -1
- package/dist/subagent/types.js.map +1 -1
- package/dist/subagent/validation.d.ts +14 -14
- package/dist/subagent/validation.d.ts.map +1 -1
- package/dist/subagent/validation.js +52 -238
- package/dist/subagent/validation.js.map +1 -1
- package/dist/subagent-command.d.ts +2 -1
- package/dist/subagent-command.d.ts.map +1 -1
- package/dist/subagent-command.js +115 -19
- package/dist/subagent-command.js.map +1 -1
- package/dist/subagent-host.d.ts.map +1 -1
- package/dist/subagent-host.js +43 -16
- package/dist/subagent-host.js.map +1 -1
- package/dist/subagent-profile-tool.d.ts +25 -2
- package/dist/subagent-profile-tool.d.ts.map +1 -1
- package/dist/subagent-profile-tool.js +41 -9
- package/dist/subagent-profile-tool.js.map +1 -1
- package/dist/subagent-tool.d.ts +31 -4
- package/dist/subagent-tool.d.ts.map +1 -1
- package/dist/subagent-tool.js +311 -137
- package/dist/subagent-tool.js.map +1 -1
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/web-editor/client-script.generated.d.ts +1 -1
- package/dist/web-editor/client-script.generated.d.ts.map +1 -1
- package/dist/web-editor/client-script.generated.js +1 -1
- package/dist/web-editor/client-script.generated.js.map +1 -1
- package/dist/web-editor/client-styles.d.ts +2 -0
- package/dist/web-editor/client-styles.d.ts.map +1 -0
- package/dist/web-editor/client-styles.generated.d.ts +2 -0
- package/dist/web-editor/client-styles.generated.d.ts.map +1 -0
- package/dist/web-editor/client-styles.generated.js +3 -0
- package/dist/web-editor/client-styles.generated.js.map +1 -0
- package/dist/web-editor/client-styles.js +2 -0
- package/dist/web-editor/client-styles.js.map +1 -0
- package/dist/web-editor/page.d.ts +2 -0
- package/dist/web-editor/page.d.ts.map +1 -1
- package/dist/web-editor/page.js +11 -73
- package/dist/web-editor/page.js.map +1 -1
- package/dist/web-editor/server.d.ts.map +1 -1
- package/dist/web-editor/server.js +176 -1
- package/dist/web-editor/server.js.map +1 -1
- package/dist/web-editor/styles.d.ts.map +1 -1
- package/dist/web-editor/styles.js +60 -3
- package/dist/web-editor/styles.js.map +1 -1
- package/dist/web-editor/types.d.ts +87 -0
- package/dist/web-editor/types.d.ts.map +1 -1
- package/dist/web-host.d.ts +13 -2
- package/dist/web-host.d.ts.map +1 -1
- package/dist/web-host.js +371 -27
- package/dist/web-host.js.map +1 -1
- package/docs/README.md +41 -0
- package/docs/concepts/agent-profiles.md +60 -0
- package/docs/concepts/prompt-stacks.md +95 -0
- package/docs/design/README.md +17 -0
- package/docs/design/roadmap-0.4-archive.md +216 -0
- package/docs/design/subagents/design-review.md +220 -0
- package/docs/design/subagents/interface-design.md +274 -0
- package/docs/design/subagents/sdk-spike-findings.md +117 -0
- package/docs/development/complexity-review.md +86 -0
- package/docs/development/release.md +31 -0
- package/docs/development/roadmap.md +36 -0
- package/docs/development/scoped-global-profiles-stacks.md +325 -0
- package/docs/development/setup.md +75 -0
- package/docs/getting-started.md +95 -0
- package/docs/guides/custom-macros-and-slots.md +68 -0
- package/docs/guides/debugging.md +39 -0
- package/docs/guides/delegation.md +107 -0
- package/docs/guides/sillytavern-import.md +47 -0
- package/docs/guides/use-cases.md +65 -0
- package/docs/guides/web-editor.md +75 -0
- package/docs/reference/commands.md +60 -0
- package/docs/reference/configuration.md +66 -0
- package/docs/reference/features.md +280 -0
- package/docs/reference/macros-and-slots.md +82 -0
- package/docs/reference/public-api.md +28 -0
- package/docs/reference/stack-schema.md +167 -0
- package/docs/reference/subagent-adapter.md +204 -0
- package/docs/zh-CN/README.md +37 -0
- package/docs/zh-CN/concepts/agent-profiles.md +46 -0
- package/docs/zh-CN/concepts/prompt-stacks.md +42 -0
- package/docs/zh-CN/getting-started.md +81 -0
- package/docs/zh-CN/guides/delegation.md +66 -0
- package/docs/zh-CN/guides/web-editor.md +45 -0
- package/docs/zh-CN/reference/commands.md +60 -0
- package/package.json +29 -15
- package/dist/subagent/backend-registry.d.ts +0 -75
- package/dist/subagent/backend-registry.d.ts.map +0 -1
- package/dist/subagent/backend-registry.js +0 -463
- package/dist/subagent/backend-registry.js.map +0 -1
- package/dist/subagent/diagnostics.d.ts +0 -3
- package/dist/subagent/diagnostics.d.ts.map +0 -1
- package/dist/subagent/diagnostics.js +0 -5
- package/dist/subagent/diagnostics.js.map +0 -1
- package/dist/subagent/pi-model-runtime.d.ts +0 -8
- package/dist/subagent/pi-model-runtime.d.ts.map +0 -1
- package/dist/subagent/pi-model-runtime.js +0 -22
- package/dist/subagent/pi-model-runtime.js.map +0 -1
- package/dist/subagent/pi-sdk-backend.d.ts +0 -23
- package/dist/subagent/pi-sdk-backend.d.ts.map +0 -1
- package/dist/subagent/pi-sdk-backend.js +0 -383
- package/dist/subagent/pi-sdk-backend.js.map +0 -1
- package/dist/subagent/pi-subprocess-backend.d.ts +0 -72
- package/dist/subagent/pi-subprocess-backend.d.ts.map +0 -1
- package/dist/subagent/pi-subprocess-backend.js +0 -756
- package/dist/subagent/pi-subprocess-backend.js.map +0 -1
- package/dist/subagent/subprocess-bridge.d.ts +0 -21
- package/dist/subagent/subprocess-bridge.d.ts.map +0 -1
- package/dist/subagent/subprocess-bridge.js +0 -87
- package/dist/subagent/subprocess-bridge.js.map +0 -1
- package/dist/subagent/subprocess-report.d.ts +0 -4
- package/dist/subagent/subprocess-report.d.ts.map +0 -1
- package/dist/subagent/subprocess-report.js +0 -55
- package/dist/subagent/subprocess-report.js.map +0 -1
- package/dist/subagent-contract.d.ts +0 -8
- package/dist/subagent-contract.d.ts.map +0 -1
- package/dist/subagent-contract.js +0 -8
- package/dist/subagent-contract.js.map +0 -1
- package/dist/web-editor/client/api.d.ts +0 -9
- package/dist/web-editor/client/api.d.ts.map +0 -1
- package/dist/web-editor/client/api.js +0 -26
- package/dist/web-editor/client/api.js.map +0 -1
- package/dist/web-editor/client/dom.d.ts +0 -13
- package/dist/web-editor/client/dom.d.ts.map +0 -1
- package/dist/web-editor/client/dom.js +0 -30
- package/dist/web-editor/client/dom.js.map +0 -1
- package/dist/web-editor/client/inspector.d.ts +0 -22
- package/dist/web-editor/client/inspector.d.ts.map +0 -1
- package/dist/web-editor/client/inspector.js +0 -226
- package/dist/web-editor/client/inspector.js.map +0 -1
- package/dist/web-editor/client/main.d.ts +0 -2
- package/dist/web-editor/client/main.d.ts.map +0 -1
- package/dist/web-editor/client/main.js +0 -1468
- package/dist/web-editor/client/main.js.map +0 -1
- package/dist/web-editor/client/policy-editor.d.ts +0 -16
- package/dist/web-editor/client/policy-editor.d.ts.map +0 -1
- package/dist/web-editor/client/policy-editor.js +0 -330
- package/dist/web-editor/client/policy-editor.js.map +0 -1
- package/dist/web-editor/client/regex-editor.d.ts +0 -19
- package/dist/web-editor/client/regex-editor.d.ts.map +0 -1
- package/dist/web-editor/client/regex-editor.js +0 -281
- package/dist/web-editor/client/regex-editor.js.map +0 -1
- package/dist/web-editor/client/types.d.ts +0 -60
- package/dist/web-editor/client/types.d.ts.map +0 -1
- package/dist/web-editor/client/types.js +0 -2
- package/dist/web-editor/client/types.js.map +0 -1
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import type { AgentProfile, AgentProfileDiagnostic } from "../agent-profile.ts";
|
|
2
|
+
import type { AgentProfilePreview, AgentProfileRuntimeStatus } from "../profile-service.ts";
|
|
1
3
|
import type { PromptStack, PromptStackDiagnostic } from "../types.ts";
|
|
2
4
|
export interface WebEditorStackSummary {
|
|
3
5
|
id: string;
|
|
6
|
+
selector: string;
|
|
7
|
+
scope: "global" | "project";
|
|
4
8
|
name?: string;
|
|
5
9
|
filePath: string;
|
|
6
10
|
active: boolean;
|
|
@@ -14,6 +18,14 @@ export interface WebEditorStackSummary {
|
|
|
14
18
|
export interface WebEditorHost {
|
|
15
19
|
cwd: string;
|
|
16
20
|
listStacks(): WebEditorStackSummary[];
|
|
21
|
+
listProfiles(): WebEditorProfileCollection;
|
|
22
|
+
reloadProfiles(): Promise<WebEditorOperationResult<WebEditorProfileCollection>>;
|
|
23
|
+
validateProfile(profile: AgentProfile, existingId?: string, scope?: "global" | "project"): WebEditorProfileValidation;
|
|
24
|
+
createProfile(profile: AgentProfile, scope?: "global" | "project"): Promise<WebEditorOperationResult<WebEditorProfileMutation>>;
|
|
25
|
+
saveProfile(id: string, profile: AgentProfile): Promise<WebEditorOperationResult<WebEditorProfileMutation>>;
|
|
26
|
+
applyProfile(id: string): Promise<WebEditorOperationResult<WebEditorProfileMutation>>;
|
|
27
|
+
deleteProfile(id: string): Promise<WebEditorOperationResult<WebEditorProfileMutation>>;
|
|
28
|
+
updateSubagentPolicy(id: string, update: WebEditorSubagentPolicyUpdate): Promise<WebEditorOperationResult<WebEditorProfileMutation>>;
|
|
17
29
|
listResources(): WebEditorPolicyResources;
|
|
18
30
|
getStack(id: string): {
|
|
19
31
|
stack: PromptStack;
|
|
@@ -54,6 +66,79 @@ export interface WebEditorHost {
|
|
|
54
66
|
stacks: WebEditorStackSummary[];
|
|
55
67
|
}>>;
|
|
56
68
|
}
|
|
69
|
+
export interface WebEditorProfileEntry {
|
|
70
|
+
profile: AgentProfile;
|
|
71
|
+
filePath: string;
|
|
72
|
+
selector: string;
|
|
73
|
+
scope: "global" | "project";
|
|
74
|
+
preview: AgentProfilePreview;
|
|
75
|
+
errors: number;
|
|
76
|
+
warnings: number;
|
|
77
|
+
lastApplied: boolean;
|
|
78
|
+
subagent: WebEditorSubagentProfilePolicy;
|
|
79
|
+
}
|
|
80
|
+
export interface WebEditorSubagentBackendOption {
|
|
81
|
+
id: string;
|
|
82
|
+
version: string;
|
|
83
|
+
}
|
|
84
|
+
export interface WebEditorSubagentProfilePolicy {
|
|
85
|
+
enabled: boolean;
|
|
86
|
+
enabledSource: "project-profile" | "global-profile" | "built-in";
|
|
87
|
+
backend: string;
|
|
88
|
+
backendSource: string;
|
|
89
|
+
backendRegistered: boolean;
|
|
90
|
+
timeoutMs: number;
|
|
91
|
+
timeoutSource: string;
|
|
92
|
+
configured: {
|
|
93
|
+
enabled?: boolean;
|
|
94
|
+
backend?: string;
|
|
95
|
+
timeoutMs?: number;
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
export interface WebEditorSubagentSummary {
|
|
99
|
+
defaultBackend: string;
|
|
100
|
+
defaultBackendSource: string;
|
|
101
|
+
timeoutMs: number;
|
|
102
|
+
timeoutSource: string;
|
|
103
|
+
allowAgentInvocationWithoutApproval: boolean;
|
|
104
|
+
backends: WebEditorSubagentBackendOption[];
|
|
105
|
+
warnings: string[];
|
|
106
|
+
}
|
|
107
|
+
export interface WebEditorSubagentPolicyUpdate {
|
|
108
|
+
enabled?: boolean;
|
|
109
|
+
backend?: string | null;
|
|
110
|
+
timeoutMs?: number | null;
|
|
111
|
+
}
|
|
112
|
+
export interface WebEditorProfileCollection {
|
|
113
|
+
trusted: boolean;
|
|
114
|
+
profileDirectory: string;
|
|
115
|
+
profiles: WebEditorProfileEntry[];
|
|
116
|
+
status: AgentProfileRuntimeStatus;
|
|
117
|
+
models: WebEditorProfileModelOption[];
|
|
118
|
+
promptStacks: Array<{
|
|
119
|
+
id: string;
|
|
120
|
+
name?: string;
|
|
121
|
+
selector: string;
|
|
122
|
+
scope: "global" | "project";
|
|
123
|
+
}>;
|
|
124
|
+
subagents: WebEditorSubagentSummary;
|
|
125
|
+
}
|
|
126
|
+
export interface WebEditorProfileModelOption {
|
|
127
|
+
provider: string;
|
|
128
|
+
id: string;
|
|
129
|
+
name?: string;
|
|
130
|
+
available: boolean;
|
|
131
|
+
}
|
|
132
|
+
export interface WebEditorProfileValidation {
|
|
133
|
+
preview: AgentProfilePreview;
|
|
134
|
+
diagnostics: AgentProfileDiagnostic[];
|
|
135
|
+
errors: number;
|
|
136
|
+
warnings: number;
|
|
137
|
+
}
|
|
138
|
+
export interface WebEditorProfileMutation {
|
|
139
|
+
collection: WebEditorProfileCollection;
|
|
140
|
+
selectedPath: string;
|
|
141
|
+
}
|
|
57
142
|
export interface WebEditorPreviewSection {
|
|
58
143
|
id: string;
|
|
59
144
|
title: string;
|
|
@@ -94,6 +179,8 @@ export type WebEditorPayloadSnapshot = {
|
|
|
94
179
|
export interface WebEditorCreateStackOptions {
|
|
95
180
|
activate?: boolean;
|
|
96
181
|
overwrite?: boolean;
|
|
182
|
+
/** Explicit target scope. Defaults to project for unqualified web create routes. */
|
|
183
|
+
scope?: "global" | "project";
|
|
97
184
|
}
|
|
98
185
|
export interface WebEditorPolicyResource {
|
|
99
186
|
name: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/web-editor/types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/web-editor/types.ts"],"names":[],"mappings":"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"}
|
package/dist/web-host.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import type
|
|
3
|
-
import
|
|
2
|
+
import { type AgentProfileProvenance, type LoadedAgentProfile, type ResolvedAgentProfile } from "./agent-profile.ts";
|
|
3
|
+
import { type AgentProfileApplicationResult, type AgentProfileCurrentRuntime } from "./profile-service.ts";
|
|
4
|
+
import type { LoadedPromptStack, PromptStack, PromptStackDiagnostic } from "./types.ts";
|
|
5
|
+
import type { WebEditorHost, WebEditorOperationResult, WebEditorPayloadSnapshot, WebEditorPolicyResources, WebEditorPreview, WebEditorStackSummary, WebEditorSubagentBackendOption } from "./web-editor/index.ts";
|
|
4
6
|
export interface WebHostRuntime {
|
|
5
7
|
getStacks(): LoadedPromptStack[];
|
|
6
8
|
getActive(): LoadedPromptStack | undefined;
|
|
@@ -14,6 +16,15 @@ export interface WebHostRuntime {
|
|
|
14
16
|
diagnostics: PromptStackDiagnostic[];
|
|
15
17
|
};
|
|
16
18
|
getPolicyResources(): WebEditorPolicyResources;
|
|
19
|
+
getProfiles(): LoadedAgentProfile[];
|
|
20
|
+
getLastAppliedProfile(): AgentProfileProvenance | undefined;
|
|
21
|
+
getCurrentProfileRuntime(): AgentProfileCurrentRuntime;
|
|
22
|
+
getSubagentBackends(): WebEditorSubagentBackendOption[];
|
|
23
|
+
resolveProfile(target: LoadedAgentProfile): ResolvedAgentProfile;
|
|
24
|
+
previewToolNames(stack: PromptStack | undefined): string[];
|
|
25
|
+
reloadProfiles(): void | Promise<void>;
|
|
26
|
+
isIdle(): boolean;
|
|
27
|
+
applyProfile(target: ResolvedAgentProfile): Promise<AgentProfileApplicationResult>;
|
|
17
28
|
getPayload(): WebEditorOperationResult<WebEditorPayloadSnapshot>;
|
|
18
29
|
armPayload(savePath?: string): WebEditorOperationResult<WebEditorPayloadSnapshot>;
|
|
19
30
|
clearPayload(): WebEditorOperationResult<WebEditorPayloadSnapshot>;
|
package/dist/web-host.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web-host.d.ts","sourceRoot":"","sources":["../src/web-host.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"web-host.d.ts","sourceRoot":"","sources":["../src/web-host.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAON,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,MAAM,oBAAoB,CAAC;AAoB5B,OAAO,EAKN,KAAK,6BAA6B,EAClC,KAAK,0BAA0B,EAC/B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACxF,OAAO,KAAK,EAEX,aAAa,EACb,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,EACxB,gBAAgB,EAIhB,qBAAqB,EACrB,8BAA8B,EAG9B,MAAM,uBAAuB,CAAC;AAE/B,MAAM,WAAW,cAAc;IAC9B,SAAS,IAAI,iBAAiB,EAAE,CAAC;IACjC,SAAS,IAAI,iBAAiB,GAAG,SAAS,CAAC;IAC3C,WAAW,IAAI,MAAM,GAAG,SAAS,CAAC;IAClC,mBAAmB,IAAI,MAAM,GAAG,SAAS,CAAC;IAC1C,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;IAC3C,YAAY,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,YAAY,CAAC,MAAM,EAAE,iBAAiB,GAAG;QACxC,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,gBAAgB,CAAC;QAC1B,WAAW,EAAE,qBAAqB,EAAE,CAAC;KACrC,CAAC;IACF,kBAAkB,IAAI,wBAAwB,CAAC;IAC/C,WAAW,IAAI,kBAAkB,EAAE,CAAC;IACpC,qBAAqB,IAAI,sBAAsB,GAAG,SAAS,CAAC;IAC5D,wBAAwB,IAAI,0BAA0B,CAAC;IACvD,mBAAmB,IAAI,8BAA8B,EAAE,CAAC;IACxD,cAAc,CAAC,MAAM,EAAE,kBAAkB,GAAG,oBAAoB,CAAC;IACjE,gBAAgB,CAAC,KAAK,EAAE,WAAW,GAAG,SAAS,GAAG,MAAM,EAAE,CAAC;IAC3D,cAAc,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,IAAI,OAAO,CAAC;IAClB,YAAY,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,6BAA6B,CAAC,CAAC;IACnF,UAAU,IAAI,wBAAwB,CAAC,wBAAwB,CAAC,CAAC;IACjE,UAAU,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,wBAAwB,CAAC,wBAAwB,CAAC,CAAC;IAClF,YAAY,IAAI,wBAAwB,CAAC,wBAAwB,CAAC,CAAC;CACnE;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,gBAAgB,EAAE,OAAO,EAAE,cAAc,GAAG,aAAa,CA+CjG;AAwWD,wBAAgB,YAAY,CAAC,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAE,iBAAiB,GAAG,SAAS,GAAG,qBAAqB,CAiBpH;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,iBAAiB,EAAE,EAAE,MAAM,EAAE,iBAAiB,GAAG,SAAS,GAAG,qBAAqB,EAAE,CAE1H;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,gBAAgB,GAAG;IAAE,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAmC/H"}
|
package/dist/web-host.js
CHANGED
|
@@ -1,13 +1,30 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import { agentProfilePath, agentProfilesDir, isResolvedAgentProfileUsable, validateAgentProfile, validateAgentProfilePromptStackScope, } from "./agent-profile.js";
|
|
4
|
+
import { DEFAULT_SUBAGENT_BACKEND_ID, loadForgeSubagentSettings, resolveSubagentProfilePolicy, updateForgeSubagentProfileConfig, } from "./forge-config.js";
|
|
5
|
+
import { isSafeGlobalPromptStackMutationPath, isSafePromptStackMutationPath, isValidPromptStackId, promptStackPath, validatePromptStack, } from "./loader.js";
|
|
6
|
+
import { globalAgentProfilePath, globalPromptStacksDir } from "./storage.js";
|
|
7
|
+
import { formatResourceKey, parseResourceSelector } from "./resource-identity.js";
|
|
8
|
+
import { resolveResourceSelector } from "./catalog.js";
|
|
9
|
+
import { createAgentProfilePreview, deleteAgentProfile, getAgentProfileRuntimeStatus, writeAgentProfile, } from "./profile-service.js";
|
|
4
10
|
export function createWebEditorHost(ctx, runtime) {
|
|
5
11
|
return {
|
|
6
12
|
cwd: ctx.cwd,
|
|
7
13
|
listStacks: () => stackSummaries(runtime.getStacks(), runtime.getActive()),
|
|
14
|
+
listProfiles: () => profileCollection(ctx, runtime),
|
|
15
|
+
reloadProfiles: async () => {
|
|
16
|
+
await runtime.reloadProfiles();
|
|
17
|
+
return { ok: true, ...profileCollection(ctx, runtime) };
|
|
18
|
+
},
|
|
19
|
+
validateProfile: (profile, existingId, scope) => profileValidation(ctx, runtime, profile, existingId, scope),
|
|
20
|
+
createProfile: (profile, scope) => createProfileFile(ctx, runtime, profile, scope),
|
|
21
|
+
saveProfile: (selector, profile) => saveProfileFile(ctx, runtime, selector, profile),
|
|
22
|
+
applyProfile: (selector) => applyProfileRuntime(ctx, runtime, selector),
|
|
23
|
+
deleteProfile: (selector) => deleteProfileFile(ctx, runtime, selector),
|
|
24
|
+
updateSubagentPolicy: (selector, update) => updateSubagentPolicy(ctx, runtime, selector, update),
|
|
8
25
|
listResources: () => runtime.getPolicyResources(),
|
|
9
|
-
getStack: (
|
|
10
|
-
const loaded = runtime
|
|
26
|
+
getStack: (selector) => {
|
|
27
|
+
const loaded = resolveStack(runtime, selector);
|
|
11
28
|
return loaded ? { stack: loaded.stack, filePath: loaded.filePath, diagnostics: loaded.diagnostics } : undefined;
|
|
12
29
|
},
|
|
13
30
|
createStack: (stack, options) => createStackFile(ctx, runtime, stack, options),
|
|
@@ -15,19 +32,19 @@ export function createWebEditorHost(ctx, runtime) {
|
|
|
15
32
|
deleteStack: (id) => deleteStackFile(ctx, runtime, id),
|
|
16
33
|
validateStack: (stack) => validatePromptStack(stack),
|
|
17
34
|
previewStack: (id, stack) => {
|
|
18
|
-
const target = runtime
|
|
35
|
+
const target = resolveStack(runtime, id);
|
|
19
36
|
if (!target)
|
|
20
37
|
return { ok: false, status: 404, error: `Unknown prompt stack: ${id}` };
|
|
21
38
|
const diagnostics = validatePromptStack(stack);
|
|
22
|
-
const preview = runtime.buildPreview({ stack, filePath: target.filePath, diagnostics });
|
|
39
|
+
const preview = runtime.buildPreview({ stack, filePath: target.filePath, scope: target.scope, key: target.key, diagnostics });
|
|
23
40
|
return { ok: true, text: preview.text, preview: preview.preview, diagnostics: preview.diagnostics };
|
|
24
41
|
},
|
|
25
42
|
getPayload: () => runtime.getPayload(),
|
|
26
43
|
armPayload: (savePath) => runtime.armPayload(savePath),
|
|
27
44
|
clearPayload: () => runtime.clearPayload(),
|
|
28
|
-
activateStack: (
|
|
29
|
-
if (!runtime.setActive(
|
|
30
|
-
return { ok: false, status: 404, error: `Unknown prompt stack: ${
|
|
45
|
+
activateStack: (selector) => {
|
|
46
|
+
if (!runtime.setActive(selector))
|
|
47
|
+
return { ok: false, status: 404, error: `Unknown prompt stack: ${selector}` };
|
|
31
48
|
return { ok: true, activeId: runtime.getActiveId(), stacks: stackSummaries(runtime.getStacks(), runtime.getActive()) };
|
|
32
49
|
},
|
|
33
50
|
disableStacks: () => {
|
|
@@ -40,11 +57,322 @@ export function createWebEditorHost(ctx, runtime) {
|
|
|
40
57
|
},
|
|
41
58
|
};
|
|
42
59
|
}
|
|
60
|
+
/** Unqualified selectors address project profiles only; global profiles require `global:<id>`. */
|
|
61
|
+
function resolveProfilesForMutation(runtime, selector) {
|
|
62
|
+
const parsed = parseResourceSelector(selector);
|
|
63
|
+
if (!parsed.ok)
|
|
64
|
+
return [];
|
|
65
|
+
const scope = parsed.selector.scope ?? "project";
|
|
66
|
+
return runtime.getProfiles().filter((loaded) => loaded.scope === scope && loaded.profile.id === parsed.selector.id);
|
|
67
|
+
}
|
|
68
|
+
function profileCollection(ctx, runtime) {
|
|
69
|
+
const profiles = runtime.getProfiles();
|
|
70
|
+
const current = runtime.getCurrentProfileRuntime();
|
|
71
|
+
const lastApplied = runtime.getLastAppliedProfile();
|
|
72
|
+
const availableModels = new Set(ctx.modelRegistry.getAvailable().map((model) => modelKey(model.provider, model.id)));
|
|
73
|
+
const subagentSettings = loadForgeSubagentSettings(ctx);
|
|
74
|
+
const subagentBackends = runtime.getSubagentBackends();
|
|
75
|
+
const registeredBackends = new Set(subagentBackends.map((backend) => backend.id));
|
|
76
|
+
return {
|
|
77
|
+
trusted: ctx.isProjectTrusted(),
|
|
78
|
+
profileDirectory: agentProfilesDir(ctx.cwd),
|
|
79
|
+
profiles: profiles.map((loaded) => {
|
|
80
|
+
const resolved = runtime.resolveProfile(loaded);
|
|
81
|
+
const targetEffectiveTools = resolved.promptStack || resolved.loaded.profile.promptStack === null
|
|
82
|
+
? runtime.previewToolNames(resolved.promptStack?.stack)
|
|
83
|
+
: [];
|
|
84
|
+
const preview = createAgentProfilePreview(resolved, current, targetEffectiveTools);
|
|
85
|
+
return {
|
|
86
|
+
profile: structuredClone(loaded.profile),
|
|
87
|
+
filePath: loaded.filePath,
|
|
88
|
+
selector: formatResourceKey(loaded.key),
|
|
89
|
+
scope: loaded.scope,
|
|
90
|
+
preview,
|
|
91
|
+
errors: preview.diagnostics.filter((diagnostic) => diagnostic.level === "error").length,
|
|
92
|
+
warnings: preview.diagnostics.filter((diagnostic) => diagnostic.level === "warning").length,
|
|
93
|
+
lastApplied: lastApplied?.sourcePath === loaded.filePath,
|
|
94
|
+
subagent: subagentPolicySummary(subagentSettings, loaded, registeredBackends),
|
|
95
|
+
};
|
|
96
|
+
}),
|
|
97
|
+
status: getAgentProfileRuntimeStatus(profiles, lastApplied, current),
|
|
98
|
+
models: ctx.modelRegistry.getAll().map((model) => ({
|
|
99
|
+
provider: model.provider,
|
|
100
|
+
id: model.id,
|
|
101
|
+
name: model.name,
|
|
102
|
+
available: availableModels.has(modelKey(model.provider, model.id)),
|
|
103
|
+
})),
|
|
104
|
+
promptStacks: runtime.getStacks().map((loaded) => ({
|
|
105
|
+
id: loaded.stack.id,
|
|
106
|
+
name: loaded.stack.name,
|
|
107
|
+
selector: formatResourceKey(loaded.key),
|
|
108
|
+
scope: loaded.scope,
|
|
109
|
+
})),
|
|
110
|
+
subagents: {
|
|
111
|
+
defaultBackend: subagentSettings.backend ?? DEFAULT_SUBAGENT_BACKEND_ID,
|
|
112
|
+
defaultBackendSource: subagentSettings.backendSource ?? "built-in",
|
|
113
|
+
timeoutMs: subagentSettings.timeoutMs,
|
|
114
|
+
timeoutSource: subagentSettings.timeoutSource,
|
|
115
|
+
allowAgentInvocationWithoutApproval: subagentSettings.allowAgentInvocationWithoutApproval,
|
|
116
|
+
backends: subagentBackends,
|
|
117
|
+
warnings: [...subagentSettings.warnings],
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function subagentPolicySummary(settings, loaded, registeredBackends) {
|
|
122
|
+
const selector = formatResourceKey(loaded.key);
|
|
123
|
+
const policy = resolveSubagentProfilePolicy(settings, selector);
|
|
124
|
+
const configured = settings.profiles[selector];
|
|
125
|
+
return {
|
|
126
|
+
enabled: policy.enabled,
|
|
127
|
+
enabledSource: policy.enabledSource,
|
|
128
|
+
backend: policy.backend.id,
|
|
129
|
+
backendSource: policy.backend.source,
|
|
130
|
+
backendRegistered: registeredBackends.has(policy.backend.id),
|
|
131
|
+
timeoutMs: policy.timeout.milliseconds,
|
|
132
|
+
timeoutSource: policy.timeout.source,
|
|
133
|
+
configured: configuredSubagentProfile(configured),
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function configuredSubagentProfile(configured) {
|
|
137
|
+
if (!configured)
|
|
138
|
+
return {};
|
|
139
|
+
return {
|
|
140
|
+
enabled: configured.enabled,
|
|
141
|
+
backend: configured.backend,
|
|
142
|
+
timeoutMs: configured.timeoutMs,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
function profileValidation(ctx, runtime, profile, existingId, validationScope) {
|
|
146
|
+
const profiles = runtime.getProfiles();
|
|
147
|
+
const existingSelector = existingId ? parseResourceSelector(existingId) : undefined;
|
|
148
|
+
const existingMatches = existingSelector?.ok
|
|
149
|
+
? profiles.filter((loaded) => loaded.scope === (existingSelector.selector.scope ?? "project") && loaded.profile.id === existingSelector.selector.id)
|
|
150
|
+
: [];
|
|
151
|
+
const existing = existingMatches.length === 1 ? existingMatches[0] : undefined;
|
|
152
|
+
const scope = existing?.scope ?? validationScope ?? "project";
|
|
153
|
+
const filePath = existing?.filePath ?? (scope === "global" ? globalAgentProfilePath(profile.id) : agentProfilePath(ctx.cwd, profile.id));
|
|
154
|
+
const diagnostics = [
|
|
155
|
+
...validateAgentProfile(profile),
|
|
156
|
+
...validateAgentProfilePromptStackScope(profile, scope),
|
|
157
|
+
];
|
|
158
|
+
const otherProfiles = existing
|
|
159
|
+
? profiles.filter((loaded) => loaded.scope === scope && loaded.filePath !== filePath)
|
|
160
|
+
: profiles.filter((loaded) => loaded.scope === scope);
|
|
161
|
+
if (otherProfiles.some((loaded) => loaded.profile.id === profile.id)) {
|
|
162
|
+
diagnostics.push({
|
|
163
|
+
level: "error",
|
|
164
|
+
field: "id",
|
|
165
|
+
message: `Duplicate profile id: ${profile.id} already exists in another file.`,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
if (!existing && existsSync(filePath)) {
|
|
169
|
+
diagnostics.push({
|
|
170
|
+
level: "error",
|
|
171
|
+
field: "id",
|
|
172
|
+
message: `Profile file already exists: ${filePath}`,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
if (profile.autoActivate && otherProfiles.some((loaded) => loaded.profile.autoActivate === true)) {
|
|
176
|
+
diagnostics.push({
|
|
177
|
+
level: "error",
|
|
178
|
+
field: "autoActivate",
|
|
179
|
+
message: "Multiple profiles request auto-activation; exactly one is allowed.",
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
const resolved = runtime.resolveProfile({ profile, filePath, scope, key: { scope, id: profile.id }, diagnostics });
|
|
183
|
+
const targetEffectiveTools = resolved.promptStack || profile.promptStack === null
|
|
184
|
+
? runtime.previewToolNames(resolved.promptStack?.stack)
|
|
185
|
+
: [];
|
|
186
|
+
const preview = createAgentProfilePreview(resolved, runtime.getCurrentProfileRuntime(), targetEffectiveTools);
|
|
187
|
+
return {
|
|
188
|
+
preview,
|
|
189
|
+
diagnostics: preview.diagnostics,
|
|
190
|
+
errors: preview.diagnostics.filter((diagnostic) => diagnostic.level === "error").length,
|
|
191
|
+
warnings: preview.diagnostics.filter((diagnostic) => diagnostic.level === "warning").length,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
async function createProfileFile(ctx, runtime, profile, scope = "project") {
|
|
195
|
+
if (!ctx.isProjectTrusted()) {
|
|
196
|
+
return { ok: false, status: 403, error: "Project is not trusted; refusing to create agent profiles." };
|
|
197
|
+
}
|
|
198
|
+
if (runtime.getProfiles().some((loaded) => loaded.scope === scope && loaded.profile.id === profile.id)) {
|
|
199
|
+
return { ok: false, status: 409, error: `Agent profile already exists: ${profile.id}` };
|
|
200
|
+
}
|
|
201
|
+
const conflict = autoActivateConflictError(runtime.getProfiles(), profile, scope);
|
|
202
|
+
if (conflict)
|
|
203
|
+
return { ok: false, status: 409, error: conflict };
|
|
204
|
+
const result = writeAgentProfile(ctx.cwd, profile, { scope });
|
|
205
|
+
if (!result.ok)
|
|
206
|
+
return profileWriteError(profile.id, result);
|
|
207
|
+
await runtime.reloadProfiles();
|
|
208
|
+
return {
|
|
209
|
+
ok: true,
|
|
210
|
+
collection: profileCollection(ctx, runtime),
|
|
211
|
+
selectedPath: result.filePath,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
async function saveProfileFile(ctx, runtime, id, profile) {
|
|
215
|
+
if (!ctx.isProjectTrusted()) {
|
|
216
|
+
return { ok: false, status: 403, error: "Project is not trusted; refusing to save agent profiles." };
|
|
217
|
+
}
|
|
218
|
+
const matches = resolveProfilesForMutation(runtime, id);
|
|
219
|
+
if (matches.length === 0)
|
|
220
|
+
return { ok: false, status: 404, error: `Unknown agent profile: ${id}` };
|
|
221
|
+
if (matches.length > 1) {
|
|
222
|
+
return { ok: false, status: 409, error: `Cannot save agent profile ${id} while duplicate profile ids exist.` };
|
|
223
|
+
}
|
|
224
|
+
if (profile.id !== matches[0].profile.id) {
|
|
225
|
+
return { ok: false, status: 400, error: "Profile id is immutable during save; create a new profile to use a different id." };
|
|
226
|
+
}
|
|
227
|
+
const conflict = autoActivateConflictError(runtime.getProfiles(), profile, matches[0].scope, matches[0].profile.id);
|
|
228
|
+
if (conflict)
|
|
229
|
+
return { ok: false, status: 409, error: conflict };
|
|
230
|
+
const result = writeAgentProfile(ctx.cwd, profile, {
|
|
231
|
+
filePath: matches[0].filePath,
|
|
232
|
+
overwrite: true,
|
|
233
|
+
scope: matches[0].scope,
|
|
234
|
+
});
|
|
235
|
+
if (!result.ok)
|
|
236
|
+
return profileWriteError(id, result);
|
|
237
|
+
await runtime.reloadProfiles();
|
|
238
|
+
return {
|
|
239
|
+
ok: true,
|
|
240
|
+
collection: profileCollection(ctx, runtime),
|
|
241
|
+
selectedPath: result.filePath,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
async function updateSubagentPolicy(ctx, runtime, id, update) {
|
|
245
|
+
if (!ctx.isProjectTrusted()) {
|
|
246
|
+
return { ok: false, status: 403, error: "Project is not trusted; refusing to change subagent delegation." };
|
|
247
|
+
}
|
|
248
|
+
const matches = resolveProfilesForMutation(runtime, id);
|
|
249
|
+
if (matches.length === 0)
|
|
250
|
+
return { ok: false, status: 404, error: `Unknown agent profile: ${id}` };
|
|
251
|
+
if (matches.length > 1) {
|
|
252
|
+
return { ok: false, status: 409, error: `Cannot configure subagent delegation for ${id} while duplicate profile ids exist.` };
|
|
253
|
+
}
|
|
254
|
+
const result = updateForgeSubagentProfileConfig(ctx.cwd, matches[0].profile.id, update, { scope: matches[0].scope });
|
|
255
|
+
if (!result.ok)
|
|
256
|
+
return { ok: false, status: 400, error: result.error };
|
|
257
|
+
return {
|
|
258
|
+
ok: true,
|
|
259
|
+
collection: profileCollection(ctx, runtime),
|
|
260
|
+
selectedPath: matches[0].filePath,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
function autoActivateConflictError(profiles, profile, scope, excludeId) {
|
|
264
|
+
if (profile.autoActivate !== true)
|
|
265
|
+
return undefined;
|
|
266
|
+
const conflict = profiles.find((loaded) => loaded.scope === scope && loaded.profile.autoActivate === true && loaded.profile.id !== excludeId);
|
|
267
|
+
return conflict
|
|
268
|
+
? `Multiple ${scope} profiles request auto-activation; exactly one is allowed (already requested by ${conflict.profile.id}).`
|
|
269
|
+
: undefined;
|
|
270
|
+
}
|
|
271
|
+
async function applyProfileRuntime(ctx, runtime, id) {
|
|
272
|
+
if (!ctx.isProjectTrusted()) {
|
|
273
|
+
return { ok: false, status: 403, error: "Project is not trusted; refusing to apply agent profiles." };
|
|
274
|
+
}
|
|
275
|
+
if (!runtime.isIdle()) {
|
|
276
|
+
return { ok: false, status: 409, error: "Wait for the current agent operation to finish before applying a profile." };
|
|
277
|
+
}
|
|
278
|
+
const matches = resolveProfilesForMutation(runtime, id);
|
|
279
|
+
if (matches.length === 0)
|
|
280
|
+
return { ok: false, status: 404, error: `Unknown agent profile: ${id}` };
|
|
281
|
+
if (matches.length > 1) {
|
|
282
|
+
return { ok: false, status: 409, error: `Cannot apply agent profile ${id} while duplicate profile ids exist.` };
|
|
283
|
+
}
|
|
284
|
+
const resolved = runtime.resolveProfile(matches[0]);
|
|
285
|
+
if (!isResolvedAgentProfileUsable(resolved) || !resolved.model) {
|
|
286
|
+
return { ok: false, status: 400, error: `Agent profile ${id} failed preflight; runtime state was not changed.` };
|
|
287
|
+
}
|
|
288
|
+
const result = await runtime.applyProfile(resolved);
|
|
289
|
+
if (!result.ok) {
|
|
290
|
+
const rollback = result.rollbackErrors.length
|
|
291
|
+
? ` Rollback problems: ${result.rollbackErrors.join("; ")}.`
|
|
292
|
+
: " Previous runtime state was restored.";
|
|
293
|
+
return { ok: false, status: 500, error: `${result.detail}${result.detail.endsWith(".") ? "" : "."}${rollback}` };
|
|
294
|
+
}
|
|
295
|
+
return {
|
|
296
|
+
ok: true,
|
|
297
|
+
collection: profileCollection(ctx, runtime),
|
|
298
|
+
selectedPath: matches[0].filePath,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
async function deleteProfileFile(ctx, runtime, id) {
|
|
302
|
+
if (!ctx.isProjectTrusted()) {
|
|
303
|
+
return { ok: false, status: 403, error: "Project is not trusted; refusing to delete agent profiles." };
|
|
304
|
+
}
|
|
305
|
+
const matches = resolveProfilesForMutation(runtime, id);
|
|
306
|
+
if (matches.length === 0)
|
|
307
|
+
return { ok: false, status: 404, error: `Unknown agent profile: ${id}` };
|
|
308
|
+
if (matches.length > 1) {
|
|
309
|
+
return { ok: false, status: 409, error: `Cannot delete agent profile ${id} while duplicate profile ids exist.` };
|
|
310
|
+
}
|
|
311
|
+
const subagentSettings = loadForgeSubagentSettings(ctx);
|
|
312
|
+
const result = deleteAgentProfile(ctx.cwd, matches[0]);
|
|
313
|
+
if (!result.ok) {
|
|
314
|
+
if (result.reason === "invalid-path")
|
|
315
|
+
return { ok: false, status: 403, error: "Refusing to delete outside agent-profile storage." };
|
|
316
|
+
if (result.reason === "missing")
|
|
317
|
+
return { ok: false, status: 404, error: `Agent profile file is missing: ${result.filePath}` };
|
|
318
|
+
if (result.reason === "changed") {
|
|
319
|
+
return { ok: false, status: 409, error: `Agent profile ${id} changed on disk; refresh before deleting it.` };
|
|
320
|
+
}
|
|
321
|
+
return { ok: false, status: 500, error: result.error ?? `Failed to delete agent profile ${id}.` };
|
|
322
|
+
}
|
|
323
|
+
if (Object.hasOwn(subagentSettings.profiles, formatResourceKey(matches[0].key))) {
|
|
324
|
+
const cleared = updateForgeSubagentProfileConfig(ctx.cwd, matches[0].profile.id, {
|
|
325
|
+
enabled: false,
|
|
326
|
+
backend: null,
|
|
327
|
+
timeoutMs: null,
|
|
328
|
+
}, { scope: matches[0].scope });
|
|
329
|
+
if (!cleared.ok) {
|
|
330
|
+
await runtime.reloadProfiles();
|
|
331
|
+
return {
|
|
332
|
+
ok: false,
|
|
333
|
+
status: 500,
|
|
334
|
+
error: `Deleted agent profile ${id}, but failed to remove its delegation settings: ${cleared.error}`,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
await runtime.reloadProfiles();
|
|
339
|
+
const collection = profileCollection(ctx, runtime);
|
|
340
|
+
return {
|
|
341
|
+
ok: true,
|
|
342
|
+
collection,
|
|
343
|
+
selectedPath: collection.profiles[0]?.filePath ?? "",
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
function profileWriteError(id, result) {
|
|
347
|
+
if (result.reason === "exists")
|
|
348
|
+
return { ok: false, status: 409, error: `Agent profile already exists: ${id}` };
|
|
349
|
+
if (result.reason === "invalid-path")
|
|
350
|
+
return { ok: false, status: 403, error: result.error ?? "Refusing to write outside agent-profile storage." };
|
|
351
|
+
if (result.reason === "validation") {
|
|
352
|
+
return {
|
|
353
|
+
ok: false,
|
|
354
|
+
status: 400,
|
|
355
|
+
error: result.diagnostics.map((diagnostic) => diagnostic.message).join(" "),
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
return { ok: false, status: 500, error: result.error ?? `Failed to write agent profile ${id}.` };
|
|
359
|
+
}
|
|
360
|
+
function modelKey(provider, id) {
|
|
361
|
+
return `${provider}\0${id}`;
|
|
362
|
+
}
|
|
363
|
+
function resolveStack(runtime, selector) {
|
|
364
|
+
const parsed = parseResourceSelector(selector);
|
|
365
|
+
if (!parsed.ok)
|
|
366
|
+
return undefined;
|
|
367
|
+
return resolveResourceSelector(runtime.getStacks(), parsed.selector);
|
|
368
|
+
}
|
|
43
369
|
export function stackSummary(loaded, active) {
|
|
44
370
|
const errors = loaded.diagnostics.filter((d) => d.level === "error").length;
|
|
45
371
|
const warnings = loaded.diagnostics.filter((d) => d.level === "warning").length;
|
|
46
372
|
return {
|
|
47
373
|
id: loaded.stack.id,
|
|
374
|
+
selector: formatResourceKey(loaded.key),
|
|
375
|
+
scope: loaded.scope,
|
|
48
376
|
name: loaded.stack.name,
|
|
49
377
|
filePath: loaded.filePath,
|
|
50
378
|
active: loaded === active,
|
|
@@ -96,22 +424,26 @@ async function saveStackFile(ctx, runtime, id, stack) {
|
|
|
96
424
|
if (!ctx.isProjectTrusted()) {
|
|
97
425
|
return { ok: false, status: 403, error: "Project is not trusted; refusing to save prompt stacks." };
|
|
98
426
|
}
|
|
99
|
-
const target = runtime
|
|
427
|
+
const target = resolveStack(runtime, id);
|
|
100
428
|
if (!target)
|
|
101
429
|
return { ok: false, status: 404, error: `Unknown prompt stack: ${id}` };
|
|
102
430
|
const idError = validateWebStackId(stack.id);
|
|
103
431
|
if (idError)
|
|
104
432
|
return { ok: false, status: 400, error: idError };
|
|
105
|
-
if (stack.id !== id) {
|
|
433
|
+
if (stack.id !== target.stack.id) {
|
|
106
434
|
return { ok: false, status: 400, error: "Stack id is immutable during save; fork the stack to create a new id." };
|
|
107
435
|
}
|
|
108
|
-
|
|
109
|
-
|
|
436
|
+
const safe = target.scope === "project"
|
|
437
|
+
? isSafePromptStackMutationPath(ctx.cwd, target.filePath)
|
|
438
|
+
: isSafeGlobalPromptStackMutationPath(target.filePath);
|
|
439
|
+
if (!safe) {
|
|
440
|
+
return { ok: false, status: 403, error: "Refusing to save outside prompt-stack storage or through a symbolic link." };
|
|
110
441
|
}
|
|
111
442
|
writeFileSync(target.filePath, `${JSON.stringify(stack, null, 2)}\n`, "utf8");
|
|
112
|
-
const preferredId = runtime.getActive()
|
|
443
|
+
const preferredId = runtime.getActive() === target ? formatResourceKey(target.key) : runtime.getSelectedActiveId();
|
|
113
444
|
await runtime.reloadStacks(preferredId);
|
|
114
|
-
const saved = runtime.getStacks().find((candidate) => candidate.
|
|
445
|
+
const saved = runtime.getStacks().find((candidate) => candidate.scope === target.scope && candidate.stack.id === target.stack.id)
|
|
446
|
+
?? runtime.getStacks().find((candidate) => candidate.filePath === target.filePath);
|
|
115
447
|
if (!saved)
|
|
116
448
|
return { ok: false, status: 500, error: "Saved stack could not be reloaded." };
|
|
117
449
|
return { ok: true, stack: stackSummary(saved, runtime.getActive()), stacks: stackSummaries(runtime.getStacks(), runtime.getActive()) };
|
|
@@ -123,24 +455,33 @@ async function createStackFile(ctx, runtime, stack, options) {
|
|
|
123
455
|
const idError = validateWebStackId(stack.id);
|
|
124
456
|
if (idError)
|
|
125
457
|
return { ok: false, status: 400, error: idError };
|
|
126
|
-
const
|
|
458
|
+
const scope = options.scope ?? "project";
|
|
459
|
+
const existingById = runtime.getStacks().find((candidate) => candidate.scope === scope && candidate.stack.id === stack.id);
|
|
127
460
|
if (existingById && !options.overwrite) {
|
|
128
461
|
return { ok: false, status: 409, error: `Prompt stack already exists: ${stack.id}` };
|
|
129
462
|
}
|
|
130
|
-
const targetPath = existingById && options.overwrite
|
|
131
|
-
|
|
132
|
-
|
|
463
|
+
const targetPath = existingById && options.overwrite
|
|
464
|
+
? existingById.filePath
|
|
465
|
+
: scope === "global"
|
|
466
|
+
? join(globalPromptStacksDir(), `${stack.id}.json`)
|
|
467
|
+
: promptStackPath(ctx.cwd, stack.id);
|
|
468
|
+
const safe = scope === "project"
|
|
469
|
+
? isSafePromptStackMutationPath(ctx.cwd, targetPath)
|
|
470
|
+
: isSafeGlobalPromptStackMutationPath(targetPath);
|
|
471
|
+
if (!safe) {
|
|
472
|
+
return { ok: false, status: 403, error: `Refusing to create outside ${scope} prompt-stack storage or through a symbolic link.` };
|
|
133
473
|
}
|
|
134
474
|
if (!existingById && existsSync(targetPath) && !options.overwrite) {
|
|
135
475
|
return { ok: false, status: 409, error: `Prompt stack already exists: ${stack.id}` };
|
|
136
476
|
}
|
|
137
477
|
const previousSelection = runtime.getSelectedActiveId();
|
|
478
|
+
const createdSelector = formatResourceKey({ scope, id: stack.id });
|
|
138
479
|
mkdirSync(dirname(targetPath), { recursive: true });
|
|
139
480
|
writeFileSync(targetPath, `${JSON.stringify(stack, null, 2)}\n`, "utf8");
|
|
140
|
-
await runtime.reloadStacks(options.activate ?
|
|
481
|
+
await runtime.reloadStacks(options.activate ? createdSelector : (previousSelection ?? "none"));
|
|
141
482
|
if (options.activate)
|
|
142
|
-
runtime.setActive(
|
|
143
|
-
const created = runtime.getStacks().find((candidate) => candidate.
|
|
483
|
+
runtime.setActive(createdSelector);
|
|
484
|
+
const created = runtime.getStacks().find((candidate) => candidate.scope === scope && candidate.filePath === targetPath);
|
|
144
485
|
if (!created)
|
|
145
486
|
return { ok: false, status: 500, error: "Created stack could not be reloaded." };
|
|
146
487
|
return { ok: true, stack: stackSummary(created, runtime.getActive()), stacks: stackSummaries(runtime.getStacks(), runtime.getActive()) };
|
|
@@ -149,13 +490,16 @@ async function deleteStackFile(ctx, runtime, id) {
|
|
|
149
490
|
if (!ctx.isProjectTrusted()) {
|
|
150
491
|
return { ok: false, status: 403, error: "Project is not trusted; refusing to delete prompt stacks." };
|
|
151
492
|
}
|
|
152
|
-
const target = runtime
|
|
493
|
+
const target = resolveStack(runtime, id);
|
|
153
494
|
if (!target)
|
|
154
495
|
return { ok: false, status: 404, error: `Unknown prompt stack: ${id}` };
|
|
155
|
-
|
|
156
|
-
|
|
496
|
+
const safe = target.scope === "project"
|
|
497
|
+
? isSafePromptStackMutationPath(ctx.cwd, target.filePath)
|
|
498
|
+
: isSafeGlobalPromptStackMutationPath(target.filePath);
|
|
499
|
+
if (!safe) {
|
|
500
|
+
return { ok: false, status: 403, error: "Refusing to delete outside prompt-stack storage or through a symbolic link." };
|
|
157
501
|
}
|
|
158
|
-
const wasActive = runtime.getActive()
|
|
502
|
+
const wasActive = runtime.getActive() === target;
|
|
159
503
|
unlinkSync(target.filePath);
|
|
160
504
|
if (wasActive) {
|
|
161
505
|
runtime.setActive("none");
|
|
@@ -169,8 +513,8 @@ async function deleteStackFile(ctx, runtime, id) {
|
|
|
169
513
|
function validateWebStackId(id) {
|
|
170
514
|
if (!id.trim())
|
|
171
515
|
return "Stack id must not be empty.";
|
|
172
|
-
if (
|
|
173
|
-
return "Stack id
|
|
516
|
+
if (!isValidPromptStackId(id)) {
|
|
517
|
+
return "Stack id must start with a letter or number and contain only letters, numbers, dots, underscores, and hyphens.";
|
|
174
518
|
}
|
|
175
519
|
return undefined;
|
|
176
520
|
}
|