@zihanw/pi-forge 0.4.0 → 0.5.0
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 +49 -1
- package/README.md +11 -11
- package/README.zh-CN.md +4 -6
- package/SUBAGENT_ADAPTER_CONTRACT.md +3 -1
- package/dist/agent-profile.d.ts +21 -42
- package/dist/agent-profile.d.ts.map +1 -1
- package/dist/agent-profile.js +82 -194
- 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/codecs/agent-profile.d.ts +53 -0
- package/dist/codecs/agent-profile.d.ts.map +1 -0
- package/dist/codecs/agent-profile.js +176 -0
- package/dist/codecs/agent-profile.js.map +1 -0
- package/dist/codecs/index.d.ts +5 -0
- package/dist/codecs/index.d.ts.map +1 -0
- package/dist/codecs/index.js +3 -0
- package/dist/codecs/index.js.map +1 -0
- package/dist/codecs/prompt-stack.d.ts +18 -0
- package/dist/codecs/prompt-stack.d.ts.map +1 -0
- package/dist/codecs/prompt-stack.js +479 -0
- package/dist/codecs/prompt-stack.js.map +1 -0
- package/dist/compile-cycle.d.ts +18 -0
- package/dist/compile-cycle.d.ts.map +1 -0
- package/dist/compile-cycle.js +13 -0
- package/dist/compile-cycle.js.map +1 -0
- package/dist/compiler.d.ts +10 -4
- package/dist/compiler.d.ts.map +1 -1
- package/dist/compiler.js +53 -19
- package/dist/compiler.js.map +1 -1
- package/dist/extension-registry.d.ts.map +1 -1
- package/dist/extension-registry.js +5 -2
- package/dist/extension-registry.js.map +1 -1
- package/dist/forge-config.d.ts +2 -81
- package/dist/forge-config.d.ts.map +1 -1
- package/dist/forge-config.js +5 -280
- package/dist/forge-config.js.map +1 -1
- package/dist/forge-v1/analyzer.d.ts +3 -0
- package/dist/forge-v1/analyzer.d.ts.map +1 -0
- package/dist/forge-v1/analyzer.js +50 -0
- package/dist/forge-v1/analyzer.js.map +1 -0
- package/dist/forge-v1/index.d.ts +6 -0
- package/dist/forge-v1/index.d.ts.map +1 -0
- package/dist/forge-v1/index.js +13 -0
- package/dist/forge-v1/index.js.map +1 -0
- package/dist/forge-v1/parser.d.ts +3 -0
- package/dist/forge-v1/parser.d.ts.map +1 -0
- package/dist/forge-v1/parser.js +186 -0
- package/dist/forge-v1/parser.js.map +1 -0
- package/dist/forge-v1/renderer.d.ts +9 -0
- package/dist/forge-v1/renderer.d.ts.map +1 -0
- package/dist/forge-v1/renderer.js +181 -0
- package/dist/forge-v1/renderer.js.map +1 -0
- package/dist/forge-v1/types.d.ts +87 -0
- package/dist/forge-v1/types.d.ts.map +1 -0
- package/dist/forge-v1/types.js +4 -0
- package/dist/forge-v1/types.js.map +1 -0
- package/dist/index.d.ts +12 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +49 -59
- package/dist/index.js.map +1 -1
- package/dist/lifecycle.d.ts +7 -5
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/lifecycle.js +44 -110
- package/dist/lifecycle.js.map +1 -1
- package/dist/loader.d.ts +16 -3
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +42 -440
- package/dist/loader.js.map +1 -1
- package/dist/macro-engine.d.ts +9 -14
- package/dist/macro-engine.d.ts.map +1 -1
- package/dist/macro-engine.js +5 -238
- package/dist/macro-engine.js.map +1 -1
- package/dist/payload-command.d.ts +6 -6
- package/dist/payload-command.d.ts.map +1 -1
- package/dist/payload-command.js.map +1 -1
- package/dist/payload-state.d.ts +16 -0
- package/dist/payload-state.d.ts.map +1 -0
- package/dist/payload-state.js +14 -0
- package/dist/payload-state.js.map +1 -0
- package/dist/preset-command.d.ts +4 -4
- package/dist/preset-command.d.ts.map +1 -1
- package/dist/preset-command.js +55 -98
- package/dist/preset-command.js.map +1 -1
- package/dist/preview.d.ts +4 -4
- package/dist/preview.d.ts.map +1 -1
- package/dist/preview.js +17 -8
- package/dist/preview.js.map +1 -1
- package/dist/profile-command.d.ts +2 -2
- package/dist/profile-command.d.ts.map +1 -1
- package/dist/profile-command.js +52 -26
- package/dist/profile-command.js.map +1 -1
- package/dist/profile-service.d.ts +5 -2
- package/dist/profile-service.d.ts.map +1 -1
- package/dist/profile-service.js +63 -42
- package/dist/profile-service.js.map +1 -1
- package/dist/prompt-analysis.d.ts +24 -0
- package/dist/prompt-analysis.d.ts.map +1 -0
- package/dist/prompt-analysis.js +84 -0
- package/dist/prompt-analysis.js.map +1 -0
- package/dist/prompt-runtime.d.ts +19 -0
- package/dist/prompt-runtime.d.ts.map +1 -0
- package/dist/prompt-runtime.js +30 -0
- package/dist/prompt-runtime.js.map +1 -0
- package/dist/regex.js +6 -12
- package/dist/regex.js.map +1 -1
- package/dist/render-helpers.d.ts +2 -10
- package/dist/render-helpers.d.ts.map +1 -1
- package/dist/render-helpers.js +3 -53
- package/dist/render-helpers.js.map +1 -1
- package/dist/repositories/agent-profile.d.ts +36 -0
- package/dist/repositories/agent-profile.d.ts.map +1 -0
- package/dist/repositories/agent-profile.js +153 -0
- package/dist/repositories/agent-profile.js.map +1 -0
- package/dist/repositories/index.d.ts +3 -0
- package/dist/repositories/index.d.ts.map +1 -0
- package/dist/repositories/index.js +3 -0
- package/dist/repositories/index.js.map +1 -0
- package/dist/repositories/prompt-stack.d.ts +57 -0
- package/dist/repositories/prompt-stack.d.ts.map +1 -0
- package/dist/repositories/prompt-stack.js +175 -0
- package/dist/repositories/prompt-stack.js.map +1 -0
- 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 +2 -2
- package/dist/runtime/profile-runtime.d.ts.map +1 -1
- package/dist/runtime/profile-runtime.js +18 -10
- package/dist/runtime/profile-runtime.js.map +1 -1
- package/dist/runtime/prompt-stack-runtime.d.ts +5 -4
- package/dist/runtime/prompt-stack-runtime.d.ts.map +1 -1
- package/dist/runtime/prompt-stack-runtime.js +47 -52
- package/dist/runtime/prompt-stack-runtime.js.map +1 -1
- package/dist/runtime/tool-policy-runtime.d.ts +2 -2
- package/dist/runtime/tool-policy-runtime.d.ts.map +1 -1
- package/dist/runtime/tool-policy-runtime.js +3 -3
- package/dist/runtime/tool-policy-runtime.js.map +1 -1
- package/dist/session-adapter.d.ts +17 -0
- package/dist/session-adapter.d.ts.map +1 -0
- package/dist/session-adapter.js +57 -0
- package/dist/session-adapter.js.map +1 -0
- package/dist/slot-renderers.d.ts +16 -3
- package/dist/slot-renderers.d.ts.map +1 -1
- package/dist/slot-renderers.js +15 -63
- package/dist/slot-renderers.js.map +1 -1
- package/dist/stack-migration.d.ts +6 -0
- package/dist/stack-migration.d.ts.map +1 -1
- package/dist/stack-migration.js +49 -52
- package/dist/stack-migration.js.map +1 -1
- package/dist/storage.d.ts +10 -0
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +45 -10
- package/dist/storage.js.map +1 -1
- package/dist/subagent/fingerprints.d.ts +24 -0
- package/dist/subagent/fingerprints.d.ts.map +1 -0
- package/dist/subagent/fingerprints.js +81 -0
- package/dist/subagent/fingerprints.js.map +1 -0
- package/dist/subagent/host-port.d.ts +296 -0
- package/dist/subagent/host-port.d.ts.map +1 -0
- package/dist/subagent/host-port.js +560 -0
- package/dist/subagent/host-port.js.map +1 -0
- package/dist/subagent/index.d.ts +10 -10
- package/dist/subagent/index.d.ts.map +1 -1
- package/dist/subagent/index.js +9 -10
- package/dist/subagent/index.js.map +1 -1
- package/dist/subagent-host.d.ts +99 -18
- package/dist/subagent-host.d.ts.map +1 -1
- package/dist/subagent-host.js +185 -162
- package/dist/subagent-host.js.map +1 -1
- package/dist/template-render.d.ts +18 -0
- package/dist/template-render.d.ts.map +1 -0
- package/dist/template-render.js +232 -0
- package/dist/template-render.js.map +1 -0
- package/dist/types.d.ts +43 -27
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +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.generated.d.ts.map +1 -1
- package/dist/web-editor/client-styles.generated.js +1 -1
- package/dist/web-editor/client-styles.generated.js.map +1 -1
- package/dist/web-editor/server.d.ts.map +1 -1
- package/dist/web-editor/server.js +32 -72
- 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 +13 -0
- package/dist/web-editor/styles.js.map +1 -1
- package/dist/web-editor/types.d.ts +10 -37
- package/dist/web-editor/types.d.ts.map +1 -1
- package/dist/web-host.d.ts +4 -2
- package/dist/web-host.d.ts.map +1 -1
- package/dist/web-host.js +110 -138
- package/dist/web-host.js.map +1 -1
- package/dist/workspace.d.ts +74 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +351 -0
- package/dist/workspace.js.map +1 -0
- package/docs/README.md +6 -4
- package/docs/concepts/agent-profiles.md +2 -2
- package/docs/concepts/prompt-stacks.md +12 -7
- package/docs/design/README.md +21 -3
- package/docs/design/architecture-0.5.md +211 -0
- package/docs/design/archive/0.5-full-proposal/0.5-consumer-audit.md +62 -0
- package/docs/design/archive/0.5-full-proposal/0.5-inventory.md +208 -0
- package/docs/design/archive/0.5-full-proposal/0.5-phase0-decision-drafts.md +237 -0
- package/docs/design/archive/0.5-full-proposal/README.md +12 -0
- package/docs/design/archive/0.5-full-proposal/architecture-0.5.md +423 -0
- package/docs/design/archive/0.5-full-proposal/host-discovery-spike.md +103 -0
- package/docs/design/archive/0.5-full-proposal/template-language-spike.md +156 -0
- package/docs/design/context-diff-plan.md +72 -0
- package/docs/design/decision-template.md +33 -0
- package/docs/design/roadmap-0.4-archive.md +1 -1
- package/docs/design/subagents/interface-design.md +1 -1
- package/docs/development/architecture-rules.md +148 -0
- package/docs/development/roadmap.md +39 -13
- package/docs/development/scoped-global-profiles-stacks.md +325 -0
- package/docs/development/setup.md +6 -4
- package/docs/getting-started.md +9 -6
- package/docs/guides/custom-macros-and-slots.md +8 -7
- package/docs/guides/debugging.md +1 -1
- package/docs/guides/delegation.md +25 -21
- package/docs/guides/migrating-to-0.5.md +107 -0
- package/docs/guides/use-cases.md +7 -11
- package/docs/guides/web-editor.md +7 -11
- package/docs/reference/commands.md +4 -3
- package/docs/reference/configuration.md +18 -17
- package/docs/reference/features.md +34 -79
- package/docs/reference/macros-and-slots.md +70 -49
- package/docs/reference/public-api.md +64 -17
- package/docs/reference/stack-schema.md +14 -9
- package/docs/reference/subagent-host-port.md +49 -0
- package/docs/zh-CN/README.md +3 -3
- package/docs/zh-CN/concepts/agent-profiles.md +4 -2
- package/docs/zh-CN/concepts/prompt-stacks.md +9 -7
- package/docs/zh-CN/getting-started.md +10 -7
- package/docs/zh-CN/guides/delegation.md +11 -13
- package/docs/zh-CN/guides/migrating-to-0.5.md +92 -0
- package/docs/zh-CN/guides/web-editor.md +7 -7
- package/docs/zh-CN/reference/commands.md +6 -3
- package/examples/custom-system-status-extension/README.md +3 -3
- package/examples/custom-system-status-extension/index.ts +2 -1
- package/examples/custom-system-status-extension/prompt-stack.json +4 -3
- package/examples/default-prompt-stack.json +9 -4
- package/examples/image-reader-prompt-stack.json +16 -26
- package/examples/reviewer-prompt-stack.json +13 -24
- package/package.json +101 -120
- package/dist/runtime/subagent-runtime.d.ts +0 -45
- package/dist/runtime/subagent-runtime.d.ts.map +0 -1
- package/dist/runtime/subagent-runtime.js +0 -335
- package/dist/runtime/subagent-runtime.js.map +0 -1
- package/dist/runtime-state.d.ts +0 -30
- package/dist/runtime-state.d.ts.map +0 -1
- package/dist/runtime-state.js +0 -17
- package/dist/runtime-state.js.map +0 -1
- package/dist/sillytavern-importer/items.d.ts +0 -3
- package/dist/sillytavern-importer/items.d.ts.map +0 -1
- package/dist/sillytavern-importer/items.js +0 -88
- package/dist/sillytavern-importer/items.js.map +0 -1
- package/dist/sillytavern-importer/macros.d.ts +0 -15
- package/dist/sillytavern-importer/macros.d.ts.map +0 -1
- package/dist/sillytavern-importer/macros.js +0 -141
- package/dist/sillytavern-importer/macros.js.map +0 -1
- package/dist/sillytavern-importer/prompt-order.d.ts +0 -6
- package/dist/sillytavern-importer/prompt-order.d.ts.map +0 -1
- package/dist/sillytavern-importer/prompt-order.js +0 -38
- package/dist/sillytavern-importer/prompt-order.js.map +0 -1
- package/dist/sillytavern-importer/regex.d.ts +0 -3
- package/dist/sillytavern-importer/regex.d.ts.map +0 -1
- package/dist/sillytavern-importer/regex.js +0 -275
- package/dist/sillytavern-importer/regex.js.map +0 -1
- package/dist/sillytavern-importer/report.d.ts +0 -21
- package/dist/sillytavern-importer/report.d.ts.map +0 -1
- package/dist/sillytavern-importer/report.js +0 -166
- package/dist/sillytavern-importer/report.js.map +0 -1
- package/dist/sillytavern-importer/types.d.ts +0 -106
- package/dist/sillytavern-importer/types.d.ts.map +0 -1
- package/dist/sillytavern-importer/types.js +0 -2
- package/dist/sillytavern-importer/types.js.map +0 -1
- package/dist/sillytavern-importer.d.ts +0 -5
- package/dist/sillytavern-importer.d.ts.map +0 -1
- package/dist/sillytavern-importer.js +0 -117
- package/dist/sillytavern-importer.js.map +0 -1
- package/dist/subagent/canonical.d.ts +0 -22
- package/dist/subagent/canonical.d.ts.map +0 -1
- package/dist/subagent/canonical.js +0 -24
- package/dist/subagent/canonical.js.map +0 -1
- package/dist/subagent/context.d.ts +0 -8
- package/dist/subagent/context.d.ts.map +0 -1
- package/dist/subagent/context.js +0 -125
- package/dist/subagent/context.js.map +0 -1
- package/dist/subagent/contract.d.ts +0 -10
- package/dist/subagent/contract.d.ts.map +0 -1
- package/dist/subagent/contract.js +0 -10
- package/dist/subagent/contract.js.map +0 -1
- package/dist/subagent/plan.d.ts +0 -18
- package/dist/subagent/plan.d.ts.map +0 -1
- package/dist/subagent/plan.js +0 -157
- package/dist/subagent/plan.js.map +0 -1
- package/dist/subagent/preflight.d.ts +0 -4
- package/dist/subagent/preflight.d.ts.map +0 -1
- package/dist/subagent/preflight.js +0 -108
- package/dist/subagent/preflight.js.map +0 -1
- package/dist/subagent/request.d.ts +0 -4
- package/dist/subagent/request.d.ts.map +0 -1
- package/dist/subagent/request.js +0 -122
- package/dist/subagent/request.js.map +0 -1
- package/dist/subagent/response.d.ts +0 -8
- package/dist/subagent/response.d.ts.map +0 -1
- package/dist/subagent/response.js +0 -155
- package/dist/subagent/response.js.map +0 -1
- package/dist/subagent/tools.d.ts +0 -4
- package/dist/subagent/tools.d.ts.map +0 -1
- package/dist/subagent/tools.js +0 -42
- package/dist/subagent/tools.js.map +0 -1
- package/dist/subagent/types.d.ts +0 -268
- package/dist/subagent/types.d.ts.map +0 -1
- package/dist/subagent/types.js +0 -3
- package/dist/subagent/types.js.map +0 -1
- package/dist/subagent/validation.d.ts +0 -35
- package/dist/subagent/validation.d.ts.map +0 -1
- package/dist/subagent/validation.js +0 -314
- package/dist/subagent/validation.js.map +0 -1
- package/dist/subagent-command.d.ts +0 -4
- package/dist/subagent-command.d.ts.map +0 -1
- package/dist/subagent-command.js +0 -246
- package/dist/subagent-command.js.map +0 -1
- package/dist/subagent-profile-tool.d.ts +0 -49
- package/dist/subagent-profile-tool.d.ts.map +0 -1
- package/dist/subagent-profile-tool.js +0 -124
- package/dist/subagent-profile-tool.js.map +0 -1
- package/dist/subagent-tool.d.ts +0 -53
- package/dist/subagent-tool.d.ts.map +0 -1
- package/dist/subagent-tool.js +0 -456
- package/dist/subagent-tool.js.map +0 -1
- package/docs/guides/sillytavern-import.md +0 -47
- package/docs/reference/subagent-adapter.md +0 -204
- package/examples/sillytavern-dm-writer-prompt-stack.json +0 -190
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
# Scoped global profiles and prompt stacks
|
|
2
|
+
|
|
3
|
+
[Documentation](../README.md) · [Roadmap](roadmap.md)
|
|
4
|
+
|
|
5
|
+
Status: accepted design; implementation complete for 0.4.1 (identity, catalogs, scoped stacks/profiles, persistence, auto-activation, delegation, zh-CN docs, and web-editor global create/fork/import with explicit scope). Historical record: the delegation-policy references to `.pi/forge/config.json` `subagents.*` below are superseded in 0.5 — delegation configuration moved to the optional package's dedicated `subagents.json` files (see the [0.5 migration guide](../guides/migrating-to-0.5.md)).
|
|
6
|
+
|
|
7
|
+
## Confirmed design decisions
|
|
8
|
+
|
|
9
|
+
Recorded before implementation started; these resolve the options left open by the analysis above.
|
|
10
|
+
|
|
11
|
+
- **D1** Unified resource ID grammar: `/^[A-Za-z0-9][A-Za-z0-9._-]*$/` for both profiles and stacks. `:` is reserved for scope qualification and rejected in JSON IDs (with a diagnostic, not a load failure).
|
|
12
|
+
- **D2** When capturing/saving a profile, `promptStack` is serialized relative to the target profile scope: same scope writes a bare ID, a different scope writes a qualified selector (`global:<id>`), and a global profile is never allowed to reference a project stack (the save is rejected).
|
|
13
|
+
- **D3** Global profiles/stacks are loaded and can be browsed/previewed in untrusted projects, but applying a profile or stack still requires project trust.
|
|
14
|
+
- **D4** Subagent delegation remains entirely disabled in untrusted projects, including for global profiles.
|
|
15
|
+
- **D5** `default.json` has no special auto-activation role anymore. Only `autoActivate: true` participates in standalone stack activation. A `default.json` without an explicit `autoActivate` field receives a one-time migration warning; `autoActivate: false` remains an explicit opt-out. Multiple `autoActivate: true` stacks in the same scope fail closed.
|
|
16
|
+
- **D6** Legacy provenance records without a scope field are interpreted as project-scoped.
|
|
17
|
+
- **D7** `forge_subagent` accepts a bare `profileId` through effective lookup (project first) and `global:<id>` for exact global access; tool descriptions and `forge_subagent_profiles` explain the canonical selectors.
|
|
18
|
+
- **D8** New session entries and provenance persist the string selector form (`project:<id>` / `global:<id>`); `none` stays a scope-independent bare opt-out.
|
|
19
|
+
- **D9** Runtime state keeps flat `Loaded*[]` arrays whose entries carry `scope`/`key`; a shared catalog module owns `all`/`effective`/exact resolution.
|
|
20
|
+
- **D10** Web editor API routes encode scope as a single path segment (`scope:id`, e.g. `/api/stacks/global:reviewer`).
|
|
21
|
+
- **D11** A new `PI_FORGE_GLOBAL_DIR` environment override replaces the real `~/.pi/forge` for tests and embedders; loaders accept an explicit global Forge directory, and `globalForgeDir()` is only the default.
|
|
22
|
+
- **D12** Slice 5 is split into 5a (forge-config data model, scoped authorization, and unit tests) and 5b (discovery, tool descriptions, approval display, commands, docs, and browser verification).
|
|
23
|
+
- **D13** The web editor may edit/delete global resources when the route uses an explicit scope; unqualified routes remain project-only.
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
This note defines the resource identity, lookup, activation, persistence, and delegation model for adding user-global agent profiles and prompt stacks without weakening project shadowing or authorization boundaries.
|
|
27
|
+
|
|
28
|
+
## Goals
|
|
29
|
+
|
|
30
|
+
- Reuse profiles and prompt stacks across projects.
|
|
31
|
+
- Keep common commands concise through project-over-global shadowing.
|
|
32
|
+
- Preserve an explicit way to address either scope when IDs collide.
|
|
33
|
+
- Make stored profile dependencies deterministic rather than dependent on later shadowing.
|
|
34
|
+
- Keep global and project delegation authorization separate.
|
|
35
|
+
- Preserve existing project-only files and unqualified commands where no collision exists.
|
|
36
|
+
|
|
37
|
+
## Non-goals
|
|
38
|
+
|
|
39
|
+
- Do not add inheritance or merging between two profile or stack definitions.
|
|
40
|
+
- Do not make profiles continuously own runtime state.
|
|
41
|
+
- Do not move tool or skill policy from prompt stacks into profiles.
|
|
42
|
+
- Do not let a global profile depend on project-controlled prompt content.
|
|
43
|
+
- Do not add writable subagents, compaction settings, or a concurrency cap as part of this feature.
|
|
44
|
+
|
|
45
|
+
## Storage and identity
|
|
46
|
+
|
|
47
|
+
Global resources use the existing user-owned Forge root:
|
|
48
|
+
|
|
49
|
+
```text
|
|
50
|
+
~/.pi/forge/prompt-stacks/*.json
|
|
51
|
+
~/.pi/forge/agent-profiles/*.json
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Project resources keep their current locations:
|
|
55
|
+
|
|
56
|
+
```text
|
|
57
|
+
<project>/.pi/forge/prompt-stacks/*.json
|
|
58
|
+
<project>/.pi/forge/agent-profiles/*.json
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The JSON `id` remains an unqualified value such as `reviewer`. Scope comes from the storage location and must not be duplicated as an editable field in the file.
|
|
62
|
+
|
|
63
|
+
Every loaded resource must carry a first-class scoped identity:
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
type ResourceScope = "global" | "project";
|
|
67
|
+
|
|
68
|
+
interface ResourceKey {
|
|
69
|
+
scope: ResourceScope;
|
|
70
|
+
id: string;
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Do not repeatedly infer scope from `filePath`. Loaded profiles and stacks should expose their scope/key directly, and runtime state should compare keys rather than bare IDs.
|
|
75
|
+
|
|
76
|
+
Duplicate IDs are errors only within one scope. A project and global resource with the same ID form a valid shadow pair.
|
|
77
|
+
|
|
78
|
+
## Selector syntax
|
|
79
|
+
|
|
80
|
+
Commands, completion candidates, profile stack references, persisted diagnostics, and delegation discovery use one selector grammar:
|
|
81
|
+
|
|
82
|
+
```text
|
|
83
|
+
reviewer
|
|
84
|
+
project:reviewer
|
|
85
|
+
global:reviewer
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Existing resource IDs cannot contain `:`, so qualification is unambiguous. Reject unknown scope prefixes, empty IDs, and malformed selectors with a specific diagnostic.
|
|
89
|
+
|
|
90
|
+
The canonical formatter should return:
|
|
91
|
+
|
|
92
|
+
- `reviewer` only when presenting the effective unqualified resource;
|
|
93
|
+
- `project:reviewer` or `global:reviewer` when exact identity matters;
|
|
94
|
+
- qualified selectors for both resources when a collision must be shown.
|
|
95
|
+
|
|
96
|
+
Internally, parse selectors into `{ scope?: ResourceScope; id: string }` and resolve them to a required `ResourceKey` before mutation, application, persistence, or delegation.
|
|
97
|
+
|
|
98
|
+
## Two lookup modes
|
|
99
|
+
|
|
100
|
+
Unqualified interactive selection and unqualified profile dependencies deliberately use different lookup rules.
|
|
101
|
+
|
|
102
|
+
### Effective lookup
|
|
103
|
+
|
|
104
|
+
Commands such as `/preset use` and `/profile use` use effective lookup:
|
|
105
|
+
|
|
106
|
+
1. A qualified selector resolves only the named scope.
|
|
107
|
+
2. An unqualified selector resolves the project resource when present.
|
|
108
|
+
3. Otherwise it resolves the global resource.
|
|
109
|
+
4. A project definition shadows the same-ID global definition even when the project definition is invalid. The invalid shadow fails closed; it must not silently fall back to the global resource.
|
|
110
|
+
|
|
111
|
+
Examples:
|
|
112
|
+
|
|
113
|
+
```text
|
|
114
|
+
/profile use reviewer # project first, otherwise global
|
|
115
|
+
/profile use global:reviewer # exact global profile
|
|
116
|
+
/preset use project:reviewer # exact project stack
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Both colliding resources remain inspectable and explicitly selectable. Shadowing is an ergonomic default, not deletion of the global definition.
|
|
120
|
+
|
|
121
|
+
### Profile dependency lookup
|
|
122
|
+
|
|
123
|
+
A profile's `promptStack` is a stored dependency and must remain stable when unrelated files are later added. Its unqualified reference therefore resolves relative to the profile's own scope rather than through effective lookup.
|
|
124
|
+
|
|
125
|
+
| Profile scope | `"reviewer"` | `"project:reviewer"` | `"global:reviewer"` |
|
|
126
|
+
|---|---|---|---|
|
|
127
|
+
| Project | project stack | project stack | global stack |
|
|
128
|
+
| Global | global stack | rejected | global stack |
|
|
129
|
+
|
|
130
|
+
Consequences:
|
|
131
|
+
|
|
132
|
+
- A project profile may use either a project stack or an explicitly qualified global stack.
|
|
133
|
+
- A project profile with `"promptStack": "reviewer"` does not fall back to a global stack when the project stack is missing. The diagnostic should suggest `global:reviewer` when that global stack exists.
|
|
134
|
+
- A global profile may use only global stacks. `project:*` is rejected even if the project is trusted.
|
|
135
|
+
- Adding a project stack later cannot silently change the dependency of a project profile that explicitly uses `global:reviewer`.
|
|
136
|
+
- A project cannot replace the prompt or tool policy of a user-authorized global profile.
|
|
137
|
+
|
|
138
|
+
The string form remains sufficient for profile schema v1 because qualification expands the accepted reference syntax without adding a new field or object shape. Existing project profiles keep resolving their unqualified stack IDs to project stacks.
|
|
139
|
+
|
|
140
|
+
## Loading and catalogs
|
|
141
|
+
|
|
142
|
+
Global definitions are user-owned and may load independently of project trust. Project definitions load only when the project is trusted.
|
|
143
|
+
|
|
144
|
+
Pure loaders and tests must not accidentally read the developer's real home directory. Prefer an explicit catalog/repository input for the global Forge directory over relying on a process-wide environment variable. Existing project-only public loader functions may remain as compatibility wrappers while the extension runtime adopts scoped catalog loaders.
|
|
145
|
+
|
|
146
|
+
Maintain both views:
|
|
147
|
+
|
|
148
|
+
- `all`: every loaded scoped definition, including shadowed resources;
|
|
149
|
+
- `effective`: one resource per unqualified ID after project-over-global shadowing.
|
|
150
|
+
|
|
151
|
+
Centralize resolution helpers instead of continuing to use bare `array.find(candidate.id === id)` calls. Application, preview, mutation, auto-activation, subagent preparation, and the editor must resolve through the same catalog semantics.
|
|
152
|
+
|
|
153
|
+
## Selection and persistence
|
|
154
|
+
|
|
155
|
+
New session entries must persist the exact scoped key, not just the bare ID. This prevents a restored global selection from changing to a newly created project shadow after reload or tree navigation.
|
|
156
|
+
|
|
157
|
+
For compatibility:
|
|
158
|
+
|
|
159
|
+
- Read legacy branch entries containing only `activeStackId` using effective lookup.
|
|
160
|
+
- Write new entries with a scoped active-stack reference.
|
|
161
|
+
- Preserve the explicit `none`/`off` selection as a scope-independent opt-out.
|
|
162
|
+
- Profile provenance should add the profile scope/key while continuing to accept older provenance that has only `profileId` and `sourcePath`.
|
|
163
|
+
- Drift snapshots should store the resolved scoped stack reference so status can distinguish definition changes from a scope change.
|
|
164
|
+
|
|
165
|
+
Profile application remains transactional and one-shot. Later manual model/thinking changes remain respected; the selected stack continues enforcing its existing policy exactly as it does now.
|
|
166
|
+
|
|
167
|
+
## Auto-activation
|
|
168
|
+
|
|
169
|
+
Restored branch state and explicit opt-out continue to take precedence over all fresh-session defaults.
|
|
170
|
+
|
|
171
|
+
For agent profiles:
|
|
172
|
+
|
|
173
|
+
1. Inspect project `autoActivate: true` candidates first.
|
|
174
|
+
2. If any project candidate exists, do not fall back to a global candidate.
|
|
175
|
+
3. Exactly one usable project candidate applies; an invalid or ambiguous project selection fails closed.
|
|
176
|
+
4. If no project candidate exists, apply the same rules to global candidates.
|
|
177
|
+
5. A project and global auto-activation candidate are not a conflict because project scope has explicit precedence.
|
|
178
|
+
|
|
179
|
+
For standalone prompt-stack activation, apply the same scope precedence after profile auto-activation has declined to select a profile:
|
|
180
|
+
|
|
181
|
+
1. Only stacks with `autoActivate: true` participate; `default.json` has no filename-based activation role (D5).
|
|
182
|
+
2. Resolve project candidates before global candidates.
|
|
183
|
+
3. A same-ID project stack shadows the global stack, including an invalid shadow or `autoActivate: false` opt-out.
|
|
184
|
+
4. Exactly one usable candidate applies; multiple `autoActivate: true` stacks in the same scope fail closed.
|
|
185
|
+
5. Do not silently activate the global same-ID stack through an invalid or opted-out project shadow.
|
|
186
|
+
6. Preserve the existing rule that agent-profile auto-activation takes precedence over standalone stack activation, including profiles whose `promptStack` is `null`.
|
|
187
|
+
|
|
188
|
+
## Commands and editor behavior
|
|
189
|
+
|
|
190
|
+
Unqualified commands use effective lookup. Qualified commands address exact scope.
|
|
191
|
+
|
|
192
|
+
Recommended command behavior:
|
|
193
|
+
|
|
194
|
+
```text
|
|
195
|
+
/preset use reviewer
|
|
196
|
+
/preset use global:reviewer
|
|
197
|
+
/profile use project:reviewer
|
|
198
|
+
/profile preview global:reviewer
|
|
199
|
+
/profile save reviewer # project by default
|
|
200
|
+
/profile save global:reviewer # explicit global mutation
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Mutations must resolve the target scope before computing a path. Existing overwrite, changed-file, containment, and symbolic-link protections apply independently to each storage root. Global mutation must always be explicit; an unqualified save/fork/import continues to target project storage.
|
|
204
|
+
|
|
205
|
+
The web editor should:
|
|
206
|
+
|
|
207
|
+
- show global/project badges on profiles and stacks;
|
|
208
|
+
- show `shadows global:<id>` and `shadowed by project:<id>` states;
|
|
209
|
+
- retain both resources in navigation when IDs collide;
|
|
210
|
+
- require explicit scope for create, fork, import, save-as, and delete targets;
|
|
211
|
+
- prevent editing a shadowed global resource through an unqualified project route;
|
|
212
|
+
- keep the current token, trust, idle-state, overwrite, and browser-test protections for mutations.
|
|
213
|
+
|
|
214
|
+
Completions may prefer concise unqualified effective selectors, but must also offer qualified selectors when a collision exists or when the user has begun typing a scope prefix.
|
|
215
|
+
|
|
216
|
+
## Delegation boundary
|
|
217
|
+
|
|
218
|
+
Delegation authorization follows the profile's scope, not the effective unqualified ID:
|
|
219
|
+
|
|
220
|
+
- `~/.pi/forge/config.json` `subagents.profiles.<id>` authorizes only `global:<id>`.
|
|
221
|
+
- `<project>/.pi/forge/config.json` `subagents.profiles.<id>` authorizes only `project:<id>`.
|
|
222
|
+
- Same-ID global and project profiles never inherit enablement, backend, or timeout policy from one another.
|
|
223
|
+
- General backend, timeout, and summary defaults retain their current global-then-project layering.
|
|
224
|
+
- Deleting a profile clears delegation policy only from the matching scope's config.
|
|
225
|
+
- A global profile remains bound to global prompt content even when a project profile or stack shadows the same ID.
|
|
226
|
+
|
|
227
|
+
`forge_subagent_profiles` should return canonical callable selectors. When both scopes expose the same ID, the project profile may use the concise effective selector and the global profile must remain callable as `global:<id>`. The `forge_subagent` parameter, `/forge-agent` commands, embedded description summary, preparation lookup, approval display, fingerprints, and reports must retain exact scope.
|
|
228
|
+
|
|
229
|
+
Global profiles are user-owned, but ordinary delegation safety does not change: profiles remain disabled unless authorized in the matching config, unattended invocation remains a separate trusted-project decision, and read-only still does not imply an OS sandbox.
|
|
230
|
+
|
|
231
|
+
## Compatibility and migration
|
|
232
|
+
|
|
233
|
+
- No files move automatically.
|
|
234
|
+
- Existing `.pi/forge` and legacy `.pi/prompt-stacks` resources remain project-scoped.
|
|
235
|
+
- Existing project profile `promptStack` strings remain project-relative.
|
|
236
|
+
- Existing unqualified commands behave the same when no global collision exists.
|
|
237
|
+
- Legacy bare-ID session entries restore through effective lookup; all new entries record scope.
|
|
238
|
+
- Same-ID cross-scope definitions are valid and must not receive duplicate-ID errors.
|
|
239
|
+
- Duplicate IDs within one scope keep the current fail-closed diagnostics.
|
|
240
|
+
- Global `subagents.profiles` entries, which currently warn and are ignored, become scoped authorization for global profiles only. Document this behavior change prominently.
|
|
241
|
+
- Public loaded-resource types may add scope/key metadata without removing existing fields; compatibility helpers should continue accepting legacy bare IDs where persisted data requires them.
|
|
242
|
+
|
|
243
|
+
## Implementation slices
|
|
244
|
+
|
|
245
|
+
Each slice should land with focused tests and leave the full verification surface green.
|
|
246
|
+
|
|
247
|
+
### Slice 1: scoped identity and storage
|
|
248
|
+
|
|
249
|
+
- Add `ResourceScope`, `ResourceKey`, selector parsing/formatting, and exact/effective resolution primitives.
|
|
250
|
+
- Add global profile/stack directory and safe mutation-path helpers.
|
|
251
|
+
- Add scope/key metadata to loaded resources.
|
|
252
|
+
- Keep JSON IDs unqualified and validate selector syntax separately from ID syntax.
|
|
253
|
+
- Add table-driven parser, formatter, storage-containment, and same-ID-key tests.
|
|
254
|
+
|
|
255
|
+
Exit criterion: scoped resources can be represented and addressed without changing runtime loading behavior.
|
|
256
|
+
|
|
257
|
+
### Slice 2: scoped stack catalog and persistence
|
|
258
|
+
|
|
259
|
+
- Load global stacks plus trusted project/legacy stacks into `all` and `effective` views.
|
|
260
|
+
- Implement project shadowing, exact qualified selection, and invalid-shadow fail-closed behavior.
|
|
261
|
+
- Replace bare-ID runtime lookups with catalog resolution.
|
|
262
|
+
- Persist scoped active-stack references and restore legacy bare-ID entries.
|
|
263
|
+
- Apply scoped standalone stack auto-activation and explicit opt-out rules.
|
|
264
|
+
|
|
265
|
+
Exit criterion: `/preset` runtime behavior, branch restoration, tool policy, preview, and stack diagnostics operate correctly across both scopes before profiles are migrated.
|
|
266
|
+
|
|
267
|
+
### Slice 3: scoped profiles and dependency resolution
|
|
268
|
+
|
|
269
|
+
- Load global and trusted-project profiles with duplicate and auto-activation diagnostics scoped correctly.
|
|
270
|
+
- Implement the profile-to-stack resolution matrix.
|
|
271
|
+
- Extend preview, application, rollback, provenance, drift, save, delete, and reload with exact scoped keys.
|
|
272
|
+
- Preserve profile auto-activation precedence over standalone stacks.
|
|
273
|
+
- Extend host/subagent profile snapshots and fingerprints with resolved scope where required without changing legacy provenance fingerprint interpretation.
|
|
274
|
+
|
|
275
|
+
Exit criterion: global and project profiles apply deterministically, including explicit project-to-global stack reuse and rejection of global-to-project references.
|
|
276
|
+
|
|
277
|
+
### Slice 4: commands and web editor
|
|
278
|
+
|
|
279
|
+
- Add qualified parsing and completions to `/preset`, `/profile`, and editor APIs.
|
|
280
|
+
- Make unqualified mutations project-scoped and global mutations explicit.
|
|
281
|
+
- Show scope, collisions, shadow relationships, exact dependencies, and scoped drift in human surfaces.
|
|
282
|
+
- Add real-browser coverage for browsing, applying, editing, forking, deleting, collision handling, and failed scoped preflight.
|
|
283
|
+
|
|
284
|
+
Exit criterion: users can understand and manage both scopes without an unqualified action mutating a global resource.
|
|
285
|
+
|
|
286
|
+
### Slice 5: scoped delegation, documentation, and release verification
|
|
287
|
+
|
|
288
|
+
- Accept global profile authorization from global config and project profile authorization from project config.
|
|
289
|
+
- Update discovery, embedded summaries, callable selectors, `/forge-agent`, preparation, approval, reports, and policy cleanup.
|
|
290
|
+
- Test same-ID profiles with independent enablement/backend/timeout settings and no authority inheritance.
|
|
291
|
+
- Update English and Chinese concepts, guides, commands, configuration, schema/reference, feature inventory, changelog, and roadmap.
|
|
292
|
+
- Regenerate tracked browser assets and `dist`, then run `npm run verify` and a packed-install smoke test.
|
|
293
|
+
|
|
294
|
+
Exit criterion: scoped ordinary use and scoped delegation are documented, fail closed, package-clean, and verified end to end.
|
|
295
|
+
|
|
296
|
+
## Required scenario coverage
|
|
297
|
+
|
|
298
|
+
At minimum, automated tests should cover:
|
|
299
|
+
|
|
300
|
+
- Global-only, project-only, and same-ID collision lookup.
|
|
301
|
+
- Exact global access while shadowed.
|
|
302
|
+
- Invalid project shadow without global fallback.
|
|
303
|
+
- Global profile to global stack.
|
|
304
|
+
- Project profile to unqualified project stack.
|
|
305
|
+
- Project profile to explicitly qualified global stack.
|
|
306
|
+
- Missing project stack with a same-ID global suggestion but no fallback.
|
|
307
|
+
- Rejected global profile to project stack.
|
|
308
|
+
- Project auto-activation precedence, global fallback, ambiguity, invalid candidate, restored branch, and explicit opt-out.
|
|
309
|
+
- `default.json` no longer auto-activates by filename; missing `autoActivate` yields a migration warning (D5).
|
|
310
|
+
- Scoped session restoration after a new shadow appears.
|
|
311
|
+
- Scoped provenance and drift after source edits or scope changes.
|
|
312
|
+
- Independent global/project delegation authorization for the same ID.
|
|
313
|
+
- Deletion clearing only matching-scope delegation policy.
|
|
314
|
+
- Untrusted projects loading global resources but not project resources.
|
|
315
|
+
- Web-editor collision navigation and explicit-scope mutation safeguards.
|
|
316
|
+
|
|
317
|
+
## Architectural guardrails
|
|
318
|
+
|
|
319
|
+
- Keep resolution in shared catalog/services; do not duplicate shadow rules across commands, the editor, and subagent code.
|
|
320
|
+
- Never use project-over-global effective lookup for a stored global profile dependency.
|
|
321
|
+
- Never infer delegation authority from a bare ID after profile resolution.
|
|
322
|
+
- Never persist a new active selection or provenance record without exact scope.
|
|
323
|
+
- Never silently fall back across scopes after an explicit selector or an invalid shadow.
|
|
324
|
+
- Keep profile application transactional and tool/skill policy owned by the resolved prompt stack.
|
|
325
|
+
- Require the complete unit, browser, type, generated-output, documentation, and package verification surface for the final slice.
|
|
@@ -14,6 +14,8 @@ pi
|
|
|
14
14
|
|
|
15
15
|
Trust the project in Pi and use `/reload` when needed.
|
|
16
16
|
|
|
17
|
+
Before making structural changes, read the [architecture and development rules](architecture-rules.md) and the active [0.5 architecture plan](../design/architecture-0.5.md). Boundary, schema, persistence, public API, and product changes require an accepted architecture decision before implementation.
|
|
18
|
+
|
|
17
19
|
The npm package loads compiled `dist/index.js` and intentionally omits physical `src/` files. Clone or fork the repository to inspect or modify source; do not edit generated files in `node_modules`.
|
|
18
20
|
|
|
19
21
|
## Load the extension
|
|
@@ -67,9 +69,9 @@ Document the tested range separately from peer constraints. Pi-coupled experimen
|
|
|
67
69
|
|
|
68
70
|
## Package boundaries
|
|
69
71
|
|
|
70
|
-
- `@zihanw/pi-forge` is the Pi extension and stable macro/slot registration surface.
|
|
71
|
-
- `@zihanw/pi-forge/subagent` is the
|
|
72
|
-
- `@zihanw/pi-
|
|
73
|
-
-
|
|
72
|
+
- `@zihanw/pi-forge` is the Pi extension (default export) and the stable macro/slot registration surface; no other root exports or `src/*` aliases exist.
|
|
73
|
+
- `@zihanw/pi-forge/subagent` is the experimental versioned host-port entry point (wire DTOs, validators, transport, client/host lifecycle, canonical fingerprints).
|
|
74
|
+
- `@zihanw/pi-forge-subagents` is the optional package owning subagent execution, configuration, and the 0.4 execution contract.
|
|
75
|
+
- `@zihanw/pi-subagent-runtime` owns execution lifecycle and fresh-process backends (a dependency of the optional package, not of the main package).
|
|
74
76
|
|
|
75
77
|
See the [public API policy](../reference/public-api.md).
|
package/docs/getting-started.md
CHANGED
|
@@ -62,7 +62,7 @@ Select the model, thinking level, and prompt stack you want in Pi, then save the
|
|
|
62
62
|
/profile use reviewer
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
Profiles live in `.pi/forge/agent-profiles/*.json`. Applying one is a preflighted, one-shot operation: later manual model/thinking changes remain until you apply the profile again. Read [agent-profile concepts](concepts/agent-profiles.md) for validation, auto-activation, and drift semantics.
|
|
65
|
+
Profiles live in `.pi/forge/agent-profiles/*.json` by default; `/profile save global:<id>` writes to `~/.pi/forge/agent-profiles`. Applying one is a preflighted, one-shot operation: later manual model/thinking changes remain until you apply the profile again. Read [agent-profile concepts](concepts/agent-profiles.md) for validation, auto-activation, and drift semantics.
|
|
66
66
|
|
|
67
67
|
## Storage and migration
|
|
68
68
|
|
|
@@ -70,12 +70,15 @@ Profiles live in `.pi/forge/agent-profiles/*.json`. Applying one is a preflighte
|
|
|
70
70
|
|---|---|
|
|
71
71
|
| `.pi/forge/prompt-stacks/` | Project prompt stacks |
|
|
72
72
|
| `.pi/forge/agent-profiles/` | Project agent profiles |
|
|
73
|
-
| `.pi/forge/config.json` | Trusted project configuration
|
|
73
|
+
| `.pi/forge/config.json` | Trusted project configuration (`webEditor.*`) |
|
|
74
74
|
| `.pi/forge/extensions/` | Trusted project macro/slot registration code |
|
|
75
|
-
| `~/.pi/forge/
|
|
75
|
+
| `~/.pi/forge/prompt-stacks/` | User-global prompt stacks |
|
|
76
|
+
| `~/.pi/forge/agent-profiles/` | User-global agent profiles |
|
|
77
|
+
| `~/.pi/forge/config.json` | User defaults (`webEditor.*`) |
|
|
78
|
+
| `.pi/forge/subagents.json` / `~/.pi/forge/subagents.json` | Delegation authorization owned by the optional `@zihanw/pi-forge-subagents` package |
|
|
76
79
|
| `~/.pi/forge/extensions/` | Trusted user macro/slot registration code |
|
|
77
80
|
|
|
78
|
-
Legacy `.pi/prompt-stacks/*.json` files remain readable.
|
|
81
|
+
Legacy `.pi/prompt-stacks/*.json` files remain readable. Command-created stacks go to `.pi/forge/prompt-stacks`; use the web editor's `global` scope selector to create stacks in `~/.pi/forge/prompt-stacks`. Same-named new-location files shadow legacy ones. Migrate safely with:
|
|
79
82
|
|
|
80
83
|
```text
|
|
81
84
|
/preset migrate-stacks --dry-run
|
|
@@ -87,7 +90,7 @@ Add `--overwrite` only when target replacement is intended. Add `--delete-legacy
|
|
|
87
90
|
## Where to go next
|
|
88
91
|
|
|
89
92
|
- Learn the [prompt-stack model](concepts/prompt-stacks.md).
|
|
90
|
-
- Fork a [focused reviewer](../examples/reviewer-prompt-stack.json)
|
|
91
|
-
- Use the [SillyTavern importer](guides/sillytavern-import.md).
|
|
93
|
+
- Fork a [focused reviewer](../examples/reviewer-prompt-stack.json).
|
|
92
94
|
- Learn [macros and slots](reference/macros-and-slots.md).
|
|
95
|
+
- Read the [0.5 migration guide](guides/migrating-to-0.5.md).
|
|
93
96
|
- Inspect the [complete commands](reference/commands.md) and [stack schema](reference/stack-schema.md).
|
|
@@ -15,8 +15,9 @@ Modules receive the pi-forge API directly, so they do not need to import the pac
|
|
|
15
15
|
export default function register(api) {
|
|
16
16
|
api.registerMacro({
|
|
17
17
|
name: "ticketId",
|
|
18
|
-
description: "Current ticket id from
|
|
19
|
-
|
|
18
|
+
description: "Current ticket id from static parameters.",
|
|
19
|
+
dependencies: ["parameters.ticket.id"],
|
|
20
|
+
render: ({ env, helpers }) => String(env.parameters["ticket.id"]),
|
|
20
21
|
});
|
|
21
22
|
|
|
22
23
|
api.registerSlot({
|
|
@@ -25,10 +26,10 @@ export default function register(api) {
|
|
|
25
26
|
options: {
|
|
26
27
|
heading: { type: "string", default: "Ticket context" },
|
|
27
28
|
},
|
|
28
|
-
render: (
|
|
29
|
-
String(
|
|
30
|
-
"- Ticket: " +
|
|
31
|
-
"- Project: " +
|
|
29
|
+
render: ({ item, options, env, helpers }) => [
|
|
30
|
+
String(options.heading ?? "Ticket context") + ":",
|
|
31
|
+
"- Ticket: " + String(env.parameters["ticket.id"]),
|
|
32
|
+
"- Project: " + helpers.normalizePath(String(env.runtime.cwd)),
|
|
32
33
|
].join("\n"),
|
|
33
34
|
});
|
|
34
35
|
}
|
|
@@ -57,7 +58,7 @@ Use the slot declaratively:
|
|
|
57
58
|
- Missing custom slots are validation warnings until their module is loaded.
|
|
58
59
|
- Registration ownership is disposed when the runtime shuts down.
|
|
59
60
|
|
|
60
|
-
The API provides `
|
|
61
|
+
The API provides `forgeDir`, `extensionPath`, helpers, registration functions, and `getRegisteredMacros()` / `getRegisteredSlots()`. Custom macro renderers receive a frozen `{ env, helpers }` and dependencies from the declaration. Global `forgeDir` is `~/.pi/forge`; project `forgeDir` is `<project>/.pi/forge`.
|
|
61
62
|
|
|
62
63
|
Reusable Pi packages may import `registerMacro` and `registerSlot` from `@zihanw/pi-forge`. The directory loaders are intended for small trusted customizations without package boilerplate.
|
|
63
64
|
|
package/docs/guides/debugging.md
CHANGED
|
@@ -30,7 +30,7 @@ Saved payloads can contain prompt and conversation content. Keep them out of ver
|
|
|
30
30
|
|
|
31
31
|
## Common checks
|
|
32
32
|
|
|
33
|
-
- Unexpected duplicate task: set the `chat-history` slot's `includeLastUserMessage` to `false` when a later block uses `{{lastUserMessage}}`.
|
|
33
|
+
- Unexpected duplicate task: set the `chat-history` slot's `includeLastUserMessage` to `false` when a later block uses `{{ runtime.lastUserMessage }}`.
|
|
34
34
|
- Missing tool: inspect stack `allow`/`deny` policy and `/preset status`; the tool-call guard enforces the selected stack even if another extension modifies active tools.
|
|
35
35
|
- Skill still visible: use `replace` mode when Pi's base prompt must not include its own skill listing.
|
|
36
36
|
- Missing custom slot: trust the project, check `.pi/forge/extensions`, reload, and inspect diagnostics.
|
|
@@ -4,33 +4,31 @@
|
|
|
4
4
|
|
|
5
5
|
> **Experimental:** This API and its backends may change independently of stable prompt-stack and profile behavior.
|
|
6
6
|
|
|
7
|
-
pi-forge
|
|
7
|
+
The optional `@zihanw/pi-forge-subagents` package executes an explicitly authorized agent profile as a separate, clean, one-shot Pi process. It runs in the foreground and returns a bounded report to the parent conversation.
|
|
8
8
|
|
|
9
9
|
## Enable a profile
|
|
10
10
|
|
|
11
|
-
Profiles are not delegatable by default. Enable each eligible ID in the trusted project's `.pi/forge/
|
|
11
|
+
Profiles are not delegatable by default. Enable each eligible ID in the trusted project's `.pi/forge/subagents.json`:
|
|
12
12
|
|
|
13
13
|
```json
|
|
14
14
|
{
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
"timeoutMs": 180000
|
|
27
|
-
}
|
|
15
|
+
"backend": "pi-subprocess-readonly",
|
|
16
|
+
"timeoutMs": 60000,
|
|
17
|
+
"profiles": {
|
|
18
|
+
"reviewer": {
|
|
19
|
+
"enabled": true,
|
|
20
|
+
"timeoutMs": 300000
|
|
21
|
+
},
|
|
22
|
+
"rpc-reviewer": {
|
|
23
|
+
"enabled": true,
|
|
24
|
+
"backend": "pi-rpc-readonly",
|
|
25
|
+
"timeoutMs": 180000
|
|
28
26
|
}
|
|
29
27
|
}
|
|
30
28
|
}
|
|
31
29
|
```
|
|
32
30
|
|
|
33
|
-
|
|
31
|
+
Legacy `.pi/forge/config.json.subagents` is accepted as read-only fallback with a warning. Enablement follows the profile's scope. A global `~/.pi/forge/subagents.json` may define general `backend` and `timeoutMs` defaults and may authorize `global:<id>` profiles through its own `profiles` map. The trusted project's `subagents.json` authorizes `project:<id>` profiles. Same-ID global and project profiles never inherit enablement, backend, or timeout policy from one another. Disabled or unlisted profiles are hidden from discovery and rejected even if guessed.
|
|
34
32
|
|
|
35
33
|
## Discover, plan, and run
|
|
36
34
|
|
|
@@ -45,8 +43,16 @@ Humans use:
|
|
|
45
43
|
|
|
46
44
|
`plan` resolves the profile and stack, compiles and validates the exact immutable provider-bound plan, displays it, and discards it without provider transport.
|
|
47
45
|
|
|
46
|
+
Profile selectors accept the same grammar everywhere: `reviewer` (project first), `project:reviewer`, or `global:reviewer`. When both scopes expose the same ID, the project profile keeps the concise selector and the global profile remains callable as `global:<id>`.
|
|
47
|
+
|
|
48
48
|
The parent model uses `forge_subagent_profiles` to discover enabled profiles and `forge_subagent` to invoke one. A restrictive parent stack must allow both tool names. Discovery is local/no-egress and reports metadata, resolution readiness, effective backend/timeout, approval mode, and whether parent tool policy permits invocation.
|
|
49
49
|
|
|
50
|
+
Projects with only a few frequently used profiles can set `summaryInToolDescription: true` (global or trusted-project `subagents.json`). The `forge_subagent` tool description then carries a compact summary of enabled profiles—id, model, thinking level, stack, backend, and timeout—so the parent model does not need a discovery call to pick a profile. Ready profiles appear first; unavailable enabled profiles remain visible with their first resolution error so the model knows not to invoke them. The summary rides in every request, is capped at 8 profiles and 1,000 characters, and refreshes with profiles, stacks, and configuration; `forge_subagent_profiles` remains the authoritative full-detail surface.
|
|
51
|
+
|
|
52
|
+
## Parallel invocation
|
|
53
|
+
|
|
54
|
+
`forge_subagent` is a parallel-execution tool: the parent model may issue several calls in one turn, and they prepare and run concurrently. Interactive approval dialogs are serialized one at a time because Pi's selector/editor UI is a single slot—a second concurrent dialog would clear the first and leave it unresolved—so each call waits its turn for the dialog and then executes immediately, letting approved runs overlap. Unattended invocation needs no dialog and is fully concurrent. Each run is an independent `pi` subprocess and provider request; a burst of parallel calls multiplies provider cost and process load, so keep the parent tool policy conservative until a configurable concurrency cap lands.
|
|
55
|
+
|
|
50
56
|
## Backends and precedence
|
|
51
57
|
|
|
52
58
|
Two fresh-process backends are registered:
|
|
@@ -66,13 +72,11 @@ To authorize the parent model without per-run approval:
|
|
|
66
72
|
|
|
67
73
|
```json
|
|
68
74
|
{
|
|
69
|
-
"
|
|
70
|
-
"allowAgentInvocationWithoutApproval": true
|
|
71
|
-
}
|
|
75
|
+
"allowAgentInvocationWithoutApproval": true
|
|
72
76
|
}
|
|
73
77
|
```
|
|
74
78
|
|
|
75
|
-
This affects only `forge_subagent`; `/forge-agent run` remains interactive. It is ignored in untrusted projects and malformed values fail closed. Treat this project
|
|
79
|
+
This affects only `forge_subagent`; `/forge-agent run` remains interactive. It is ignored in untrusted projects and malformed values fail closed. Treat this project `subagents.json` as an authorization file: do not enable or commit it unless every parent agent allowed to call `forge_subagent` may send the compiled prompt and readable file contents to the selected provider without asking again.
|
|
76
80
|
|
|
77
81
|
## Child context and output
|
|
78
82
|
|
|
@@ -96,4 +100,4 @@ The current backends are **shared-user, not operating-system sandboxes**.
|
|
|
96
100
|
|
|
97
101
|
The default tools intentionally provide no mutation path. Do not add write, edit, or shell access to this shared-user design. OS isolation and separately approved staged writes remain future work.
|
|
98
102
|
|
|
99
|
-
For integration authors, see the [
|
|
103
|
+
For integration authors, see the [subagent host port contract](../reference/subagent-host-port.md).
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Migrating to pi-forge 0.5
|
|
2
|
+
|
|
3
|
+
[Documentation](../README.md)
|
|
4
|
+
|
|
5
|
+
0.5.0 is a breaking cleanup release. This page is the migration note for the
|
|
6
|
+
changes landed so far (Lane 1a-1c plus the compiler/extension conformance
|
|
7
|
+
pass in Lane 1d).
|
|
8
|
+
|
|
9
|
+
## What was removed
|
|
10
|
+
|
|
11
|
+
- SillyTavern importer (`/preset import-silly`), its reports, guide, example,
|
|
12
|
+
and tests. Convert SillyTavern presets with pi-forge 0.4 before upgrading.
|
|
13
|
+
- Mutable turn/session variables, variable mutation macros,
|
|
14
|
+
`pi-forge-variable-state` session entries, and the `variables` slot.
|
|
15
|
+
- Regex `display` and `both` effects; `outgoing` and `finalize` remain.
|
|
16
|
+
|
|
17
|
+
## Template syntax changes
|
|
18
|
+
|
|
19
|
+
Prompt text now compiles with the closed `forge-v1` grammar.
|
|
20
|
+
|
|
21
|
+
| 0.4 construct | 0.5 forge-v1 |
|
|
22
|
+
|---|---|
|
|
23
|
+
| `{{name}}` (static) | `{{ parameters.name }}` |
|
|
24
|
+
| `{{lastUserMessage}}` | `{{ runtime.lastUserMessage }}` |
|
|
25
|
+
| `{{date}}` / `{{time}}` / `{{cwd}}` | `{{ runtime.date }}` / `{{ runtime.time }}` / `{{ runtime.cwd }}` |
|
|
26
|
+
| `{{tools}}` | `{{ runtime.selectedToolsText }}` |
|
|
27
|
+
| `{{upper::x}}` | `{{ x \| upper }}` |
|
|
28
|
+
| `{{iftools::bash::A::B}}` | `{% if runtime.tool.bash %}A{% else %}B{% endif %}` |
|
|
29
|
+
| custom `{{myMacro}}` | `{{ extensions.myMacro }}` |
|
|
30
|
+
|
|
31
|
+
Unknown paths, unknown filters, parse errors, cycles, and output-limit breaches
|
|
32
|
+
are compile errors; a failing block is omitted instead of re-injecting raw
|
|
33
|
+
template text.
|
|
34
|
+
|
|
35
|
+
## Schema v2
|
|
36
|
+
|
|
37
|
+
Schema v2 stacks store immutable static values in `parameters` (JSON-compatible)
|
|
38
|
+
instead of the legacy string-only `variables` field:
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"schemaVersion": 2,
|
|
43
|
+
"parameters": { "char": "Konata" }
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Unversioned / v1 stacks continue to load through the legacy `variables` reader.
|
|
48
|
+
|
|
49
|
+
## Running the migration utility
|
|
50
|
+
|
|
51
|
+
A mechanical, diagnostics-first script converts a saved stack file:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
node scripts/migrate-stack-v2.mjs .pi/forge/prompt-stacks/default.json --dry-run
|
|
55
|
+
node scripts/migrate-stack-v2.mjs .pi/forge/prompt-stacks/default.json --write
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
It renames `variables` to `parameters`, maps runtime/parameter paths, and
|
|
59
|
+
converts simple filter pipelines. Non-mechanical constructs are reported and
|
|
60
|
+
the file is only written when they are absent. A schema v2 file that still
|
|
61
|
+
contains a legacy `variables` field is left untouched and only warned about.
|
|
62
|
+
|
|
63
|
+
## Preview and finalize
|
|
64
|
+
|
|
65
|
+
Preview never applies `finalize`; it now reports an informational diagnostic.
|
|
66
|
+
`finalize` remains a destructive, lifecycle-owned transform that replaces the
|
|
67
|
+
stored assistant message.
|
|
68
|
+
|
|
69
|
+
## Lane 2: scoped global profiles and prompt stacks
|
|
70
|
+
|
|
71
|
+
- User-global resources now live in `~/.pi/forge/prompt-stacks` and `~/.pi/forge/agent-profiles` alongside the project stores. Profile and stack selectors accept explicit scopes: `project:<id>`, `global:<id>`, with bare IDs resolving project-first.
|
|
72
|
+
- Same-ID project resources shadow their global counterparts; global stacks cannot reference project resources (and vice versa) — references resolve within the referenced resource's scope.
|
|
73
|
+
- Untrusted projects fail closed: only global resources load, all mutation routes are rejected, and `session_shutdown` no longer disposes a trusted workspace while sessions may still be active (idle workspaces are swept after an hour; hosts stop independently).
|
|
74
|
+
- The web editor gained scope selectors for creating stacks/profiles into either store and routes global mutations through explicit `global:<id>` selectors.
|
|
75
|
+
|
|
76
|
+
## Lane 3: subagent package split
|
|
77
|
+
|
|
78
|
+
Subagent execution moved out of the main package into the optional `@zihanw/pi-forge-subagents` package (requires `@zihanw/pi-forge@^0.5.0`). Install it separately to keep foreground delegation.
|
|
79
|
+
|
|
80
|
+
- **Commands:** `/subagents` and `/subagent-run` were removed from the main package. The optional package registers `/forge-agent backends|plan|run`.
|
|
81
|
+
- **Model tools:** `forge_subagent_profiles` and `forge_subagent` are registered by the optional package.
|
|
82
|
+
- **Configuration:** `subagents.*` moved out of `.pi/forge/config.json` into dedicated `.pi/forge/subagents.json` (trusted project) and `~/.pi/forge/subagents.json` (user defaults). The optional package reads legacy `config.json.subagents` sections as a read-only fallback with a warning; it never writes them. Copy the values into `subagents.json` to silence the warning.
|
|
83
|
+
- **Web editor:** the delegation card was removed from the main editor; edit `subagents.json` directly.
|
|
84
|
+
- **Architecture:** the main package's prompt compiler is host-neutral (no subagent assumptions), and `ForgeWorkspace` is the single owner of resource state and compilation contexts.
|
|
85
|
+
|
|
86
|
+
## Lane 4: Forge-native host contract and public surface
|
|
87
|
+
|
|
88
|
+
- The main package no longer depends on `@zihanw/pi-subagent-runtime` and no longer exports the 0.4 execution contract. That contract (`AgentRequest`, `createAgentExecutionPlan`, `validateAgentRequest`, `negotiateSubagentTools`, preflight/plan/response validators, …) now lives in `@zihanw/pi-forge-subagents` for its own runtime wiring; it is not a public surface of either package for third-party consumers.
|
|
89
|
+
- `@zihanw/pi-forge/subagent` now exports only the versioned host port: wire DTOs and validators, `ForgeHostTransport`, `ForgeHost`/`ForgeHostClient`, lifecycle constants, and the Forge-owned canonical fingerprint helpers. `resolveSubagentHostProfile` / `prepareSubagentHostPlan` were replaced by the host-port operations `resolveProfile` and `prepare`.
|
|
90
|
+
- The package root exports only the default extension factory, `registerMacro`/`registerSlot`, and their contract types. All other root re-exports (loader, agent-profile, profile-service, catalog, resource-identity, render-helper values, the `forge-v1` engine, registry readers) were removed.
|
|
91
|
+
- All `@zihanw/pi-forge/src/*` subpath aliases and the `./examples/*` export were removed; `check-package` rejects them.
|
|
92
|
+
|
|
93
|
+
### Import migration table
|
|
94
|
+
|
|
95
|
+
| 0.4 import | 0.5 replacement |
|
|
96
|
+
|---|---|
|
|
97
|
+
| `@zihanw/pi-forge` (default, `registerMacro`, `registerSlot`) | unchanged |
|
|
98
|
+
| `@zihanw/pi-forge/subagent` host-port names (`ForgeHost*`, validators, fingerprints) | unchanged |
|
|
99
|
+
| `@zihanw/pi-forge/subagent` execution contract (`AgentRequest`, `createAgentExecutionPlan`, …) | internal to `@zihanw/pi-forge-subagents`; no public replacement |
|
|
100
|
+
| `@zihanw/pi-forge/subagent` `resolveSubagentHostProfile` / `prepareSubagentHostPlan` | host-port operations via `ForgeHostClient` |
|
|
101
|
+
| `@zihanw/pi-forge/src/*` aliases | removed; no replacement (internals) |
|
|
102
|
+
| root loader/profile/catalog/engine re-exports | removed; no replacement (internals) |
|
|
103
|
+
|
|
104
|
+
## Compatibility notes
|
|
105
|
+
|
|
106
|
+
- The wire shape of the host port is additive across `FORGE_HOST_PORT_VERSION = 1`; unknown operations are rejected with a plain `{ ok: false, error }` result (`"Unknown Forge host operation: …"`), not a thrown error, and optional packages must treat any operation failure as terminal for that request.
|
|
107
|
+
- Vendored fingerprint helpers in the main package are pinned by golden vectors to stay byte-compatible with `@zihanw/pi-subagent-runtime` canonical serialization; plan sealing still happens only in the optional package.
|