indusagi-coding-agent 0.2.3 → 0.2.4

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 (31) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/entry.js +1733 -572
  3. package/dist/guardrails.js +21 -6
  4. package/dist/index.js +1687 -552
  5. package/dist/types/boot/heap.d.ts +31 -0
  6. package/dist/types/boot/runners/delegate-runner.d.ts +21 -1
  7. package/dist/types/boot/runners/server-mode.d.ts +71 -0
  8. package/dist/types/boot/runners/session.d.ts +24 -1
  9. package/dist/types/boot/runners/session.test.d.ts +6 -1
  10. package/dist/types/boot/server-token.d.ts +97 -0
  11. package/dist/types/capability-deck/contract.d.ts +7 -6
  12. package/dist/types/conductor/conductor.d.ts +24 -0
  13. package/dist/types/conductor/contract.d.ts +71 -7
  14. package/dist/types/conductor/index.d.ts +3 -3
  15. package/dist/types/conductor/permissions.d.ts +74 -4
  16. package/dist/types/conductor/post-edit-diagnostics.test.d.ts +8 -3
  17. package/dist/types/conductor/quota-error.d.ts +35 -0
  18. package/dist/types/console/auth-status.d.ts +28 -0
  19. package/dist/types/console/components/TerminalConsole.d.ts +0 -5
  20. package/dist/types/console/contract.d.ts +13 -0
  21. package/dist/types/console/input/index.d.ts +1 -1
  22. package/dist/types/console/input/keymap.d.ts +1 -1
  23. package/dist/types/console/input/paste.d.ts +53 -1
  24. package/dist/types/console/overlays/approval-queue.d.ts +18 -1
  25. package/dist/types/console/overlays/index.d.ts +1 -1
  26. package/dist/types/launch/login.d.ts +68 -0
  27. package/dist/types/launch/oauth.test.d.ts +20 -0
  28. package/dist/types/window-budget/summarize/condense.d.ts +6 -0
  29. package/dist/types/workflow-engine/agent-runner.d.ts +20 -1
  30. package/dist/types/workspace/brand.d.ts +1 -1
  31. package/package.json +2 -2
@@ -0,0 +1,35 @@
1
+ /**
2
+ * quota-error.ts — maps the indus model-gateway's usage-limit response into a
3
+ * friendly, user-facing fault message.
4
+ *
5
+ * When a no-local-key, logged-in user runs a turn, the framework adapter is
6
+ * pointed at `${INDUS_SERVER_URL}/gateway/<provider>` (see the conductor's
7
+ * baseUrl rewrite). If that user is over their monthly token allowance, the
8
+ * server replies — *before* forwarding upstream — with:
9
+ *
10
+ * HTTP/1.1 429 Too Many Requests
11
+ * Content-Type: application/json
12
+ *
13
+ * { "error": "quota_exceeded", "used": <number>, "limit": <number> }
14
+ *
15
+ * The provider SDK / raw-fetch adapter turns that 429 into a thrown error. By
16
+ * the time it reaches the conductor it may be wrapped (an SDK `APIError`, a
17
+ * generic `Error`, a nested `cause` chain, or a plain string), so detection must
18
+ * be tolerant and walk the whole error chain rather than trust a single shape.
19
+ *
20
+ * This module is intentionally transport-agnostic and dependency-free so it can
21
+ * be unit-tested in isolation and imported from the conductor's retry chokepoint
22
+ * without pulling in any network/runtime modules.
23
+ */
24
+ /** Detects the gateway's 429 quota body anywhere in the error chain. */
25
+ export declare function isQuotaFault(error: unknown): boolean;
26
+ /**
27
+ * Friendly user-facing text; `undefined` if `error` is not a quota fault.
28
+ *
29
+ * Includes the `<used>/<limit>` parenthetical when both numbers are parseable,
30
+ * and otherwise falls back to the same sentence without it. The `indus signin
31
+ * <provider>` hint steers the user toward supplying their own key (which takes
32
+ * the direct, un-metered local-key path), and the upgrade hint covers raising
33
+ * the server-side allowance.
34
+ */
35
+ export declare function quotaErrorMessage(error: unknown): string | undefined;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Shared "does the user have a usable credential for this provider" probe.
3
+ *
4
+ * Used anywhere the console needs to know which providers are actually
5
+ * callable — the `/model` picker (only list authenticated providers) and the
6
+ * banner's Session panel (don't display an unauthenticated model as if it were
7
+ * ready to use) both need the exact same answer, so it lives here once.
8
+ */
9
+ import type { OverlayServices } from "./contract";
10
+ /**
11
+ * Load the set of provider ids the user has USABLE credentials for, live, so a
12
+ * mid-session `/login` (either a local vault sign-in or the "Indus Server"
13
+ * server-tier device flow) is reflected without a restart.
14
+ *
15
+ * Two independent sources count: (1) any saved account in the local vault for a
16
+ * provider `listLoginProviders()` names, and (2) a valid server session token,
17
+ * which makes every gateway-eligible provider (`serverTierProviders()` —
18
+ * minimax, sarvam) usable even though the server tier never writes into the
19
+ * vault. Returns `null` until the asynchronous probe settles.
20
+ *
21
+ * `refreshKey` re-runs the probe whenever it changes by reference/value — a
22
+ * short-lived overlay (the `/model` picker) can leave it at its default since
23
+ * it remounts fresh on every open anyway, but a component mounted once for the
24
+ * whole session (the banner, the status bar) MUST pass something that changes
25
+ * right when a sign-in completes (e.g. the console's current status toast),
26
+ * otherwise this only ever reflects whatever was true at session start.
27
+ */
28
+ export declare function useAuthenticatedProviders(services: OverlayServices | undefined, refreshKey?: unknown): Set<string> | null;
@@ -24,9 +24,4 @@
24
24
  * `indusagi/react-ink`.
