@nifrajs/coding-agent 3.2.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 (211) hide show
  1. package/EXTENSIONS.md +25 -0
  2. package/PERFORMANCE.md +19 -0
  3. package/README.md +69 -0
  4. package/REGISTRY.md +15 -0
  5. package/SECURITY.md +32 -0
  6. package/dist/approvals.d.ts +70 -0
  7. package/dist/approvals.d.ts.map +1 -0
  8. package/dist/approvals.js +174 -0
  9. package/dist/approvals.js.map +1 -0
  10. package/dist/capabilities.d.ts +20 -0
  11. package/dist/capabilities.d.ts.map +1 -0
  12. package/dist/capabilities.js +49 -0
  13. package/dist/capabilities.js.map +1 -0
  14. package/dist/cli.d.ts +24 -0
  15. package/dist/cli.d.ts.map +1 -0
  16. package/dist/cli.js +380 -0
  17. package/dist/cli.js.map +1 -0
  18. package/dist/context.d.ts +17 -0
  19. package/dist/context.d.ts.map +1 -0
  20. package/dist/context.js +66 -0
  21. package/dist/context.js.map +1 -0
  22. package/dist/deployment-adapters.d.ts +40 -0
  23. package/dist/deployment-adapters.d.ts.map +1 -0
  24. package/dist/deployment-adapters.js +147 -0
  25. package/dist/deployment-adapters.js.map +1 -0
  26. package/dist/diff.d.ts +17 -0
  27. package/dist/diff.d.ts.map +1 -0
  28. package/dist/diff.js +61 -0
  29. package/dist/diff.js.map +1 -0
  30. package/dist/errors.d.ts +9 -0
  31. package/dist/errors.d.ts.map +1 -0
  32. package/dist/errors.js +35 -0
  33. package/dist/errors.js.map +1 -0
  34. package/dist/extensions.d.ts +104 -0
  35. package/dist/extensions.d.ts.map +1 -0
  36. package/dist/extensions.js +284 -0
  37. package/dist/extensions.js.map +1 -0
  38. package/dist/handoffs.d.ts +97 -0
  39. package/dist/handoffs.d.ts.map +1 -0
  40. package/dist/handoffs.js +199 -0
  41. package/dist/handoffs.js.map +1 -0
  42. package/dist/healing.d.ts +56 -0
  43. package/dist/healing.d.ts.map +1 -0
  44. package/dist/healing.js +54 -0
  45. package/dist/healing.js.map +1 -0
  46. package/dist/host.d.ts +61 -0
  47. package/dist/host.d.ts.map +1 -0
  48. package/dist/host.js +369 -0
  49. package/dist/host.js.map +1 -0
  50. package/dist/index.d.ts +26 -0
  51. package/dist/index.d.ts.map +1 -0
  52. package/dist/index.js +26 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/isolated-worker.d.ts +2 -0
  55. package/dist/isolated-worker.d.ts.map +1 -0
  56. package/dist/isolated-worker.js +155 -0
  57. package/dist/isolated-worker.js.map +1 -0
  58. package/dist/isolated.d.ts +52 -0
  59. package/dist/isolated.d.ts.map +1 -0
  60. package/dist/isolated.js +293 -0
  61. package/dist/isolated.js.map +1 -0
  62. package/dist/native.d.ts +92 -0
  63. package/dist/native.d.ts.map +1 -0
  64. package/dist/native.js +339 -0
  65. package/dist/native.js.map +1 -0
  66. package/dist/orchestration/artifact-port.d.ts +30 -0
  67. package/dist/orchestration/artifact-port.d.ts.map +1 -0
  68. package/dist/orchestration/artifact-port.js +59 -0
  69. package/dist/orchestration/artifact-port.js.map +1 -0
  70. package/dist/orchestration/catalog.d.ts +71 -0
  71. package/dist/orchestration/catalog.d.ts.map +1 -0
  72. package/dist/orchestration/catalog.js +46 -0
  73. package/dist/orchestration/catalog.js.map +1 -0
  74. package/dist/orchestration/compile.d.ts +59 -0
  75. package/dist/orchestration/compile.d.ts.map +1 -0
  76. package/dist/orchestration/compile.js +268 -0
  77. package/dist/orchestration/compile.js.map +1 -0
  78. package/dist/orchestration/dispatch.d.ts +115 -0
  79. package/dist/orchestration/dispatch.d.ts.map +1 -0
  80. package/dist/orchestration/dispatch.js +220 -0
  81. package/dist/orchestration/dispatch.js.map +1 -0
  82. package/dist/orchestration/durable-jobs.d.ts +35 -0
  83. package/dist/orchestration/durable-jobs.d.ts.map +1 -0
  84. package/dist/orchestration/durable-jobs.js +273 -0
  85. package/dist/orchestration/durable-jobs.js.map +1 -0
  86. package/dist/orchestration/effect-key.d.ts +23 -0
  87. package/dist/orchestration/effect-key.d.ts.map +1 -0
  88. package/dist/orchestration/effect-key.js +24 -0
  89. package/dist/orchestration/effect-key.js.map +1 -0
  90. package/dist/orchestration/evidence-store.d.ts +75 -0
  91. package/dist/orchestration/evidence-store.d.ts.map +1 -0
  92. package/dist/orchestration/evidence-store.js +183 -0
  93. package/dist/orchestration/evidence-store.js.map +1 -0
  94. package/dist/orchestration/hash.d.ts +12 -0
  95. package/dist/orchestration/hash.d.ts.map +1 -0
  96. package/dist/orchestration/hash.js +43 -0
  97. package/dist/orchestration/hash.js.map +1 -0
  98. package/dist/orchestration/host.d.ts +121 -0
  99. package/dist/orchestration/host.d.ts.map +1 -0
  100. package/dist/orchestration/host.js +334 -0
  101. package/dist/orchestration/host.js.map +1 -0
  102. package/dist/orchestration/index.d.ts +20 -0
  103. package/dist/orchestration/index.d.ts.map +1 -0
  104. package/dist/orchestration/index.js +19 -0
  105. package/dist/orchestration/index.js.map +1 -0
  106. package/dist/orchestration/policy.d.ts +63 -0
  107. package/dist/orchestration/policy.d.ts.map +1 -0
  108. package/dist/orchestration/policy.js +80 -0
  109. package/dist/orchestration/policy.js.map +1 -0
  110. package/dist/orchestration/recovery.d.ts +87 -0
  111. package/dist/orchestration/recovery.d.ts.map +1 -0
  112. package/dist/orchestration/recovery.js +197 -0
  113. package/dist/orchestration/recovery.js.map +1 -0
  114. package/dist/orchestration/tracer.d.ts +31 -0
  115. package/dist/orchestration/tracer.d.ts.map +1 -0
  116. package/dist/orchestration/tracer.js +141 -0
  117. package/dist/orchestration/tracer.js.map +1 -0
  118. package/dist/plans.d.ts +35 -0
  119. package/dist/plans.d.ts.map +1 -0
  120. package/dist/plans.js +63 -0
  121. package/dist/plans.js.map +1 -0
  122. package/dist/presets.d.ts +10 -0
  123. package/dist/presets.d.ts.map +1 -0
  124. package/dist/presets.js +70 -0
  125. package/dist/presets.js.map +1 -0
  126. package/dist/process.d.ts +6 -0
  127. package/dist/process.d.ts.map +1 -0
  128. package/dist/process.js +42 -0
  129. package/dist/process.js.map +1 -0
  130. package/dist/registry.d.ts +37 -0
  131. package/dist/registry.d.ts.map +1 -0
  132. package/dist/registry.js +51 -0
  133. package/dist/registry.js.map +1 -0
  134. package/dist/replay.d.ts +24 -0
  135. package/dist/replay.d.ts.map +1 -0
  136. package/dist/replay.js +154 -0
  137. package/dist/replay.js.map +1 -0
  138. package/dist/rpc.d.ts +51 -0
  139. package/dist/rpc.d.ts.map +1 -0
  140. package/dist/rpc.js +412 -0
  141. package/dist/rpc.js.map +1 -0
  142. package/dist/session-migration.d.ts +59 -0
  143. package/dist/session-migration.d.ts.map +1 -0
  144. package/dist/session-migration.js +315 -0
  145. package/dist/session-migration.js.map +1 -0
  146. package/dist/sessions.d.ts +74 -0
  147. package/dist/sessions.d.ts.map +1 -0
  148. package/dist/sessions.js +222 -0
  149. package/dist/sessions.js.map +1 -0
  150. package/dist/subagents.d.ts +51 -0
  151. package/dist/subagents.d.ts.map +1 -0
  152. package/dist/subagents.js +141 -0
  153. package/dist/subagents.js.map +1 -0
  154. package/dist/tools.d.ts +13 -0
  155. package/dist/tools.d.ts.map +1 -0
  156. package/dist/tools.js +37 -0
  157. package/dist/tools.js.map +1 -0
  158. package/dist/ui.d.ts +42 -0
  159. package/dist/ui.d.ts.map +1 -0
  160. package/dist/ui.js +93 -0
  161. package/dist/ui.js.map +1 -0
  162. package/dist/verification.d.ts +34 -0
  163. package/dist/verification.d.ts.map +1 -0
  164. package/dist/verification.js +91 -0
  165. package/dist/verification.js.map +1 -0
  166. package/dist/workflows.d.ts +98 -0
  167. package/dist/workflows.d.ts.map +1 -0
  168. package/dist/workflows.js +174 -0
  169. package/dist/workflows.js.map +1 -0
  170. package/package.json +84 -0
  171. package/src/approvals.ts +249 -0
  172. package/src/capabilities.ts +74 -0
  173. package/src/cli.ts +405 -0
  174. package/src/context.ts +81 -0
  175. package/src/deployment-adapters.ts +181 -0
  176. package/src/diff.ts +80 -0
  177. package/src/errors.ts +46 -0
  178. package/src/extensions.ts +402 -0
  179. package/src/handoffs.ts +299 -0
  180. package/src/healing.ts +93 -0
  181. package/src/host.ts +465 -0
  182. package/src/index.ts +165 -0
  183. package/src/isolated-worker.ts +177 -0
  184. package/src/isolated.ts +344 -0
  185. package/src/native.ts +478 -0
  186. package/src/orchestration/artifact-port.ts +75 -0
  187. package/src/orchestration/catalog.ts +102 -0
  188. package/src/orchestration/compile.ts +373 -0
  189. package/src/orchestration/dispatch.ts +383 -0
  190. package/src/orchestration/durable-jobs.ts +374 -0
  191. package/src/orchestration/effect-key.ts +35 -0
  192. package/src/orchestration/evidence-store.ts +233 -0
  193. package/src/orchestration/hash.ts +43 -0
  194. package/src/orchestration/host.ts +445 -0
  195. package/src/orchestration/index.ts +131 -0
  196. package/src/orchestration/policy.ts +116 -0
  197. package/src/orchestration/recovery.ts +271 -0
  198. package/src/orchestration/tracer.ts +177 -0
  199. package/src/plans.ts +105 -0
  200. package/src/presets.ts +90 -0
  201. package/src/process.ts +47 -0
  202. package/src/registry.ts +80 -0
  203. package/src/replay.ts +190 -0
  204. package/src/rpc.ts +598 -0
  205. package/src/session-migration.ts +401 -0
  206. package/src/sessions.ts +303 -0
  207. package/src/subagents.ts +210 -0
  208. package/src/tools.ts +52 -0
  209. package/src/ui.ts +137 -0
  210. package/src/verification.ts +133 -0
  211. package/src/workflows.ts +279 -0
