@zihanw/pi-forge 0.3.1 → 0.4.0-beta.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 +160 -0
- package/PUBLIC_API.md +28 -0
- package/README.md +168 -35
- package/README.zh-CN.md +168 -35
- package/SUBAGENT_ADAPTER_CONTRACT.md +199 -0
- package/dist/agent-profile.d.ts +71 -0
- package/dist/agent-profile.d.ts.map +1 -0
- package/dist/agent-profile.js +303 -0
- package/dist/agent-profile.js.map +1 -0
- package/dist/forge-config.d.ts +8 -0
- package/dist/forge-config.d.ts.map +1 -0
- package/dist/forge-config.js +40 -0
- package/dist/forge-config.js.map +1 -0
- package/dist/forge-extensions.d.ts +28 -0
- package/dist/forge-extensions.d.ts.map +1 -0
- package/dist/forge-extensions.js +198 -0
- package/dist/forge-extensions.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +75 -349
- package/dist/index.js.map +1 -1
- package/dist/lifecycle.d.ts +11 -3
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/lifecycle.js +92 -6
- package/dist/lifecycle.js.map +1 -1
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +116 -5
- package/dist/loader.js.map +1 -1
- package/dist/payload-capture.d.ts.map +1 -1
- package/dist/payload-capture.js +27 -0
- package/dist/payload-capture.js.map +1 -1
- package/dist/payload-command.d.ts +3 -3
- package/dist/payload-command.d.ts.map +1 -1
- package/dist/payload-command.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 +12 -3
- package/dist/preset-command.js.map +1 -1
- package/dist/preview.d.ts +2 -2
- package/dist/preview.d.ts.map +1 -1
- package/dist/preview.js +2 -3
- package/dist/preview.js.map +1 -1
- package/dist/profile-command.d.ts +12 -0
- package/dist/profile-command.d.ts.map +1 -0
- package/dist/profile-command.js +291 -0
- package/dist/profile-command.js.map +1 -0
- package/dist/profile-service.d.ts +103 -0
- package/dist/profile-service.d.ts.map +1 -0
- package/dist/profile-service.js +215 -0
- package/dist/profile-service.js.map +1 -0
- package/dist/runtime/profile-runtime.d.ts +13 -0
- package/dist/runtime/profile-runtime.d.ts.map +1 -0
- package/dist/runtime/profile-runtime.js +47 -0
- package/dist/runtime/profile-runtime.js.map +1 -0
- package/dist/runtime/prompt-stack-runtime.d.ts +22 -0
- package/dist/runtime/prompt-stack-runtime.d.ts.map +1 -0
- package/dist/runtime/prompt-stack-runtime.js +104 -0
- package/dist/runtime/prompt-stack-runtime.js.map +1 -0
- package/dist/runtime/subagent-runtime.d.ts +30 -0
- package/dist/runtime/subagent-runtime.d.ts.map +1 -0
- package/dist/runtime/subagent-runtime.js +114 -0
- package/dist/runtime/subagent-runtime.js.map +1 -0
- package/dist/runtime/tool-policy-runtime.d.ts +15 -0
- package/dist/runtime/tool-policy-runtime.d.ts.map +1 -0
- package/dist/runtime/tool-policy-runtime.js +170 -0
- package/dist/runtime/tool-policy-runtime.js.map +1 -0
- package/dist/runtime/web-editor-runtime.d.ts +9 -0
- package/dist/runtime/web-editor-runtime.d.ts.map +1 -0
- package/dist/runtime/web-editor-runtime.js +131 -0
- package/dist/runtime/web-editor-runtime.js.map +1 -0
- package/dist/runtime-state.d.ts +6 -0
- package/dist/runtime-state.d.ts.map +1 -1
- package/dist/runtime-state.js +4 -0
- package/dist/runtime-state.js.map +1 -1
- package/dist/storage.d.ts +7 -0
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +22 -0
- package/dist/storage.js.map +1 -1
- package/dist/subagent/backend-registry.d.ts +75 -0
- package/dist/subagent/backend-registry.d.ts.map +1 -0
- package/dist/subagent/backend-registry.js +463 -0
- package/dist/subagent/backend-registry.js.map +1 -0
- package/dist/subagent/canonical.d.ts +10 -0
- package/dist/subagent/canonical.d.ts.map +1 -0
- package/dist/subagent/canonical.js +52 -0
- package/dist/subagent/canonical.js.map +1 -0
- package/dist/subagent/context.d.ts +8 -0
- package/dist/subagent/context.d.ts.map +1 -0
- package/dist/subagent/context.js +125 -0
- package/dist/subagent/context.js.map +1 -0
- package/dist/subagent/contract.d.ts +11 -0
- package/dist/subagent/contract.d.ts.map +1 -0
- package/dist/subagent/contract.js +11 -0
- package/dist/subagent/contract.js.map +1 -0
- package/dist/subagent/diagnostics.d.ts +3 -0
- package/dist/subagent/diagnostics.d.ts.map +1 -0
- package/dist/subagent/diagnostics.js +5 -0
- package/dist/subagent/diagnostics.js.map +1 -0
- package/dist/subagent/index.d.ts +13 -0
- package/dist/subagent/index.d.ts.map +1 -0
- package/dist/subagent/index.js +13 -0
- package/dist/subagent/index.js.map +1 -0
- package/dist/subagent/pi-model-runtime.d.ts +8 -0
- package/dist/subagent/pi-model-runtime.d.ts.map +1 -0
- package/dist/subagent/pi-model-runtime.js +22 -0
- package/dist/subagent/pi-model-runtime.js.map +1 -0
- package/dist/subagent/pi-sdk-backend.d.ts +23 -0
- package/dist/subagent/pi-sdk-backend.d.ts.map +1 -0
- package/dist/subagent/pi-sdk-backend.js +383 -0
- package/dist/subagent/pi-sdk-backend.js.map +1 -0
- package/dist/subagent/pi-subprocess-backend.d.ts +72 -0
- package/dist/subagent/pi-subprocess-backend.d.ts.map +1 -0
- package/dist/subagent/pi-subprocess-backend.js +756 -0
- package/dist/subagent/pi-subprocess-backend.js.map +1 -0
- package/dist/subagent/plan.d.ts +14 -0
- package/dist/subagent/plan.d.ts.map +1 -0
- package/dist/subagent/plan.js +160 -0
- package/dist/subagent/plan.js.map +1 -0
- package/dist/subagent/preflight.d.ts +4 -0
- package/dist/subagent/preflight.d.ts.map +1 -0
- package/dist/subagent/preflight.js +108 -0
- package/dist/subagent/preflight.js.map +1 -0
- package/dist/subagent/request.d.ts +4 -0
- package/dist/subagent/request.d.ts.map +1 -0
- package/dist/subagent/request.js +122 -0
- package/dist/subagent/request.js.map +1 -0
- package/dist/subagent/response.d.ts +8 -0
- package/dist/subagent/response.d.ts.map +1 -0
- package/dist/subagent/response.js +155 -0
- package/dist/subagent/response.js.map +1 -0
- package/dist/subagent/subprocess-bridge.d.ts +21 -0
- package/dist/subagent/subprocess-bridge.d.ts.map +1 -0
- package/dist/subagent/subprocess-bridge.js +87 -0
- package/dist/subagent/subprocess-bridge.js.map +1 -0
- package/dist/subagent/subprocess-report.d.ts +4 -0
- package/dist/subagent/subprocess-report.d.ts.map +1 -0
- package/dist/subagent/subprocess-report.js +55 -0
- package/dist/subagent/subprocess-report.js.map +1 -0
- package/dist/subagent/tools.d.ts +4 -0
- package/dist/subagent/tools.d.ts.map +1 -0
- package/dist/subagent/tools.js +42 -0
- package/dist/subagent/tools.js.map +1 -0
- package/dist/subagent/types.d.ts +384 -0
- package/dist/subagent/types.d.ts.map +1 -0
- package/dist/subagent/types.js +3 -0
- package/dist/subagent/types.js.map +1 -0
- package/dist/subagent/validation.d.ts +35 -0
- package/dist/subagent/validation.d.ts.map +1 -0
- package/dist/subagent/validation.js +500 -0
- package/dist/subagent/validation.js.map +1 -0
- package/dist/subagent-command.d.ts +4 -0
- package/dist/subagent-command.d.ts.map +1 -0
- package/dist/subagent-command.js +153 -0
- package/dist/subagent-command.js.map +1 -0
- package/dist/subagent-contract.d.ts +8 -0
- package/dist/subagent-contract.d.ts.map +1 -0
- package/dist/subagent-contract.js +8 -0
- package/dist/subagent-contract.js.map +1 -0
- package/dist/subagent-host.d.ts +44 -0
- package/dist/subagent-host.d.ts.map +1 -0
- package/dist/subagent-host.js +291 -0
- package/dist/subagent-host.js.map +1 -0
- package/dist/subagent-profile-tool.d.ts +26 -0
- package/dist/subagent-profile-tool.d.ts.map +1 -0
- package/dist/subagent-profile-tool.js +93 -0
- package/dist/subagent-profile-tool.js.map +1 -0
- package/dist/subagent-tool.d.ts +50 -0
- package/dist/subagent-tool.d.ts.map +1 -0
- package/dist/subagent-tool.js +385 -0
- package/dist/subagent-tool.js.map +1 -0
- package/dist/web-editor/client/api.d.ts +9 -0
- package/dist/web-editor/client/api.d.ts.map +1 -0
- package/dist/web-editor/client/api.js +26 -0
- package/dist/web-editor/client/api.js.map +1 -0
- package/dist/web-editor/client/dom.d.ts +13 -0
- package/dist/web-editor/client/dom.d.ts.map +1 -0
- package/dist/web-editor/client/dom.js +30 -0
- package/dist/web-editor/client/dom.js.map +1 -0
- package/dist/web-editor/client/inspector.d.ts +22 -0
- package/dist/web-editor/client/inspector.d.ts.map +1 -0
- package/dist/web-editor/client/inspector.js +226 -0
- package/dist/web-editor/client/inspector.js.map +1 -0
- package/dist/web-editor/client/main.d.ts +2 -0
- package/dist/web-editor/client/main.d.ts.map +1 -0
- package/dist/web-editor/client/main.js +1468 -0
- package/dist/web-editor/client/main.js.map +1 -0
- package/dist/web-editor/client/policy-editor.d.ts +16 -0
- package/dist/web-editor/client/policy-editor.d.ts.map +1 -0
- package/dist/web-editor/client/policy-editor.js +330 -0
- package/dist/web-editor/client/policy-editor.js.map +1 -0
- package/dist/web-editor/client/regex-editor.d.ts +19 -0
- package/dist/web-editor/client/regex-editor.d.ts.map +1 -0
- package/dist/web-editor/client/regex-editor.js +281 -0
- package/dist/web-editor/client/regex-editor.js.map +1 -0
- package/dist/web-editor/client/types.d.ts +60 -0
- package/dist/web-editor/client/types.d.ts.map +1 -0
- package/dist/web-editor/client/types.js +2 -0
- package/dist/web-editor/client/types.js.map +1 -0
- package/dist/web-editor/client-script.d.ts +2 -0
- package/dist/web-editor/client-script.d.ts.map +1 -0
- package/dist/web-editor/client-script.generated.d.ts +2 -0
- package/dist/web-editor/client-script.generated.d.ts.map +1 -0
- package/dist/web-editor/client-script.generated.js +3 -0
- package/dist/web-editor/client-script.generated.js.map +1 -0
- package/dist/web-editor/client-script.js +2 -0
- package/dist/web-editor/client-script.js.map +1 -0
- package/dist/web-editor/page.d.ts.map +1 -1
- package/dist/web-editor/page.js +6 -3249
- package/dist/web-editor/page.js.map +1 -1
- package/dist/web-editor/server.js +4 -4
- package/dist/web-editor/server.js.map +1 -1
- package/dist/web-editor/styles.d.ts +2 -0
- package/dist/web-editor/styles.d.ts.map +1 -0
- package/dist/web-editor/styles.js +996 -0
- package/dist/web-editor/styles.js.map +1 -0
- package/dist/web-editor/types.d.ts +8 -8
- package/dist/web-editor/types.d.ts.map +1 -1
- package/dist/web-host.d.ts +4 -4
- package/dist/web-host.d.ts.map +1 -1
- package/dist/web-host.js +15 -9
- package/dist/web-host.js.map +1 -1
- package/examples/custom-system-status-extension/README.md +34 -27
- package/examples/custom-system-status-extension/index.ts +71 -111
- package/examples/custom-system-status-extension/prompt-stack.json +1 -1
- package/package.json +42 -14
- package/src/compiler.ts +0 -578
- package/src/extension-registry.ts +0 -33
- package/src/index.ts +0 -430
- package/src/lifecycle.ts +0 -171
- package/src/loader.ts +0 -394
- package/src/macro-engine.ts +0 -358
- package/src/payload-capture.ts +0 -85
- package/src/payload-command.ts +0 -138
- package/src/policy.ts +0 -42
- package/src/preset-command.ts +0 -271
- package/src/preview.ts +0 -226
- package/src/regex.ts +0 -500
- package/src/render-helpers.ts +0 -169
- package/src/runtime-state.ts +0 -36
- package/src/sillytavern-importer/items.ts +0 -98
- package/src/sillytavern-importer/macros.ts +0 -159
- package/src/sillytavern-importer/prompt-order.ts +0 -54
- package/src/sillytavern-importer/regex.ts +0 -270
- package/src/sillytavern-importer/report.ts +0 -202
- package/src/sillytavern-importer/types.ts +0 -120
- package/src/sillytavern-importer.ts +0 -152
- package/src/slot-renderers.ts +0 -414
- package/src/stack-migration.ts +0 -159
- package/src/storage.ts +0 -28
- package/src/types.ts +0 -209
- package/src/web-editor/index.ts +0 -2
- package/src/web-editor/page.ts +0 -3330
- package/src/web-editor/server.ts +0 -294
- package/src/web-editor/types.ts +0 -98
- package/src/web-host.ts +0 -232
package/src/macro-engine.ts
DELETED
|
@@ -1,358 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
PromptRuntime,
|
|
3
|
-
PromptStack,
|
|
4
|
-
PromptStackDiagnostic,
|
|
5
|
-
} from "./types.ts";
|
|
6
|
-
import {
|
|
7
|
-
createVariableAccess,
|
|
8
|
-
escapeXml,
|
|
9
|
-
formatDate,
|
|
10
|
-
formatTime,
|
|
11
|
-
getRuntimeVariable,
|
|
12
|
-
promptRenderHelpers,
|
|
13
|
-
selectedToolNames,
|
|
14
|
-
type PromptRenderHelpers,
|
|
15
|
-
type PromptVariableAccess,
|
|
16
|
-
type PromptVariableScope,
|
|
17
|
-
variableValueToMacroText,
|
|
18
|
-
} from "./render-helpers.ts";
|
|
19
|
-
import { assertRegistryName, type PromptExtensionArgumentDefinition, type PromptRegistryEntry } from "./extension-registry.ts";
|
|
20
|
-
|
|
21
|
-
interface MacroExpansionState {
|
|
22
|
-
stack: PromptStack;
|
|
23
|
-
runtime: PromptRuntime;
|
|
24
|
-
diagnostics: PromptStackDiagnostic[];
|
|
25
|
-
itemId: string;
|
|
26
|
-
unknown: Set<string>;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface PromptMacroRenderContext {
|
|
30
|
-
name: string;
|
|
31
|
-
command: string;
|
|
32
|
-
stack: PromptStack;
|
|
33
|
-
runtime: PromptRuntime;
|
|
34
|
-
rawArgs: readonly string[];
|
|
35
|
-
expandArg: (index: number) => string;
|
|
36
|
-
expandJoinedArgs: (startIndex: number) => string;
|
|
37
|
-
helpers: PromptRenderHelpers;
|
|
38
|
-
variables: PromptVariableAccess;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export type PromptMacroRenderer = (context: PromptMacroRenderContext) => string | undefined;
|
|
42
|
-
|
|
43
|
-
export interface PromptMacroDefinition extends PromptRegistryEntry {
|
|
44
|
-
args?: readonly PromptExtensionArgumentDefinition[];
|
|
45
|
-
render: PromptMacroRenderer;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
interface PromptMacroRegistryState {
|
|
49
|
-
macros: Map<string, PromptMacroDefinition>;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
type PromptMacroGlobal = typeof globalThis & {
|
|
53
|
-
__piForgeMacroRegistry?: PromptMacroRegistryState;
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
function macroRegistryState(): PromptMacroRegistryState {
|
|
57
|
-
const globalScope = globalThis as PromptMacroGlobal;
|
|
58
|
-
globalScope.__piForgeMacroRegistry ??= { macros: new Map() };
|
|
59
|
-
return globalScope.__piForgeMacroRegistry;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const MACROS = macroRegistryState().macros;
|
|
63
|
-
let registeringBuiltInMacros = true;
|
|
64
|
-
|
|
65
|
-
registerMacro({ name: "cwd", description: "Current working directory.", render: ({ runtime }) => runtime.options.cwd });
|
|
66
|
-
registerMacro({ name: "date", description: "Current date in YYYY-MM-DD format.", render: ({ runtime }) => formatDate(runtime.now) });
|
|
67
|
-
registerMacro({ name: "time", description: "Current time in HH:MM:SS format.", render: ({ runtime }) => formatTime(runtime.now) });
|
|
68
|
-
registerMacro({ name: "lastUserMessage", description: "Latest user message text.", render: ({ runtime }) => runtime.latestUserMessage ?? "" });
|
|
69
|
-
registerMacro({ name: "selectedTools", description: "Comma-separated selected tool names after stack policy.", render: renderSelectedTools });
|
|
70
|
-
registerMacro({ name: "tools", description: "Alias for selectedTools.", render: renderSelectedTools });
|
|
71
|
-
registerMacro({ name: "activeModel", description: "Current model as provider/id.", render: ({ runtime }) => {
|
|
72
|
-
const model = runtime.ctx?.model;
|
|
73
|
-
return model ? `${model.provider}/${model.id}` : "";
|
|
74
|
-
} });
|
|
75
|
-
|
|
76
|
-
registerMacro({ name: "setvar", description: "Set a turn variable, or set a scoped variable with setvar::session|turn::name::value.", render: renderSetVariable });
|
|
77
|
-
registerMacro({ name: "setturnvar", description: "Set a turn variable.", render: renderSetVariable });
|
|
78
|
-
registerMacro({ name: "setsessionvar", description: "Set a session variable.", render: renderSetVariable });
|
|
79
|
-
registerMacro({ name: "getvar", description: "Read a turn, session, or static variable.", render: renderGetVariable });
|
|
80
|
-
registerMacro({ name: "var", description: "Alias for getvar.", render: renderGetVariable });
|
|
81
|
-
registerMacro({ name: "getturnvar", description: "Read a turn variable.", render: renderGetVariable });
|
|
82
|
-
registerMacro({ name: "getsessionvar", description: "Read a session variable.", render: renderGetVariable });
|
|
83
|
-
registerMacro({ name: "clearvar", description: "Clear a turn variable, or clear a scoped variable with clearvar::session|turn::name.", render: renderClearVariable });
|
|
84
|
-
registerMacro({ name: "clearturnvar", description: "Clear a turn variable.", render: renderClearVariable });
|
|
85
|
-
registerMacro({ name: "clearsessionvar", description: "Clear a session variable.", render: renderClearVariable });
|
|
86
|
-
|
|
87
|
-
registerMacro({ name: "trim", description: "Trim whitespace from an expanded argument.", args: [{ name: "value", required: true }], render: ({ expandArg }) => expandArg(0).trim() });
|
|
88
|
-
registerMacro({ name: "upper", description: "Uppercase an expanded argument.", args: [{ name: "value", required: true }], render: ({ expandArg }) => expandArg(0).toUpperCase() });
|
|
89
|
-
registerMacro({ name: "lower", description: "Lowercase an expanded argument.", args: [{ name: "value", required: true }], render: ({ expandArg }) => expandArg(0).toLowerCase() });
|
|
90
|
-
registerMacro({ name: "json", description: "JSON-string escape an expanded argument.", args: [{ name: "value", required: true }], render: ({ expandArg }) => JSON.stringify(expandArg(0)) });
|
|
91
|
-
registerMacro({ name: "xml", description: "XML-escape an expanded argument.", args: [{ name: "value", required: true }], render: ({ expandArg }) => escapeXml(expandArg(0)) });
|
|
92
|
-
|
|
93
|
-
registerMacro({ name: "ifvar", description: "Render a lazy branch based on whether a variable exists.", render: renderIfVariable });
|
|
94
|
-
registerMacro({ name: "ifeq", description: "Render a lazy branch based on whether a variable equals a string.", render: renderIfVariableEquals });
|
|
95
|
-
registerMacro({ name: "iftools", description: "Render a lazy branch based on whether a tool is selected.", render: renderIfTool });
|
|
96
|
-
registerMacro({ name: "ifslot", description: "Render a lazy branch based on whether an enabled slot exists in the stack.", render: renderIfSlot });
|
|
97
|
-
registeringBuiltInMacros = false;
|
|
98
|
-
|
|
99
|
-
export function expandMacros(
|
|
100
|
-
text: string,
|
|
101
|
-
stack: PromptStack,
|
|
102
|
-
runtime: PromptRuntime,
|
|
103
|
-
diagnostics: PromptStackDiagnostic[],
|
|
104
|
-
itemId: string,
|
|
105
|
-
): string {
|
|
106
|
-
const policy = stack.defaults?.unresolvedMacroPolicy ?? "warn";
|
|
107
|
-
const state: MacroExpansionState = { stack, runtime, diagnostics, itemId, unknown: new Set<string>() };
|
|
108
|
-
const result = expandMacroText(text, state);
|
|
109
|
-
|
|
110
|
-
for (const name of state.unknown) {
|
|
111
|
-
if (policy === "keep") continue;
|
|
112
|
-
diagnostics.push({
|
|
113
|
-
level: policy === "error" ? "error" : "warning",
|
|
114
|
-
message: `Unresolved macro: {{${name}}}`,
|
|
115
|
-
itemId,
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
return result;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
export function registerMacro(definition: PromptMacroDefinition): () => void {
|
|
123
|
-
assertRegistryName("Macro", definition.name);
|
|
124
|
-
if (MACROS.has(definition.name)) {
|
|
125
|
-
if (registeringBuiltInMacros) return () => {};
|
|
126
|
-
throw new Error(`Macro is already registered: ${definition.name}`);
|
|
127
|
-
}
|
|
128
|
-
MACROS.set(definition.name, definition);
|
|
129
|
-
return () => {
|
|
130
|
-
if (MACROS.get(definition.name) === definition) MACROS.delete(definition.name);
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export function getRegisteredMacros(): readonly PromptMacroDefinition[] {
|
|
135
|
-
return [...MACROS.values()];
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function expandMacroText(text: string, state: MacroExpansionState): string {
|
|
139
|
-
let result = "";
|
|
140
|
-
let index = 0;
|
|
141
|
-
|
|
142
|
-
while (index < text.length) {
|
|
143
|
-
const start = text.indexOf("{{", index);
|
|
144
|
-
if (start === -1) {
|
|
145
|
-
result += text.slice(index);
|
|
146
|
-
break;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
result += text.slice(index, start);
|
|
150
|
-
const end = findMacroEnd(text, start + 2);
|
|
151
|
-
if (end === undefined) {
|
|
152
|
-
result += "{{";
|
|
153
|
-
index = start + 2;
|
|
154
|
-
continue;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const expression = text.slice(start + 2, end);
|
|
158
|
-
const fullMacro = text.slice(start, end + 2);
|
|
159
|
-
result += renderMacro(expression, fullMacro, state);
|
|
160
|
-
index = end + 2;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
return result;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function findMacroEnd(text: string, start: number): number | undefined {
|
|
167
|
-
let depth = 1;
|
|
168
|
-
|
|
169
|
-
for (let index = start; index < text.length - 1; index++) {
|
|
170
|
-
const pair = text.slice(index, index + 2);
|
|
171
|
-
if (pair === "{{") {
|
|
172
|
-
depth++;
|
|
173
|
-
index++;
|
|
174
|
-
continue;
|
|
175
|
-
}
|
|
176
|
-
if (pair === "}}") {
|
|
177
|
-
depth--;
|
|
178
|
-
if (depth === 0) return index;
|
|
179
|
-
index++;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
return undefined;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
function renderMacro(rawExpression: string, fullMacro: string, state: MacroExpansionState): string {
|
|
187
|
-
const expression = rawExpression.trim();
|
|
188
|
-
if (!expression) return fullMacro;
|
|
189
|
-
|
|
190
|
-
const parts = splitMacroExpression(expression);
|
|
191
|
-
const command = parts[0]?.trim();
|
|
192
|
-
if (!command) return fullMacro;
|
|
193
|
-
|
|
194
|
-
const rawArgs = parts.slice(1);
|
|
195
|
-
const definition = MACROS.get(command);
|
|
196
|
-
if (definition) {
|
|
197
|
-
let value: string | undefined;
|
|
198
|
-
try {
|
|
199
|
-
value = definition.render(createMacroRenderContext(command, rawArgs, state));
|
|
200
|
-
} catch (error) {
|
|
201
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
202
|
-
state.diagnostics.push({
|
|
203
|
-
level: "error",
|
|
204
|
-
message: `Macro {{${command}}} failed: ${detail}`,
|
|
205
|
-
itemId: state.itemId,
|
|
206
|
-
});
|
|
207
|
-
return fullMacro;
|
|
208
|
-
}
|
|
209
|
-
if (value !== undefined) return value;
|
|
210
|
-
state.unknown.add(expression);
|
|
211
|
-
return fullMacro;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
const variableValue = getRuntimeVariable(state.runtime, state.stack, command);
|
|
215
|
-
if (variableValue !== undefined) return variableValueToMacroText(variableValue);
|
|
216
|
-
|
|
217
|
-
state.unknown.add(expression);
|
|
218
|
-
return fullMacro;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
function splitMacroExpression(expression: string): string[] {
|
|
222
|
-
const parts: string[] = [];
|
|
223
|
-
let start = 0;
|
|
224
|
-
let depth = 0;
|
|
225
|
-
|
|
226
|
-
for (let index = 0; index < expression.length - 1; index++) {
|
|
227
|
-
const pair = expression.slice(index, index + 2);
|
|
228
|
-
if (pair === "{{") {
|
|
229
|
-
depth++;
|
|
230
|
-
index++;
|
|
231
|
-
continue;
|
|
232
|
-
}
|
|
233
|
-
if (pair === "}}" && depth > 0) {
|
|
234
|
-
depth--;
|
|
235
|
-
index++;
|
|
236
|
-
continue;
|
|
237
|
-
}
|
|
238
|
-
if (pair === "::" && depth === 0) {
|
|
239
|
-
parts.push(expression.slice(start, index));
|
|
240
|
-
start = index + 2;
|
|
241
|
-
index++;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
parts.push(expression.slice(start));
|
|
246
|
-
return parts;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
function createMacroRenderContext(
|
|
250
|
-
command: string,
|
|
251
|
-
rawArgs: readonly string[],
|
|
252
|
-
state: MacroExpansionState,
|
|
253
|
-
): PromptMacroRenderContext {
|
|
254
|
-
const expandedArgs = new Map<number, string>();
|
|
255
|
-
|
|
256
|
-
const expandArg = (index: number): string => {
|
|
257
|
-
if (!expandedArgs.has(index)) {
|
|
258
|
-
expandedArgs.set(index, expandMacroText(rawArgs[index] ?? "", state));
|
|
259
|
-
}
|
|
260
|
-
return expandedArgs.get(index) ?? "";
|
|
261
|
-
};
|
|
262
|
-
|
|
263
|
-
return {
|
|
264
|
-
name: command,
|
|
265
|
-
command,
|
|
266
|
-
stack: state.stack,
|
|
267
|
-
runtime: state.runtime,
|
|
268
|
-
rawArgs,
|
|
269
|
-
expandArg,
|
|
270
|
-
expandJoinedArgs: (startIndex: number) =>
|
|
271
|
-
rawArgs.slice(startIndex).map((_, offset) => expandArg(startIndex + offset)).join("::"),
|
|
272
|
-
helpers: promptRenderHelpers,
|
|
273
|
-
variables: createVariableAccess(state.runtime, state.stack),
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
function renderSetVariable(context: PromptMacroRenderContext): string | undefined {
|
|
278
|
-
const scoped = context.command === "setvar" && isVariableScope(context.expandArg(0).trim());
|
|
279
|
-
const scope = context.command === "setsessionvar" || (scoped && context.expandArg(0).trim() === "session")
|
|
280
|
-
? "session"
|
|
281
|
-
: "turn";
|
|
282
|
-
const nameIndex = scoped ? 1 : 0;
|
|
283
|
-
const valueIndex = nameIndex + 1;
|
|
284
|
-
const name = context.expandArg(nameIndex).trim();
|
|
285
|
-
if (!name) return undefined;
|
|
286
|
-
|
|
287
|
-
context.variables.set(scope, name, context.expandJoinedArgs(valueIndex));
|
|
288
|
-
return "";
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
function renderGetVariable(context: PromptMacroRenderContext): string | undefined {
|
|
292
|
-
const name = context.expandArg(0).trim();
|
|
293
|
-
if (!name) return undefined;
|
|
294
|
-
|
|
295
|
-
if (context.command === "getturnvar") return context.variables.toMacroText(context.variables.get(name, "turn"));
|
|
296
|
-
if (context.command === "getsessionvar") return context.variables.toMacroText(context.variables.get(name, "session"));
|
|
297
|
-
return context.variables.toMacroText(context.variables.get(name));
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
function renderClearVariable(context: PromptMacroRenderContext): string | undefined {
|
|
301
|
-
const scoped = context.command === "clearvar" && isVariableScope(context.expandArg(0).trim());
|
|
302
|
-
const scope = context.command === "clearsessionvar" || (scoped && context.expandArg(0).trim() === "session")
|
|
303
|
-
? "session"
|
|
304
|
-
: "turn";
|
|
305
|
-
const name = context.expandArg(scoped ? 1 : 0).trim();
|
|
306
|
-
if (!name) return undefined;
|
|
307
|
-
|
|
308
|
-
context.variables.clear(scope, name);
|
|
309
|
-
return "";
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
function renderSelectedTools({ stack, runtime }: PromptMacroRenderContext): string {
|
|
313
|
-
return selectedToolNames(stack, runtime).join(", ");
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
function renderIfVariable(context: PromptMacroRenderContext): string | undefined {
|
|
317
|
-
const name = context.expandArg(0).trim();
|
|
318
|
-
if (!name) return undefined;
|
|
319
|
-
|
|
320
|
-
return renderConditionalBranch(context, context.variables.get(name) !== undefined, 1, 2);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
function renderIfVariableEquals(context: PromptMacroRenderContext): string | undefined {
|
|
324
|
-
const name = context.expandArg(0).trim();
|
|
325
|
-
if (!name || context.rawArgs.length < 2) return undefined;
|
|
326
|
-
|
|
327
|
-
const value = context.variables.get(name);
|
|
328
|
-
const expected = context.expandArg(1);
|
|
329
|
-
return renderConditionalBranch(context, value !== undefined && variableValueToMacroText(value) === expected, 2, 3);
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
function renderIfTool(context: PromptMacroRenderContext): string | undefined {
|
|
333
|
-
const name = context.expandArg(0).trim();
|
|
334
|
-
if (!name) return undefined;
|
|
335
|
-
|
|
336
|
-
return renderConditionalBranch(context, selectedToolNames(context.stack, context.runtime).includes(name), 1, 2);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
function renderIfSlot(context: PromptMacroRenderContext): string | undefined {
|
|
340
|
-
const name = context.expandArg(0).trim();
|
|
341
|
-
if (!name) return undefined;
|
|
342
|
-
|
|
343
|
-
const hasSlot = context.stack.items.some((item) => item.enabled !== false && item.kind === "slot" && item.slot === name);
|
|
344
|
-
return renderConditionalBranch(context, hasSlot, 1, 2);
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
function renderConditionalBranch(
|
|
348
|
-
context: PromptMacroRenderContext,
|
|
349
|
-
condition: boolean,
|
|
350
|
-
thenIndex: number,
|
|
351
|
-
elseIndex: number,
|
|
352
|
-
): string {
|
|
353
|
-
return condition ? context.expandArg(thenIndex) : context.expandArg(elseIndex);
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
function isVariableScope(value: string): value is PromptVariableScope {
|
|
357
|
-
return value === "turn" || value === "session";
|
|
358
|
-
}
|
package/src/payload-capture.ts
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import type { WebEditorPayloadCapture } from "./web-editor/index.ts";
|
|
2
|
-
|
|
3
|
-
export function createProviderPayloadCapture(value: unknown, options: { stackId?: string; savePath?: string } = {}): WebEditorPayloadCapture {
|
|
4
|
-
const formatted = formatProviderPayload(value);
|
|
5
|
-
return {
|
|
6
|
-
capturedAt: new Date().toISOString(),
|
|
7
|
-
stackId: options.stackId,
|
|
8
|
-
savePath: options.savePath,
|
|
9
|
-
payload: formatted.payload,
|
|
10
|
-
text: formatted.text,
|
|
11
|
-
chars: formatted.chars,
|
|
12
|
-
approxTokens: formatted.approxTokens,
|
|
13
|
-
truncated: formatted.truncated,
|
|
14
|
-
error: formatted.error,
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function formatProviderPayload(value: unknown): { payload?: unknown; text: string; chars: number; approxTokens: number; truncated: boolean; error?: string } {
|
|
19
|
-
try {
|
|
20
|
-
const payload = redactPayload(value);
|
|
21
|
-
const renderedJson = JSON.stringify(payload, null, 2);
|
|
22
|
-
const text = renderedJson === undefined ? String(payload) : renderedJson;
|
|
23
|
-
const maxChars = 200_000;
|
|
24
|
-
const truncated = text.length > maxChars;
|
|
25
|
-
const rendered = truncated ? `${text.slice(0, maxChars)}\n\n[pi-forge: payload truncated after ${maxChars} chars]` : text;
|
|
26
|
-
return {
|
|
27
|
-
payload: truncated ? undefined : payload,
|
|
28
|
-
text: rendered,
|
|
29
|
-
chars: rendered.length,
|
|
30
|
-
approxTokens: estimatePayloadTokens(rendered),
|
|
31
|
-
truncated,
|
|
32
|
-
};
|
|
33
|
-
} catch (error) {
|
|
34
|
-
const text = `Failed to stringify provider payload: ${error instanceof Error ? error.message : String(error)}`;
|
|
35
|
-
return {
|
|
36
|
-
text,
|
|
37
|
-
chars: text.length,
|
|
38
|
-
approxTokens: estimatePayloadTokens(text),
|
|
39
|
-
truncated: false,
|
|
40
|
-
error: text,
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export function estimatePayloadTokens(payload: string): number {
|
|
46
|
-
return Math.max(1, Math.ceil(payload.length / 4));
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function redactPayload(value: unknown, depth = 0): unknown {
|
|
50
|
-
if (depth > 8) return "[pi-forge: max depth reached]";
|
|
51
|
-
if (typeof value === "string") return redactLongString(value);
|
|
52
|
-
if (value === null || typeof value !== "object") return value;
|
|
53
|
-
if (Array.isArray(value)) {
|
|
54
|
-
const maxItems = 80;
|
|
55
|
-
const items = value.slice(0, maxItems).map((item) => redactPayload(item, depth + 1));
|
|
56
|
-
if (value.length > maxItems) items.push(`[pi-forge: ${value.length - maxItems} more items omitted]`);
|
|
57
|
-
return items;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const result: Record<string, unknown> = {};
|
|
61
|
-
let count = 0;
|
|
62
|
-
for (const [key, raw] of Object.entries(value as Record<string, unknown>)) {
|
|
63
|
-
if (++count > 120) {
|
|
64
|
-
result["[pi-forge: omitted]"] = "object has more than 120 keys";
|
|
65
|
-
break;
|
|
66
|
-
}
|
|
67
|
-
if (isSecretKey(key)) {
|
|
68
|
-
result[key] = "[redacted]";
|
|
69
|
-
continue;
|
|
70
|
-
}
|
|
71
|
-
result[key] = redactPayload(raw, depth + 1);
|
|
72
|
-
}
|
|
73
|
-
return result;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function isSecretKey(key: string): boolean {
|
|
77
|
-
return /(api[-_]?key|authorization|bearer|token|secret|password|cookie|credential)/i.test(key);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function redactLongString(value: string): string {
|
|
81
|
-
if (/^data:image\//.test(value)) return "[image data omitted]";
|
|
82
|
-
if (value.length > 8_000 && /^[A-Za-z0-9+/=\r\n]+$/.test(value)) return `[base64-like data omitted: ${value.length} chars]`;
|
|
83
|
-
if (value.length > 12_000) return `${value.slice(0, 12_000)}\n[pi-forge: string truncated from ${value.length} chars]`;
|
|
84
|
-
return value;
|
|
85
|
-
}
|
package/src/payload-command.ts
DELETED
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { dirname, join } from "node:path";
|
|
3
|
-
import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
4
|
-
import { createProviderPayloadCapture } from "./payload-capture.ts";
|
|
5
|
-
import type { PayloadDisplayTarget, PiForgeRuntimeState } from "./runtime-state.ts";
|
|
6
|
-
import type { LoadedPromptStack } from "./types.ts";
|
|
7
|
-
import type { WebEditorPayloadCapture, WebEditorPayloadSnapshot } from "./web-editor/index.ts";
|
|
8
|
-
|
|
9
|
-
export function registerPayloadCommands(pi: ExtensionAPI, state: PiForgeRuntimeState): void {
|
|
10
|
-
pi.registerCommand("intercept", {
|
|
11
|
-
description: "Display the next provider payload before it is sent",
|
|
12
|
-
handler: async (_args, ctx) => {
|
|
13
|
-
armPayloadIntercept(state, ctx);
|
|
14
|
-
},
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
pi.registerCommand("payload", {
|
|
18
|
-
description: "Inspect or save provider payloads: /payload next [save=<path>]",
|
|
19
|
-
getArgumentCompletions: (prefix) => {
|
|
20
|
-
const parts = prefix.trimStart().split(/\s+/);
|
|
21
|
-
if (parts.length <= 1 && !prefix.endsWith(" ")) {
|
|
22
|
-
return ["next"].filter((cmd) => cmd.startsWith(parts[0] ?? "")).map((cmd) => ({ value: cmd, label: cmd }));
|
|
23
|
-
}
|
|
24
|
-
if (parts[0] === "next" && parts.length <= 2) {
|
|
25
|
-
const suggestion = "save=.pi/forge/payloads/last.json";
|
|
26
|
-
return suggestion.startsWith(parts[1] ?? "") ? [{ value: `next ${suggestion}`, label: suggestion }] : null;
|
|
27
|
-
}
|
|
28
|
-
return null;
|
|
29
|
-
},
|
|
30
|
-
handler: async (args, ctx) => {
|
|
31
|
-
const [command = "next", ...rest] = args.trim() ? args.trim().split(/\s+/) : ["next"];
|
|
32
|
-
if (command !== "next") {
|
|
33
|
-
ctx.ui.notify(`Unknown /payload subcommand: ${command}`, "warning");
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
const saveArg = rest.find((arg) => arg.startsWith("save="));
|
|
37
|
-
const savePath = saveArg?.slice("save=".length).trim() || undefined;
|
|
38
|
-
armPayloadIntercept(state, ctx, savePath);
|
|
39
|
-
},
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function registerPayloadRequestHandler(
|
|
44
|
-
pi: ExtensionAPI,
|
|
45
|
-
state: PiForgeRuntimeState,
|
|
46
|
-
getActive: () => LoadedPromptStack | undefined,
|
|
47
|
-
): void {
|
|
48
|
-
pi.on("before_provider_request", async (event, ctx) => {
|
|
49
|
-
if (!state.interceptNextProviderPayload) return;
|
|
50
|
-
const savePath = state.interceptPayloadSavePath;
|
|
51
|
-
const displayTarget = state.interceptPayloadDisplayTarget;
|
|
52
|
-
state.interceptNextProviderPayload = false;
|
|
53
|
-
state.interceptPayloadSavePath = undefined;
|
|
54
|
-
state.interceptPayloadDisplayTarget = "editor";
|
|
55
|
-
state.payloadCaptureArmedAt = undefined;
|
|
56
|
-
ctx.ui.setStatus("pi-forge-intercept", undefined);
|
|
57
|
-
|
|
58
|
-
const capture = captureProviderPayload(state, getActive(), event.payload, savePath);
|
|
59
|
-
if (savePath) {
|
|
60
|
-
if (!ctx.isProjectTrusted()) {
|
|
61
|
-
ctx.ui.notify("pi-forge: project is not trusted; refusing to save provider payload.", "warning");
|
|
62
|
-
} else {
|
|
63
|
-
const resolvedPath = savePath.startsWith("/") ? savePath : join(ctx.cwd, savePath);
|
|
64
|
-
mkdirSync(dirname(resolvedPath), { recursive: true });
|
|
65
|
-
writeFileSync(resolvedPath, capture.text, "utf8");
|
|
66
|
-
ctx.ui.notify(`pi-forge: provider payload saved to ${resolvedPath} (${capture.chars} chars, ~${capture.approxTokens} tokens)`, "info");
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (displayTarget === "web") {
|
|
71
|
-
ctx.ui.notify(`pi-forge: provider payload captured for web editor (${capture.chars} chars, ~${capture.approxTokens} tokens).`, "info");
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (ctx.hasUI) {
|
|
76
|
-
await ctx.ui.editor(`pi-forge: provider payload (${capture.chars} chars, ~${capture.approxTokens} tokens)`, capture.text);
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
console.log(capture.text);
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export function armPayloadIntercept(
|
|
85
|
-
state: PiForgeRuntimeState,
|
|
86
|
-
ctx: ExtensionCommandContext,
|
|
87
|
-
savePath?: string,
|
|
88
|
-
displayTarget: PayloadDisplayTarget = "editor",
|
|
89
|
-
): void {
|
|
90
|
-
state.interceptNextProviderPayload = true;
|
|
91
|
-
state.interceptPayloadSavePath = savePath;
|
|
92
|
-
state.interceptPayloadDisplayTarget = displayTarget;
|
|
93
|
-
state.payloadCaptureArmedAt = new Date().toISOString();
|
|
94
|
-
state.latestProviderPayloadCapture = undefined;
|
|
95
|
-
ctx.ui.setStatus("pi-forge-intercept", ctx.ui.theme.fg("warning", savePath ? "payload:armed+save" : "payload:armed"));
|
|
96
|
-
if (displayTarget === "web") {
|
|
97
|
-
ctx.ui.notify(savePath ? `pi-forge: next provider payload will be captured in the web editor and saved to ${savePath}.` : "pi-forge: next provider payload will be captured in the web editor.", "info");
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
ctx.ui.notify(savePath ? `pi-forge: next provider payload will be displayed and saved to ${savePath}.` : "pi-forge: next provider payload will be displayed before sending.", "info");
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
export function clearPayloadCapture(state: PiForgeRuntimeState, ctx: ExtensionCommandContext): void {
|
|
104
|
-
state.interceptNextProviderPayload = false;
|
|
105
|
-
state.interceptPayloadSavePath = undefined;
|
|
106
|
-
state.interceptPayloadDisplayTarget = "editor";
|
|
107
|
-
state.payloadCaptureArmedAt = undefined;
|
|
108
|
-
state.latestProviderPayloadCapture = undefined;
|
|
109
|
-
ctx.ui.setStatus("pi-forge-intercept", undefined);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export function webPayloadSnapshot(state: PiForgeRuntimeState): WebEditorPayloadSnapshot {
|
|
113
|
-
if (state.interceptNextProviderPayload) {
|
|
114
|
-
return {
|
|
115
|
-
status: "armed",
|
|
116
|
-
armedAt: state.payloadCaptureArmedAt,
|
|
117
|
-
savePath: state.interceptPayloadSavePath,
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
if (state.latestProviderPayloadCapture) {
|
|
121
|
-
return {
|
|
122
|
-
status: "captured",
|
|
123
|
-
capture: state.latestProviderPayloadCapture,
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
return { status: "idle" };
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function captureProviderPayload(
|
|
130
|
-
state: PiForgeRuntimeState,
|
|
131
|
-
active: LoadedPromptStack | undefined,
|
|
132
|
-
value: unknown,
|
|
133
|
-
savePath?: string,
|
|
134
|
-
): WebEditorPayloadCapture {
|
|
135
|
-
const capture = createProviderPayloadCapture(value, { stackId: active?.stack.id, savePath });
|
|
136
|
-
state.latestProviderPayloadCapture = capture;
|
|
137
|
-
return capture;
|
|
138
|
-
}
|
package/src/policy.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import type { PromptResourcePolicy } from "./types.ts";
|
|
2
|
-
|
|
3
|
-
export function hasResourcePolicy(policy: PromptResourcePolicy | undefined): boolean {
|
|
4
|
-
return !!policy && (hasEffectiveAllowPolicy(policy.allow) || hasPatterns(policy.deny));
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export function applyResourcePolicy(names: string[], policy: PromptResourcePolicy | undefined): string[] {
|
|
8
|
-
if (!hasResourcePolicy(policy)) return names;
|
|
9
|
-
if (hasEffectiveAllowPolicy(policy?.allow)) {
|
|
10
|
-
return names.filter((name) => matchesAnyPattern(name, policy.allow!));
|
|
11
|
-
}
|
|
12
|
-
if (hasPatterns(policy?.deny)) {
|
|
13
|
-
return names.filter((name) => !matchesAnyPattern(name, policy.deny!));
|
|
14
|
-
}
|
|
15
|
-
return names;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function matchesAnyPattern(name: string, patterns: string[]): boolean {
|
|
19
|
-
return patterns.some((pattern) => resourcePatternMatches(name, pattern));
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function resourcePatternMatches(name: string, pattern: string): boolean {
|
|
23
|
-
if (pattern === "*") return true;
|
|
24
|
-
if (!pattern.includes("*")) return name === pattern;
|
|
25
|
-
const escaped = pattern
|
|
26
|
-
.split("*")
|
|
27
|
-
.map(escapeRegExp)
|
|
28
|
-
.join(".*");
|
|
29
|
-
return new RegExp(`^${escaped}$`).test(name);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function hasPatterns(value: string[] | undefined): value is string[] {
|
|
33
|
-
return Array.isArray(value) && value.length > 0;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function hasEffectiveAllowPolicy(value: string[] | undefined): value is string[] {
|
|
37
|
-
return hasPatterns(value) && value.some((pattern) => pattern !== "*");
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function escapeRegExp(value: string): string {
|
|
41
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
42
|
-
}
|