@zihanw/pi-forge 0.4.0-beta.1 → 0.4.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.
Files changed (186) hide show
  1. package/CHANGELOG.md +37 -1
  2. package/PUBLIC_API.md +3 -26
  3. package/README.md +90 -601
  4. package/README.zh-CN.md +86 -585
  5. package/SUBAGENT_ADAPTER_CONTRACT.md +3 -197
  6. package/dist/forge-config.d.ts +80 -0
  7. package/dist/forge-config.d.ts.map +1 -1
  8. package/dist/forge-config.js +268 -18
  9. package/dist/forge-config.js.map +1 -1
  10. package/dist/index.d.ts +1 -4
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +29 -4
  13. package/dist/index.js.map +1 -1
  14. package/dist/lifecycle.js +1 -1
  15. package/dist/profile-service.d.ts +1 -1
  16. package/dist/profile-service.d.ts.map +1 -1
  17. package/dist/profile-service.js +10 -5
  18. package/dist/profile-service.js.map +1 -1
  19. package/dist/runtime/subagent-runtime.d.ts +23 -8
  20. package/dist/runtime/subagent-runtime.d.ts.map +1 -1
  21. package/dist/runtime/subagent-runtime.js +283 -62
  22. package/dist/runtime/subagent-runtime.js.map +1 -1
  23. package/dist/storage.d.ts +1 -0
  24. package/dist/storage.d.ts.map +1 -1
  25. package/dist/storage.js +15 -1
  26. package/dist/storage.js.map +1 -1
  27. package/dist/subagent/canonical.d.ts +19 -7
  28. package/dist/subagent/canonical.d.ts.map +1 -1
  29. package/dist/subagent/canonical.js +19 -47
  30. package/dist/subagent/canonical.js.map +1 -1
  31. package/dist/subagent/contract.d.ts +1 -2
  32. package/dist/subagent/contract.d.ts.map +1 -1
  33. package/dist/subagent/contract.js +1 -2
  34. package/dist/subagent/contract.js.map +1 -1
  35. package/dist/subagent/index.d.ts +4 -3
  36. package/dist/subagent/index.d.ts.map +1 -1
  37. package/dist/subagent/index.js +4 -3
  38. package/dist/subagent/index.js.map +1 -1
  39. package/dist/subagent/plan.d.ts +5 -1
  40. package/dist/subagent/plan.d.ts.map +1 -1
  41. package/dist/subagent/plan.js +28 -31
  42. package/dist/subagent/plan.js.map +1 -1
  43. package/dist/subagent/types.d.ts +62 -178
  44. package/dist/subagent/types.d.ts.map +1 -1
  45. package/dist/subagent/types.js +1 -1
  46. package/dist/subagent/types.js.map +1 -1
  47. package/dist/subagent/validation.d.ts +14 -14
  48. package/dist/subagent/validation.d.ts.map +1 -1
  49. package/dist/subagent/validation.js +52 -238
  50. package/dist/subagent/validation.js.map +1 -1
  51. package/dist/subagent-command.d.ts.map +1 -1
  52. package/dist/subagent-command.js +109 -16
  53. package/dist/subagent-command.js.map +1 -1
  54. package/dist/subagent-host.d.ts.map +1 -1
  55. package/dist/subagent-host.js +1 -0
  56. package/dist/subagent-host.js.map +1 -1
  57. package/dist/subagent-profile-tool.d.ts +25 -2
  58. package/dist/subagent-profile-tool.d.ts.map +1 -1
  59. package/dist/subagent-profile-tool.js +39 -8
  60. package/dist/subagent-profile-tool.js.map +1 -1
  61. package/dist/subagent-tool.d.ts +6 -3
  62. package/dist/subagent-tool.d.ts.map +1 -1
  63. package/dist/subagent-tool.js +85 -14
  64. package/dist/subagent-tool.js.map +1 -1
  65. package/dist/web-editor/client-script.generated.d.ts +1 -1
  66. package/dist/web-editor/client-script.generated.d.ts.map +1 -1
  67. package/dist/web-editor/client-script.generated.js +1 -1
  68. package/dist/web-editor/client-script.generated.js.map +1 -1
  69. package/dist/web-editor/client-styles.d.ts +2 -0
  70. package/dist/web-editor/client-styles.d.ts.map +1 -0
  71. package/dist/web-editor/client-styles.generated.d.ts +2 -0
  72. package/dist/web-editor/client-styles.generated.d.ts.map +1 -0
  73. package/dist/web-editor/client-styles.generated.js +3 -0
  74. package/dist/web-editor/client-styles.generated.js.map +1 -0
  75. package/dist/web-editor/client-styles.js +2 -0
  76. package/dist/web-editor/client-styles.js.map +1 -0
  77. package/dist/web-editor/page.d.ts +2 -0
  78. package/dist/web-editor/page.d.ts.map +1 -1
  79. package/dist/web-editor/page.js +11 -73
  80. package/dist/web-editor/page.js.map +1 -1
  81. package/dist/web-editor/server.d.ts.map +1 -1
  82. package/dist/web-editor/server.js +148 -0
  83. package/dist/web-editor/server.js.map +1 -1
  84. package/dist/web-editor/styles.d.ts.map +1 -1
  85. package/dist/web-editor/styles.js +60 -3
  86. package/dist/web-editor/styles.js.map +1 -1
  87. package/dist/web-editor/types.d.ts +79 -0
  88. package/dist/web-editor/types.d.ts.map +1 -1
  89. package/dist/web-host.d.ts +13 -2
  90. package/dist/web-host.d.ts.map +1 -1
  91. package/dist/web-host.js +301 -0
  92. package/dist/web-host.js.map +1 -1
  93. package/docs/README.md +41 -0
  94. package/docs/concepts/agent-profiles.md +60 -0
  95. package/docs/concepts/prompt-stacks.md +90 -0
  96. package/docs/design/README.md +17 -0
  97. package/docs/design/roadmap-0.4-archive.md +216 -0
  98. package/docs/design/subagents/design-review.md +220 -0
  99. package/docs/design/subagents/interface-design.md +274 -0
  100. package/docs/design/subagents/sdk-spike-findings.md +117 -0
  101. package/docs/development/complexity-review.md +86 -0
  102. package/docs/development/release.md +31 -0
  103. package/docs/development/roadmap.md +42 -0
  104. package/docs/development/setup.md +75 -0
  105. package/docs/getting-started.md +93 -0
  106. package/docs/guides/custom-macros-and-slots.md +68 -0
  107. package/docs/guides/debugging.md +39 -0
  108. package/docs/guides/delegation.md +99 -0
  109. package/docs/guides/sillytavern-import.md +47 -0
  110. package/docs/guides/use-cases.md +65 -0
  111. package/docs/guides/web-editor.md +75 -0
  112. package/docs/reference/commands.md +60 -0
  113. package/docs/reference/configuration.md +64 -0
  114. package/docs/reference/features.md +279 -0
  115. package/docs/reference/macros-and-slots.md +82 -0
  116. package/docs/reference/public-api.md +28 -0
  117. package/docs/reference/stack-schema.md +167 -0
  118. package/docs/reference/subagent-adapter.md +204 -0
  119. package/docs/zh-CN/README.md +37 -0
  120. package/docs/zh-CN/concepts/agent-profiles.md +44 -0
  121. package/docs/zh-CN/concepts/prompt-stacks.md +40 -0
  122. package/docs/zh-CN/getting-started.md +79 -0
  123. package/docs/zh-CN/guides/delegation.md +66 -0
  124. package/docs/zh-CN/guides/web-editor.md +45 -0
  125. package/docs/zh-CN/reference/commands.md +58 -0
  126. package/package.json +28 -14
  127. package/dist/subagent/backend-registry.d.ts +0 -75
  128. package/dist/subagent/backend-registry.d.ts.map +0 -1
  129. package/dist/subagent/backend-registry.js +0 -463
  130. package/dist/subagent/backend-registry.js.map +0 -1
  131. package/dist/subagent/diagnostics.d.ts +0 -3
  132. package/dist/subagent/diagnostics.d.ts.map +0 -1
  133. package/dist/subagent/diagnostics.js +0 -5
  134. package/dist/subagent/diagnostics.js.map +0 -1
  135. package/dist/subagent/pi-model-runtime.d.ts +0 -8
  136. package/dist/subagent/pi-model-runtime.d.ts.map +0 -1
  137. package/dist/subagent/pi-model-runtime.js +0 -22
  138. package/dist/subagent/pi-model-runtime.js.map +0 -1
  139. package/dist/subagent/pi-sdk-backend.d.ts +0 -23
  140. package/dist/subagent/pi-sdk-backend.d.ts.map +0 -1
  141. package/dist/subagent/pi-sdk-backend.js +0 -383
  142. package/dist/subagent/pi-sdk-backend.js.map +0 -1
  143. package/dist/subagent/pi-subprocess-backend.d.ts +0 -72
  144. package/dist/subagent/pi-subprocess-backend.d.ts.map +0 -1
  145. package/dist/subagent/pi-subprocess-backend.js +0 -756
  146. package/dist/subagent/pi-subprocess-backend.js.map +0 -1
  147. package/dist/subagent/subprocess-bridge.d.ts +0 -21
  148. package/dist/subagent/subprocess-bridge.d.ts.map +0 -1
  149. package/dist/subagent/subprocess-bridge.js +0 -87
  150. package/dist/subagent/subprocess-bridge.js.map +0 -1
  151. package/dist/subagent/subprocess-report.d.ts +0 -4
  152. package/dist/subagent/subprocess-report.d.ts.map +0 -1
  153. package/dist/subagent/subprocess-report.js +0 -55
  154. package/dist/subagent/subprocess-report.js.map +0 -1
  155. package/dist/subagent-contract.d.ts +0 -8
  156. package/dist/subagent-contract.d.ts.map +0 -1
  157. package/dist/subagent-contract.js +0 -8
  158. package/dist/subagent-contract.js.map +0 -1
  159. package/dist/web-editor/client/api.d.ts +0 -9
  160. package/dist/web-editor/client/api.d.ts.map +0 -1
  161. package/dist/web-editor/client/api.js +0 -26
  162. package/dist/web-editor/client/api.js.map +0 -1
  163. package/dist/web-editor/client/dom.d.ts +0 -13
  164. package/dist/web-editor/client/dom.d.ts.map +0 -1
  165. package/dist/web-editor/client/dom.js +0 -30
  166. package/dist/web-editor/client/dom.js.map +0 -1
  167. package/dist/web-editor/client/inspector.d.ts +0 -22
  168. package/dist/web-editor/client/inspector.d.ts.map +0 -1
  169. package/dist/web-editor/client/inspector.js +0 -226
  170. package/dist/web-editor/client/inspector.js.map +0 -1
  171. package/dist/web-editor/client/main.d.ts +0 -2
  172. package/dist/web-editor/client/main.d.ts.map +0 -1
  173. package/dist/web-editor/client/main.js +0 -1468
  174. package/dist/web-editor/client/main.js.map +0 -1
  175. package/dist/web-editor/client/policy-editor.d.ts +0 -16
  176. package/dist/web-editor/client/policy-editor.d.ts.map +0 -1
  177. package/dist/web-editor/client/policy-editor.js +0 -330
  178. package/dist/web-editor/client/policy-editor.js.map +0 -1
  179. package/dist/web-editor/client/regex-editor.d.ts +0 -19
  180. package/dist/web-editor/client/regex-editor.d.ts.map +0 -1
  181. package/dist/web-editor/client/regex-editor.js +0 -281
  182. package/dist/web-editor/client/regex-editor.js.map +0 -1
  183. package/dist/web-editor/client/types.d.ts +0 -60
  184. package/dist/web-editor/client/types.d.ts.map +0 -1
  185. package/dist/web-editor/client/types.js +0 -2
  186. package/dist/web-editor/client/types.js.map +0 -1
