indusagi-coding-agent 0.2.8 → 0.2.10

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 (222) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/entry.js +4 -4
  3. package/dist/index.js +4 -4
  4. package/package.json +3 -2
  5. package/src/_decls/entry.ts +18 -0
  6. package/src/_decls/guardrails.ts +35 -0
  7. package/src/_decls/index.ts +26 -0
  8. package/src/addons/contract.ts +236 -0
  9. package/src/addons/dispatch/event-dispatcher.ts +164 -0
  10. package/src/addons/dispatch/index.ts +25 -0
  11. package/src/addons/dispatch/tool-interceptor.ts +208 -0
  12. package/src/addons/host.ts +225 -0
  13. package/src/addons/index.ts +112 -0
  14. package/src/addons/manifest.ts +158 -0
  15. package/src/addons/sandbox.ts +170 -0
  16. package/src/addons/surface.ts +78 -0
  17. package/src/boot/auth-vault.ts +195 -0
  18. package/src/boot/boot.ts +138 -0
  19. package/src/boot/contract.ts +238 -0
  20. package/src/boot/heap.ts +59 -0
  21. package/src/boot/index.ts +28 -0
  22. package/src/boot/invocation.ts +93 -0
  23. package/src/boot/runners/addon-wiring.ts +153 -0
  24. package/src/boot/runners/checkpoint.ts +169 -0
  25. package/src/boot/runners/delegate-runner.ts +294 -0
  26. package/src/boot/runners/index.ts +13 -0
  27. package/src/boot/runners/link-runner.ts +45 -0
  28. package/src/boot/runners/memdir.ts +168 -0
  29. package/src/boot/runners/oneshot-runner.ts +58 -0
  30. package/src/boot/runners/read-state.ts +90 -0
  31. package/src/boot/runners/registry.ts +42 -0
  32. package/src/boot/runners/repl-runner.ts +143 -0
  33. package/src/boot/runners/server-mode.ts +121 -0
  34. package/src/boot/runners/session.ts +641 -0
  35. package/src/boot/server-token.ts +148 -0
  36. package/src/boot/stages.ts +167 -0
  37. package/src/boot/upgrade/apply.ts +94 -0
  38. package/src/boot/upgrade/index.ts +13 -0
  39. package/src/boot/upgrade/upgrades.ts +289 -0
  40. package/src/briefing/compose.ts +150 -0
  41. package/src/briefing/context-docs.ts +19 -0
  42. package/src/briefing/contract.ts +717 -0
  43. package/src/briefing/index.ts +31 -0
  44. package/src/briefing/macros.ts +97 -0
  45. package/src/briefing/skills.ts +47 -0
  46. package/src/capability-deck/bridge-ledger/index.ts +27 -0
  47. package/src/capability-deck/bridge-ledger/key.ts +67 -0
  48. package/src/capability-deck/bridge-ledger/ledger.ts +131 -0
  49. package/src/capability-deck/bridge-ledger/network.ts +117 -0
  50. package/src/capability-deck/builtin-bridge.ts +312 -0
  51. package/src/capability-deck/cards/bg-process-card.ts +335 -0
  52. package/src/capability-deck/cards/index.ts +115 -0
  53. package/src/capability-deck/cards/memory-card.ts +146 -0
  54. package/src/capability-deck/cards/plan-file.ts +97 -0
  55. package/src/capability-deck/cards/plan-tools.ts +185 -0
  56. package/src/capability-deck/cards/saas-card.ts +183 -0
  57. package/src/capability-deck/cards/task-card.ts +207 -0
  58. package/src/capability-deck/cards/todo-card.ts +168 -0
  59. package/src/capability-deck/cards/workflow-card.ts +247 -0
  60. package/src/capability-deck/contract.ts +388 -0
  61. package/src/capability-deck/index.ts +48 -0
  62. package/src/capability-deck/manifest.ts +109 -0
  63. package/src/capability-deck/provision.ts +169 -0
  64. package/src/channels/contract.ts +191 -0
  65. package/src/channels/framer.ts +50 -0
  66. package/src/channels/index.ts +101 -0
  67. package/src/channels/link/dialog.ts +129 -0
  68. package/src/channels/link/driver.ts +190 -0
  69. package/src/channels/link/index.ts +34 -0
  70. package/src/channels/link/server.ts +134 -0
  71. package/src/channels/oneshot.ts +90 -0
  72. package/src/channels/ops.ts +65 -0
  73. package/src/channels/session-ops.ts +81 -0
  74. package/src/conductor/bash-guard.ts +599 -0
  75. package/src/conductor/catalog/catalog.ts +116 -0
  76. package/src/conductor/catalog/index.ts +8 -0
  77. package/src/conductor/catalog/matcher.ts +134 -0
  78. package/src/conductor/conductor.ts +234 -0
  79. package/src/conductor/contract.ts +842 -0
  80. package/src/conductor/diagnostics.ts +227 -0
  81. package/src/conductor/index.ts +33 -0
  82. package/src/conductor/permissions.ts +588 -0
  83. package/src/conductor/quota-error.ts +49 -0
  84. package/src/conductor/signal-hub/hub.ts +46 -0
  85. package/src/conductor/signal-hub/index.ts +2 -0
  86. package/src/conductor/signal-hub/translate.test.ts +81 -0
  87. package/src/conductor/signal-hub/translate.ts +74 -0
  88. package/src/conductor/skill-parse/index.ts +2 -0
  89. package/src/conductor/skill-parse/parse.ts +108 -0
  90. package/src/conductor/transcript-store/index.ts +22 -0
  91. package/src/conductor/transcript-store/serialize.ts +116 -0
  92. package/src/conductor/transcript-store/store.ts +205 -0
  93. package/src/console/auth-status.ts +56 -0
  94. package/src/console/components/AgentsView.ts +165 -0
  95. package/src/console/components/BackgroundAgents.ts +155 -0
  96. package/src/console/components/Banner.ts +334 -0
  97. package/src/console/components/Composer.ts +94 -0
  98. package/src/console/components/StatusBar.ts +49 -0
  99. package/src/console/components/TerminalConsole.ts +1090 -0
  100. package/src/console/components/WorkingIndicator.ts +98 -0
  101. package/src/console/components/banner-sweep.ts +24 -0
  102. package/src/console/components/welcome.ts +74 -0
  103. package/src/console/contract.ts +630 -0
  104. package/src/console/index.ts +34 -0
  105. package/src/console/input/complete.ts +127 -0
  106. package/src/console/input/dir-reader.ts +34 -0
  107. package/src/console/input/index.ts +23 -0
  108. package/src/console/input/keymap.ts +159 -0
  109. package/src/console/input/paste.ts +104 -0
  110. package/src/console/mount.ts +56 -0
  111. package/src/console/overlays/approval-queue.ts +57 -0
  112. package/src/console/overlays/approval.ts +130 -0
  113. package/src/console/overlays/auth.ts +342 -0
  114. package/src/console/overlays/boards.ts +308 -0
  115. package/src/console/overlays/host.ts +36 -0
  116. package/src/console/overlays/index.ts +26 -0
  117. package/src/console/overlays/pickers.ts +258 -0
  118. package/src/console/overlays/sessions.ts +190 -0
  119. package/src/console/reducer.ts +182 -0
  120. package/src/console/slash/builtins.ts +81 -0
  121. package/src/console/slash/commands/dynamic.ts +83 -0
  122. package/src/console/slash/commands/integrations.ts +695 -0
  123. package/src/console/slash/commands/shared.ts +75 -0
  124. package/src/console/slash/commands/transcript.ts +263 -0
  125. package/src/console/slash/commands/workbench.ts +246 -0
  126. package/src/console/slash/index.ts +15 -0
  127. package/src/console/slash/registry.ts +70 -0
  128. package/src/console/slash/resolve.ts +63 -0
  129. package/src/console/startup.ts +209 -0
  130. package/src/console/theme/adapter.ts +45 -0
  131. package/src/console/theme/index.ts +7 -0
  132. package/src/console/theme/palette.ts +68 -0
  133. package/src/console/theme/resolve.ts +39 -0
  134. package/src/console/theme/tokens.ts +71 -0
  135. package/src/entry.ts +55 -0
  136. package/src/guardrails.ts +37 -0
  137. package/src/index.ts +18 -0
  138. package/src/insight/channel.ts +88 -0
  139. package/src/insight/contract.ts +185 -0
  140. package/src/insight/index.ts +110 -0
  141. package/src/insight/recorder.ts +213 -0
  142. package/src/insight/redaction.ts +157 -0
  143. package/src/insight/replay.ts +158 -0
  144. package/src/insight/sampling.ts +70 -0
  145. package/src/insight/serialize.ts +50 -0
  146. package/src/insight/sinks/console.ts +64 -0
  147. package/src/insight/sinks/file.ts +40 -0
  148. package/src/insight/sinks/index.ts +24 -0
  149. package/src/insight/sinks/stream.ts +54 -0
  150. package/src/integrations/sarvam/attach.ts +239 -0
  151. package/src/integrations/sarvam/config.ts +156 -0
  152. package/src/integrations/sarvam/index.ts +25 -0
  153. package/src/integrations/sarvam/sarvam.test.ts +60 -0
  154. package/src/integrations/sarvam/types.ts +27 -0
  155. package/src/integrations/zoho/attach.ts +342 -0
  156. package/src/integrations/zoho/config.ts +125 -0
  157. package/src/integrations/zoho/index.ts +27 -0
  158. package/src/integrations/zoho/types.ts +21 -0
  159. package/src/integrations/zoho/zoho.test.ts +50 -0
  160. package/src/kit/clipboard-image.ts +107 -0
  161. package/src/kit/external-editor.ts +48 -0
  162. package/src/kit/image.ts +59 -0
  163. package/src/kit/index.ts +51 -0
  164. package/src/kit/shell.ts +19 -0
  165. package/src/kit/tool-fetch.ts +85 -0
  166. package/src/launch/catalog.ts +148 -0
  167. package/src/launch/contract.ts +187 -0
  168. package/src/launch/credentials.ts +625 -0
  169. package/src/launch/index.ts +98 -0
  170. package/src/launch/invocation/attachments.ts +179 -0
  171. package/src/launch/invocation/flags.ts +196 -0
  172. package/src/launch/invocation/index.ts +25 -0
  173. package/src/launch/invocation/read.ts +260 -0
  174. package/src/launch/invocation/usage.ts +67 -0
  175. package/src/launch/login.ts +324 -0
  176. package/src/launch/oauth.test.ts +18 -0
  177. package/src/launch/oauth.ts +203 -0
  178. package/src/launch/packages.ts +194 -0
  179. package/src/launch/pickers.ts +189 -0
  180. package/src/runtime-bridge/bridges/_drive.ts +96 -0
  181. package/src/runtime-bridge/bridges/builtins.ts +68 -0
  182. package/src/runtime-bridge/bridges/claude-cli.ts +123 -0
  183. package/src/runtime-bridge/bridges/codex-cli.ts +142 -0
  184. package/src/runtime-bridge/bridges/index.ts +33 -0
  185. package/src/runtime-bridge/bridges/indusagi-cli.ts +155 -0
  186. package/src/runtime-bridge/broker.ts +227 -0
  187. package/src/runtime-bridge/contract.ts +122 -0
  188. package/src/runtime-bridge/index.ts +79 -0
  189. package/src/runtime-bridge/sink.ts +180 -0
  190. package/src/sessions/contract.ts +81 -0
  191. package/src/sessions/index.ts +13 -0
  192. package/src/sessions/library.ts +229 -0
  193. package/src/settings/contract.ts +114 -0
  194. package/src/settings/index.ts +32 -0
  195. package/src/settings/manager.ts +117 -0
  196. package/src/transcript-export/index.ts +45 -0
  197. package/src/transcript-export/publish.ts +260 -0
  198. package/src/transcript-export/sgr.ts +315 -0
  199. package/src/transcript-export/template.ts +272 -0
  200. package/src/transcript-export/theme-bridge.ts +150 -0
  201. package/src/window-budget/budget/estimate.ts +135 -0
  202. package/src/window-budget/budget/gate.ts +33 -0
  203. package/src/window-budget/budget/index.ts +16 -0
  204. package/src/window-budget/budget/slice.ts +56 -0
  205. package/src/window-budget/condenser.ts +58 -0
  206. package/src/window-budget/contract.ts +184 -0
  207. package/src/window-budget/index.ts +19 -0
  208. package/src/window-budget/microcompact.ts +95 -0
  209. package/src/window-budget/rehydrate.ts +136 -0
  210. package/src/window-budget/summarize/condense.ts +103 -0
  211. package/src/window-budget/summarize/index.ts +14 -0
  212. package/src/window-budget/summarize/prompt.ts +149 -0
  213. package/src/workflow-engine/agent-runner.ts +181 -0
  214. package/src/workflow-engine/display.ts +224 -0
  215. package/src/workflow-engine/engine.ts +294 -0
  216. package/src/workflow-engine/index.ts +23 -0
  217. package/src/workflow-engine/parse.ts +172 -0
  218. package/src/workflow-engine/structured-output.ts +35 -0
  219. package/src/workspace/brand.ts +29 -0
  220. package/src/workspace/index.ts +18 -0
  221. package/src/workspace/locator.ts +103 -0
  222. package/src/workspace/runtime-detect.ts +64 -0
