indusagi-coding-agent 0.1.62 → 0.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 (62) hide show
  1. package/dist/entry.js +5395 -1509
  2. package/dist/types/boot/contract.d.ts +2 -0
  3. package/dist/types/boot/runners/addon-wiring.d.ts +103 -0
  4. package/dist/types/boot/runners/addon-wiring.test.d.ts +19 -0
  5. package/dist/types/boot/runners/checkpoint.d.ts +133 -0
  6. package/dist/types/boot/runners/checkpoint.test.d.ts +12 -0
  7. package/dist/types/boot/runners/delegate-runner.d.ts +83 -0
  8. package/dist/types/boot/runners/delegate-runner.test.d.ts +13 -0
  9. package/dist/types/boot/runners/memdir.d.ts +103 -0
  10. package/dist/types/boot/runners/memdir.test.d.ts +12 -0
  11. package/dist/types/boot/runners/read-state.d.ts +82 -0
  12. package/dist/types/boot/runners/read-state.test.d.ts +10 -0
  13. package/dist/types/boot/runners/session.d.ts +37 -2
  14. package/dist/types/boot/runners/session.test.d.ts +10 -0
  15. package/dist/types/briefing/context-docs.d.ts +38 -0
  16. package/dist/types/briefing/context-docs.test.d.ts +18 -0
  17. package/dist/types/briefing/index.d.ts +2 -0
  18. package/dist/types/capability-deck/cards/index.d.ts +6 -0
  19. package/dist/types/capability-deck/cards/memory-card.d.ts +9 -10
  20. package/dist/types/capability-deck/cards/plan-file.d.ts +56 -0
  21. package/dist/types/capability-deck/cards/plan-tools.d.ts +97 -0
  22. package/dist/types/capability-deck/cards/plan-tools.test.d.ts +9 -0
  23. package/dist/types/capability-deck/checkpoint.int.test.d.ts +25 -0
  24. package/dist/types/capability-deck/index.d.ts +1 -1
  25. package/dist/types/capability-deck/read-edit-gate.int.test.d.ts +21 -0
  26. package/dist/types/conductor/bash-guard.d.ts +106 -0
  27. package/dist/types/conductor/bash-guard.test.d.ts +17 -0
  28. package/dist/types/conductor/conductor.d.ts +37 -6
  29. package/dist/types/conductor/contract.d.ts +214 -2
  30. package/dist/types/conductor/diagnostics.d.ts +183 -0
  31. package/dist/types/conductor/diagnostics.test.d.ts +10 -0
  32. package/dist/types/conductor/index.d.ts +4 -1
  33. package/dist/types/conductor/permission-gate.integration.test.d.ts +22 -0
  34. package/dist/types/conductor/permission-wiring.test.d.ts +14 -0
  35. package/dist/types/conductor/permissions.d.ts +217 -0
  36. package/dist/types/conductor/permissions.test.d.ts +12 -0
  37. package/dist/types/conductor/plan-mode.integration.test.d.ts +23 -0
  38. package/dist/types/conductor/post-edit-diagnostics.test.d.ts +13 -0
  39. package/dist/types/conductor/transcript-store/serialize.test.d.ts +10 -0
  40. package/dist/types/conductor/transcript-store/store.d.ts +18 -0
  41. package/dist/types/console/components/StatusBar.d.ts +14 -3
  42. package/dist/types/console/components/WorkingIndicator.d.ts +44 -0
  43. package/dist/types/console/components/WorkingIndicator.test.d.ts +9 -0
  44. package/dist/types/console/contract.d.ts +2 -1
  45. package/dist/types/console/input/keymap.d.ts +10 -1
  46. package/dist/types/console/overlays/approval-queue.d.ts +71 -0
  47. package/dist/types/console/overlays/approval.d.ts +104 -0
  48. package/dist/types/console/overlays/approval.test.d.ts +17 -0
  49. package/dist/types/console/overlays/host.d.ts +4 -3
  50. package/dist/types/console/overlays/index.d.ts +2 -0
  51. package/dist/types/launch/contract.d.ts +2 -0
  52. package/dist/types/launch/index.d.ts +1 -1
  53. package/dist/types/launch/oauth.d.ts +13 -0
  54. package/dist/types/settings/contract.d.ts +47 -0
  55. package/dist/types/settings/index.d.ts +2 -2
  56. package/dist/types/window-budget/condenser.d.ts +15 -1
  57. package/dist/types/window-budget/index.d.ts +3 -1
  58. package/dist/types/window-budget/microcompact.d.ts +68 -0
  59. package/dist/types/window-budget/microcompact.test.d.ts +16 -0
  60. package/dist/types/window-budget/rehydrate.d.ts +56 -0
  61. package/dist/types/workspace/brand.d.ts +1 -1
  62. package/package.json +2 -2