@@ -1,199 +1,5 @@
1
- # Subagent Adapter Contract
1
+ # Subagent adapter contract
2
2
 
3
- Status: exported pure contract, host-preparation utilities, optional backend registry, retained `pi-sdk-isolated` compatibility adapter, and a default-approval `pi-subprocess-readonly` foreground path for the 0.4 beta. This is a narrow one-shot delegation boundary, not a background orchestration runner or an OS sandbox.
3
+ The authoritative experimental contract moved to [`docs/reference/subagent-adapter.md`](docs/reference/subagent-adapter.md).
4
4
 
5
- ## Public Surface
6
-
7
- New integrations should import this experimental 0.4 surface from `@zihanw/pi-forge/subagent`. The package root retains the same exports through the 0.4 prereleases for compatibility. Stability classifications and compatibility-path policy are recorded in [`PUBLIC_API.md`](PUBLIC_API.md).
8
-
9
- The package root exports:
10
-
11
- - `AgentRequest`, `AgentProfileSnapshot`, `BackendPreflightResult`, `AgentExecutionPlan`, and `AgentResponse`.
12
- - Granular access, limit, tool, media, context, artifact, trace, usage, and diagnostic types.
13
- - Host resolution through `resolveSubagentHostProfile()`.
14
- - Tool negotiation through `negotiateSubagentTools()`.
15
- - Deterministic context preparation through `budgetSubagentContext()`, `renderSubagentSelectedContext()`, and `prepareSubagentInitialMessages()`.
16
- - Protected Pi-message helpers used by the SDK spike.
17
- - Plan construction through `createAgentExecutionPlan()`.
18
- - Pure request, snapshot, preflight, plan, response, artifact, and trace validators.
19
- - Canonical `sha256:v1` profile, stack, and execution fingerprints.
20
- - Optional backend registration, validated dispatch, cancellation/timeout arbitration, response normalization, and authorization-scoped trace routing through `SubagentBackendRegistry`.
21
- - Experimental `PiSdkIsolatedBackend` compatibility adapter and the default `PiSubprocessBackend`, including their descriptors/IDs, report types, and host preparation through `prepareSubagentHostPlan()`.
22
-
23
- The existing `agentProfileFingerprint()` remains unchanged. It is still the legacy JSON provenance value used for branch drift. New portable fingerprints use separately named functions and semantics.
24
-
25
- ## Required Flow
26
-
27
- ```text
28
- AgentRequest
29
- -> resolveSubagentHostProfile
30
- -> SubagentBackendRegistry discovery/preflight
31
- -> registry-mediated exact or backend-assisted preparation
32
- -> createAgentExecutionPlan
33
- -> registry-validated backend execution
34
- -> validateAgentResponse
35
- ```
36
-
37
- No stage may substitute parent-runtime model objects, credentials, source file paths, or raw session history for the portable artifacts.
38
-
39
- ### 1. Request validation
40
-
41
- `validateAgentRequest()` checks:
42
-
43
- - Schema, IDs, task text/media references, and media digests.
44
- - Explicit selected-context byte budgets and provenance.
45
- - Delegation depth.
46
- - Access-level/workspace/working-directory/network/process combinations.
47
- - Required versus best-effort hard limits.
48
- - Result-projection bounds and remote-egress consent.
49
-
50
- Media references are opaque host resources with content digests. The contract does not place local absolute paths or media bytes in the portable request.
51
-
52
- ### 2. Host resolution
53
-
54
- `resolveSubagentHostProfile()` performs only backend-independent work:
55
-
56
- - Validates the loaded profile and exact prompt-stack reference.
57
- - Accepts null, default/replace, append, and prepend stack modes.
58
- - Scans prompt-stack items for custom macro and slot dependencies.
59
- - Requires those registrations to be loaded before final resolution.
60
- - Produces a path-free immutable profile snapshot and portable fingerprints.
61
-
62
- It deliberately does not inspect a model registry, authentication, backend tools, mounts, or limits. Parent `/profile use` resolution remains separate.
63
-
64
- Unknown macro commands and custom slots are treated as missing subagent dependencies. Static stack variables and built-in macros/slots are excluded. Custom registrations without a `source` still resolve but produce a warning because their dependency identity is anonymous.
65
-
66
- ### 3. Backend preflight
67
-
68
- An accepted `BackendPreflightResult` must identify the exact model/thinking level, dynamic tool catalog, granular capabilities, effective access receipt, and accepted limit receipt.
69
-
70
- `validateBackendPreflight()` enforces:
71
-
72
- - Exact profile model and thinking-level agreement.
73
- - Explicit consent for remote provider transport.
74
- - Requested media MIME support.
75
- - No missing, extra, upgraded, or mode-mismatched mounts.
76
- - Working-directory containment through backend mount IDs.
77
- - Read/write, symlink, process, and denied-network enforcement claims.
78
- - Every required limit uses `backend-hard` enforcement.
79
- - Best-effort limits are reported honestly, such as Pi SDK host-abort timeouts.
80
- - Rejected preflight results contain at least one error diagnostic.
81
-
82
- Prompt tool filtering is not accepted as an access receipt.
83
-
84
- ### 4. Tool negotiation
85
-
86
- Each backend tool declares a stable backend ID, policy-facing name, and effects:
87
-
88
- - `filesystem-read`
89
- - `filesystem-write`
90
- - `process`
91
- - `network`
92
-
93
- `negotiateSubagentTools()` applies prompt-stack policy to names, then removes tools whose declared effects exceed request access. Effect-free tools may remain under filesystem access `none`; network and process are independently controlled. Unmatched allow patterns remain warnings.
94
-
95
- Adapters must classify tool effects conservatively. A tool with undeclared effects invalidates the backend's enforcement claim even if name filtering succeeds.
96
-
97
- ### 5. Context and exact preparation
98
-
99
- `budgetSubagentContext()` measures the exact UTF-8 bytes of the rendered selected-context envelope. Required items are retained first. Optional items are considered newest-to-oldest without partial item truncation, and returned in original order. Required overflow fails preparation.
100
-
101
- `prepareSubagentInitialMessages()` creates:
102
-
103
- 1. One quoted selected-context message when the budget retains context.
104
- 2. Host-prepared prompt-stack messages.
105
- 3. The complete protected task/media message as the final user message.
106
-
107
- Prompt-stack messages cannot claim reserved selected-context or delegated-task markers.
108
-
109
- Backends such as Pi SDK may expose exact base-prompt runtime inputs only in a pre-provider hook. They may call the host preparer there, but provider transport must remain blocked until `createAgentExecutionPlan()` succeeds. A `partial` prompt-runtime preflight cannot produce an execution plan.
110
-
111
- ### 6. Plan and fingerprints
112
-
113
- `createAgentExecutionPlan()` revalidates the request, snapshot, preflight, deterministic context receipt, tool negotiation, runtime fidelity, and protected final task. It creates the run ID correlation and execution fingerprint before provider transport.
114
-
115
- The execution fingerprint covers all serialized plan fields except itself, including compiled system/messages, profile/stack/dependency provenance, the complete preflight receipt and adapter version, exact model/thinking, effective backend tool IDs, access and limit receipts, prompt-runtime fingerprint, context receipt, and result-projection bound.
116
-
117
- Canonical serialization sorts object keys, omits undefined object fields, rejects cycles/non-finite numbers/non-JSON values, preserves array order, and normalizes negative zero.
118
-
119
- ### 7. Response validation
120
-
121
- `validateAgentResponse()` enforces the terminal status matrix:
122
-
123
- | Status | Required terminal field | Output rule |
124
- |---|---|---|
125
- | `completed` | none | absent or `partial: false` |
126
- | `failed` | structured `error` | absent or `partial: true` |
127
- | `cancelled` | `reason` | absent or `partial: true` |
128
- | `timed-out` | `reason`, `enforcedTimeoutMs` | absent or `partial: true` |
129
- | `limit-reached` | `reachedLimit` | absent or `partial: true` |
130
-
131
- It also validates request/run/backend correlation, model and fingerprints, effective backend tool IDs, backend-produced enforcement receipts, duration, token/cost units, artifact namespaces, relative paths, cleanup ownership, and authorized trace handles. Cost requires an ISO 4217 currency code.
132
-
133
- ### 8. Optional backend registry
134
-
135
- `SubagentBackendRegistry` starts empty and never installs a default backend. It:
136
-
137
- - Validates backend descriptors and rejects duplicate identities.
138
- - Binds accepted preflight IDs to the exact backend, request, and profile fingerprint used during discovery.
139
- - Routes exact-preflight preparation directly to the host preparer and requires backend-assisted adapters to invoke the same host boundary.
140
- - Binds the exact runtime fingerprint, compiled system/messages, effective tools, and context receipt returned by host preparation; recomputing an execution fingerprint cannot substitute a different plan.
141
- - Routes dry-plan discard through the owning backend before forgetting the preflight binding.
142
- - Rejects malformed, tampered, foreign, or unbound execution plans before transport.
143
- - Arbitrates backend completion, explicit user cancellation, external abort signals, and declared host-abort timeouts through one terminal result.
144
- - Discards prepared backend state without invoking execution when cancellation wins before backend dispatch.
145
- - Normalizes thrown provider failures and malformed backend responses into contract-valid failed responses.
146
- - Replaces backend-reported duration with host-observed duration.
147
- - Keeps opaque backend trace IDs behind host-generated handles and enforces authorization scope, backend routing, expiry, and explicit forgetting during inspection.
148
- - Refuses backend unregistration while an execution remains active or is draining after cancellation.
149
-
150
- The registry validates receipts but does not manufacture filesystem, process, network, token, turn, or output isolation. Those remain adapter responsibilities.
151
-
152
- Access receipts may explicitly declare `executionBoundary: "shared-user"`. This boundary means the subprocess retains the invoking user's operating-system permissions and its effective access is constrained only by the tools exposed to the model. A shared-user receipt cannot claim mount, symlink, process, or network isolation. Omitting the field preserves the legacy `isolated` interpretation.
153
-
154
- ### 9. Experimental foreground subprocess and approval path
155
-
156
- `PiSubprocessBackend` is the extension's deliberately narrow default adapter:
157
-
158
- - It resolves the exact profile model through Pi's existing `ModelRegistry`, reuses the parent Pi 0.80.10 `ModelRuntime` so preparation sees the same authentication, and prepares the exact prompt inside an in-process Pi session held behind a provider gate.
159
- - After approval, it disposes the preparation session and launches a fresh foreground Pi subprocess with the approved model, thinking level, system prompt, messages, and tool IDs. Pi's ordinary text stdout is drained separately from a dedicated newline-delimited report channel.
160
- - Its bridge preserves the exact prepared messages and rejects tools outside the approved allowlist. Candidate tools are limited to `read`, `grep`, `find`, and `ls`, then intersected with prompt-stack policy.
161
- - It loads no write/edit/shell tools, skills, prompt templates, context files, themes, or third-party Pi extensions and writes no child session file.
162
- - It accepts text-only, one-shot, sequential `read-only` requests rooted at the project working directory, with no process tool and optional host-abort timeout. It advertises no artifact retention or contract trace inspection.
163
- - It records a bounded foreground execution report containing sanitized transcript events, tool calls/results, usage, stderr, status, and execution identity. Inline images remain available to the child model but cross the report boundary only as MIME/encoded-size metadata. Base64-like text is redacted, individual strings are capped, and retained messages form a 512 KiB rolling tail so large tool histories cannot make the parent TUI/session retain unbounded data. Temporary bridge inputs are mode `0600` and removed during cleanup.
164
- - Retained textual tool results are ordinary parent-session tool details. `/tree` can move the active branch away from them but does not erase abandoned entries from Pi's on-disk session JSONL; callers handling sensitive files must treat session-data deletion as a separate operation.
165
-
166
- This backend declares `executionBoundary: "shared-user"`. It does not create allowed-root mount containment, symlink-safe path containment, process isolation, or agent-network isolation. The subprocess retains the invoking user's OS permissions; `read-only` describes the tools exposed to the model, not a security sandbox. Network is therefore honestly recorded as allowed even though no dedicated network or shell tool is exposed.
167
-
168
- The model-callable `forge_subagent_profiles` tool reads the already-loaded host profile catalog without preparing a prompt or contacting a provider. It exposes IDs, names, descriptions, declared model/thinking/stack metadata, ready/unavailable resolution diagnostics, and whether parent policy currently exposes the invocation tool. A restrictive parent stack must allow both `forge_subagent_profiles` and `forge_subagent` for discovery followed by delegation.
169
-
170
- The model-callable `forge_subagent` tool and `/forge-agent run` use the same registry path. Both prepare an exact immutable plan while provider transport remains closed. `/forge-agent run` always shows a compact approval summary, allows inspection of the complete prompt, and requires interactive approval bound to the execution fingerprint. The tool does the same by default, but a trusted project may set `subagents.allowAgentInvocationWithoutApproval: true` in `.pi/forge/config.json`; this permits non-UI model invocation and records `trusted-project-config` in the result receipt without weakening preflight or plan binding. Missing, malformed, and untrusted-project settings fail closed. The tool returns bounded content to the parent model and expandable execution details to the human. `/forge-agent plan` still prepares and discards without provider transport; `/forge-agent backends` shows capabilities. The older access-none `PiSdkIsolatedBackend` remains exported and tested for compatibility but is not the extension default.
171
-
172
- ## Adapter-Enforced Responsibilities
173
-
174
- The exported validators cannot create isolation. Every adapter remains responsible for:
175
-
176
- - Credential and model availability in its own runtime.
177
- - Backend-side mount materialization and path canonicalization immediately before access.
178
- - Symlink-race-safe containment.
179
- - Process and agent-network isolation.
180
- - Accurate tool effects and stable tool mappings.
181
- - Required hard timeout, turn, token, and output limits.
182
- - Cancellation settlement and cleanup.
183
- - Media transport and remote-egress behavior.
184
- - Artifact authorization, retention, and cleanup.
185
- - Trace storage, authorization, redaction, pagination, and expiry.
186
- - Returning actual enforcement receipts rather than echoing request fields.
187
-
188
- An adapter must reject preflight when it cannot enforce a required field. The retained Pi SDK adapter can execute only access `none`; the subprocess adapter accepts shared-user read-only access and network allow. Both use best-effort host abort rather than a backend-hard timeout. Provider transport is always a separate, explicitly approved egress path.
189
-
190
- ## Deliberately Not Included
191
-
192
- - Filesystem writes, process/shell tools, media input, background runs, or general backend selection/configuration in the shipped path.
193
- - OS-level filesystem, process, or network sandboxing for the shared-user subprocess.
194
- - Automatic parent-history/context selection; the delegated task is explicit and starts a clean conversation.
195
- - Session resume, retries, queues, chains, or pipelines.
196
- - Artifact/trace storage implementations.
197
- - Automatic provider fallback.
198
-
199
- Those belong to later iterations and cannot be inferred from these pure types alone.
5
+ This compatibility pointer remains at the published root path so existing links continue to work.
@@ -1,8 +1,88 @@
1
1
  import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