@@ -0,0 +1,48 @@
1
+ /**
2
+ * External-editor kit — hand the composer buffer off to the user's `$EDITOR`,
3
+ * wait for them to close it, and read the edited text back.
4
+ */
5
+ import { spawnSync } from "node:child_process";
6
+ import { readFileSync, unlinkSync, writeFileSync } from "node:fs";
7
+ import { tmpdir } from "node:os";
8
+ import { join } from "node:path";
9
+
10
+ const FALLBACK_EDITOR = "vi";
11
+
12
+ export interface ExternalEditorOptions {
13
+ readonly env?: NodeJS.ProcessEnv;
14
+ readonly dir?: string;
15
+ }
16
+
17
+ function resolveEditor(env: NodeJS.ProcessEnv): string[] {
18
+ const configured = env.VISUAL || env.EDITOR || FALLBACK_EDITOR;
19
+ const parts = configured.split(/\s+/).filter((part) => part.length > 0);
20
+ return parts.length > 0 ? parts : [FALLBACK_EDITOR];
21
+ }
22
+
23
+ export function openInExternalEditor(
24
+ buffer: string,
25
+ options: ExternalEditorOptions = {},
26
+ ): string | null {
27
+ const env = options.env ?? process.env;
28
+ const dir = options.dir ?? tmpdir();
29
+ const name = `indus-editor-${Date.now().toString(36)}-${Math.random()
30
+ .toString(36)
31
+ .slice(2, 8)}.md`;
32
+ const path = join(dir, name);
33
+ const [editor, ...editorArgs] = resolveEditor(env);
34
+ try {
35
+ writeFileSync(path, buffer, "utf8");
36
+ const result = spawnSync(editor, [...editorArgs, path], { stdio: "inherit" });
37
+ if (result.error || result.status !== 0) return null;
38
+ return readFileSync(path, "utf8").replace(/\n$/, "");
39
+ } catch {
40
+ return null;
41
+ } finally {
42
+ try {
43
+ unlinkSync(path);
44
+ } catch {
45
+ /* ignore cleanup errors */
46
+ }
47
+ }
48
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Image kit — magic-byte sniffing for the two raster formats the agent ships
3
+ * support for, plus a tiny asset-naming helper.
4
+ */
5
+
6
+ export type ImageFormat = "png" | "jpeg";
7
+ export type ImageMediaType = "image/png" | "image/jpeg";
8
+
9
+ const PNG_SIGNATURE: readonly number[] = [137, 80, 78, 71, 13, 10, 26, 10];
10
+ const JPEG_SIGNATURE: readonly number[] = [255, 216, 255];
11
+
12
+ export const IMAGE_SNIFF_BYTES: number = PNG_SIGNATURE.length;
13
+
14
+ export type ByteSource = ArrayLike<number>;
15
+
16
+ function startsWith(bytes: ArrayLike<number>, signature: readonly number[]): boolean {
17
+ if (bytes.length < signature.length) return false;
18
+ for (let index = 0; index < signature.length; index += 1) {
19
+ if (bytes[index] !== signature[index]) return false;
20
+ }
21
+ return true;
22
+ }
23
+
24
+ export function sniffImageFormat(bytes: ByteSource): ImageFormat | null {
25
+ if (startsWith(bytes, PNG_SIGNATURE)) return "png";
26
+ if (startsWith(bytes, JPEG_SIGNATURE)) return "jpeg";
27
+ return null;
28
+ }
29
+
30
+ export function mediaTypeForImageFormat(format: ImageFormat): ImageMediaType {
31
+ return format === "png" ? "image/png" : "image/jpeg";
32
+ }
33
+
34
+ export function detectImageMediaType(bytes: ByteSource): ImageMediaType | null {
35
+ const format = sniffImageFormat(bytes);
36
+ return format === null ? null : mediaTypeForImageFormat(format);
37
+ }
38
+
39
+ export function isSupportedImage(bytes: ByteSource): boolean {
40
+ return sniffImageFormat(bytes) !== null;
41
+ }
42
+
43
+ export interface AssetNameContext {
44
+ readonly platform?: string;
45
+ readonly arch?: string;
46
+ readonly version?: string;
47
+ readonly name?: string;
48
+ }
49
+
50
+ const ASSET_TOKENS = ["platform", "arch", "version", "name"];
51
+
52
+ export function resolveAssetName(template: string, context: AssetNameContext): string {
53
+ let rendered = template;
54
+ for (const token of ASSET_TOKENS) {
55
+ const value = context[token as keyof AssetNameContext] ?? "";
56
+ rendered = rendered.split(`{${token}}`).join(value);
57
+ }
58
+ return rendered;
59
+ }
@@ -0,0 +1,51 @@
1
+ // @ts-nocheck
2
+ // Type declarations recovered from dist/types (no runtime body)
3
+ /**
4
+ * Kit subsystem — public barrel.
5
+ *
6
+ * `kit/` holds the agent's framework-agnostic leaf helpers: small, pure, Node-
7
+ * builtin-only utilities with no dependency on the framework or on any sibling
8
+ * subsystem. It re-exports three groups:
9
+ *
10
+ * - **tool-fetch** — the managed-binary provisioner stub (fd / rg): managed
11
+ * path resolution, regex-driven release-asset selection, and a download-
12
+ * request builder stamped with this kit's own {@link KIT_USER_AGENT}. The
13
+ * network is injected, never imported.
14
+ * - **image** — PNG / JPEG magic-byte sniffing (interface-dictated
15
+ * signatures) and the `{token}` asset-name renderer.
16
+ * - **shell** — POSIX shell-argument quoting and command assembly.
17
+ *
18
+ * Consumers import from `src/kit` rather than reaching into individual modules.
19
+ * The upstream filler libraries (generic array / string / date / json / etc.
20
+ * stdlib clones) are intentionally omitted: they had zero consumers, so they
21
+ * are not rebuilt here.
22
+ */
23
+ export type {
24
+ ToolDescriptor,
25
+ ReleaseAsset,
26
+ ReleaseInfo,
27
+ ReleaseLookup,
28
+ DownloadRequest,
29
+ ProvisionPlan,
30
+ } from "./tool-fetch.js";
31
+ export {
32
+ KIT_USER_AGENT,
33
+ resolveManagedBinaryPath,
34
+ pickReleaseAsset,
35
+ buildDownloadRequest,
36
+ planProvision,
37
+ } from "./tool-fetch.js";
38
+ export type { ImageFormat, ImageMediaType, ByteSource, AssetNameContext } from "./image.js";
39
+ export {
40
+ IMAGE_SNIFF_BYTES,
41
+ sniffImageFormat,
42
+ mediaTypeForImageFormat,
43
+ detectImageMediaType,
44
+ isSupportedImage,
45
+ resolveAssetName,
46
+ } from "./image.js";
47
+ export { quoteArg, needsQuoting, buildShellCommand } from "./shell.js";
48
+ export type { ClipboardImageOptions } from "./clipboard-image.js";
49
+ export { readClipboardImage } from "./clipboard-image.js";
50
+ export type { ExternalEditorOptions } from "./external-editor.js";
51
+ export { openInExternalEditor } from "./external-editor.js";
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Shell kit — POSIX shell-argument quoting and command assembly.
3
+ */
4
+
5
+ const SHELL_SAFE = /^[A-Za-z0-9_@%+=:,./-]+$/;
6
+
7
+ export function quoteArg(arg: string): string {
8
+ if (arg.length === 0) return "''";
9
+ if (SHELL_SAFE.test(arg)) return arg;
10
+ return `'${arg.split("'").join("'\\''")}'`;
11
+ }
12
+
13
+ export function needsQuoting(arg: string): boolean {
14
+ return arg.length === 0 || !SHELL_SAFE.test(arg);
15
+ }
16
+
17
+ export function buildShellCommand(args: readonly string[]): string {
18
+ return args.map(quoteArg).join(" ");
19
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Tool-fetch kit — a managed-binary provisioner stub for the native helpers the
3
+ * agent shells out to (a fast file finder and a fast content grep, fd / rg).
4
+ */
5
+ import { join } from "node:path";
6
+
7
+ export const KIT_USER_AGENT = "indusagi-kit-provisioner/1.0";
8
+
9
+ export interface ToolDescriptor {
10
+ readonly bin: string;
11
+ readonly repo: string;
12
+ readonly assetMatcher: RegExp;
13
+ }
14
+
15
+ export function resolveManagedBinaryPath(
16
+ binDir: string,
17
+ bin: string,
18
+ platform: NodeJS.Platform = process.platform,
19
+ ): string {
20
+ const fileName = platform === "win32" ? `${bin}.exe` : bin;
21
+ return join(binDir, fileName);
22
+ }
23
+
24
+ export interface ReleaseAsset {
25
+ readonly name: string;
26
+ readonly url: string;
27
+ }
28
+
29
+ export interface ReleaseInfo {
30
+ readonly tag: string;
31
+ readonly assets: readonly ReleaseAsset[];
32
+ }
33
+
34
+ export type ReleaseLookup = (repo: string) => Promise<ReleaseInfo>;
35
+
36
+ export function pickReleaseAsset(
37
+ descriptor: ToolDescriptor,
38
+ release: ReleaseInfo,
39
+ ): ReleaseAsset | null {
40
+ for (const asset of release.assets) {
41
+ if (descriptor.assetMatcher.test(asset.name)) return asset;
42
+ }
43
+ return null;
44
+ }
45
+
46
+ export interface DownloadRequest {
47
+ readonly url: string;
48
+ readonly assetName: string;
49
+ readonly headers: Readonly<Record<string, string>>;
50
+ }
51
+
52
+ export function buildDownloadRequest(asset: ReleaseAsset): DownloadRequest {
53
+ return {
54
+ url: asset.url,
55
+ assetName: asset.name,
56
+ headers: {
57
+ "User-Agent": KIT_USER_AGENT,
58
+ Accept: "application/octet-stream",
59
+ },
60
+ };
61
+ }
62
+
63
+ export interface ProvisionPlan {
64
+ readonly bin: string;
65
+ readonly targetPath: string;
66
+ readonly tag: string;
67
+ readonly download: DownloadRequest;
68
+ }
69
+
70
+ export async function planProvision(
71
+ descriptor: ToolDescriptor,
72
+ binDir: string,
73
+ lookup: ReleaseLookup,
74
+ platform: NodeJS.Platform = process.platform,
75
+ ): Promise<ProvisionPlan | null> {
76
+ const release = await lookup(descriptor.repo);
77
+ const asset = pickReleaseAsset(descriptor, release);
78
+ if (asset === null) return null;
79
+ return {
80
+ bin: descriptor.bin,
81
+ targetPath: resolveManagedBinaryPath(binDir, descriptor.bin, platform),
82
+ tag: release.tag,
83
+ download: buildDownloadRequest(asset),
84
+ };
85
+ }
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Model catalog printer — `printModelCatalog`.
3
+ */
4
+ import { ModelRegistry, type KnownProvider, type Model } from "indusagi/ai";
5
+ import type { CatalogFilter } from "./contract.js";
6
+
7
+ export interface CatalogIo {
8
+ print(line: string): void;
9
+ }
10
+
11
+ export function defaultCatalogIo(): CatalogIo {
12
+ return {
13
+ print(line: string): void {
14
+ process.stdout.write(line.endsWith("\n") ? line : `${line}\n`);
15
+ },
16
+ };
17
+ }
18
+
19
+ export interface CatalogModelSource {
20
+ providers(): readonly (KnownProvider | string)[];
21
+ models(provider: string): readonly Model<Model<string>["api"]>[];
22
+ }
23
+
24
+ export function registrySource(registry: ModelRegistry = new ModelRegistry()): CatalogModelSource {
25
+ return {
26
+ providers: (): readonly (KnownProvider | string)[] => registry.getProviders(),
27
+ models: (provider: string): readonly Model<Model<string>["api"]>[] =>
28
+ registry.getModels(provider),
29
+ };
30
+ }
31
+
32
+ interface CatalogRow {
33
+ provider: string;
34
+ modelId: string;
35
+ contextWindow: number;
36
+ maxOutput: number;
37
+ thinking: boolean;
38
+ images: boolean;
39
+ }
40
+
41
+ const HEADERS = [
42
+ "Provider",
43
+ "Model",
44
+ "Context",
45
+ "Max Output",
46
+ "Thinking",
47
+ "Images",
48
+ ];
49
+
50
+ function toRow(model: Model<Model<string>["api"]>): CatalogRow {
51
+ const inputs = Array.isArray(model.input) ? model.input : [];
52
+ return {
53
+ provider: String(model.provider),
54
+ modelId: model.id,
55
+ contextWindow: typeof model.contextWindow === "number" ? model.contextWindow : 0,
56
+ maxOutput: typeof model.maxTokens === "number" ? model.maxTokens : 0,
57
+ thinking: model.reasoning === true,
58
+ images: inputs.includes("image"),
59
+ };
60
+ }
61
+
62
+ function filterRows(rows: readonly CatalogRow[], filter: CatalogFilter): CatalogRow[] {
63
+ const providerNeedle =
64
+ filter.provider !== undefined ? String(filter.provider).toLowerCase() : undefined;
65
+ const searchNeedle = filter.search?.trim().toLowerCase();
66
+ return rows.filter((row) => {
67
+ if (providerNeedle !== undefined && row.provider.toLowerCase() !== providerNeedle) {
68
+ return false;
69
+ }
70
+ if (filter.thinkingOnly === true && !row.thinking) return false;
71
+ if (filter.imagesOnly === true && !row.images) return false;
72
+ if (searchNeedle !== undefined && searchNeedle.length > 0) {
73
+ const haystack = `${row.provider}/${row.modelId}`.toLowerCase();
74
+ if (!haystack.includes(searchNeedle)) return false;
75
+ }
76
+ return true;
77
+ });
78
+ }
79
+
80
+ function sortRows(rows: readonly CatalogRow[]): CatalogRow[] {
81
+ return [...rows].sort((a, b) => {
82
+ if (a.provider !== b.provider) return a.provider < b.provider ? -1 : 1;
83
+ if (a.modelId !== b.modelId) return a.modelId < b.modelId ? -1 : 1;
84
+ return 0;
85
+ });
86
+ }
87
+
88
+ function formatTokenCount(tokens: number): string {
89
+ if (tokens <= 0) return "-";
90
+ if (tokens >= 1e6) {
91
+ const millions = tokens / 1e6;
92
+ return `${millions % 1 === 0 ? millions.toFixed(0) : millions.toFixed(1)}M`;
93
+ }
94
+ if (tokens >= 1e3) return `${Math.round(tokens / 1e3)}K`;
95
+ return String(tokens);
96
+ }
97
+
98
+ function cells(row: CatalogRow): string[] {
99
+ return [
100
+ row.provider,
101
+ row.modelId,
102
+ formatTokenCount(row.contextWindow),
103
+ formatTokenCount(row.maxOutput),
104
+ row.thinking ? "yes" : "no",
105
+ row.images ? "yes" : "no",
106
+ ];
107
+ }
108
+
109
+ function pad(value: string, width: number): string {
110
+ return value.length >= width ? value : `${value}${" ".repeat(width - value.length)}`;
111
+ }
112
+
113
+ function layout(rows: readonly CatalogRow[]): string[] {
114
+ const body = rows.map(cells);
115
+ const widths = HEADERS.map(
116
+ (header, col) => body.reduce((max, row) => Math.max(max, row[col].length), header.length),
117
+ );
118
+ const render = (row: string[]): string =>
119
+ row.map((cell, col) => pad(cell, widths[col])).join(" ").trimEnd();
120
+ const rule = widths.map((width) => "-".repeat(width)).join(" ");
121
+ return [render(HEADERS), rule, ...body.map(render)];
122
+ }
123
+
124
+ /**
125
+ * Print the model catalog table.
126
+ */
127
+ export function printModelCatalog(
128
+ io: CatalogIo = defaultCatalogIo(),
129
+ filter: CatalogFilter = {},
130
+ source: CatalogModelSource = registrySource(),
131
+ ): void {
132
+ const all: CatalogRow[] = [];
133
+ for (const provider of source.providers()) {
134
+ let models: readonly Model<Model<string>["api"]>[];
135
+ try {
136
+ models = source.models(String(provider));
137
+ } catch {
138
+ continue;
139
+ }
140
+ for (const model of models) all.push(toRow(model));
141
+ }
142
+ const selected = sortRows(filterRows(all, filter));
143
+ if (selected.length === 0) {
144
+ io.print("No models match the given filter.");
145
+ return;
146
+ }
147
+ for (const line of layout(selected)) io.print(line);
148
+ }
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Launch contract — the FROZEN type surface of Phase 10 (command-line surface).
3
+ *
4
+ * This module is the single typed seam between a raw `argv` and a fully
5
+ * configured run. It owns the *application* command line: the declarative flag
6
+ * table, the parsed {@link Invocation} those flags fold into, the gathered
7
+ * `@file` {@link Attachments}, and the typed {@link CredentialFault} the
8
+ * api-key sign-in surface raises.
9
+ */
10
+ import type { SessionInfo as ResumeRef, SessionListProgress, ThinkingLevel } from "indusagi/agent";
11
+ import type { ImageContent, KnownProvider, ModelRegistry, OAuthCredentials } from "indusagi/ai";
12
+ import type { Settings } from "indusagi/shell-app";
13
+ import type { RunnerId } from "../boot/contract.js";
14
+
15
+ export type {
16
+ ResumeRef,
17
+ ThinkingLevel,
18
+ SessionListProgress,
19
+ ImageContent,
20
+ KnownProvider,
21
+ ModelRegistry,
22
+ OAuthCredentials,
23
+ Settings,
24
+ RunnerId,
25
+ };
26
+
27
+ export type OutputMode = "text" | "json" | "rpc";
28
+
29
+ export const THINKING_EFFORTS = [
30
+ "off",
31
+ "minimal",
32
+ "low",
33
+ "medium",
34
+ "high",
35
+ "xhigh",
36
+ ] as const;
37
+
38
+ export type ThinkingEffort = (typeof THINKING_EFFORTS)[number];
39
+
40
+ export function isThinkingEffort(value: string): value is ThinkingEffort {
41
+ return (THINKING_EFFORTS as readonly string[]).includes(value);
42
+ }
43
+
44
+ export function isOutputMode(value: string): value is OutputMode {
45
+ return value === "text" || value === "json" || value === "rpc";
46
+ }
47
+
48
+ export const TOOL_NAMES = [
49
+ "read",
50
+ "write",
51
+ "edit",
52
+ "bash",
53
+ "grep",
54
+ "find",
55
+ "ls",
56
+ "task",
57
+ "todo_read",
58
+ "todo_write",
59
+ "web_fetch",
60
+ "web_search",
61
+ "composio",
62
+ ] as const;
63
+
64
+ export type ToolName = (typeof TOOL_NAMES)[number];
65
+
66
+ export function isToolName(value: string): value is ToolName {
67
+ return (TOOL_NAMES as readonly string[]).includes(value);
68
+ }
69
+
70
+ export type FlagKind = "boolean" | "string" | "number" | "list";
71
+
72
+ export type FlagDefault = boolean | string | number | readonly string[];
73
+
74
+ export interface FlagSpec {
75
+ readonly name: string;
76
+ readonly aliases?: readonly string[];
77
+ readonly kind: FlagKind;
78
+ readonly describe: string;
79
+ readonly default?: FlagDefault;
80
+ }
81
+
82
+ export interface Invocation {
83
+ readonly mode: OutputMode;
84
+ readonly prompt?: string;
85
+ readonly flags: Record<string, FlagValue>;
86
+ readonly positionals: string[];
87
+ readonly attachments?: Attachments;
88
+ readonly model?: string;
89
+ readonly fallbackModel?: string;
90
+ readonly account?: string;
91
+ readonly cwd?: string;
92
+ readonly system?: string;
93
+ readonly appendSystem?: string;
94
+ readonly thinking?: ThinkingEffort;
95
+ readonly tools?: ToolName[];
96
+ readonly noTools: boolean;
97
+ readonly mcp: string[];
98
+ readonly print: boolean;
99
+ readonly interactive: boolean;
100
+ readonly help: boolean;
101
+ readonly version: boolean;
102
+ }
103
+
104
+ export type FlagValue = boolean | string | number | string[];
105
+
106
+ export interface Attachments {
107
+ readonly prose: string;
108
+ readonly media: ImageContent[];
109
+ }
110
+
111
+ export interface AttachmentOptions {
112
+ readonly cwd: string;
113
+ }
114
+
115
+ export type CredentialVerb = "signin" | "signout";
116
+
117
+ export interface ProviderEntry {
118
+ readonly id: KnownProvider | string;
119
+ readonly label: string;
120
+ readonly envKey: string;
121
+ readonly docsUrl: string;
122
+ }
123
+
124
+ export type CredentialFaultKind =
125
+ | "unknown-provider"
126
+ | "invalid-key"
127
+ | "invalid-account"
128
+ | "name-collision"
129
+ | "not-found"
130
+ | "vault"
131
+ | "aborted";
132
+
133
+ export interface CredentialFault {
134
+ readonly kind: CredentialFaultKind;
135
+ readonly message: string;
136
+ readonly hint?: string;
137
+ readonly cause?: unknown;
138
+ }
139
+
140
+ export function credentialFault(
141
+ kind: CredentialFaultKind,
142
+ message: string,
143
+ extra?: { hint?: string; cause?: unknown },
144
+ ): CredentialFault {
145
+ return {
146
+ kind,
147
+ message,
148
+ ...(extra?.hint !== undefined ? { hint: extra.hint } : {}),
149
+ ...(extra?.cause !== undefined ? { cause: extra.cause } : {}),
150
+ };
151
+ }
152
+
153
+ export interface AuthVault {
154
+ listAccounts(provider: string): Promise<string[]>;
155
+ defaultAccount(provider: string): Promise<string | undefined>;
156
+ putApiKey(provider: string, account: string, apiKey: string, makeDefault?: boolean): Promise<void>;
157
+ putOAuth(provider: string, account: string, credentials: OAuthCredentials, makeDefault?: boolean): Promise<void>;
158
+ authKind(provider: string, account: string): Promise<"apiKey" | "oauth" | undefined>;
159
+ readUsableKey(provider: string, account: string): Promise<string | undefined>;
160
+ remove(provider: string, account?: string): Promise<boolean>;
161
+ }
162
+
163
+ export interface CredentialCommandOptions {
164
+ readonly vault: AuthVault;
165
+ readonly profileDir: string;
166
+ }
167
+
168
+ export interface CatalogFilter {
169
+ readonly provider?: KnownProvider | string;
170
+ readonly thinkingOnly?: boolean;
171
+ readonly imagesOnly?: boolean;
172
+ readonly search?: string;
173
+ }
174
+
175
+ export type SessionLoader = (onProgress?: SessionListProgress) => Promise<ResumeRef[]>;
176
+
177
+ export interface ResumeFault {
178
+ readonly message: string;
179
+ readonly cause?: unknown;
180
+ }
181
+
182
+ export interface SettingsBrowseOptions {
183
+ readonly settings: Settings;
184
+ readonly resolvedPaths: Readonly<Record<string, readonly string[]>>;
185
+ readonly cwd: string;
186
+ readonly profileDir: string;
187
+ }