25
25
  */
26
26
  import type { ConsoleProps } from "../contract";
27
- /**
28
- * The interactive console surface.
29
- *
30
- * @param props the conductor to drive, the resolved theme, and the slash registry
31
- */
32
27
  export declare function TerminalConsole(props: ConsoleProps): JSX.Element;
@@ -359,6 +359,12 @@ export type ConsoleEvent = {
359
359
  } | {
360
360
  readonly type: "buffer:insert";
361
361
  readonly text: string;
362
+ }
363
+ /** Swap the first occurrence of `find` for `replaceWith` (paste-marker growth). */
364
+ | {
365
+ readonly type: "buffer:replaceSpan";
366
+ readonly find: string;
367
+ readonly replaceWith: string;
362
368
  } | {
363
369
  readonly type: "buffer:erasePrev";
364
370
  } | {
@@ -548,6 +554,13 @@ export interface OverlayServices {
548
554
  readonly openLoginUrl: (url: string) => Promise<boolean>;
549
555
  /** The credential store sign-in / sign-out overlays read and write. */
550
556
  readonly vault: AuthVault;
557
+ /**
558
+ * Recompute the server-tier gateway routing map from current vault/token
559
+ * state and push it onto the live conductor, so a sign-in that happens
560
+ * mid-session (the "Indus Server" entry in `/login`) takes effect on the
561
+ * NEXT turn without needing a session restart.
562
+ */
563
+ readonly refreshGatewayRouting: () => Promise<void>;
551
564
  }
552
565
  /**
553
566
  * What the root `TerminalConsole` surface receives at mount.
@@ -18,7 +18,7 @@
18
18
  export type { KeyChord, ConsoleVerb, ConsoleIntent, ChordOutcome, ChordLatch, ChordStep, } from "./keymap";
19
19
  export { NO_INTENT, readKey, NO_CHORD, advanceChord } from "./keymap";
20
20
  export type { PasteThresholds, PasteVault, PasteCapture, } from "./paste";
21
- export { PASTE_THRESHOLDS, PASTE_BURST_GAP_MS, EMPTY_PASTE_VAULT, pasteMarker, classifyPaste, coalescePaste, expandMarkers, hasMarkers, } from "./paste";
21
+ export { PASTE_THRESHOLDS, PASTE_BURST_GAP_MS, PASTE_CONTINUATION_MS, PASTE_MARKER_LINE_CAP, EMPTY_PASTE_VAULT, pasteMarker, classifyPaste, coalescePaste, appendToPaste, pasteLines, expandMarkers, hasMarkers, } from "./paste";
22
22
  export type { CompletionKind, Suggestion, TokenSpan, CompletionResult, DirEntry, DirReader, } from "./complete";
23
23
  export { completeAt, applySuggestion } from "./complete";
24
24
  export { createDirReader } from "./dir-reader";
@@ -115,7 +115,7 @@ export interface KeyChord {
115
115
  * Inert
116
116
  * - `none` — the keystroke carries no console meaning.
117
117
  */
118
- export type ConsoleVerb = "text:type" | "text:newline" | "edit:erasePrev" | "edit:eraseNext" | "edit:clearLine" | "nav:left" | "nav:right" | "nav:home" | "nav:end" | "nav:up" | "nav:down" | "flow:submit" | "flow:dismiss" | "flow:accept" | "flow:interrupt" | "flow:suspend" | "flow:cycleModel" | "model:cycleThinking" | "mode:cyclePermission" | "mode:togglePlan" | "queue:dequeue" | "input:pasteImage" | "input:externalEditor" | "overlay:open" | "view:expandTools" | "view:toggleReasoning" | "none";
118
+ export type ConsoleVerb = "text:type" | "text:newline" | "edit:erasePrev" | "edit:eraseNext" | "edit:clearLine" | "nav:left" | "nav:right" | "nav:home" | "nav:end" | "nav:up" | "nav:down" | "flow:submit" | "flow:dismiss" | "flow:accept" | "flow:interrupt" | "flow:suspend" | "flow:cycleModel" | "model:cycleThinking" | "mode:cyclePermission" | "mode:togglePlan" | "queue:dequeue" | "queue:steer" | "input:pasteImage" | "input:externalEditor" | "overlay:open" | "view:expandTools" | "view:toggleReasoning" | "none";
119
119
  /**
120
120
  * A classified keystroke: a {@link ConsoleVerb} plus the small payload a verb
121
121
  * may carry — the literal text for a `text:type` insert, or the target overlay
@@ -41,7 +41,14 @@ export interface PasteThresholds {
41
41
  /** Minimum character count to treat a chunk as a large paste. */
42
42
  readonly chars: number;
43
43
  }