2
+ /** Backend used when neither a per-run override nor a configured default applies. */
3
+ export declare const DEFAULT_SUBAGENT_BACKEND_ID = "pi-subprocess-readonly";
4
+ /** Preserve the original foreground-run timeout unless the user configures one. */
5
+ export declare const DEFAULT_SUBAGENT_TIMEOUT_MS = 60000;
6
+ export declare const MIN_SUBAGENT_TIMEOUT_MS = 1000;
7
+ export declare const MAX_SUBAGENT_TIMEOUT_MS = 3600000;
8
+ /**
9
+ * Development/test override for the global config location. Keeps automated
10
+ * tests hermetic regardless of the developer's real ~/.pi/forge/config.json.
11
+ * Not part of the supported user-facing configuration surface.
12
+ */
13
+ export declare const GLOBAL_FORGE_CONFIG_PATH_ENV = "PI_FORGE_GLOBAL_CONFIG_PATH";
14
+ export type ForgeSubagentBackendSource = "explicit" | "project-profile" | "project" | "global" | "built-in";
15
+ export type ForgeSubagentConfigSource = "project" | "global";
16
+ export type ForgeSubagentProfileSource = "project-profile";
17
+ export interface ForgeSubagentProfileSettings {
18
+ enabled?: boolean;
19
+ enabledSource?: ForgeSubagentProfileSource;
20
+ backend?: string;
21
+ backendSource?: ForgeSubagentProfileSource;
22
+ timeoutMs?: number;
23
+ timeoutSource?: ForgeSubagentProfileSource;
24
+ }
2
25
  export interface ForgeSubagentSettings {
3
26
  allowAgentInvocationWithoutApproval: boolean;
27
+ /** Configured default backend ID; a trusted project config wins over the global config. */
28
+ backend?: string;
29
+ backendSource?: ForgeSubagentConfigSource;
30
+ /** Best-effort foreground timeout; a trusted project config wins over the global config. */
31
+ timeoutMs: number;
32
+ timeoutSource: ForgeSubagentConfigSource | "built-in";
33
+ /** Per-profile delegation allowlist and execution overrides. Unlisted profiles are not delegatable. */
34
+ profiles: Record<string, ForgeSubagentProfileSettings>;
4
35
  configPath: string;
36
+ globalConfigPath: string;
5
37
  warnings: string[];
6
38
  }