package/EXTENSIONS.md ADDED
@@ -0,0 +1,25 @@
1
+ # Nifra agent extensions
2
+
3
+ Extensions are project-local TypeScript modules under `.nifra/extensions/`. They are discovered
4
+ only when the host is configured for that project; no dependency or home-directory scan is implicit.
5
+
6
+ ```ts
7
+ export const capabilities = ["filesystem.read"] as const
8
+
9
+ export default ({ registerCommand, registerWorkflow }) => {
10
+ registerCommand("status", async (_args, context) => ({ cwd: context.cwd }))
11
+ registerWorkflow("verify", () => ({
12
+ type: "verify",
13
+ id: "check",
14
+ run: async () => true,
15
+ }))
16
+ }
17
+ ```
18
+
19
+ The host syntax-checks a changed module, stages a complete replacement graph, and only then
20
+ disposes the previous graph. A failed load leaves the last known-good graph active. Extensions can
21
+ declare capabilities, but untrusted capabilities are rejected before registration. Workflows run
22
+ with bounded step and depth ceilings through `workflow.run`.
23
+
24
+ Use `nifra-agent` `/reload` or the Workbench preview/activate controls after the file is saved.
25
+ The stable Workbench shell, approval UX, and token boundary are not replaceable by an extension.
package/PERFORMANCE.md ADDED
@@ -0,0 +1,19 @@
1
+ # Agent performance evidence
2
+
3
+ Run the reproducible local measurements with:
4
+
5
+ ```sh
6
+ bun run bench:agent -- --events=100000 --json
7
+ bun run bench:agent:reload -- --runs=20 --json
8
+ bun run bench:pi -- --turns=1000 --json
9
+ bun run demo:agent-extension
10
+ ```
11
+
12
+ The bounded event stream and context window stay constant-size under event growth. The Pi adapter
13
+ benchmark compares the same no-model JSONL process against the protocol adapter; the result is
14
+ machine-load sensitive, so record the full JSON output and hardware when publishing a comparison.
15
+
16
+ Agent Platform checks additionally keep plan compilation, evidence projection, recovery schedules,
17
+ gateway retries, and Workbench replay views payload-free. The Workbench reference check uses 2,000
18
+ evidence rows, a 100-row visible window, and a 256-node graph; it enforces the recorded projection
19
+ and render budgets without serializing content.
package/README.md ADDED
@@ -0,0 +1,69 @@
1
+ # @nifrajs/coding-agent
2
+
3
+ Standalone, extensible Nifra coding-agent host and CLI.
4
+
5
+ The package provides `nifra-agent` in interactive, one-shot, JSON, and local
6
+ loopback RPC modes. It adds sessions, checkpoints, bounded compaction,
7
+ transactional TypeScript extensions, self-healing repair stages, workflows,
8
+ bounded subagents, and Nifra verification descriptors without changing Nifra's
9
+ framework runtime.
10
+
11
+ Extensions can register bounded workflows that are listed and run through the
12
+ authenticated RPC surface. Capability manifests, project workspace policies,
13
+ optional isolated-worktree leases, and a pre-activation syntax gate keep those
14
+ customizations explicit and replaceable.
15
+
16
+ ```sh
17
+ bunx nifra-agent --backend pi
18
+ bunx nifra-agent --backend pi --message "run the checks and explain failures"
19
+ bunx nifra-agent --backend pi --verify-after-turn check --max-repair-attempts 2
20
+ bunx nifra-agent --backend replay --replay ./session-events.jsonl --json
21
+ ```
22
+
23
+ When --verify-after-turn is enabled, a failed gate becomes a bounded repair turn: the host sends
24
+ the failure diagnostics back to the agent, runs the gate again, and stops on success or after the
25
+ configured attempt cap. Use --max-repair-attempts 0 for observe-only verification.
26
+
27
+ For embedding, use `CodingAgentHost` or `CodingAgentRpcServer`. The host keeps
28
+ live event queues bounded, filters verification subprocess environments, and
29
+ requires explicit local RPC authorization. Install this package only when an
30
+ application wants the agent product.
31
+
32
+ RPC failures return actionable bounded error messages by default. For a trusted
33
+ loopback debugger, set `exposeErrorStacks: true` (or pass
34
+ `--expose-error-stacks` to `nifra-agent --rpc`) to include bounded exception
35
+ stacks. This option is rejected for remote binding.
36
+
37
+ `IsolatedExtensionWorker` is an opt-in process-backed crash-containment seam for
38
+ extensions. It is not a hostile-code sandbox; use OS-level isolation before
39
+ loading code you do not trust.
40
+
41
+ `NifraBackend` is a small provider port for a future native backend. It accepts
42
+ an injected model implementation and bounded tools without importing a provider
43
+ SDK. `ReplayBackend` and `readReplayEvents` provide deterministic protocol
44
+ replays for CI and Workbench regression tests.
45
+
46
+ ## At-least-once run dispatch
47
+
48
+ `@nifrajs/coding-agent/orchestration` also exports an evidence-only run dispatch port and an adapter
49
+ over `@nifrajs/jobs`. Dispatch is at-least-once: a lease may be delivered again after worker loss or
50
+ lease expiry. Every logical node attempt receives a stable idempotency key derived from the plan,
51
+ run, node, and attempt boundary. Effects must provide a matching proof before recovery can settle a
52
+ completed boundary; an unproven post-effect failure is dead-lettered rather than guessed safe.
53
+
54
+ `createMemoryRunDispatchStore()` is disposable single-process test infrastructure. It makes no
55
+ durability, hosted-worker, retention, tenant-authorization, or exactly-once guarantee. Durable
56
+ operated adapters implement the exported `RunDispatchStore` and `DurableDispatchAdapter` ports in
57
+ their own data layer, including authorization, row policy, retention, reconciliation, and worker
58
+ health. The public package does not store prompts, model output, tool arguments, or job payloads in
59
+ its dispatch evidence.
60
+
61
+ Legacy `FileSessionStore` files remain supported for explicit local compatibility. Use
62
+ `nifra-agent --migrate-session <id> --migrate-from <legacy-dir> --migrate-to <evidence-dir>` to
63
+ create a separately validated, evidence-only target. The source is left untouched and the command
64
+ does not switch an active configuration pointer; see
65
+ [`docs/agent-platform/protocol-and-session-migration.md`](../../docs/agent-platform/protocol-and-session-migration.md)
66
+ for rollback and protocol compatibility details.
67
+
68
+ For AI agents, see [`LLM.md`](./LLM.md) and the full corpus
69
+ [`../../llms-full.txt`](../../llms-full.txt).
package/REGISTRY.md ADDED
@@ -0,0 +1,15 @@
1
+ # Agent tool and workflow registry proposal
2
+
3
+ The optional registry is intentionally a local seam in preview releases:
4
+
5
+ 1. An extension declares a stable tool or workflow id and a bounded capability list.
6
+ 2. The host validates and stages the extension graph.
7
+ 3. Authenticated clients query `workflow.list`, `ui.snapshot`, and session capabilities.
8
+ 4. Invocation stays in the local host, under the host's approval, workspace, and resource limits.
9
+
10
+ A future public registry can distribute signed metadata and versioned manifests. It must not move
11
+ credentials, tenant state, pricing, prompt IP, or operated execution into the public package.
12
+
13
+ Agent Platform registry snapshots are canonical and digestable. Descriptor adapters expose identity,
14
+ schema digest, capability tokens, and policy classes only. Invocation, credentials, signed
15
+ distribution, retention, and organization policy remain host or caller responsibilities.
package/SECURITY.md ADDED
@@ -0,0 +1,32 @@
1
+ # Nifra agent security model
2
+
3
+ The preview is local-first and fail-closed:
4
+
5
+ - RPC binds to loopback and requires a random bearer token; remote binding is opt-in.
6
+ - RPC error stacks are omitted by default; `exposeErrorStacks` is an explicit loopback-only
7
+ diagnostics mode and is rejected when remote binding is enabled.
8
+ - Project extensions are explicit, path-bounded, syntax-checked, capability-checked, and
9
+ transactionally reloaded.
10
+ - Session evidence is bounded, redacted for secret-shaped keys, and written as append-only JSONL.
11
+ - Tool approvals are host-owned and auditable. A workflow or subagent cannot raise its own limits.
12
+ - Subagents can be restricted to project roots or a caller-provided isolated-worktree lease.
13
+ - The isolated extension worker contains crashes but is not a hostile-code sandbox. Use OS-level
14
+ isolation before loading code that is not trusted.
15
+ - No telemetry, hosted state, remote credentials, or model-provider SDK is required by the
16
+ framework packages.
17
+
18
+ The capability manifest is a public declaration seam, not a sandbox by itself. Operators must pair
19
+ it with OS policy, a sandbox, or an approval broker appropriate to the deployment.
20
+
21
+ ## Release regression coverage
22
+
23
+ The security suite fails closed for the following named boundaries: strict plan and evidence parsing,
24
+ capability and child-authority escalation, approval and handoff expiry, workspace and symlink escape,
25
+ content-bearing evidence, unauthorised remote RPC binding, contradictory adapter capability claims,
26
+ false hostile-code isolation claims, and credential-shaped values in logs. Stable failure codes are
27
+ asserted at each boundary. Local process and replay deployment profiles explicitly report that they
28
+ are not hostile-code sandboxes.
29
+
30
+ Legacy session migration is a separate local operation. It validates source records, writes only
31
+ structural evidence to a new target, rejects overlapping roots and existing targets, validates the
32
+ committed file, and never rewrites the source. See the public migration guide for rollback.
@@ -0,0 +1,70 @@
1
+ import { type AgentApprovalRequiredEvent, type AgentApprovalResolvedEvent, type DecisionCoordinate } from "@nifrajs/agent-protocol";
2
+ export interface ApprovalRequest {
3
+ readonly id: string;
4
+ readonly sessionId: string;
5
+ readonly turnId?: string;
6
+ readonly action: string;
7
+ readonly capability: string;
8
+ readonly reason?: string;
9
+ /**
10
+ * Optional decision-boundary coordinate. When present, {@link ApprovalManager.resolveMatched}
11
+ * admits a decision only if it names this exact run, node, capability, request id, and vector, and
12
+ * arrives before expiry. Coordinate-less approvals keep their original untyped {@link resolve} path.
13
+ */
14
+ readonly coordinate?: DecisionCoordinate;
15
+ readonly createdAt: number;
16
+ readonly expiresAt: number;
17
+ }
18
+ /** Stable, content-free reasons a coordinate-matched resolution is refused. */
19
+ export type ApprovalMatchRejection = "unknown_boundary" | "identity_mismatch" | "stale_vector" | "expired" | "illegal_transition";
20
+ export type ApprovalMatchResult = {
21
+ readonly ok: true;
22
+ readonly decision: ApprovalDecision;
23
+ } | {
24
+ readonly ok: false;
25
+ readonly code: ApprovalMatchRejection;
26
+ };
27
+ export interface ApprovalDecision {
28
+ readonly approvalId: string;
29
+ readonly approved: boolean;
30
+ readonly reason?: string;
31
+ readonly at: number;
32
+ }
33
+ export interface ApprovalManagerOptions {
34
+ readonly maxPending?: number;
35
+ readonly timeoutMs?: number;
36
+ readonly onRequired?: (request: ApprovalRequest) => void | PromiseLike<void>;
37
+ readonly onResolved?: (decision: ApprovalDecision) => void | PromiseLike<void>;
38
+ }
39
+ /**
40
+ * Small approval broker shared by RPC, Workbench, and workflow extensions.
41
+ *
42
+ * Approval state is deliberately bounded and expires closed (denied) by default. It is a policy
43
+ * seam, not a security boundary: filesystem/process isolation still belongs to the host or OS.
44
+ */
45
+ export declare class ApprovalManager {
46
+ private readonly options;
47
+ private readonly pendingApprovals;
48
+ constructor(options?: ApprovalManagerOptions);
49
+ get pending(): readonly ApprovalRequest[];
50
+ /** Convert a streamed backend approval event into a resolvable pending request. */
51
+ observe(event: AgentApprovalRequiredEvent): Promise<ApprovalRequest | undefined>;
52
+ /** Publish a pending approval without waiting for its decision (useful for transports). */
53
+ offer(input: Omit<ApprovalRequest, "createdAt" | "expiresAt">): Promise<ApprovalRequest | undefined>;
54
+ /** Create a host-owned approval that can be awaited by a workflow or extension. */
55
+ request(input: Omit<ApprovalRequest, "createdAt" | "expiresAt">): Promise<boolean>;
56
+ /**
57
+ * Resolve an approval that was opened with a {@link DecisionCoordinate}, admitting the decision only
58
+ * when it matches the live boundary and is still fresh. Every failure is content-free and fails
59
+ * closed: an unknown id, a coordinate-less approval, a mismatched or superseded coordinate, or an
60
+ * expired boundary resumes no work. This adds a typed path alongside the untyped {@link resolve}; it
61
+ * never loosens it.
62
+ */
63
+ resolveMatched(coordinate: DecisionCoordinate, approved: boolean, now?: number): ApprovalMatchResult;
64
+ resolve(approvalId: string, approved: boolean, reason?: string): ApprovalDecision | undefined;
65
+ close(): void;
66
+ private create;
67
+ }
68
+ export declare function approvalRequestFromEvent(event: AgentApprovalRequiredEvent): ApprovalRequest;
69
+ export declare function approvalResolvedEvent(sessionId: string, seq: number, decision: ApprovalDecision, turnId?: string): AgentApprovalResolvedEvent;
70
+ //# sourceMappingURL=approvals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approvals.d.ts","sourceRoot":"","sources":["../src/approvals.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,174 @@
1
+ import { coordinateIsFresh, coordinatesMatch, nextApprovalState, } from "@nifrajs/agent-protocol";
2
+ /**
3
+ * Small approval broker shared by RPC, Workbench, and workflow extensions.
4
+ *
5
+ * Approval state is deliberately bounded and expires closed (denied) by default. It is a policy
6
+ * seam, not a security boundary: filesystem/process isolation still belongs to the host or OS.
7
+ */
8
+ export class ApprovalManager {
9
+ options;
10
+ pendingApprovals = new Map();
11
+ constructor(options = {}) {
12
+ this.options = {
13
+ ...options,
14
+ maxPending: options.maxPending ?? 32,
15
+ timeoutMs: options.timeoutMs ?? 5 * 60_000,
16
+ };
17
+ if (!Number.isSafeInteger(this.options.maxPending) || this.options.maxPending < 1)
18
+ throw new RangeError("approvals: maxPending must be positive");
19
+ if (!Number.isSafeInteger(this.options.timeoutMs) ||
20
+ this.options.timeoutMs < 1 ||
21
+ this.options.timeoutMs > 24 * 60 * 60_000)
22
+ throw new RangeError("approvals: timeoutMs must be between 1ms and 24h");
23
+ }
24
+ get pending() {
25
+ return Object.freeze([...this.pendingApprovals.values()].map(({ request }) => request));
26
+ }
27
+ /** Convert a streamed backend approval event into a resolvable pending request. */
28
+ async observe(event) {
29
+ if (this.pendingApprovals.has(event.approvalId))
30
+ return this.pendingApprovals.get(event.approvalId)?.request;
31
+ return this.create({
32
+ id: event.approvalId,
33
+ sessionId: event.sessionId,
34
+ turnId: event.turnId,
35
+ action: event.action,
36
+ capability: event.capability,
37
+ ...(event.reason === undefined ? {} : { reason: event.reason }),
38
+ });
39
+ }
40
+ /** Publish a pending approval without waiting for its decision (useful for transports). */
41
+ async offer(input) {
42
+ return this.create(input);
43
+ }
44
+ /** Create a host-owned approval that can be awaited by a workflow or extension. */
45
+ async request(input) {
46
+ const request = await this.offer(input);
47
+ if (request === undefined)
48
+ return false;
49
+ const pending = this.pendingApprovals.get(request.id);
50
+ if (pending === undefined)
51
+ return false;
52
+ return new Promise((resolve) => {
53
+ // Replace the resolver only for this host-owned request; observed backend requests are
54
+ // intentionally notification-only and are resolved through `resolve`.
55
+ const current = this.pendingApprovals.get(request.id);
56
+ if (current === undefined)
57
+ return resolve(false);
58
+ this.pendingApprovals.set(request.id, { ...current, resolve });
59
+ });
60
+ }
61
+ /**
62
+ * Resolve an approval that was opened with a {@link DecisionCoordinate}, admitting the decision only
63
+ * when it matches the live boundary and is still fresh. Every failure is content-free and fails
64
+ * closed: an unknown id, a coordinate-less approval, a mismatched or superseded coordinate, or an
65
+ * expired boundary resumes no work. This adds a typed path alongside the untyped {@link resolve}; it
66
+ * never loosens it.
67
+ */
68
+ resolveMatched(coordinate, approved, now = Date.now()) {
69
+ const pending = this.pendingApprovals.get(coordinate.requestId);
70
+ if (pending === undefined)
71
+ return { ok: false, code: "unknown_boundary" };
72
+ const bound = pending.request.coordinate;
73
+ if (bound === undefined)
74
+ return { ok: false, code: "identity_mismatch" };
75
+ if (!coordinatesMatch(bound, coordinate))
76
+ return {
77
+ ok: false,
78
+ code: bound.vector !== coordinate.vector ? "stale_vector" : "identity_mismatch",
79
+ };
80
+ if (!coordinateIsFresh(bound, now)) {
81
+ this.resolve(coordinate.requestId, false, "approval expired");
82
+ return { ok: false, code: "expired" };
83
+ }
84
+ if (nextApprovalState("pending", approved ? "approve" : "deny") === undefined)
85
+ return { ok: false, code: "illegal_transition" };
86
+ const decision = this.resolve(coordinate.requestId, approved);
87
+ if (decision === undefined)
88
+ return { ok: false, code: "unknown_boundary" };
89
+ return { ok: true, decision };
90
+ }
91
+ resolve(approvalId, approved, reason) {
92
+ const pending = this.pendingApprovals.get(approvalId);
93
+ if (pending === undefined)
94
+ return undefined;
95
+ clearTimeout(pending.timer);
96
+ this.pendingApprovals.delete(approvalId);
97
+ pending.resolve(approved === true);
98
+ const decision = {
99
+ approvalId,
100
+ approved: approved === true,
101
+ ...(reason === undefined ? {} : { reason: reason.slice(0, 512) }),
102
+ at: Date.now(),
103
+ };
104
+ void this.options.onResolved?.(decision);
105
+ return decision;
106
+ }
107
+ close() {
108
+ for (const approvalId of this.pendingApprovals.keys())
109
+ this.resolve(approvalId, false, "approval manager closed");
110
+ }
111
+ async create(input) {
112
+ if (this.pendingApprovals.size >= this.options.maxPending)
113
+ return undefined;
114
+ if (!/^[A-Za-z0-9._:-]{1,128}$/.test(input.id))
115
+ throw new TypeError("approvals: approval id is invalid");
116
+ if (!/^[A-Za-z0-9._:-]{1,128}$/.test(input.sessionId))
117
+ throw new TypeError("approvals: session id is invalid");
118
+ if (!input.action || input.action.length > 512)
119
+ throw new TypeError("approvals: action is empty or too long");
120
+ if (!input.capability || input.capability.length > 128)
121
+ throw new TypeError("approvals: capability is empty or too long");
122
+ const createdAt = Date.now();
123
+ const request = Object.freeze({
124
+ ...input,
125
+ ...(input.turnId === undefined ? {} : { turnId: input.turnId }),
126
+ ...(input.reason === undefined ? {} : { reason: input.reason.slice(0, 512) }),
127
+ ...(input.coordinate === undefined ? {} : { coordinate: input.coordinate }),
128
+ createdAt,
129
+ expiresAt: createdAt + this.options.timeoutMs,
130
+ });
131
+ let resolveApproval = (_approved) => { };
132
+ const timer = setTimeout(() => {
133
+ this.resolve(request.id, false, "approval timed out");
134
+ }, this.options.timeoutMs);
135
+ timer.unref?.();
136
+ const pending = {
137
+ request,
138
+ resolve: (approved) => resolveApproval(approved),
139
+ timer,
140
+ };
141
+ this.pendingApprovals.set(request.id, pending);
142
+ await this.options.onRequired?.(request);
143
+ // A backend-observed request is resolved through `resolve`; a host request swaps this closure
144
+ // from the promise below before returning to the workflow.
145
+ resolveApproval = (_approved) => { };
146
+ return request;
147
+ }
148
+ }
149
+ export function approvalRequestFromEvent(event) {
150
+ return Object.freeze({
151
+ id: event.approvalId,
152
+ sessionId: event.sessionId,
153
+ turnId: event.turnId,
154
+ action: event.action,
155
+ capability: event.capability,
156
+ ...(event.reason === undefined ? {} : { reason: event.reason }),
157
+ createdAt: event.at,
158
+ expiresAt: event.at + 5 * 60_000,
159
+ });
160
+ }
161
+ export function approvalResolvedEvent(sessionId, seq, decision, turnId) {
162
+ return Object.freeze({
163
+ version: 1,
164
+ sessionId,
165
+ seq,
166
+ at: decision.at,
167
+ type: "approval.resolved",
168
+ ...(turnId === undefined ? {} : { turnId }),
169
+ approvalId: decision.approvalId,
170
+ approved: decision.approved,
171
+ ...(decision.reason === undefined ? {} : { reason: decision.reason }),
172
+ });
173
+ }
174
+ //# sourceMappingURL=approvals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approvals.js","sourceRoot":"","sources":["../src/approvals.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Small, backend-neutral capability manifest.
3
+ *
4
+ * The manifest is deliberately descriptive: an operator still decides which capabilities are
5
+ * trusted, and implementations remain free to enforce them with a sandbox, OS policy, or approval
6
+ * broker. Keeping this seam in the optional agent package avoids putting process/filesystem policy
7
+ * into Nifra's framework runtime.
8
+ */
9
+ export declare const AGENT_CAPABILITY_MANIFEST_VERSION: 1;
10
+ export type AgentCapability = "filesystem.read" | "filesystem.write" | "process.exec" | "network.request" | "credentials.read";
11
+ export interface AgentCapabilityManifest {
12
+ readonly version: typeof AGENT_CAPABILITY_MANIFEST_VERSION;
13
+ readonly requested: readonly AgentCapability[];
14
+ readonly trusted: readonly AgentCapability[];
15
+ readonly reason?: string;
16
+ }
17
+ export declare function createCapabilityManifest(requested: readonly AgentCapability[], trusted?: readonly AgentCapability[], reason?: string): AgentCapabilityManifest;
18
+ export declare function deniedCapabilities(manifest: AgentCapabilityManifest): readonly AgentCapability[];
19
+ export declare function parseCapabilityManifest(value: unknown): AgentCapabilityManifest;
20
+ //# sourceMappingURL=capabilities.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,eAAO,MAAM,iCAAiC,EAAG,CAAU,CAAA;AAE3D,MAAM,MAAM,eAAe,GACvB,iBAAiB,GACjB,kBAAkB,GAClB,cAAc,GACd,iBAAiB,GACjB,kBAAkB,CAAA;AAEtB,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,OAAO,EAAE,OAAO,iCAAiC,CAAA;IAC1D,QAAQ,CAAC,SAAS,EAAE,SAAS,eAAe,EAAE,CAAA;IAC9C,QAAQ,CAAC,OAAO,EAAE,SAAS,eAAe,EAAE,CAAA;IAC5C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,SAAS,eAAe,EAAE,EACrC,OAAO,GAAE,SAAS,eAAe,EAAO,EACxC,MAAM,CAAC,EAAE,MAAM,GACd,uBAAuB,CASzB;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,uBAAuB,GAAG,SAAS,eAAe,EAAE,CAGhG;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,uBAAuB,CAe/E"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Small, backend-neutral capability manifest.
3
+ *
4
+ * The manifest is deliberately descriptive: an operator still decides which capabilities are
5
+ * trusted, and implementations remain free to enforce them with a sandbox, OS policy, or approval
6
+ * broker. Keeping this seam in the optional agent package avoids putting process/filesystem policy
7
+ * into Nifra's framework runtime.
8
+ */
9
+ export const AGENT_CAPABILITY_MANIFEST_VERSION = 1;
10
+ export function createCapabilityManifest(requested, trusted = [], reason) {
11
+ const unique = (values) => Object.freeze([...new Set(values)]);
12
+ return Object.freeze({
13
+ version: AGENT_CAPABILITY_MANIFEST_VERSION,
14
+ requested: unique(requested),
15
+ trusted: unique(trusted),
16
+ ...(reason === undefined ? {} : { reason: reason.slice(0, 512) }),
17
+ });
18
+ }
19
+ export function deniedCapabilities(manifest) {
20
+ const trusted = new Set(manifest.trusted);
21
+ return Object.freeze(manifest.requested.filter((capability) => !trusted.has(capability)));
22
+ }
23
+ export function parseCapabilityManifest(value) {
24
+ if (value === null || typeof value !== "object" || Array.isArray(value))
25
+ throw new TypeError("capability manifest must be an object");
26
+ const record = value;
27
+ if (record.version !== AGENT_CAPABILITY_MANIFEST_VERSION)
28
+ throw new TypeError("unsupported capability manifest version");
29
+ const requested = parseCapabilities(record.requested, "requested");
30
+ const trusted = parseCapabilities(record.trusted, "trusted");
31
+ if (record.reason !== undefined && typeof record.reason !== "string")
32
+ throw new TypeError("capability manifest reason must be a string");
33
+ return createCapabilityManifest(requested, trusted, typeof record.reason === "string" ? record.reason : undefined);
34
+ }
35
+ function parseCapabilities(value, name) {
36
+ if (!Array.isArray(value))
37
+ throw new TypeError(`capability manifest ${name} must be an array`);
38
+ const allowed = new Set([
39
+ "filesystem.read",
40
+ "filesystem.write",
41
+ "process.exec",
42
+ "network.request",
43
+ "credentials.read",
44
+ ]);
45
+ if (value.some((item) => typeof item !== "string" || !allowed.has(item)))
46
+ throw new TypeError(`capability manifest ${name} contains an unknown capability`);
47
+ return value;
48
+ }
49
+ //# sourceMappingURL=capabilities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,iCAAiC,GAAG,CAAU,CAAA;AAgB3D,MAAM,UAAU,wBAAwB,CACtC,SAAqC,EACrC,UAAsC,EAAE,EACxC,MAAe;IAEf,MAAM,MAAM,GAAG,CAAC,MAAkC,EAA8B,EAAE,CAChF,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;IACrC,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,OAAO,EAAE,iCAAiC;QAC1C,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC;QAC5B,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC;QACxB,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;KAClE,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,QAAiC;IAClE,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;IACzC,OAAO,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA;AAC3F,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,KAAc;IACpD,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACrE,MAAM,IAAI,SAAS,CAAC,uCAAuC,CAAC,CAAA;IAC9D,MAAM,MAAM,GAAG,KAAgC,CAAA;IAC/C,IAAI,MAAM,CAAC,OAAO,KAAK,iCAAiC;QACtD,MAAM,IAAI,SAAS,CAAC,yCAAyC,CAAC,CAAA;IAChE,MAAM,SAAS,GAAG,iBAAiB,CAAC,MAAM,CAAC,SAAS,EAAE,WAAW,CAAC,CAAA;IAClE,MAAM,OAAO,GAAG,iBAAiB,CAAC,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;IAC5D,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,IAAI,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ;QAClE,MAAM,IAAI,SAAS,CAAC,6CAA6C,CAAC,CAAA;IACpE,OAAO,wBAAwB,CAC7B,SAAS,EACT,OAAO,EACP,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAC9D,CAAA;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAc,EAAE,IAAY;IACrD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,uBAAuB,IAAI,mBAAmB,CAAC,CAAA;IAC9F,MAAM,OAAO,GAAG,IAAI,GAAG,CAAkB;QACvC,iBAAiB;QACjB,kBAAkB;QAClB,cAAc;QACd,iBAAiB;QACjB,kBAAkB;KACnB,CAAC,CAAA;IACF,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAuB,CAAC,CAAC;QACzF,MAAM,IAAI,SAAS,CAAC,uBAAuB,IAAI,iCAAiC,CAAC,CAAA;IACnF,OAAO,KAA0B,CAAA;AACnC,CAAC"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env bun
2
+ export interface CliOptions {
3
+ readonly backend: string;
4
+ readonly cwd: string;
5
+ readonly once?: string;
6
+ readonly json: boolean;
7
+ readonly noSession: boolean;
8
+ readonly piCommand: string;
9
+ readonly replayFile?: string;
10
+ readonly sessionDir?: string;
11
+ readonly rpc: boolean;
12
+ readonly host: string;
13
+ readonly port: number;
14
+ readonly authToken?: string;
15
+ readonly exposeErrorStacks: boolean;
16
+ readonly sessionId?: string;
17
+ readonly migrateSession?: string;
18
+ readonly migrationSource?: string;
19
+ readonly migrationTarget?: string;
20
+ readonly verifyAfterTurn: readonly ("check" | "assure" | "test")[];
21
+ readonly maxRepairAttempts: number;
22
+ }
23
+ export declare function parseArgs(args: readonly string[]): CliOptions;
24
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AA8CA,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAA;IACnC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAA;IAChC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,eAAe,EAAE,SAAS,CAAC,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC,EAAE,CAAA;IAClE,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAA;CACnC;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,CA2F7D"}