@cruxy/cli 1.0.3 → 1.0.5
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/package.json +2 -2
- package/dist/agent/budget.d.ts +0 -52
- package/dist/agent/index.d.ts +0 -3
- package/dist/agent/loop.d.ts +0 -159
- package/dist/agent/prompts.d.ts +0 -69
- package/dist/agent/session.d.ts +0 -212
- package/dist/approval/classify.d.ts +0 -18
- package/dist/approval/index.d.ts +0 -6
- package/dist/approval/mutex.d.ts +0 -45
- package/dist/approval/policy.d.ts +0 -43
- package/dist/approval/prompt.d.ts +0 -48
- package/dist/approval/service.d.ts +0 -36
- package/dist/approval/types.d.ts +0 -82
- package/dist/brand/index.d.ts +0 -1
- package/dist/brand/voice.d.ts +0 -94
- package/dist/checkpoint/capture.d.ts +0 -17
- package/dist/checkpoint/gate-hook.d.ts +0 -28
- package/dist/checkpoint/gate.d.ts +0 -71
- package/dist/checkpoint/git-store.d.ts +0 -61
- package/dist/checkpoint/index.d.ts +0 -10
- package/dist/checkpoint/restore.d.ts +0 -23
- package/dist/checkpoint/service.d.ts +0 -89
- package/dist/checkpoint/set-rollback.d.ts +0 -51
- package/dist/checkpoint/set.d.ts +0 -44
- package/dist/checkpoint/shadow-store.d.ts +0 -23
- package/dist/checkpoint/types.d.ts +0 -164
- package/dist/cli/commands/checkpoint.d.ts +0 -7
- package/dist/cli/commands/config.d.ts +0 -2
- package/dist/cli/commands/hooks.d.ts +0 -8
- package/dist/cli/commands/index.d.ts +0 -7
- package/dist/cli/commands/init.d.ts +0 -7
- package/dist/cli/commands/login.d.ts +0 -8
- package/dist/cli/commands/mcp.d.ts +0 -9
- package/dist/cli/commands/memory.d.ts +0 -8
- package/dist/cli/commands/pr.d.ts +0 -8
- package/dist/cli/commands/rollback.d.ts +0 -18
- package/dist/cli/commands/run.d.ts +0 -2
- package/dist/cli/commands/skills.d.ts +0 -8
- package/dist/cli/commands/test.d.ts +0 -9
- package/dist/cli/commands/usage.d.ts +0 -9
- package/dist/cli/onboard.d.ts +0 -25
- package/dist/cli/program.d.ts +0 -2
- package/dist/cli/repl.d.ts +0 -27
- package/dist/cli/session-factory.d.ts +0 -42
- package/dist/cli/stream-print.d.ts +0 -14
- package/dist/components/autocomplete.d.ts +0 -32
- package/dist/components/frame.d.ts +0 -28
- package/dist/components/fuzzy.d.ts +0 -61
- package/dist/components/index.d.ts +0 -6
- package/dist/components/input.d.ts +0 -78
- package/dist/components/keys.d.ts +0 -48
- package/dist/components/select.d.ts +0 -28
- package/dist/config/credentials.d.ts +0 -18
- package/dist/config/index.d.ts +0 -5
- package/dist/config/manager.d.ts +0 -39
- package/dist/config/owner-only.d.ts +0 -19
- package/dist/config/paths.d.ts +0 -9
- package/dist/config/project.d.ts +0 -10
- package/dist/config/schema.d.ts +0 -2143
- package/dist/constants.d.ts +0 -65
- package/dist/errors/boundary.d.ts +0 -43
- package/dist/errors/constructors.d.ts +0 -411
- package/dist/errors/format.d.ts +0 -31
- package/dist/errors/index.d.ts +0 -4
- package/dist/errors/types.d.ts +0 -270
- package/dist/hooks/config.d.ts +0 -21
- package/dist/hooks/index.d.ts +0 -7
- package/dist/hooks/router.d.ts +0 -58
- package/dist/hooks/runner.d.ts +0 -88
- package/dist/hooks/service.d.ts +0 -38
- package/dist/hooks/slash.d.ts +0 -48
- package/dist/hooks/trust.d.ts +0 -46
- package/dist/hooks/types.d.ts +0 -147
- package/dist/index.d.ts +0 -2
- package/dist/indexing/chunker.d.ts +0 -28
- package/dist/indexing/embedder.d.ts +0 -98
- package/dist/indexing/index.d.ts +0 -9
- package/dist/indexing/indexer.d.ts +0 -45
- package/dist/indexing/retriever.d.ts +0 -61
- package/dist/indexing/service.d.ts +0 -49
- package/dist/indexing/store.d.ts +0 -103
- package/dist/indexing/types.d.ts +0 -78
- package/dist/indexing/util.d.ts +0 -34
- package/dist/indexing/walker.d.ts +0 -53
- package/dist/jobs/approval-queue.d.ts +0 -85
- package/dist/jobs/dispatch-tool.d.ts +0 -34
- package/dist/jobs/index.d.ts +0 -6
- package/dist/jobs/log-buffer.d.ts +0 -31
- package/dist/jobs/log-renderer.d.ts +0 -32
- package/dist/jobs/manager.d.ts +0 -139
- package/dist/jobs/types.d.ts +0 -81
- package/dist/lsp/client.d.ts +0 -25
- package/dist/lsp/index.d.ts +0 -8
- package/dist/lsp/pool.d.ts +0 -48
- package/dist/lsp/registry.d.ts +0 -38
- package/dist/lsp/server.d.ts +0 -48
- package/dist/lsp/service.d.ts +0 -44
- package/dist/lsp/tools/common.d.ts +0 -50
- package/dist/lsp/tools/find-definition.d.ts +0 -23
- package/dist/lsp/tools/find-references.d.ts +0 -23
- package/dist/lsp/tools/get-diagnostics.d.ts +0 -17
- package/dist/lsp/tools/hover.d.ts +0 -23
- package/dist/lsp/tools/index.d.ts +0 -4
- package/dist/lsp/transport.d.ts +0 -39
- package/dist/lsp/types.d.ts +0 -107
- package/dist/mcp/adapter.d.ts +0 -44
- package/dist/mcp/bounds.d.ts +0 -35
- package/dist/mcp/client.d.ts +0 -19
- package/dist/mcp/demarcate.d.ts +0 -12
- package/dist/mcp/http-transport.d.ts +0 -89
- package/dist/mcp/index.d.ts +0 -12
- package/dist/mcp/service.d.ts +0 -71
- package/dist/mcp/sibling-banner.d.ts +0 -25
- package/dist/mcp/transport.d.ts +0 -30
- package/dist/mcp/trust-gate.d.ts +0 -59
- package/dist/mcp/trust.d.ts +0 -62
- package/dist/mcp/types.d.ts +0 -62
- package/dist/mcp/url-guard.d.ts +0 -48
- package/dist/memory/index.d.ts +0 -7
- package/dist/memory/recall.d.ts +0 -56
- package/dist/memory/remember-tool.d.ts +0 -28
- package/dist/memory/secrets.d.ts +0 -29
- package/dist/memory/service.d.ts +0 -92
- package/dist/memory/store.d.ts +0 -32
- package/dist/memory/trust.d.ts +0 -52
- package/dist/memory/types.d.ts +0 -101
- package/dist/net/ip-guard.d.ts +0 -55
- package/dist/onboarding/detect.d.ts +0 -26
- package/dist/onboarding/flow.d.ts +0 -28
- package/dist/onboarding/index.d.ts +0 -5
- package/dist/onboarding/io.d.ts +0 -9
- package/dist/onboarding/steps.d.ts +0 -17
- package/dist/onboarding/types.d.ts +0 -81
- package/dist/plan/approve.d.ts +0 -16
- package/dist/plan/execute.d.ts +0 -28
- package/dist/plan/index.d.ts +0 -7
- package/dist/plan/policy.d.ts +0 -26
- package/dist/plan/render.d.ts +0 -5
- package/dist/plan/service.d.ts +0 -58
- package/dist/plan/submit-plan.d.ts +0 -33
- package/dist/plan/types.d.ts +0 -60
- package/dist/render/capabilities.d.ts +0 -31
- package/dist/render/diff.d.ts +0 -18
- package/dist/render/highlight.d.ts +0 -47
- package/dist/render/index.d.ts +0 -22
- package/dist/render/layout.d.ts +0 -59
- package/dist/render/motion.d.ts +0 -76
- package/dist/render/plain-renderer.d.ts +0 -39
- package/dist/render/resize.d.ts +0 -36
- package/dist/render/screen-reader-renderer.d.ts +0 -45
- package/dist/render/state.d.ts +0 -49
- package/dist/render/tty-renderer.d.ts +0 -106
- package/dist/render/types.d.ts +0 -201
- package/dist/routing/index.d.ts +0 -2
- package/dist/routing/resolve.d.ts +0 -17
- package/dist/routing/router.d.ts +0 -47
- package/dist/routing/types.d.ts +0 -42
- package/dist/sandbox/detect.d.ts +0 -22
- package/dist/sandbox/docker-runtime.d.ts +0 -32
- package/dist/sandbox/index.d.ts +0 -7
- package/dist/sandbox/policy.d.ts +0 -26
- package/dist/sandbox/service.d.ts +0 -64
- package/dist/sandbox/types.d.ts +0 -123
- package/dist/skills/index.d.ts +0 -4
- package/dist/skills/loader.d.ts +0 -43
- package/dist/skills/parser.d.ts +0 -31
- package/dist/skills/service.d.ts +0 -41
- package/dist/skills/types.d.ts +0 -94
- package/dist/subagent/index.d.ts +0 -5
- package/dist/subagent/orchestrator.d.ts +0 -169
- package/dist/subagent/registry-scope.d.ts +0 -41
- package/dist/subagent/semaphore.d.ts +0 -56
- package/dist/subagent/spawn-tool.d.ts +0 -86
- package/dist/subagent/types.d.ts +0 -65
- package/dist/testing/detect.d.ts +0 -3
- package/dist/testing/index.d.ts +0 -5
- package/dist/testing/parse.d.ts +0 -33
- package/dist/testing/run-tests-tool.d.ts +0 -64
- package/dist/testing/runner.d.ts +0 -26
- package/dist/testing/sandbox-runner.d.ts +0 -16
- package/dist/testing/types.d.ts +0 -66
- package/dist/theme/index.d.ts +0 -2
- package/dist/theme/resolve.d.ts +0 -43
- package/dist/theme/tokens.d.ts +0 -125
- package/dist/tools/create-pull-request.d.ts +0 -27
- package/dist/tools/file/apply-patch.d.ts +0 -94
- package/dist/tools/file/edit-file.d.ts +0 -12
- package/dist/tools/file/glob.d.ts +0 -17
- package/dist/tools/file/grep-files.d.ts +0 -43
- package/dist/tools/file/index.d.ts +0 -7
- package/dist/tools/file/match.d.ts +0 -43
- package/dist/tools/file/paths.d.ts +0 -160
- package/dist/tools/file/read-file.d.ts +0 -8
- package/dist/tools/file/write-file.d.ts +0 -10
- package/dist/tools/git-status.d.ts +0 -15
- package/dist/tools/index.d.ts +0 -9
- package/dist/tools/list-files.d.ts +0 -13
- package/dist/tools/list-skills.d.ts +0 -9
- package/dist/tools/load-skill.d.ts +0 -21
- package/dist/tools/registry.d.ts +0 -23
- package/dist/tools/search-codebase.d.ts +0 -35
- package/dist/tools/shell/exec.d.ts +0 -53
- package/dist/tools/shell/index.d.ts +0 -1
- package/dist/tools/shell/resolve-shell.d.ts +0 -81
- package/dist/tools/shell/run-command.d.ts +0 -14
- package/dist/tools/types.d.ts +0 -257
- package/dist/usage/collect.d.ts +0 -53
- package/dist/usage/cost.d.ts +0 -19
- package/dist/usage/index.d.ts +0 -15
- package/dist/usage/store.d.ts +0 -37
- package/dist/usage/summary.d.ts +0 -32
- package/dist/usage/types.d.ts +0 -283
- package/dist/utils/child-tree.d.ts +0 -33
- package/dist/utils/git.d.ts +0 -17
- package/dist/utils/logger.d.ts +0 -18
- package/dist/utils/process-tree.d.ts +0 -16
- package/dist/vcs/auth.d.ts +0 -22
- package/dist/vcs/generate.d.ts +0 -74
- package/dist/vcs/git.d.ts +0 -60
- package/dist/vcs/github.d.ts +0 -50
- package/dist/vcs/guidance.d.ts +0 -20
- package/dist/vcs/index.d.ts +0 -7
- package/dist/vcs/service.d.ts +0 -61
- package/dist/vcs/types.d.ts +0 -73
- package/dist/web/demarcate.d.ts +0 -13
- package/dist/web/fetch.d.ts +0 -11
- package/dist/web/index.d.ts +0 -7
- package/dist/web/provider.d.ts +0 -29
- package/dist/web/search.d.ts +0 -17
- package/dist/web/ssrf.d.ts +0 -41
- package/dist/web/tools.d.ts +0 -20
- package/dist/web/types.d.ts +0 -64
- package/dist/workspace/add-root.d.ts +0 -27
- package/dist/workspace/index.d.ts +0 -6
- package/dist/workspace/resolve.d.ts +0 -54
- package/dist/workspace/select.d.ts +0 -41
- package/dist/workspace/types.d.ts +0 -30
- package/dist/workspace/workspace.d.ts +0 -61
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cruxy/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "an agentic coding CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"undici": "^6.21.0",
|
|
37
37
|
"zod": "^3.23.8",
|
|
38
38
|
"zod-to-json-schema": "^3.23.5",
|
|
39
|
-
"@cruxy/sdk": "0.2.
|
|
39
|
+
"@cruxy/sdk": "0.2.2"
|
|
40
40
|
},
|
|
41
41
|
"optionalDependencies": {
|
|
42
42
|
"better-sqlite3": "^12.11.1"
|
package/dist/agent/budget.d.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import type { Usage } from "@cruxy/sdk";
|
|
2
|
-
import type { LoopBudget } from "./loop.js";
|
|
3
|
-
/**
|
|
4
|
-
* The live budget primitive for the agent loop: iteration + token + optional
|
|
5
|
-
* wall-clock caps, checked by {@link runAgent} before every model turn (see
|
|
6
|
-
* `LoopBudget`). A tripped cap stops the run with a human-readable reason and
|
|
7
|
-
* the coherent partial history — the loop never runs unbounded.
|
|
8
|
-
*
|
|
9
|
-
* It lives beside the loop it guards: the loop defines the `LoopBudget` seam,
|
|
10
|
-
* this is its one concrete implementation, and the subagent orchestrator, the
|
|
11
|
-
* job manager, and {@link Session} (per-turn token guard) all consume it.
|
|
12
|
-
*/
|
|
13
|
-
/**
|
|
14
|
-
* Hard caps a run executes under. `maxTokens` is always finite; `maxIterations`
|
|
15
|
-
* is finite for a subagent (bounded by construction) but may be
|
|
16
|
-
* `Number.POSITIVE_INFINITY` for a token-only guard where iteration count is
|
|
17
|
-
* bounded elsewhere (a main turn is already capped by `agent.maxIterations` in
|
|
18
|
-
* the loop). `timeoutMs` is an optional wall-clock backstop on top.
|
|
19
|
-
*/
|
|
20
|
-
export interface BudgetLimits {
|
|
21
|
-
/** Cap on the run's model turns (may be `Infinity` for a token-only guard). */
|
|
22
|
-
maxIterations: number;
|
|
23
|
-
/** Cap on the run's combined input+output tokens. */
|
|
24
|
-
maxTokens: number;
|
|
25
|
-
/** Optional wall-clock cap in milliseconds. */
|
|
26
|
-
timeoutMs?: number;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Resolve the effective limits for one spawn: start from the configured
|
|
30
|
-
* ceilings and let overrides only *narrow* them. A request above a ceiling is
|
|
31
|
-
* clamped down, not honored — "budget overrides within limits" by construction.
|
|
32
|
-
*/
|
|
33
|
-
export declare function resolveBudget(defaults: BudgetLimits, overrides?: Partial<BudgetLimits>): BudgetLimits;
|
|
34
|
-
/**
|
|
35
|
-
* A live budget for one run. The wall clock starts at construction (spawn /
|
|
36
|
-
* turn start); the clock source is injectable so tests never sleep.
|
|
37
|
-
*/
|
|
38
|
-
export declare class Budget implements LoopBudget {
|
|
39
|
-
private readonly limits;
|
|
40
|
-
private readonly now;
|
|
41
|
-
private readonly startedAt;
|
|
42
|
-
constructor(limits: BudgetLimits, now?: () => number);
|
|
43
|
-
/**
|
|
44
|
-
* The reason to stop before the next model turn, or `null` to continue.
|
|
45
|
-
* Checked at iteration boundaries — the in-flight turn always completes, so
|
|
46
|
-
* overshoot is bounded by one turn.
|
|
47
|
-
*/
|
|
48
|
-
exceeded(state: {
|
|
49
|
-
iterations: number;
|
|
50
|
-
usage: Usage;
|
|
51
|
-
}): string | null;
|
|
52
|
-
}
|
package/dist/agent/index.d.ts
DELETED
package/dist/agent/loop.d.ts
DELETED
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
import type { Message, Provider, Usage } from "@cruxy/sdk";
|
|
2
|
-
import type { CruxyConfig } from "../config/index.js";
|
|
3
|
-
import type { HookEvent } from "../hooks/index.js";
|
|
4
|
-
import type { StreamRenderer } from "../render/index.js";
|
|
5
|
-
import { type Router, type TaskClass } from "../routing/index.js";
|
|
6
|
-
import type { ToolContext } from "../tools/index.js";
|
|
7
|
-
import { ToolRegistry } from "../tools/index.js";
|
|
8
|
-
/** Optional per-fire context (C.26 step 5). For tool-scoped events the loop
|
|
9
|
-
* passes the raw tool-call `input` so a multi-root {@link HookRouter} can resolve
|
|
10
|
-
* the ONE acting root and fire only that root's hooks. Session lifecycle events
|
|
11
|
-
* (`before-run`/`after-run`) carry no hint — they have no acting root and fan
|
|
12
|
-
* every trusted root. Ignored by the single-root runner. */
|
|
13
|
-
export interface HookFireHint {
|
|
14
|
-
input?: unknown;
|
|
15
|
-
}
|
|
16
|
-
/** The lifecycle-hook firing seam (C.19). Structural so the loop stays
|
|
17
|
-
* decoupled from the concrete `HookRunner`. `fire` resolves when hooks pass (or
|
|
18
|
-
* advisory ones fail) and throws `CRUXY_E_HOOK_FAILED` on a blocking failure. */
|
|
19
|
-
export interface LifecycleHookRunner {
|
|
20
|
-
fire(event: HookEvent, ctx: ToolContext, hint?: HookFireHint): Promise<void>;
|
|
21
|
-
}
|
|
22
|
-
export interface RunAgentArgs {
|
|
23
|
-
/**
|
|
24
|
-
* The full running conversation. The caller owns history and must append the
|
|
25
|
-
* user turn before calling; `runAgent` does not fabricate the initial array.
|
|
26
|
-
*/
|
|
27
|
-
messages: Message[];
|
|
28
|
-
/** A constructed provider to stream from. */
|
|
29
|
-
provider: Provider;
|
|
30
|
-
/** The tool catalogue advertised to the model and dispatched against. */
|
|
31
|
-
registry: ToolRegistry;
|
|
32
|
-
/** Resolved CLI configuration (turn ceiling, etc.). */
|
|
33
|
-
config: CruxyConfig;
|
|
34
|
-
/** Ambient capabilities handed to each tool. */
|
|
35
|
-
ctx: ToolContext;
|
|
36
|
-
/**
|
|
37
|
-
* The render seam (U.2): assistant text streams through `renderer.write`
|
|
38
|
-
* delta by delta (each non-empty segment closed via `endSegment`), and
|
|
39
|
-
* tool-call progress is surfaced as transient `status` + committed `note`
|
|
40
|
-
* lines. When omitted, behavior is unchanged (one buffered print per turn,
|
|
41
|
-
* no tool-call chrome). The loop never touches stdout directly.
|
|
42
|
-
*/
|
|
43
|
-
renderer?: StreamRenderer;
|
|
44
|
-
/** Git context (branch + dirty) for the system prompt's Environment section. */
|
|
45
|
-
git?: {
|
|
46
|
-
branch: string;
|
|
47
|
-
dirty: boolean;
|
|
48
|
-
} | null;
|
|
49
|
-
/** Project instructions (e.g. from CRUXY.md) folded into the system prompt. */
|
|
50
|
-
projectInstructions?: string | null;
|
|
51
|
-
/** Persistent memory (C.29): the pre-rendered recall block for the system
|
|
52
|
-
* prompt, or null. Reference data only — never influences the U.3 gate. */
|
|
53
|
-
recalledMemory?: string | null;
|
|
54
|
-
/** Plan mode's propose phase (C.31): inject the plan-first system directive. */
|
|
55
|
-
planMode?: boolean;
|
|
56
|
-
/** Subagent runs (C.14): inject the bounded-subtask system directive. */
|
|
57
|
-
subagent?: boolean;
|
|
58
|
-
/**
|
|
59
|
-
* Optional hard budget (C.14): checked before every model turn; a non-null
|
|
60
|
-
* reason stops the loop with `stop: "budget"` and the partial history. The
|
|
61
|
-
* in-flight turn (model call + its tool executions) always completes, so
|
|
62
|
-
* histories stay coherent — overshoot is bounded by one turn.
|
|
63
|
-
*/
|
|
64
|
-
budget?: LoopBudget;
|
|
65
|
-
/**
|
|
66
|
-
* Lifecycle hooks (C.19). When set, `before-tool` fires before each tool call
|
|
67
|
-
* (a blocking failure fails the call closed — the tool does NOT run), and
|
|
68
|
-
* `after-tool` / `on-file-change` fire after. Omitted for subagents and the
|
|
69
|
-
* no-hooks path, so their tools never fire hooks.
|
|
70
|
-
*/
|
|
71
|
-
hooks?: LifecycleHookRunner;
|
|
72
|
-
/**
|
|
73
|
-
* Multi-model routing (C.30): when set, the tier for `taskClass` is resolved
|
|
74
|
-
* ONCE up front (fail loud before any model turn) and its wire model overrides
|
|
75
|
-
* the provider default for every turn in this run; the tier is surfaced on the
|
|
76
|
-
* live line. Omitted → no override, the provider's default model is used
|
|
77
|
-
* (unchanged behavior).
|
|
78
|
-
*/
|
|
79
|
-
router?: Router;
|
|
80
|
-
/** The declared task class for routing; defaults to `main-turn`. Ignored
|
|
81
|
-
* unless `router` is set. */
|
|
82
|
-
taskClass?: TaskClass;
|
|
83
|
-
/**
|
|
84
|
-
* Usage telemetry (C.22): fired ONCE per completed model request with the
|
|
85
|
-
* routing tier (C.30) and the provider's usage for THAT request — or
|
|
86
|
-
* `usage: undefined` when the provider emitted no usage event, so the caller
|
|
87
|
-
* records it as unknown (never a fabricated zero). LOCAL accounting only:
|
|
88
|
-
* this is a callback into the process, nothing is transmitted. Omitted → no
|
|
89
|
-
* collection, behavior unchanged.
|
|
90
|
-
*/
|
|
91
|
-
onRequestUsage?: (req: {
|
|
92
|
-
tier?: string;
|
|
93
|
-
usage?: Usage;
|
|
94
|
-
}) => void;
|
|
95
|
-
/**
|
|
96
|
-
* Cooperative cancellation (C.33). When the signal aborts, the loop stops at
|
|
97
|
-
* the NEXT turn boundary and returns `stop: "aborted"` with the coherent
|
|
98
|
-
* partial history — the in-flight turn (model call + its tool executions)
|
|
99
|
-
* always completes first, exactly like a tripped {@link budget}, so overshoot
|
|
100
|
-
* is bounded by one turn. Used by the parallel orchestrator to cancel sibling
|
|
101
|
-
* subagents on a fatal failure or Ctrl-C; omitted → no cancellation (unchanged).
|
|
102
|
-
* The same signal reaches tools via `ctx.signal`, so an in-flight shell child
|
|
103
|
-
* is kill-tree'd rather than orphaned.
|
|
104
|
-
*/
|
|
105
|
-
signal?: AbortSignal;
|
|
106
|
-
/**
|
|
107
|
-
* Mid-loop compaction seam (build item 3). Called at the top of every
|
|
108
|
-
* iteration with the running history; returns the history to continue from —
|
|
109
|
-
* unchanged when under threshold, or with its older prefix summarized away
|
|
110
|
-
* when over. Supplied by {@link Session}, which reuses its own
|
|
111
|
-
* threshold/cut/summarize machinery, so the loop gains no summarization
|
|
112
|
-
* knowledge and no logic is duplicated. Omitted → history is never compacted
|
|
113
|
-
* mid-loop (unchanged behavior; subagents pass nothing).
|
|
114
|
-
*
|
|
115
|
-
* This is what keeps a long autonomous turn — where `send` compacts only once
|
|
116
|
-
* up front and never again — within the context window: without it a run that
|
|
117
|
-
* drives dozens of tool calls (each result appended, some tens of KB) grows
|
|
118
|
-
* unbounded until the next `send`, which in one-shot never comes.
|
|
119
|
-
*/
|
|
120
|
-
compact?: (messages: Message[]) => Promise<Message[]>;
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* The budget seam for {@link runAgent}: implementations track their own caps
|
|
124
|
-
* (iterations, tokens, wall clock — see `subagent/budget.ts`); the loop only
|
|
125
|
-
* asks "may I start another turn?". Kept a one-method interface so future
|
|
126
|
-
* callers (C.22 cost tracking) can slot in without touching the loop again.
|
|
127
|
-
*/
|
|
128
|
-
export interface LoopBudget {
|
|
129
|
-
/**
|
|
130
|
-
* Return a human-readable reason to stop *before* the next model turn, or
|
|
131
|
-
* `null` to continue. `iterations` = model turns completed so far.
|
|
132
|
-
*/
|
|
133
|
-
exceeded(state: {
|
|
134
|
-
iterations: number;
|
|
135
|
-
usage: Usage;
|
|
136
|
-
}): string | null;
|
|
137
|
-
}
|
|
138
|
-
export interface AgentResult {
|
|
139
|
-
/** The full conversation, including assistant tool calls and tool results. */
|
|
140
|
-
messages: Message[];
|
|
141
|
-
/** Number of model turns consumed. */
|
|
142
|
-
iterations: number;
|
|
143
|
-
/** Why the loop ended. */
|
|
144
|
-
stop: "completed" | "max_iterations" | "budget" | "aborted";
|
|
145
|
-
/** Which cap tripped, when `stop === "budget"` (from {@link LoopBudget}). */
|
|
146
|
-
stopReason?: string;
|
|
147
|
-
/** Accumulated token usage (stashed for cost tracking in C.22). */
|
|
148
|
-
usage: Usage;
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Drive the model/tool loop over an existing conversation. Streams each turn,
|
|
152
|
-
* renders assistant text, reassembles tool calls, executes them, feeds the
|
|
153
|
-
* results back, and repeats until the model stops calling tools or the turn
|
|
154
|
-
* ceiling is hit.
|
|
155
|
-
*
|
|
156
|
-
* Requires a tool-capable provider — it throws up front otherwise rather than
|
|
157
|
-
* silently running tool-less.
|
|
158
|
-
*/
|
|
159
|
-
export declare function runAgent(args: RunAgentArgs): Promise<AgentResult>;
|
package/dist/agent/prompts.d.ts
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* cruxy-code agent prompts.
|
|
3
|
-
*
|
|
4
|
-
* These are ORIGINAL prompts written for cruxy — not copied from any other
|
|
5
|
-
* tool. The system prompt is assembled at runtime from a static core plus a
|
|
6
|
-
* dynamic environment block, so the model always knows where it is, what it
|
|
7
|
-
* can do, and how it's expected to behave.
|
|
8
|
-
*/
|
|
9
|
-
import type { ShellDialect } from "../tools/shell/resolve-shell.js";
|
|
10
|
-
export interface ToolSummary {
|
|
11
|
-
name: string;
|
|
12
|
-
}
|
|
13
|
-
export interface PromptContext {
|
|
14
|
-
/** Absolute working directory the agent is rooted in. */
|
|
15
|
-
cwd: string;
|
|
16
|
-
/** node `process.platform`, e.g. "linux", "darwin", "win32". */
|
|
17
|
-
platform: string;
|
|
18
|
-
/** Provider/model string, for the model's self-awareness. */
|
|
19
|
-
model: string;
|
|
20
|
-
/** Current ISO date (so the model isn't guessing). */
|
|
21
|
-
date: string;
|
|
22
|
-
/** Tools available this session (from the tool registry). */
|
|
23
|
-
tools: ToolSummary[];
|
|
24
|
-
/** Optional git context, when the cwd is a repo. */
|
|
25
|
-
git?: {
|
|
26
|
-
branch: string;
|
|
27
|
-
dirty: boolean;
|
|
28
|
-
} | null;
|
|
29
|
-
/** Optional extra instructions (e.g. from a project CRUXY.md). */
|
|
30
|
-
projectInstructions?: string | null;
|
|
31
|
-
/**
|
|
32
|
-
* Persistent memory (C.29): the pre-rendered, demarcated recall block injected
|
|
33
|
-
* at session start. It is REFERENCE DATA, not instructions — the block carries
|
|
34
|
-
* its own data-only framing (see memory/recall.ts) and is appended as an
|
|
35
|
-
* ordinary section; the U.3 gate never reads it. Null when nothing is recalled.
|
|
36
|
-
*/
|
|
37
|
-
recalledMemory?: string | null;
|
|
38
|
-
/** Plan mode's propose phase (C.31): inject the plan-first directive. */
|
|
39
|
-
planMode?: boolean;
|
|
40
|
-
/** Subagent run (C.14): inject the bounded-subtask directive. */
|
|
41
|
-
subagent?: boolean;
|
|
42
|
-
/**
|
|
43
|
-
* The resolved shell's command dialect (from resolve-shell.ts). When it is not
|
|
44
|
-
* a POSIX shell — e.g. PowerShell, because no Git Bash was found on Windows —
|
|
45
|
-
* a directive tells the model to emit that dialect instead of bash. Absent /
|
|
46
|
-
* "posix" → no directive (bash-isms are correct there; a nudge would be wrong).
|
|
47
|
-
*/
|
|
48
|
-
shellDialect?: ShellDialect;
|
|
49
|
-
}
|
|
50
|
-
/** Assemble the full system prompt for a session. */
|
|
51
|
-
export declare function buildSystemPrompt(ctx: PromptContext): string;
|
|
52
|
-
/**
|
|
53
|
-
* Compact reminder injected after tool results when the loop has run long, to
|
|
54
|
-
* keep the model anchored to the original objective and the verify step.
|
|
55
|
-
*/
|
|
56
|
-
export declare const PROGRESS_REMINDER = "Reminder: stay focused on the original task. Before declaring done, verify your change actually works (build/tests/lint), then summarize what changed.";
|
|
57
|
-
/**
|
|
58
|
-
* System prompt for the side conversation that compacts an over-long history
|
|
59
|
-
* (see Session.compact). It runs as a standalone, tool-less completion over a
|
|
60
|
-
* rendered transcript — the goal is a synopsis dense enough that the main loop
|
|
61
|
-
* can continue without the verbatim prefix.
|
|
62
|
-
*/
|
|
63
|
-
export declare const SUMMARY_SYSTEM = "You are compacting a coding assistant's conversation to fit within its context window. Summarize the conversation so far into a compact synopsis that preserves: decisions made and their rationale, concrete file paths and identifiers touched, the current state of the work, and any open or pending tasks. Be specific and terse \u2014 omit pleasantries and restated instructions. Output only the synopsis.";
|
|
64
|
-
/**
|
|
65
|
-
* Marker embedded in the synthetic messages that replace a compacted prefix, so
|
|
66
|
-
* they're recognizable in the history (and fold cleanly into a later
|
|
67
|
-
* re-summarization rather than being mistaken for live conversation).
|
|
68
|
-
*/
|
|
69
|
-
export declare const COMPACTION_MARKER = "[conversation compacted]";
|
package/dist/agent/session.d.ts
DELETED
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
import type { Message, Provider, Usage } from "@cruxy/sdk";
|
|
2
|
-
import type { CruxyConfig } from "../config/index.js";
|
|
3
|
-
import type { StreamRenderer } from "../render/index.js";
|
|
4
|
-
import { type Router } from "../routing/index.js";
|
|
5
|
-
import type { ToolContext } from "../tools/index.js";
|
|
6
|
-
import type { ToolRegistry } from "../tools/index.js";
|
|
7
|
-
import type { JobManager } from "../jobs/index.js";
|
|
8
|
-
import { type RequestUsage, type UsageRecord } from "../usage/index.js";
|
|
9
|
-
import { type AgentResult, type LifecycleHookRunner } from "./loop.js";
|
|
10
|
-
/**
|
|
11
|
-
* Plan-mode turn runner (C.31), injected so the agent package doesn't depend on
|
|
12
|
-
* the plan package. When plan mode is on, `send` delegates the whole turn to
|
|
13
|
-
* this instead of a single `runAgent` call. Receives the running history (with
|
|
14
|
-
* the user turn already appended) and returns the extended history to adopt.
|
|
15
|
-
*/
|
|
16
|
-
export type PlanRunner = (args: {
|
|
17
|
-
messages: Message[];
|
|
18
|
-
projectInstructions: string | null;
|
|
19
|
-
recalledMemory: string | null;
|
|
20
|
-
renderer?: StreamRenderer;
|
|
21
|
-
/** Usage telemetry (C.22): forwarded to every model request the plan-mode
|
|
22
|
-
* turn drives (propose + each execution step), so plan runs are attributed
|
|
23
|
-
* exactly like a normal turn. */
|
|
24
|
-
onRequestUsage?: (req: RequestUsage) => void;
|
|
25
|
-
}) => Promise<AgentResult>;
|
|
26
|
-
export interface SessionArgs {
|
|
27
|
-
/** A constructed provider to stream from. */
|
|
28
|
-
provider: Provider;
|
|
29
|
-
/** The tool catalogue advertised to the model and dispatched against. */
|
|
30
|
-
registry: ToolRegistry;
|
|
31
|
-
/** Resolved CLI configuration. */
|
|
32
|
-
config: CruxyConfig;
|
|
33
|
-
/** Ambient capabilities handed to each tool. */
|
|
34
|
-
ctx: ToolContext;
|
|
35
|
-
/** Git context (branch + dirty), loaded at startup, for the system prompt. */
|
|
36
|
-
git?: {
|
|
37
|
-
branch: string;
|
|
38
|
-
dirty: boolean;
|
|
39
|
-
} | null;
|
|
40
|
-
/** Project instructions (e.g. CRUXY.md) folded into every turn's system prompt. */
|
|
41
|
-
projectInstructions?: string | null;
|
|
42
|
-
/**
|
|
43
|
-
* Persistent memory (C.29): the pre-rendered recall block, injected into every
|
|
44
|
-
* turn's system prompt as reference data. Built once at session start (user
|
|
45
|
-
* memory + trusted project memory); null when memory is off or empty. Fixed
|
|
46
|
-
* for the session — it does not re-read mid-session.
|
|
47
|
-
*/
|
|
48
|
-
recalledMemory?: string | null;
|
|
49
|
-
/** Start in plan mode (C.31). Toggleable at runtime via `setPlanMode`. */
|
|
50
|
-
planMode?: boolean;
|
|
51
|
-
/** The plan-mode turn runner; required for plan mode to actually engage. */
|
|
52
|
-
planRunner?: PlanRunner;
|
|
53
|
-
/**
|
|
54
|
-
* Lifecycle hooks (C.19). When set, `before-run` fires before each turn (a
|
|
55
|
-
* blocking failure — including an untrusted project — aborts the turn) and
|
|
56
|
-
* `after-run` fires after; the same runner is threaded into the agent loop for
|
|
57
|
-
* `before-tool`/`after-tool`/`on-file-change`.
|
|
58
|
-
*/
|
|
59
|
-
hooks?: LifecycleHookRunner;
|
|
60
|
-
/**
|
|
61
|
-
* Multi-model routing (C.30). When set, main turns route on `main-turn` and
|
|
62
|
-
* context compaction on `summarize`; omitted → the provider default (unchanged).
|
|
63
|
-
*/
|
|
64
|
-
router?: Router;
|
|
65
|
-
/**
|
|
66
|
-
* Usage telemetry sink (C.22): called once per `send` with that run's
|
|
67
|
-
* {@link UsageRecord} (real per-request usage, tier-attributed). The sink
|
|
68
|
-
* persists it locally — it never transmits. Omitted → no persistence.
|
|
69
|
-
*/
|
|
70
|
-
onRunUsage?: (record: UsageRecord) => void;
|
|
71
|
-
/**
|
|
72
|
-
* Session-scoped background jobs (C.28): the manager the `run_in_background`
|
|
73
|
-
* tool dispatches onto. Exposed on the session so the REPL can service pending
|
|
74
|
-
* job approvals between turns and drive `/jobs`/`/logs`/`/cancel`, and so
|
|
75
|
-
* `cruxy run` can cancel every live job on session exit. Present only when
|
|
76
|
-
* `jobs.enabled`; omitted → no background jobs (unchanged behaviour).
|
|
77
|
-
*/
|
|
78
|
-
jobs?: JobManager;
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Estimate the token footprint of a message list with a cheap chars/4 heuristic
|
|
82
|
-
* — no tokenizer dependency. Good enough to decide *when* to compact; exact
|
|
83
|
-
* counts are deferred to a later phase. Counts only textual payload (block
|
|
84
|
-
* structure and role labels are negligible and ignored).
|
|
85
|
-
*/
|
|
86
|
-
export declare function estimateTokens(messages: Message[]): number;
|
|
87
|
-
/**
|
|
88
|
-
* Owns the state of one multi-turn conversation: the running message history and
|
|
89
|
-
* the usage accumulated across turns. Each `send` continues from the prior
|
|
90
|
-
* history (tool_use/tool_result blocks included) rather than starting cold.
|
|
91
|
-
*
|
|
92
|
-
* This is also the home for context compaction: before each turn the running
|
|
93
|
-
* history is measured and, if it crosses the configured threshold, its older
|
|
94
|
-
* prefix is summarized away so the conversation stays within the model's window.
|
|
95
|
-
* The system prompt lives in `runAgent`, never in `messages`, so compaction
|
|
96
|
-
* cannot touch it.
|
|
97
|
-
*/
|
|
98
|
-
export declare class Session {
|
|
99
|
-
/** The full running conversation, replaced with the extended history each turn. */
|
|
100
|
-
messages: Message[];
|
|
101
|
-
/** Token usage summed across every `send` (and every compaction) in this session. */
|
|
102
|
-
readonly usage: Usage;
|
|
103
|
-
/** Stable id for this session (C.22), so a run's usage record groups with the
|
|
104
|
-
* other runs of the same interactive session (`cruxy usage --session`). */
|
|
105
|
-
readonly sessionId: string;
|
|
106
|
-
/** The most recent run's usage record (C.22) — the one-shot path reads it to
|
|
107
|
-
* print the end-of-run summary. */
|
|
108
|
-
lastRun?: UsageRecord;
|
|
109
|
-
private readonly args;
|
|
110
|
-
/** Mutable so `/reload` can refresh CRUXY.md mid-session. */
|
|
111
|
-
private projectInstructions;
|
|
112
|
-
/** Mutable so `/plan` can toggle plan mode mid-session. */
|
|
113
|
-
private planMode;
|
|
114
|
-
constructor(args: SessionArgs);
|
|
115
|
-
/** The ambient tool capabilities (gate + sandbox + cwd/config). Exposed so a
|
|
116
|
-
* shell-bound custom slash command (C.19) runs through the SAME gated path. */
|
|
117
|
-
get toolContext(): ToolContext;
|
|
118
|
-
/** The background-job manager (C.28), or undefined when jobs are disabled.
|
|
119
|
-
* The REPL uses it to service paused-job approvals and drive `/jobs`; `cruxy
|
|
120
|
-
* run` uses it to cancel every live job on exit. */
|
|
121
|
-
get jobs(): JobManager | undefined;
|
|
122
|
-
/** Whether plan mode is currently on. */
|
|
123
|
-
getPlanMode(): boolean;
|
|
124
|
-
/**
|
|
125
|
-
* Toggle plan mode. Only takes effect when a `planRunner` was wired (built by
|
|
126
|
-
* the session factory); without one, plan mode stays off.
|
|
127
|
-
*/
|
|
128
|
-
setPlanMode(enabled: boolean): void;
|
|
129
|
-
/**
|
|
130
|
-
* Run one user turn: append the prompt, compact if the history has grown past
|
|
131
|
-
* the threshold, drive the agent loop over the full history, adopt the
|
|
132
|
-
* extended history, and accumulate usage. Returns the turn's `AgentResult`.
|
|
133
|
-
*
|
|
134
|
-
* `renderer`, when supplied, receives assistant text deltas and tool-call
|
|
135
|
-
* progress as they stream so the caller sees the turn live (see the REPL);
|
|
136
|
-
* history is unaffected.
|
|
137
|
-
*/
|
|
138
|
-
send(userPrompt: string, renderer?: StreamRenderer): Promise<AgentResult>;
|
|
139
|
-
/**
|
|
140
|
-
* Re-read project instructions (CRUXY.md / AGENTS.md) from the working
|
|
141
|
-
* directory so edits take effect without restarting. Returns the new text, or
|
|
142
|
-
* `null` if none is present. Backs the `/reload` command.
|
|
143
|
-
*/
|
|
144
|
-
reloadProjectInstructions(): string | null;
|
|
145
|
-
/** Drop the conversation history but keep the session (for `/clear`). */
|
|
146
|
-
clear(): void;
|
|
147
|
-
/**
|
|
148
|
-
* Compact `this.messages` only when it has grown past threshold, adopting the
|
|
149
|
-
* result. On success logs a one-line notice and returns the number of older
|
|
150
|
-
* messages folded into the summary; otherwise returns `null` (under threshold,
|
|
151
|
-
* nothing safe to cut, or summary failed).
|
|
152
|
-
*/
|
|
153
|
-
maybeCompact(onRequestUsage?: (req: RequestUsage) => void): Promise<number | null>;
|
|
154
|
-
/**
|
|
155
|
-
* The mid-loop compaction seam (build item 3) handed to {@link runAgent}: same
|
|
156
|
-
* threshold/cut/summarize path as {@link maybeCompact}, but over the loop's own
|
|
157
|
-
* running history rather than `this.messages` (the loop owns and adopts its
|
|
158
|
-
* copy). Reuses the exact machinery so no summarization logic is duplicated and
|
|
159
|
-
* the loop stays ignorant of it. Under threshold it returns the history
|
|
160
|
-
* unchanged — cheap, no model call.
|
|
161
|
-
*/
|
|
162
|
-
private compactLoopHistory;
|
|
163
|
-
/**
|
|
164
|
-
* Force compaction regardless of the threshold (backs `/compact`). Returns the
|
|
165
|
-
* number of older messages summarized, or `null` if there was nothing safe to
|
|
166
|
-
* cut or the summary call failed.
|
|
167
|
-
*/
|
|
168
|
-
compact(): Promise<number | null>;
|
|
169
|
-
/**
|
|
170
|
-
* Compact `messages` when its estimated footprint exceeds
|
|
171
|
-
* `compactThreshold * maxTokens`, else return it untouched. The estimate adds a
|
|
172
|
-
* fixed `reserveTokens` allowance for the system prompt and tool schemas that
|
|
173
|
-
* {@link estimateTokens} never sees (~4.5k+ tokens of real request payload), so
|
|
174
|
-
* the trigger reflects the actual request size rather than only the visible
|
|
175
|
-
* history — otherwise the loop can sit just under the visible threshold while
|
|
176
|
-
* the real request has already overrun the window. Logs a one-line notice on a
|
|
177
|
-
* successful compaction.
|
|
178
|
-
*/
|
|
179
|
-
private compactIfOverThreshold;
|
|
180
|
-
/**
|
|
181
|
-
* Find a clean cut, summarize the older prefix into a synthetic user/assistant
|
|
182
|
-
* pair, and splice it in front of the kept-recent messages. Best-effort: a
|
|
183
|
-
* failed summary call leaves the history untouched and reports `compacted:
|
|
184
|
-
* null` (fail open — losing compaction is degraded, not unsafe). Pure with
|
|
185
|
-
* respect to `this.messages`: it returns the new array for the caller to adopt
|
|
186
|
-
* (the loop and the session each own their own history), and only accumulates
|
|
187
|
-
* the summary's usage into the session total.
|
|
188
|
-
*/
|
|
189
|
-
private runCompaction;
|
|
190
|
-
/**
|
|
191
|
-
* Choose the boundary between the summarized prefix and the kept-recent tail.
|
|
192
|
-
*
|
|
193
|
-
* Tool-call integrity is the constraint: a `tool_use` (assistant) and its
|
|
194
|
-
* matching `tool_result` (the next user message) must never straddle the cut,
|
|
195
|
-
* or the next provider call breaks. A real user *prompt* (`role:"user"` with
|
|
196
|
-
* string content) only occurs at a completed turn boundary, where every prior
|
|
197
|
-
* tool exchange is already resolved — so the kept region must begin there. The
|
|
198
|
-
* synthetic compaction-summary user message is also string content, so a
|
|
199
|
-
* repeat compaction always finds at least the previous summary as a clean cut.
|
|
200
|
-
*
|
|
201
|
-
* Start from `length - keepRecentMessages` and walk *backwards* to the nearest
|
|
202
|
-
* such prompt: this keeps at least the recent floor and lands clean. Returns
|
|
203
|
-
* the cut index, or `null` if no safe boundary leaves a non-empty prefix
|
|
204
|
-
* (e.g. a single long in-progress turn — nothing safe to compact).
|
|
205
|
-
*/
|
|
206
|
-
private findCut;
|
|
207
|
-
/**
|
|
208
|
-
* Summarize a prefix via a standalone, tool-less provider call over a rendered
|
|
209
|
-
* transcript. Throws on a stream error or empty output so callers fail open.
|
|
210
|
-
*/
|
|
211
|
-
private summarize;
|
|
212
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { ApproveAction } from "../tools/types.js";
|
|
2
|
-
import type { ApprovalRequest } from "./types.js";
|
|
3
|
-
/**
|
|
4
|
-
* Classify a pending tool action into a {@link RiskTier} + a tight session
|
|
5
|
-
* {@link Scope}. The cardinal rule: **anything unrecognized is `destructive`**
|
|
6
|
-
* (most-restrictive) so a future/unknown action can never slip through as
|
|
7
|
-
* read-only or low-risk.
|
|
8
|
-
*/
|
|
9
|
-
export declare function classify(action: ApproveAction, cwd: string): ApprovalRequest;
|
|
10
|
-
/**
|
|
11
|
-
* Tokenize a command **only if** we can positively prove it is a single, simple
|
|
12
|
-
* invocation (the granted program plus plain args, no shell features). Returns
|
|
13
|
-
* the tokens, or `null` for anything we can't prove safe — deny-by-default. This
|
|
14
|
-
* is what makes a `git` session grant refuse `git push && rm -rf /`.
|
|
15
|
-
*/
|
|
16
|
-
export declare function commandTokens(command: string): string[] | null;
|
|
17
|
-
/** Is `target` the root itself or a descendant of it? (Also true if root is a file == target.) */
|
|
18
|
-
export declare function isInside(root: string, target: string): boolean;
|
package/dist/approval/index.d.ts
DELETED
package/dist/approval/mutex.d.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import type { ApprovalDecision } from "./types.js";
|
|
2
|
-
import type { ApproveAction } from "../tools/types.js";
|
|
3
|
-
/**
|
|
4
|
-
* The approval mutex (C.33, JC-C) — the spine of the concurrent-subagent safety
|
|
5
|
-
* model. Node is single-threaded, so the only hazard between parallel subagents
|
|
6
|
-
* is interleaving at `await` boundaries; the one resource they genuinely contend
|
|
7
|
-
* for is the interactive terminal (one prompt at a time) and the run's shared
|
|
8
|
-
* checkpoint state (one snapshot/set-write at a time). Serializing every
|
|
9
|
-
* *gated write* through this one lock resolves BOTH with a single mechanism:
|
|
10
|
-
*
|
|
11
|
-
* • **one prompt at a time** — a child blocked awaiting the user's keypress
|
|
12
|
-
* holds the lock, so no sibling can paint a second prompt over it (the
|
|
13
|
-
* keypress is always attributable to the one displayed prompt); and
|
|
14
|
-
* • **serialized gated writes** — the checkpoint hook (snapshot + per-root set
|
|
15
|
-
* member write) runs inside the same critical section, so two concurrent
|
|
16
|
-
* writes to disjoint roots can never race on `ensureCheckpoint`'s latch or
|
|
17
|
-
* the set manifest.
|
|
18
|
-
*
|
|
19
|
-
* It is a plain promise-chain serializer: `runExclusive(fn)` runs `fn` only
|
|
20
|
-
* after every previously-enqueued `fn` has settled. It is a LEAF lock — nothing
|
|
21
|
-
* is acquired while holding it except the terminal and the filesystem, neither
|
|
22
|
-
* of which waits on a subagent resource — so it cannot take part in a cycle
|
|
23
|
-
* (see the deadlock argument in the C.33 design doc).
|
|
24
|
-
*/
|
|
25
|
-
export declare class ApprovalMutex {
|
|
26
|
-
/** The settled-marker chain: always resolves (never rejects), so a rejecting
|
|
27
|
-
* critical section never wedges the queue for the next waiter. */
|
|
28
|
-
private tail;
|
|
29
|
-
/** Run `fn` in mutual exclusion with every other `runExclusive` on this mutex. */
|
|
30
|
-
runExclusive<T>(fn: () => Promise<T>): Promise<T>;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Wrap a fully-built gate (`ApprovalService.requestApproval` behind the C.32
|
|
34
|
-
* checkpoint hook) so that every gated action serializes through `mutex`.
|
|
35
|
-
*
|
|
36
|
-
* Every action that actually reaches the gate is a *mutation* — read-only tools
|
|
37
|
-
* never call `requestApproval` at all (see the ToolContext contract), so a
|
|
38
|
-
* parallel READ fan-out is already free of the lock and never stalls behind a
|
|
39
|
-
* sibling's pending prompt. The `read`-tier short-circuit below is therefore
|
|
40
|
-
* defensive belt-and-suspenders (mirroring `ApprovalService`'s own read check):
|
|
41
|
-
* if a read-classified action ever did flow here, it would bypass the spine
|
|
42
|
-
* rather than needlessly hold it. What the mutex serializes in practice is the
|
|
43
|
-
* mutating set — exactly the prompt + checkpoint work that must be one-at-a-time.
|
|
44
|
-
*/
|
|
45
|
-
export declare function serializeGate(gate: (action: ApproveAction) => Promise<ApprovalDecision>, mutex: ApprovalMutex, cwd: string): (action: ApproveAction) => Promise<ApprovalDecision>;
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { type PromptIO } from "./prompt.js";
|
|
2
|
-
import type { ApprovalDecision, ApprovalPolicy, ApprovalRequest, Scope } from "./types.js";
|
|
3
|
-
/**
|
|
4
|
-
* The in-memory, per-session allowlist. Grants are **scoped** (a command prefix
|
|
5
|
-
* or a path subtree) and **tier-keyed** (a `mutate` grant can never cover a
|
|
6
|
-
* `destructive` action), **never blanket**, and **never persisted**. A new
|
|
7
|
-
* session ⇒ a new allowlist (it is owned by the per-session ApprovalService).
|
|
8
|
-
*/
|
|
9
|
-
export declare class SessionAllowlist {
|
|
10
|
-
private grants;
|
|
11
|
-
/** Record a session grant for `request`'s scope. No-op when nothing is safe to grant. */
|
|
12
|
-
grant(request: ApprovalRequest): void;
|
|
13
|
-
/** Does an existing grant cover `request`? Requires same tier **and** scope match. */
|
|
14
|
-
allows(request: ApprovalRequest): boolean;
|
|
15
|
-
clear(): void;
|
|
16
|
-
size(): number;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Whether `scope` covers `request`. Shell: the command must be *provably simple*
|
|
20
|
-
* ({@link commandTokens}) and its program token must equal the granted token —
|
|
21
|
-
* so a `git` grant never matches `git push && rm -rf /`. File: every target must
|
|
22
|
-
* resolve inside the granted subtree.
|
|
23
|
-
*
|
|
24
|
-
* Multi-repo (C.26): `shell-prefix`, `shell-exact`, and `mcp-tool` grants are
|
|
25
|
-
* additionally **bound to the root they were taken in** — the grant only covers a
|
|
26
|
-
* request whose `cwd` is the same root. So "allow `git` this session" in repo A
|
|
27
|
-
* never auto-approves `git` in repo B. `file-subtree` needs no such check: it is
|
|
28
|
-
* an absolute path, so a different root is already a different subtree.
|
|
29
|
-
*/
|
|
30
|
-
export declare function scopeCovers(scope: Exclude<Scope, {
|
|
31
|
-
kind: "none";
|
|
32
|
-
}>, request: ApprovalRequest): boolean;
|
|
33
|
-
/**
|
|
34
|
-
* The default policy: consult the allowlist, otherwise prompt. On "allow this
|
|
35
|
-
* session" it records the scoped grant; a rejection carries optional feedback
|
|
36
|
-
* back to the agent.
|
|
37
|
-
*/
|
|
38
|
-
export declare class InteractivePolicy implements ApprovalPolicy {
|
|
39
|
-
private readonly allowlist;
|
|
40
|
-
private readonly io;
|
|
41
|
-
constructor(allowlist: SessionAllowlist, io: PromptIO);
|
|
42
|
-
decide(request: ApprovalRequest): Promise<ApprovalDecision>;
|
|
43
|
-
}
|