39
+ export interface ResolvedSubagentBackend {
40
+ id: string;
41
+ source: ForgeSubagentBackendSource;
42
+ }
43
+ export interface ResolvedSubagentTimeout {
44
+ milliseconds: number;
45
+ source: Exclude<ForgeSubagentBackendSource, "explicit">;
46
+ }
47
+ export interface ResolvedSubagentProfilePolicy {
48
+ profileId: string;
49
+ enabled: boolean;
50
+ enabledSource: ForgeSubagentProfileSource | "built-in";
51
+ backend: ResolvedSubagentBackend;
52
+ timeout: ResolvedSubagentTimeout;
53
+ }
54
+ /**
55
+ * Resolve the effective backend for one run: explicit per-run override, then
56
+ * a trusted-project per-profile override, then trusted-project/global defaults,
57
+ * then the built-in subprocess backend. There is deliberately no fallback when
58
+ * the resolved backend is missing or rejects the intent.
59
+ */
60
+ export declare function resolveSubagentBackend(settings: ForgeSubagentSettings, explicitBackend?: string, profileId?: string): ResolvedSubagentBackend;
61
+ export declare function resolveSubagentTimeout(settings: ForgeSubagentSettings, profileId?: string): ResolvedSubagentTimeout;
62
+ export declare function resolveSubagentProfilePolicy(settings: ForgeSubagentSettings, profileId: string, explicitBackend?: string): ResolvedSubagentProfilePolicy;
7
63
  export declare function loadForgeSubagentSettings(ctx: ExtensionContext): ForgeSubagentSettings;