@@ -11,3 +11,5 @@ export { OverlayHost, type OverlayHostProps } from "./host";
11
11
  export { PickerOverlays, type OverlayGroupProps } from "./pickers";
12
12
  export { SessionOverlays } from "./sessions";
13
13
  export { AuthOverlays } from "./auth";
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";
@@ -171,6 +171,8 @@ export interface Invocation {
171
171
  readonly attachments?: Attachments;
172
172
  /** Explicit model selector (`--model` / `-m`), provider-qualified or bare. */
173
173
  readonly model?: string;
174
+ /** Model to fall back to when the selected model is overloaded mid-turn (`--fallback-model`). */
175
+ readonly fallbackModel?: string;
174
176
  /** Named credential account to authenticate the run with (`--account`). */
175
177
  readonly account?: string;
176
178
  /** Working directory the run is scoped to (`--cwd`); absent means process cwd. */
@@ -20,7 +20,7 @@ export { runPackageCommand, defaultPackageIo, PACKAGE_COMMANDS, } from "./packag
20
20
  export type { PackageCommand, PackageIo, PackageCommandOptions, PackageResult, } from "./packages";
21
21
  export { runCredentialCommand, defaultCredentialIo, formatCredentialFault, validateApiKey, validateAccountName, findProvider, isOAuthCapable, asSigninMethod, PROVIDER_DIRECTORY, } from "./credentials";
22
22
  export type { CredentialIo, CredentialResult, SigninMethod } from "./credentials";
23
- export { registerBuiltInOAuthProviders, listLoginProviders, startOAuthLogin, openLoginUrl, } from "./oauth";
23
+ export { registerBuiltInOAuthProviders, listLoginProviders, startOAuthLogin, openLoginUrl, hasRegisteredOAuthClientId, } from "./oauth";
24
24
  export type { AuthKind, LoginProvider, OAuthLoginResult, } from "./oauth";
25
25
  export { printModelCatalog, defaultCatalogIo, registrySource } from "./catalog";
26
26
  export type { CatalogIo, CatalogModelSource } from "./catalog";
@@ -29,6 +29,19 @@ import type { AuthVault } from "./contract";
29
29
  * that are registered after the call, for callers that want to confirm the set.
30
30
  */
31
31
  export declare function registerBuiltInOAuthProviders(): string[];
32
+ /**
33
+ * Whether a registered sign-in provider has a *real* OAuth client id wired in
34
+ * (its env var is set to something other than the framework's sentinel), so its
35
+ * browser sign-in can actually complete.
36
+ *
37
+ * Reads the env var live (not at import time) so a deployer that exports the id
38
+ * before launching `/login` is honored. A provider with no known client-id
39
+ * wiring (i.e. not one of the three sentinel-shipped framework providers) is
40
+ * treated as registered — we only gate the providers we know ship a sentinel.
41
+ *
42
+ * @param providerId the registered sign-in provider id
43
+ */
44
+ export declare function hasRegisteredOAuthClientId(providerId: string): boolean;
32
45
  /** How a provider authenticates in the merged sign-in directory. */
33
46
  export type AuthKind = "oauth" | "apiKey";
34
47
  /** One row of the merged sign-in directory. */
@@ -48,6 +48,46 @@ export type DeliveryMode = "all" | "one-at-a-time";
48
48
  export declare const DELIVERY_MODES: readonly DeliveryMode[];
49
49
  /** Narrow an arbitrary value to a known {@link DeliveryMode}. */
50
50
  export declare function isDeliveryMode(value: unknown): value is DeliveryMode;
51
+ /**
52
+ * How aggressively the per-tool permission gate auto-allows tool calls before it
53
+ * falls back to asking (or denying):
54
+ *
55
+ * - `default` — consult the allow/ask/deny rules; read-only tools are
56
+ * auto-allowed, anything else with no matching allow rule
57
+ * falls through to `ask`.
58
+ * - `acceptEdits` — additionally auto-allow filesystem edits/writes (the
59
+ * mutating edit/write/multiedit tools), leaving everything
60
+ * else on the `default` path.
61
+ * - `bypass` — allow every tool with no prompt (the unsafe "trust all"
62
+ * mode; `bypassPermissions` is accepted as an alias).
63
+ * - `plan` — deny every mutating tool outright (read-only research only)
64
+ * so the agent can plan without touching the workspace.
65
+ */
66
+ export type PermissionMode = "default" | "acceptEdits" | "bypass" | "plan" | "bypassPermissions";
67
+ /** The canonical {@link PermissionMode} values, as a frozen tuple for menus/guards. */
68
+ export declare const PERMISSION_MODES: readonly PermissionMode[];
69
+ /** Narrow an arbitrary value to a known {@link PermissionMode} (folds the alias). */
70
+ export declare function isPermissionMode(value: unknown): value is PermissionMode;
71
+ /**
72
+ * The declarative permission policy a session reads at startup.
73
+ *
74
+ * `allow`/`ask`/`deny` are ordered lists of induscode-style rule strings — a bare
75
+ * tool name (`"Bash"`) or a tool name with an argument specifier
76
+ * (`"Bash(npm run test:*)"`). Across tiers the three lists are concatenated, and
77
+ * `deny` wins over `ask` wins over `allow`. `defaultMode` seeds the session's
78
+ * permission mode when no flag overrides it. Every field is optional so an empty
79
+ * `{}` (or an absent `permissions` key) keeps today's allow-all behavior.
80
+ */
81
+ export interface PermissionSettings {
82
+ /** Rule strings that auto-allow a matching tool call (lowest precedence). */
83
+ allow?: string[];
84
+ /** Rule strings that force a matching tool call to prompt for approval. */
85
+ ask?: string[];
86
+ /** Rule strings that hard-block a matching tool call (highest precedence). */
87
+ deny?: string[];
88
+ /** The permission mode the session opens in when no flag overrides it. */
89
+ defaultMode?: PermissionMode;
90
+ }
51
91
  /**
52
92
  * Every preference an interactive coding-agent session reads, as one flat,
53
93
  * fully-optional record.
@@ -111,6 +151,13 @@ export interface Preferences {
111
151
  doubleEscapeAction?: EscapeAction;
112
152
  /** Extension-package sources the launcher installs and loads (npm / git / local). */
113
153
  extensionPackages?: string[];
154
+ /**
155
+ * The declarative tool-permission policy: ordered allow/ask/deny rule lists and
156
+ * the opening permission mode. Across the project/global tiers the rule lists
157
+ * are concatenated (not overridden) and `deny > ask > allow` decides; an absent
158
+ * value (or an empty object) preserves today's allow-all behavior.
159
+ */
160
+ permissions?: PermissionSettings;
114
161
  }