44
- /** The default cut-offs above which a paste is coalesced into a marker. */
44
+ /**
45
+ * The default cut-offs above which a paste is coalesced into a marker.
46
+ *
47
+ * Matched to the reference agent: a paste of MORE than 10 lines (i.e. ≥10
48
+ * newlines) or more than 1000 characters hides behind a marker; anything
49
+ * smaller — including the common 8-line snippet — splices inline and renders
50
+ * as visible multi-line text in the composer.
51
+ */
45
52
  export declare const PASTE_THRESHOLDS: PasteThresholds;
46
53
  /**
47
54
  * The maximum gap, in milliseconds, between per-character events still treated
@@ -53,6 +60,30 @@ export declare const PASTE_THRESHOLDS: PasteThresholds;
53
60
  * it. Exposed as data so the coalescing timer and any test share one value.
54
61
  */
55
62
  export declare const PASTE_BURST_GAP_MS = 24;
63
+ /**
64
+ * How long, after a coalesced flush, a paste stays "active" — a further
65
+ * multi-character chunk landing within this window APPENDS to the active
66
+ * marker instead of minting a new one.
67
+ *
68
+ * Terminals deliver a big paste as a series of ~1KB stdin reads whose gaps can
69
+ * exceed any reasonable per-chunk debounce, so timing alone shreds one paste
70
+ * into many markers (`[Pasted #11][Pasted #12]…`, issue #18's second form).
71
+ * Sized GENEROUSLY: a very long paste (the spec case is 1000 lines) must
72
+ * survive mid-stream read hiccups as ONE marker, and the failure mode of a
73
+ * too-long window is mild — two lightning-fast deliberate pastes merge into
74
+ * one marker whose expansion is still the correct concatenated text — while a
75
+ * too-short window re-creates the shredding this exists to fix. Two human
76
+ * paste chords are >300ms apart in practice; single characters (real typing)
77
+ * never extend the window.
78
+ */
79
+ export declare const PASTE_CONTINUATION_MS = 250;
80
+ /**
81
+ * Ceiling on the line count a single marker absorbs via continuation. One
82
+ * user paste stays ONE marker up to this many lines; a paste that keeps
83
+ * streaming past it rolls over into a fresh marker ("one more paste") so a
84
+ * runaway multi-megabyte paste can't grow a single unbounded vault body.
85
+ */
86
+ export declare const PASTE_MARKER_LINE_CAP = 1000;
56
87
  /** The console's own placeholder format for a hidden paste body. */
57
88
  export declare function pasteMarker(ordinal: number, lineCount: number): string;
58
89
  /**
@@ -106,6 +137,27 @@ export interface PasteCapture {
106
137
  * @param body the full pasted text to hide
107
138
  */