64
+ export declare function isValidSubagentTimeoutMs(value: unknown): value is number;
65
+ /**
66
+ * One trusted-project per-profile delegation update. `enabled: false`,
67
+ * `backend: null`, and `timeoutMs: null` remove the explicit value; entries
68
+ * that become empty are removed so the file only records real overrides.
69
+ */
70
+ export interface ForgeSubagentProfileConfigUpdate {
71
+ enabled?: boolean;
72
+ backend?: string | null;
73
+ timeoutMs?: number | null;
74
+ }
75
+ export type ForgeSubagentProfileConfigResult = {
76
+ ok: true;
77
+ configPath: string;
78
+ } | {
79
+ ok: false;
80
+ error: string;
81
+ };
82
+ /**
83
+ * Update `subagents.profiles.<id>` in the project's `.pi/forge/config.json`,
84
+ * preserving unknown top-level, `subagents`, and per-entry fields. Callers
85
+ * must gate this on project trust; the project config is ignored otherwise.
86
+ */
87
+ export declare function updateForgeSubagentProfileConfig(cwd: string, profileId: string, update: ForgeSubagentProfileConfigUpdate): ForgeSubagentProfileConfigResult;
8
88
  //# sourceMappingURL=forge-config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"forge-config.d.ts","sourceRoot":"","sources":["../src/forge-config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAExE,MAAM,WAAW,qBAAqB;IACrC,mCAAmC,EAAE,OAAO,CAAC;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,gBAAgB,GAAG,qBAAqB,CA8BtF"}