115
162
  /** The set of legal preference keys, derived from {@link Preferences}. */
116
163
  export type SettingKey = keyof Preferences;
@@ -7,7 +7,7 @@
7
7
  * {@link PreferenceStore} reader/writer. Console surfaces and boot stages depend
8
8
  * on this module rather than reaching into the individual files.
9
9
  */
10
- export type { Preferences, SettingKey, EscapeAction, DeliveryMode, ThinkingLevel, } from "./contract";
11
- export { DEFAULT_PREFERENCES, SETTING_KEYS, ESCAPE_ACTIONS, isEscapeAction, DELIVERY_MODES, isDeliveryMode, } from "./contract";
10
+ export type { Preferences, SettingKey, EscapeAction, DeliveryMode, ThinkingLevel, PermissionMode, PermissionSettings, } from "./contract";
11
+ export { DEFAULT_PREFERENCES, SETTING_KEYS, ESCAPE_ACTIONS, isEscapeAction, DELIVERY_MODES, isDeliveryMode, PERMISSION_MODES, isPermissionMode, } from "./contract";
12
12
  export { PreferenceStore } from "./manager";
13
13
  export type { PreferenceLocations } from "./manager";
@@ -28,8 +28,22 @@
28
28
  * matching session-scope entrypoint. Both are re-exported here so callers can