108
139
  export declare function coalescePaste(body: string, vault?: PasteVault): PasteCapture;
140
+ /**
141
+ * Grow an existing paste body with a follow-on chunk, reminting its marker.
142
+ *
143
+ * The continuation path for a paste the terminal split across reads: the extra
144
+ * text is appended to `ordinal`'s stored body and a fresh marker (same ordinal,
145
+ * updated line count) is returned so the surface can swap the token already
146
+ * spliced into the buffer. `minted` is unchanged — no new ordinal is consumed.
147
+ * An unknown ordinal starts from an empty body, so the call never throws.
148
+ *
149
+ * @param ordinal the marker ordinal to grow
150
+ * @param extra the follow-on pasted text to append
151
+ * @param vault the store holding the ordinal's current body
152
+ */
153
+ export declare function appendToPaste(ordinal: number, extra: string, vault: PasteVault): PasteCapture;
154
+ /**
155
+ * The line count of an ordinal's stored body — the surface consults this
156
+ * against {@link PASTE_MARKER_LINE_CAP} to decide whether a continuation chunk
157
+ * may still append or must roll over into a fresh marker. Zero for an unknown
158
+ * ordinal or an empty body.
159
+ */
160
+ export declare function pasteLines(vault: PasteVault, ordinal: number): number;
109
161
  /**
110
162
  * Rewrite every paste marker in a buffer back to the text it stands for.
111
163
  *
@@ -15,7 +15,7 @@
15
15
  * abort/clear settles every outstanding entry with `"deny"` so a cancelled turn
16
16
  * never hangs on a pending prompt.
17
17
  */
18
- import type { ApprovalChoice } from "../../conductor";
18
+ import type { ApprovalChoice, PermissionMode } from "../../conductor";
19
19
  import type { ApprovalRequest } from "./approval";
20
20
  /** One parked approval request awaiting the user's choice. */