1
+ {"version":3,"file":"forge-config.d.ts","sourceRoot":"","sources":["../src/forge-config.ts"],"names":[],"mappings":"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"}
@@ -1,38 +1,288 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { join } from "node:path";
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { isValidAgentProfileId } from "./agent-profile.js";
4
+ import { globalForgeDir } from "./storage.js";
5
+ /** Backend used when neither a per-run override nor a configured default applies. */
6
+ export const DEFAULT_SUBAGENT_BACKEND_ID = "pi-subprocess-readonly";
7
+ /** Preserve the original foreground-run timeout unless the user configures one. */
8
+ export const DEFAULT_SUBAGENT_TIMEOUT_MS = 60_000;
9
+ export const MIN_SUBAGENT_TIMEOUT_MS = 1_000;
10
+ export const MAX_SUBAGENT_TIMEOUT_MS = 3_600_000;
11
+ /**
12
+ * Development/test override for the global config location. Keeps automated
13
+ * tests hermetic regardless of the developer's real ~/.pi/forge/config.json.
14
+ * Not part of the supported user-facing configuration surface.
15
+ */
16
+ export const GLOBAL_FORGE_CONFIG_PATH_ENV = "PI_FORGE_GLOBAL_CONFIG_PATH";
17
+ /**
18
+ * Resolve the effective backend for one run: explicit per-run override, then
19
+ * a trusted-project per-profile override, then trusted-project/global defaults,
20
+ * then the built-in subprocess backend. There is deliberately no fallback when
21
+ * the resolved backend is missing or rejects the intent.
22
+ */
23
+ export function resolveSubagentBackend(settings, explicitBackend, profileId) {
24
+ if (explicitBackend)
25
+ return { id: explicitBackend, source: "explicit" };
26
+ const profile = profileId ? configuredProfile(settings, profileId) : undefined;
27
+ if (profile?.backend)
28
+ return { id: profile.backend, source: profile.backendSource ?? "project-profile" };
29
+ if (settings.backend)
30
+ return { id: settings.backend, source: settings.backendSource ?? "global" };
31
+ return { id: DEFAULT_SUBAGENT_BACKEND_ID, source: "built-in" };
32
+ }
33
+ export function resolveSubagentTimeout(settings, profileId) {
34
+ const profile = profileId ? configuredProfile(settings, profileId) : undefined;
35
+ if (profile?.timeoutMs !== undefined) {
36
+ return { milliseconds: profile.timeoutMs, source: profile.timeoutSource ?? "project-profile" };
37
+ }
38
+ return { milliseconds: settings.timeoutMs, source: settings.timeoutSource };
39
+ }
40
+ export function resolveSubagentProfilePolicy(settings, profileId, explicitBackend) {
41
+ const profile = configuredProfile(settings, profileId);
42
+ return {
43
+ profileId,
44
+ enabled: profile?.enabled === true,
45
+ enabledSource: profile?.enabledSource ?? "built-in",
46
+ backend: resolveSubagentBackend(settings, explicitBackend, profileId),
47
+ timeout: resolveSubagentTimeout(settings, profileId),
48
+ };
49
+ }
3
50
  export function loadForgeSubagentSettings(ctx) {
4
51
  const configPath = join(ctx.cwd, ".pi", "forge", "config.json");
5
- const defaults = { allowAgentInvocationWithoutApproval: false, configPath, warnings: [] };
6
- if (!ctx.isProjectTrusted() || !existsSync(configPath))
7
- return defaults;
52
+ const globalConfigPath = process.env[GLOBAL_FORGE_CONFIG_PATH_ENV] ?? join(globalForgeDir(), "config.json");
53
+ const settings = {
54
+ allowAgentInvocationWithoutApproval: false,
55
+ timeoutMs: DEFAULT_SUBAGENT_TIMEOUT_MS,
56
+ timeoutSource: "built-in",
57
+ profiles: Object.create(null),
58
+ configPath,
59
+ globalConfigPath,
60
+ warnings: [],
61
+ };
62
+ // The global config is user-owned and always applies. The project config is
63
+ // honored only for trusted projects and overrides global values.
64
+ const globalSection = readSubagentsSection(globalConfigPath, settings.warnings);
65
+ applyBackend(globalSection, globalConfigPath, "global", settings);
66
+ applyTimeout(globalSection, globalConfigPath, "global", settings);
67
+ warnIgnoredGlobalProfiles(globalSection, globalConfigPath, settings);
68
+ if (!ctx.isProjectTrusted())
69
+ return settings;
70
+ const projectSection = readSubagentsSection(configPath, settings.warnings);
71
+ applyBackend(projectSection, configPath, "project", settings);
72
+ applyTimeout(projectSection, configPath, "project", settings);
73
+ applyProjectProfiles(projectSection, configPath, settings);
74
+ applyUnattended(projectSection, configPath, settings);
75
+ return settings;
76
+ }
77
+ function readSubagentsSection(configPath, warnings) {
78
+ if (!existsSync(configPath))
79
+ return undefined;
8
80
  let raw;
9
81
  try {
10
82
  raw = JSON.parse(readFileSync(configPath, "utf8"));
11
83
  }
12
84
  catch (error) {
13
- return {
14
- ...defaults,
15
- warnings: [`pi-forge: failed to read ${configPath}; per-run subagent approval remains required. ${error instanceof Error ? error.message : String(error)}`],
16
- };
85
+ warnings.push(`pi-forge: failed to read ${configPath}; its subagent settings are ignored. ${error instanceof Error ? error.message : String(error)}`);
86
+ return undefined;
17
87
  }
18
88
  if (!isPlainObject(raw)) {
19
- return { ...defaults, warnings: [`pi-forge: ${configPath} must be a JSON object; per-run subagent approval remains required.`] };
89
+ warnings.push(`pi-forge: ${configPath} must be a JSON object; its subagent settings are ignored.`);
90
+ return undefined;
20
91
  }
21
92
  if (raw.subagents === undefined)
22
- return defaults;
93
+ return undefined;
23
94
  if (!isPlainObject(raw.subagents)) {
24
- return { ...defaults, warnings: [`pi-forge: ${configPath} subagents must be a JSON object; per-run subagent approval remains required.`] };
95
+ warnings.push(`pi-forge: ${configPath} subagents must be a JSON object; its subagent settings are ignored.`);
96
+ return undefined;
97
+ }
98
+ return raw.subagents;
99
+ }
100
+ function applyBackend(section, configPath, source, settings) {
101
+ if (!section || section.backend === undefined)
102
+ return;
103
+ const value = section.backend;
104
+ if (typeof value !== "string" || !value.trim()) {
105
+ settings.warnings.push(`pi-forge: ${configPath} subagents.backend must be a non-empty string; the configured value is ignored.`);
106
+ return;
25
107
  }
26
- const value = raw.subagents.allowAgentInvocationWithoutApproval;
27
- if (value === undefined)
28
- return defaults;
108
+ settings.backend = value;
109
+ settings.backendSource = source;
110
+ }
111
+ function applyTimeout(section, configPath, source, settings) {
112
+ if (!section || section.timeoutMs === undefined)
113
+ return;
114
+ const value = section.timeoutMs;
115
+ if (!isValidSubagentTimeoutMs(value)) {
116
+ settings.warnings.push(`pi-forge: ${configPath} subagents.timeoutMs must be an integer from ${MIN_SUBAGENT_TIMEOUT_MS} to ${MAX_SUBAGENT_TIMEOUT_MS}; the configured value is ignored.`);
117
+ return;
118
+ }
119
+ settings.timeoutMs = value;
120
+ settings.timeoutSource = source;
121
+ }
122
+ function warnIgnoredGlobalProfiles(section, configPath, settings) {
123
+ if (!section || section.profiles === undefined)
124
+ return;
125
+ settings.warnings.push(`pi-forge: ${configPath} subagents.profiles is project-only and ignored; configure profile delegation in the trusted project's .pi/forge/config.json.`);
126
+ }
127
+ function applyProjectProfiles(section, configPath, settings) {
128
+ if (!section || section.profiles === undefined)
129
+ return;
130
+ if (!isPlainObject(section.profiles)) {
131
+ settings.warnings.push(`pi-forge: ${configPath} subagents.profiles must be a JSON object; its per-profile settings are ignored.`);
132
+ return;
133
+ }
134
+ for (const [profileId, rawProfile] of Object.entries(section.profiles)) {
135
+ const path = `subagents.profiles.${profileId}`;
136
+ if (!isValidAgentProfileId(profileId)) {
137
+ settings.warnings.push(`pi-forge: ${configPath} ${path} has an invalid profile id; the entry is ignored.`);
138
+ continue;
139
+ }
140
+ if (!isPlainObject(rawProfile)) {
141
+ settings.warnings.push(`pi-forge: ${configPath} ${path} must be a JSON object; the entry is ignored.`);
142
+ continue;
143
+ }
144
+ for (const field of Object.keys(rawProfile)) {
145
+ if (field === "enabled" || field === "backend" || field === "timeoutMs")
146
+ continue;
147
+ settings.warnings.push(`pi-forge: ${configPath} ${path}.${field} is unsupported and ignored.`);
148
+ }
149
+ const target = configuredProfile(settings, profileId) ?? {};
150
+ const profileSource = "project-profile";
151
+ if (rawProfile.enabled !== undefined) {
152
+ if (typeof rawProfile.enabled !== "boolean") {
153
+ settings.warnings.push(`pi-forge: ${configPath} ${path}.enabled must be boolean; the configured value is ignored.`);
154
+ }
155
+ else {
156
+ target.enabled = rawProfile.enabled;
157
+ target.enabledSource = profileSource;
158
+ }
159
+ }
160
+ if (rawProfile.backend !== undefined) {
161
+ if (typeof rawProfile.backend !== "string" || !rawProfile.backend.trim()) {
162
+ settings.warnings.push(`pi-forge: ${configPath} ${path}.backend must be a non-empty string; the configured value is ignored.`);
163
+ }
164
+ else {
165
+ target.backend = rawProfile.backend;
166
+ target.backendSource = profileSource;
167
+ }
168
+ }
169
+ if (rawProfile.timeoutMs !== undefined) {
170
+ if (!isValidSubagentTimeoutMs(rawProfile.timeoutMs)) {
171
+ settings.warnings.push(`pi-forge: ${configPath} ${path}.timeoutMs must be an integer from ${MIN_SUBAGENT_TIMEOUT_MS} to ${MAX_SUBAGENT_TIMEOUT_MS}; the configured value is ignored.`);
172
+ }
173
+ else {
174
+ target.timeoutMs = rawProfile.timeoutMs;
175
+ target.timeoutSource = profileSource;
176
+ }
177
+ }
178
+ if (Object.keys(target).length > 0)
179
+ settings.profiles[profileId] = target;
180
+ }
181
+ }
182
+ function applyUnattended(section, configPath, settings) {
183
+ if (!section || section.allowAgentInvocationWithoutApproval === undefined)
184
+ return;
185
+ const value = section.allowAgentInvocationWithoutApproval;
29
186
  if (typeof value !== "boolean") {
187
+ settings.warnings.push(`pi-forge: ${configPath} subagents.allowAgentInvocationWithoutApproval must be boolean; per-run subagent approval remains required.`);
188
+ return;
189
+ }
190
+ settings.allowAgentInvocationWithoutApproval = value;
191
+ }
192
+ export function isValidSubagentTimeoutMs(value) {
193
+ return Number.isSafeInteger(value)
194
+ && value >= MIN_SUBAGENT_TIMEOUT_MS
195
+ && value <= MAX_SUBAGENT_TIMEOUT_MS;
196
+ }
197
+ /**
198
+ * Update `subagents.profiles.<id>` in the project's `.pi/forge/config.json`,
199
+ * preserving unknown top-level, `subagents`, and per-entry fields. Callers
200
+ * must gate this on project trust; the project config is ignored otherwise.
201
+ */
202
+ export function updateForgeSubagentProfileConfig(cwd, profileId, update) {
203
+ if (!isValidAgentProfileId(profileId)) {
204
+ return { ok: false, error: `Invalid agent profile id: ${profileId}` };
205
+ }
206
+ if (update.backend !== undefined && update.backend !== null && (typeof update.backend !== "string" || !update.backend.trim())) {
207
+ return { ok: false, error: "subagent backend must be a non-empty string or null to clear the override." };
208
+ }
209
+ if (update.timeoutMs !== undefined && update.timeoutMs !== null && !isValidSubagentTimeoutMs(update.timeoutMs)) {
30
210
  return {
31
- ...defaults,
32
- warnings: [`pi-forge: ${configPath} subagents.allowAgentInvocationWithoutApproval must be boolean; per-run subagent approval remains required.`],
211
+ ok: false,
212
+ error: `subagent timeoutMs must be an integer from ${MIN_SUBAGENT_TIMEOUT_MS} to ${MAX_SUBAGENT_TIMEOUT_MS} or null to clear the override.`,
33
213
  };
34
214
  }
35
- return { ...defaults, allowAgentInvocationWithoutApproval: value };
215
+ const configPath = join(cwd, ".pi", "forge", "config.json");
216
+ let root = {};
217
+ if (existsSync(configPath)) {
218
+ let raw;
219
+ try {
220
+ raw = JSON.parse(readFileSync(configPath, "utf8"));
221
+ }
222
+ catch (error) {
223
+ return {
224
+ ok: false,
225
+ error: `Refusing to update unreadable ${configPath}: ${error instanceof Error ? error.message : String(error)}`,
226
+ };
227
+ }
228
+ if (!isPlainObject(raw)) {
229
+ return { ok: false, error: `Refusing to update ${configPath}: the config root must be a JSON object.` };
230
+ }
231
+ root = raw;
232
+ }
233
+ if (root.subagents !== undefined && !isPlainObject(root.subagents)) {
234
+ return { ok: false, error: `Refusing to update ${configPath}: subagents must be a JSON object.` };
235
+ }
236
+ const subagents = isPlainObject(root.subagents) ? root.subagents : {};
237
+ if (subagents.profiles !== undefined && !isPlainObject(subagents.profiles)) {
238
+ return { ok: false, error: `Refusing to update ${configPath}: subagents.profiles must be a JSON object.` };
239
+ }
240
+ const profiles = isPlainObject(subagents.profiles) ? subagents.profiles : {};
241
+ if (profiles[profileId] !== undefined && !isPlainObject(profiles[profileId])) {
242
+ return { ok: false, error: `Refusing to update ${configPath}: subagents.profiles.${profileId} must be a JSON object.` };
243
+ }
244
+ const entry = isPlainObject(profiles[profileId]) ? { ...profiles[profileId] } : {};
245
+ if (update.enabled !== undefined) {
246
+ if (update.enabled)
247
+ entry.enabled = true;
248
+ else
249
+ delete entry.enabled;
250
+ }
251
+ if (update.backend !== undefined) {
252
+ if (typeof update.backend === "string" && update.backend.trim())
253
+ entry.backend = update.backend.trim();
254
+ else
255
+ delete entry.backend;
256
+ }
257
+ if (update.timeoutMs !== undefined) {
258
+ if (update.timeoutMs === null)
259
+ delete entry.timeoutMs;
260
+ else
261
+ entry.timeoutMs = update.timeoutMs;
262
+ }
263
+ if (Object.keys(entry).length > 0)
264
+ profiles[profileId] = entry;
265
+ else
266
+ delete profiles[profileId];
267
+ if (Object.keys(profiles).length > 0)
268
+ subagents.profiles = profiles;
269
+ else
270
+ delete subagents.profiles;
271
+ if (Object.keys(subagents).length > 0)
272
+ root.subagents = subagents;
273
+ else
274
+ delete root.subagents;
275
+ try {
276
+ mkdirSync(dirname(configPath), { recursive: true });
277
+ writeFileSync(configPath, `${JSON.stringify(root, null, 2)}\n`, "utf8");
278
+ return { ok: true, configPath };
279
+ }
280
+ catch (error) {
281
+ return { ok: false, error: `Failed to write ${configPath}: ${error instanceof Error ? error.message : String(error)}` };
282
+ }
283
+ }
284
+ function configuredProfile(settings, profileId) {
285
+ return Object.hasOwn(settings.profiles, profileId) ? settings.profiles[profileId] : undefined;
36
286
  }