29
29
  * summarize a slice directly without building a full {@link Condenser}.
30
30
  */
31
- import type { AgentMessage, CondenserDeps, Condenser, Summary } from "./contract.js";
31
+ import type { AgentMessage, BudgetPolicy, CondenserDeps, Condenser, Summary } from "./contract.js";
32
32
  import { condenseScope, type SummarizeDeps } from "./summarize/index.js";
33
+ /**
34
+ * The fallback {@link BudgetPolicy} when the caller supplies none. These are
35
+ * ordinary configuration defaults — a window-relative ratio plus a token tail —
36
+ * computed from the model's own context window rather than fixed magic numbers.
37
+ * - `triggerRatio` 0.75 — condense once ~three-quarters of the window is used.
38
+ * - `keepRecent` 6000 — keep roughly the last 6k tokens of turns verbatim.
39
+ * - `reserveTokens` 2048 — carve a little headroom off the window first.
40
+ *
41
+ * Exported as {@link AUTO_CONDENSE_POLICY} so the conductor's token gate and the
42
+ * session runner's slice planner share **one** policy — the value the auto-path
43
+ * trigger ({@link isOverBudget}) compares against must equal the value the slice
44
+ * planner ({@link planSlice}) cuts with, or the gate and the cut disagree.
45
+ */
46
+ export declare const AUTO_CONDENSE_POLICY: BudgetPolicy;
33
47
  /**
34
48
  * Build a {@link Condenser} from a {@link CondenserDeps} bundle. The result plugs
35
49
  * straight into the conductor's `CondenseFn` seam.
@@ -12,4 +12,6 @@ export type { AgentMessage, BudgetPolicy, CompleteFn, CondensePlan, Condenser, C
12
12
  export { budgetLimit, estimateMessageTokens, estimateTokens, isOverBudget, planSlice, prefixTokens, } from "./budget/index.js";
13
13
  export { buildSummaryPrompt, CONDENSER_BRIEF, flattenTranscript, summarize, } from "./summarize/index.js";
14
14
  export type { SummarizeDeps } from "./summarize/index.js";
15
- export { condense, condenseScope, createCondenser } from "./condenser.js";
15
+ export { AUTO_CONDENSE_POLICY, condense, condenseScope, createCondenser } from "./condenser.js";
16
+ export { CLEARED_TOOL_RESULT, clearStaleToolResults, COMPACTABLE_TOOL_NAMES, } from "./microcompact.js";
17
+ export { rehydrateRecentReads, RESTORED_FILE_PREFIX } from "./rehydrate.js";
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Window-budget / microcompact — clear stale tool-result bodies in place.
3
+ *
4
+ * The cheapest token to reclaim is one that is already dead weight: the verbatim
5
+ * body of a tool result the model has long since acted on. Once an agent has
6
+ * read a file, run a search, or executed a command and moved several turns past
7
+ * it, the full body of that result rarely needs to stay in the window — the
8
+ * model's subsequent reasoning already captured what mattered. Yet those bodies
9
+ * (a 2,000-line `read`, a noisy `bash` log, a wide `grep`) dominate the token
10
+ * budget.
11
+ *
12
+ * **Microcompaction** runs *before* a full {@link condense}: it walks the
13
+ * transcript, keeps the last few tool results verbatim (the model may still be
14
+ * working with them), and replaces the body of every older compactable tool
15
+ * result with a short sentinel. This reclaims tokens for free — no model call,
16
+ * no summary round-trip — and often defers (or shrinks the input to) the real
17
+ * condense.
18
+ *
19
+ * Shape note (this rebuild): a tool result is its OWN top-level
20
+ * {@link ToolResultMessage} (`role: 'toolResult'`), not a block nested inside a
21
+ * user message. Clearing one therefore means replacing *that message's*
22
+ * `content` array with a single sentinel text block — never editing a sub-block
23
+ * of some other message. We only clear results whose owning assistant `toolCall`
24
+ * named a compactable tool, so structural/control results stay intact.
25
+ *
26
+ * Behavior-preserving by construction: when there is nothing to clear (no
27
+ * compactable results, or every one is within the keep window) the *same input
28
+ * reference* is returned, so a caller can cheaply detect a no-op.
29
+ */
30
+ import type { AgentMessage } from "./contract.js";
31
+ /**
32
+ * The placeholder spliced in where a stale tool-result body used to be. Kept
33
+ * short on purpose — the whole point is to reclaim the tokens the original body
34
+ * occupied — while still signalling to the model (and to a human reading the
35
+ * transcript) that real content was elided rather than lost.
36
+ */
37
+ export declare const CLEARED_TOOL_RESULT = "[Old tool result content cleared]";
38
+ /**
39
+ * The wire names of tools whose results are safe to clear once stale.
40
+ *
41
+ * These are the read-mostly / output-heavy tools whose bodies are reconstructable
42
+ * (re-read the file, re-run the search) and whose stale content the model has
43
+ * already digested. Control/state tools (todo, memory, task) are deliberately
44
+ * absent — their results can carry standing instructions the model still needs.
45
+ */
46
+ export declare const COMPACTABLE_TOOL_NAMES: ReadonlySet<string>;
47
+ /**
48
+ * Clear the bodies of stale compactable tool results, keeping the most recent
49
+ * `keepRecent` of them verbatim.
50
+ *
51
+ * Walks the transcript, identifies every `role:'toolResult'` message that
52
+ * belongs to a compactable tool call, keeps the last `keepRecent` (floored at 1
53
+ * — `slice(-0)` would keep everything), and replaces each older one's `content`
54
+ * with a single `{ type:'text', text: CLEARED_TOOL_RESULT }` block. Non-tool
55
+ * messages, control-tool results, and already-cleared results are left exactly
56
+ * as they were.
57
+ *
58
+ * Returns the **same input array reference** when nothing was cleared, so the
59
+ * caller can detect a no-op by identity. Otherwise returns a new array; cleared
60
+ * messages are fresh objects (the originals are not mutated).
61
+ *
62
+ * @param messages the active transcript, oldest-first
63
+ * @param opts.keepRecent how many most-recent compactable results to keep
64
+ * verbatim (default {@link DEFAULT_KEEP_RECENT}, floored at 1)
65
+ */
66
+ export declare function clearStaleToolResults(messages: AgentMessage[], opts?: {
67
+ keepRecent?: number;
68
+ }): AgentMessage[];
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Window-budget / microcompact + rehydrate — unit tests for item #18.
3
+ *
4
+ * Three layers ride the condense path:
5
+ * 1. microcompact ({@link clearStaleToolResults}) — blank older completed
6
+ * tool-result bodies to a sentinel, keeping the last N verbatim; no-op
7
+ * (same reference) otherwise.
8
+ * 2. rehydration ({@link rehydrateRecentReads}) — re-attach the most-recently
9
+ * dropped file reads as synthetic user messages, deduped against the kept
10
+ * tail, honoring maxFiles / tokenBudget.
11
+ * 3. circuit breaker — covered in the conductor suite (3 throwing condense
12
+ * calls stop further attempts, a success resets).
13
+ *
14
+ * Pure + network-free: no model is bound anywhere here.
15
+ */
16
+ export {};
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Window-budget / rehydrate — re-attach recently-read files after a condense.
3
+ *
4
+ * A full {@link condense} folds the dropped head of the transcript into one
5
+ * summary message. That digest captures *what happened*, but it necessarily
6
+ * loses the verbatim bodies of files the agent had just read — and those bodies
7
+ * are often exactly the working context the next turn needs (the file it was
8
+ * mid-edit on, the config it was reasoning about). Re-reading them costs a tool
9
+ * round-trip and, worse, the model may not realize it needs to.
10
+ *
11
+ * **Post-compact rehydration** softens that cliff: after the slice is dropped,
12
+ * it scans the *dropped* messages for `read` results, takes the most-recent
13
+ * handful that aren't already visible in the kept tail, and re-attaches their
14
+ * bodies as synthetic user messages ("[Restored file after compaction] …") under
15
+ * a token budget. The model keeps its working files without a re-read, while the
16
+ * older surrounding chatter still gets compressed away.
17
+ *
18
+ * Shape note (this rebuild): a read's *body* lives in its own top-level
19
+ * {@link ToolResultMessage} (`role:'toolResult'`), and the read's *path* lives in
20
+ * the owning assistant `toolCall.arguments.path` (the read tool's arg is `path`,
21
+ * not `file_path`). We pair each dropped `read` call with its result by
22
+ * `toolCallId`, dedup against paths still visible in the kept tail, and emit the
23
+ * most-recent survivors under a token cap.
24
+ *
25
+ * Behavior-preserving by construction: returns an empty array whenever there is
26
+ * nothing to restore (no dropped reads, all already visible, or the budget is
27
+ * exhausted), so the caller can splice the result unconditionally.
28
+ */
29
+ import type { AgentMessage } from "./contract.js";
30
+ /** Prefix marking a synthetic message that restores a file body post-compaction. */
31
+ export declare const RESTORED_FILE_PREFIX = "[Restored file after compaction]";
32
+ /**
33
+ * Build the synthetic user messages that re-attach the most-recently-read files
34
+ * dropped by a condense.
35
+ *
36
+ * Scans `dropped` for `read` calls + result bodies, drops any path still visible
37
+ * in `kept`, sorts the survivors most-recent-first, takes up to `maxFiles`, and
38
+ * emits each as a `user` message of the form
39
+ * `"[Restored file after compaction] <path>\n<body>"` — stopping once the running
40
+ * token estimate would exceed `tokenBudget`. The returned messages are ordered
41
+ * oldest-restored-first so they read naturally when spliced after the summary.
42
+ *
43
+ * Returns an **empty array** when nothing is restorable, so the caller can splice
44
+ * the result unconditionally (`[summary, ...restored, ...kept]`).
45
+ *
46
+ * @param dropped the condensed-away head slice (original bodies, pre-summary)
47
+ * @param kept the verbatim tail that survives the condense
48
+ * @param opts.maxFiles cap on restored files (default {@link DEFAULT_MAX_FILES})
49
+ * @param opts.tokenBudget token ceiling for the restored block (default {@link DEFAULT_TOKEN_BUDGET})
50
+ * @param opts.readToolName wire name of the read tool (default `"read"`)
51
+ */
52
+ export declare function rehydrateRecentReads(dropped: AgentMessage[], kept: AgentMessage[], opts?: {
53
+ maxFiles?: number;
54
+ tokenBudget?: number;
55
+ readToolName?: string;
56
+ }): AgentMessage[];
@@ -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.1.62";
26
+ export declare const VERSION = "0.2.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "indusagi-coding-agent",
3
- "version": "0.1.62",
3
+ "version": "0.2.0",
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",
@@ -46,7 +46,7 @@
46
46
  "@sinclair/typebox": "^0.34.49",
47
47
  "chalk": "^5.6.2",
48
48
  "highlight.js": "^11.11.1",
49
- "indusagi": "^0.12.34",
49
+ "indusagi": "^0.13.0",
50
50
  "ink": "^5.2.1",
51
51
  "jiti": "^2.7.0",
52
52
  "marked": "^18.0.4",