21
21
  export interface ApprovalEntry {
@@ -69,3 +69,20 @@ export declare function approvalQueueReducer(state: ApprovalQueueState, event: A
69
69
  * @param state the queue state
70
70
  */
71
71
  export declare function activeApproval(state: ApprovalQueueState): ApprovalEntry | undefined;
72
+ /**
73
+ * Whether switching INTO `mode` mid-prompt should release (auto-allow) every
74
+ * PARKED approval request.
75
+ *
76
+ * Only `bypass` qualifies: a parked entry already passed the deny-rule and
77
+ * catastrophic-blocklist scans before it reached `ask`, and under bypass the
78
+ * engine allows everything not denied — so settling the parked prompts with
79
+ * `allow-once` matches exactly what the mode now means, and the run resumes
80
+ * instead of idling behind a prompt the user just declared moot. Every other
81
+ * mode keeps the prompts parked: `default`/`acceptEdits` still want the answer,
82
+ * and `plan` must not auto-ALLOW a mutating call (the user can still deny).
83
+ *
84
+ * Pure; the component wires it to the actual settle.
85
+ *
86
+ * @param mode the permission mode just switched into
87
+ */
88
+ export declare function modeReleasesApprovals(mode: PermissionMode): boolean;
@@ -12,4 +12,4 @@ export { PickerOverlays, type OverlayGroupProps } from "./pickers";
12
12
  export { SessionOverlays } from "./sessions";
13
13
  export { AuthOverlays } from "./auth";
14
14
  export { ApprovalOverlays, choiceFromId, readApprovalPayload, summarizeInput, APPROVAL_CHOICES, DISMISS_CHOICE, type ApprovalRequest, type ApprovalPayload, } from "./approval";
15
- export { approvalQueueReducer, activeApproval, EMPTY_APPROVAL_QUEUE, type ApprovalEntry, type ApprovalQueueState, type ApprovalQueueEvent, } from "./approval-queue";
15
+ export { approvalQueueReducer, activeApproval, modeReleasesApprovals, EMPTY_APPROVAL_QUEUE, type ApprovalEntry, type ApprovalQueueState, type ApprovalQueueEvent, } from "./approval-queue";
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Login command — `runLogin`.
3
+ *
4
+ * The top-level `login` / `logout` / `whoami` surface that authenticates the CLI
5
+ * against the indus-server so a user with **no local provider key** can still run
6
+ * model turns through the server gateway (the session token is vended as the
7
+ * provider key downstream — see `src/boot/runners/server-mode.ts`).
8
+ *
9
+ * `login` drives the OAuth 2.0 **device-authorization** flow (RFC 8628) against
10
+ * the server's better-auth endpoints under `${INDUS_SERVER_URL}/api/auth`:
11
+ *
12
+ * 1. POST `/api/auth/device/code` → a `user_code` + verification URL.
13
+ * 2. The user opens the URL in a browser and approves the device.
14
+ * 3. We poll POST `/api/auth/device/token` until it returns an `access_token`.
15
+ * 4. The token is persisted via {@link storeServerToken} (A1's token store).
16
+ *
17
+ * This is a **pre-pipeline router**, not a runner: a no-key user cannot build a
18
+ * session, so login must short-circuit before the stage pipeline. {@link runLogin}
19
+ * therefore mirrors `runCredential` in `boot.ts` — it owns the first positional
20
+ * token only and returns `undefined` (fall through to a normal launch) when that
21
+ * token is not one of its verbs.
22
+ *
23
+ * The app does not depend on `better-auth/client`, `open`, or a spinner library,
24
+ * so the device flow is implemented over raw `fetch` and the console is driven
25
+ * with `chalk` to match the rest of the launch surface. `--server-url` and
26
+ * `--client-id` are parsed from the argv tail here (the declarative flag table is
27
+ * for the launch invocation, not these auth-only verbs).
28
+ */
29
+ import type { OAuthLoginCallbacks } from "indusagi/ai";
30
+ import type { BootContext } from "../boot/contract";
31
+ /**
32
+ * The sign-in directory id for the indus-server session (as opposed to a
33
+ * per-model-provider credential). Used by `src/launch/oauth.ts` to special-case
34
+ * this entry in `listLoginProviders` / `startOAuthLogin` so the interactive
35
+ * `/login` picker can drive the same device-authorization flow as the `indus
36
+ * login` CLI verb.
37
+ */
38
+ export declare const SERVER_TIER_PROVIDER_ID = "indus-server";
39
+ /**
40
+ * Drive the indus-server device-authorization flow through the framework's
41
+ * generic {@link OAuthLoginCallbacks} shape, so the interactive `/login` picker
42
+ * (`src/console/overlays/auth.tsx`'s `OAuthFlowDialog`) can establish a
43
+ * server-tier session the same way the `indus login` CLI verb does.
44
+ *
45
+ * Reuses the private {@link requestDeviceCode} / {@link pollForToken} helpers
46
+ * above rather than duplicating the request+poll sequence, and reports the
47
+ * verification URL / code through `callbacks.onAuth` exactly once, mirroring
48
+ * how `doLogin` renders them to the console. On success the token is persisted
49
+ * via {@link storeServerToken}; any thrown error (network failure, denial,
50
+ * expiry, timeout) propagates to the caller unchanged — `startOAuthLogin`'s
51
+ * caller (the dialog's try/catch) already renders a generic failure state.
52
+ *
53
+ * @param callbacks the framework's OAuth login callbacks (url + progress)
54
+ * @param serverUrl the indus-server base url (defaults to {@link INDUS_SERVER_URL})
55
+ * @param clientId the device-flow client id (defaults to {@link INDUS_CLIENT_ID})
56
+ */
57
+ export declare function runServerTierLogin(callbacks: OAuthLoginCallbacks, serverUrl?: string, clientId?: string): Promise<void>;
58
+ /**
59
+ * Route a `login` / `logout` / `whoami` verb, if this invocation is one.
60
+ *
61
+ * Inspects `ctx.argv[0]`: returns a numeric exit code when it handled one of the
62
+ * auth verbs, or `undefined` when the leading token is something else so the
63
+ * caller falls through to a normal launch. Modeled on `runCredential` in
64
+ * `boot.ts`; `--server-url` / `--client-id` are parsed from the argv tail.
65
+ *
66
+ * @param ctx the seeded boot context (carries the raw argv)
67
+ */
68
+ export declare function runLogin(ctx: BootContext): Promise<number | undefined>;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * `src/launch/oauth.ts` — unit tests for the indus-server bridge added to the
3
+ * merged sign-in directory and `startOAuthLogin`.
4
+ *
5
+ * Covers:
6
+ * 1. {@link listLoginProviders} includes the `indus-server` entry
7
+ * (`SERVER_TIER_PROVIDER_ID`, `authKind: "oauth"`).
8
+ * 2. {@link startOAuthLogin} for `SERVER_TIER_PROVIDER_ID` drives the device
9
+ * flow over a mocked `fetch`, reports `onAuth` exactly once with the right
10
+ * shape, reports progress, never touches the vault, and resolves.
11
+ * 3. {@link startOAuthLogin} for an unregistered id still throws the
12
+ * pre-existing "No browser sign-in is available" error (regression check).
13
+ * 4. A device/token failure (`access_denied`) propagates out of
14
+ * `startOAuthLogin` unchanged rather than being swallowed.
15
+ *
16
+ * `storeServerToken` is mocked (partial mock of `../boot/server-token`) so the
17
+ * success-path test never touches the real `~/.indusagi/agent/server-token.json`
18
+ * file on the machine running the suite.
19
+ */
20
+ export {};
@@ -38,6 +38,12 @@ export interface SummarizeDeps {
38
38
  readonly priorDigest?: string;
39
39
  /** Cancellation signal forwarded to the completer. */
40
40
  readonly signal?: AbortSignal;
41
+ /**
42
+ * Credential for the summarization model's provider, forwarded to the
43
+ * completer. Required in practice for sessions whose key is resolved
44
+ * per-call (server tier) rather than from an environment variable.
45
+ */
46
+ readonly apiKey?: string;
41
47
  /**
42
48
  * Optional cap on the digest size, in tokens, forwarded to the completer's
43
49
  * `maxTokens`. A modest ceiling keeps the summary itself from eating the
@@ -34,7 +34,7 @@
34
34
  * test seam — a unit test drives the runner with an in-memory fake instead of a
35
35
  * real network round-trip.
36
36
  */
37
- import { type AgentMessage } from "../conductor";
37
+ import { type AgentMessage, type SessionPermissionPolicy } from "../conductor";
38
38
  import { type AgentTool } from "../capability-deck";
39
39
  import { type AgentEvent } from "indusagi/agent";
40
40
  import type { WorkflowAgentRunner } from "./engine";
@@ -89,6 +89,25 @@ export interface WorkflowAgentRunnerOptions {
89
89
  * `Agent`. When omitted the runner uses `new Agent`.
90
90
  */
91
91
  readonly spawn?: (prompt: string, context: WorkflowSpawnContext) => WorkflowSubAgent;
92
+ /**
93
+ * Resolve the current server-tier gateway routing map (provider -> gateway
94
+ * base url). Called FRESH on every `run()` — never cached — so a mid-session
95
+ * `/login` (to "Indus Server") is always picked up on the very next subagent
96
+ * call. Mirrors {@link getApiKey}, which is likewise invoked per-request
97
+ * rather than resolved once at construction.
98
+ */
99
+ readonly getGatewayBaseUrls?: () => Promise<Record<string, string>>;
100
+ /**
101
+ * The parent session's live permission policy: the SAME mutable rule list the
102
+ * parent gate reads plus a live getter onto the conductor's current mode. When
103
+ * present, every spawned workflow subagent runs under a RESOLVER-LESS gate
104
+ * built from it — deny/ask rules, plan-mode enforcement, and the
105
+ * catastrophic-bash blocklist apply per inner tool call, and a mid-run mode
106
+ * switch (Shift+Tab) retargets the very next subagent tool call. A subagent
107
+ * cannot prompt, so an `ask` decision deterministically denies. Absent (a bare
108
+ * test construction), the subagent runs ungated as before.
109
+ */
110
+ readonly permissionPolicy?: SessionPermissionPolicy;
92
111
  }
93
112
  /**
94
113
  * Build a live {@link WorkflowAgentRunner} the host wires into the deck context.
@@ -23,4 +23,4 @@ export declare const BRAND: Brand;
23
23
  * Single source of truth: bump this one line per release. Co-located with the
24
24
  * brand so `boot` reads it without importing the index barrel.
25
25
  */
26
- export declare const VERSION = "0.2.3";
26
+ export declare const VERSION = "0.2.4";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "indusagi-coding-agent",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "Indusagi coding agent — a terminal-first AI coding agent, built from scratch on the indusagi framework.",
5
5
  "author": "Varun Israni",
6
6
  "license": "MIT",
@@ -57,7 +57,7 @@
57
57
  "@sinclair/typebox": "^0.34.49",
58
58
  "chalk": "^5.6.2",
59
59
  "highlight.js": "^11.11.1",
60
- "indusagi": "^0.13.2",
60
+ "indusagi": "^0.13.3",
61
61
  "ink": "^5.2.1",
62
62
  "jiti": "^2.7.0",
63
63
  "marked": "^18.0.4",