37
287
  function isPlainObject(value) {
38
288
  return !!value && typeof value === "object" && !Array.isArray(value);
@@ -1 +1 @@
1
- {"version":3,"file":"forge-config.js","sourceRoot":"","sources":["../src/forge-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AASjC,MAAM,UAAU,yBAAyB,CAAC,GAAqB;IAC9D,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;IAChE,MAAM,QAAQ,GAAG,EAAE,mCAAmC,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAc,EAAE,CAAC;IACtG,IAAI,CAAC,GAAG,CAAC,gBAAgB,EAAE,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,QAAQ,CAAC;IAExE,IAAI,GAAY,CAAC;IACjB,IAAI,CAAC;QACJ,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;IACpD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,OAAO;YACN,GAAG,QAAQ;YACX,QAAQ,EAAE,CAAC,4BAA4B,UAAU,iDAAiD,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;SAC3J,CAAC;IACH,CAAC;IACD,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,GAAG,QAAQ,EAAE,QAAQ,EAAE,CAAC,aAAa,UAAU,qEAAqE,CAAC,EAAE,CAAC;IAClI,CAAC;IACD,IAAI,GAAG,CAAC,SAAS,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC;IACjD,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;QACnC,OAAO,EAAE,GAAG,QAAQ,EAAE,QAAQ,EAAE,CAAC,aAAa,UAAU,+EAA+E,CAAC,EAAE,CAAC;IAC5I,CAAC;IACD,MAAM,KAAK,GAAG,GAAG,CAAC,SAAS,CAAC,mCAAmC,CAAC;IAChE,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC;IACzC,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO;YACN,GAAG,QAAQ;YACX,QAAQ,EAAE,CAAC,aAAa,UAAU,6GAA6G,CAAC;SAChJ,CAAC;IACH,CAAC;IACD,OAAO,EAAE,GAAG,QAAQ,EAAE,mCAAmC,EAAE,KAAK,EAAE,CAAC;AACpE,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACpC,OAAO,CAAC,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AACtE,CAAC"}
1
+ {"version":3,"file":"forge-config.js","sourceRoot":"","sources":["../src/forge-config.ts"],"names":[],"mappings":"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"}