indusagi-coding-agent 0.2.8 → 0.2.9
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 -1
- package/src/_decls/entry.ts +18 -0
- package/src/_decls/guardrails.ts +35 -0
- package/src/_decls/index.ts +26 -0
- package/src/addons/contract.ts +236 -0
- package/src/addons/dispatch/event-dispatcher.ts +164 -0
- package/src/addons/dispatch/index.ts +25 -0
- package/src/addons/dispatch/tool-interceptor.ts +208 -0
- package/src/addons/host.ts +225 -0
- package/src/addons/index.ts +112 -0
- package/src/addons/manifest.ts +158 -0
- package/src/addons/sandbox.ts +170 -0
- package/src/addons/surface.ts +78 -0
- package/src/boot/auth-vault.ts +195 -0
- package/src/boot/boot.ts +138 -0
- package/src/boot/contract.ts +238 -0
- package/src/boot/heap.ts +59 -0
- package/src/boot/index.ts +28 -0
- package/src/boot/invocation.ts +93 -0
- package/src/boot/runners/addon-wiring.ts +153 -0
- package/src/boot/runners/checkpoint.ts +169 -0
- package/src/boot/runners/delegate-runner.ts +294 -0
- package/src/boot/runners/index.ts +13 -0
- package/src/boot/runners/link-runner.ts +45 -0
- package/src/boot/runners/memdir.ts +168 -0
- package/src/boot/runners/oneshot-runner.ts +58 -0
- package/src/boot/runners/read-state.ts +90 -0
- package/src/boot/runners/registry.ts +42 -0
- package/src/boot/runners/repl-runner.ts +143 -0
- package/src/boot/runners/server-mode.ts +121 -0
- package/src/boot/runners/session.ts +641 -0
- package/src/boot/server-token.ts +148 -0
- package/src/boot/stages.ts +167 -0
- package/src/boot/upgrade/apply.ts +94 -0
- package/src/boot/upgrade/index.ts +13 -0
- package/src/boot/upgrade/upgrades.ts +289 -0
- package/src/briefing/compose.ts +150 -0
- package/src/briefing/context-docs.ts +19 -0
- package/src/briefing/contract.ts +717 -0
- package/src/briefing/index.ts +31 -0
- package/src/briefing/macros.ts +97 -0
- package/src/briefing/skills.ts +47 -0
- package/src/capability-deck/bridge-ledger/index.ts +27 -0
- package/src/capability-deck/bridge-ledger/key.ts +67 -0
- package/src/capability-deck/bridge-ledger/ledger.ts +131 -0
- package/src/capability-deck/bridge-ledger/network.ts +117 -0
- package/src/capability-deck/builtin-bridge.ts +312 -0
- package/src/capability-deck/cards/bg-process-card.ts +335 -0
- package/src/capability-deck/cards/index.ts +115 -0
- package/src/capability-deck/cards/memory-card.ts +146 -0
- package/src/capability-deck/cards/plan-file.ts +97 -0
- package/src/capability-deck/cards/plan-tools.ts +185 -0
- package/src/capability-deck/cards/saas-card.ts +183 -0
- package/src/capability-deck/cards/task-card.ts +207 -0
- package/src/capability-deck/cards/todo-card.ts +168 -0
- package/src/capability-deck/cards/workflow-card.ts +247 -0
- package/src/capability-deck/contract.ts +388 -0
- package/src/capability-deck/index.ts +48 -0
- package/src/capability-deck/manifest.ts +109 -0
- package/src/capability-deck/provision.ts +169 -0
- package/src/channels/contract.ts +191 -0
- package/src/channels/framer.ts +50 -0
- package/src/channels/index.ts +101 -0
- package/src/channels/link/dialog.ts +129 -0
- package/src/channels/link/driver.ts +190 -0
- package/src/channels/link/index.ts +34 -0
- package/src/channels/link/server.ts +134 -0
- package/src/channels/oneshot.ts +90 -0
- package/src/channels/ops.ts +65 -0
- package/src/channels/session-ops.ts +81 -0
- package/src/conductor/bash-guard.ts +599 -0
- package/src/conductor/catalog/catalog.ts +116 -0
- package/src/conductor/catalog/index.ts +8 -0
- package/src/conductor/catalog/matcher.ts +134 -0
- package/src/conductor/conductor.ts +234 -0
- package/src/conductor/contract.ts +842 -0
- package/src/conductor/diagnostics.ts +227 -0
- package/src/conductor/index.ts +33 -0
- package/src/conductor/permissions.ts +588 -0
- package/src/conductor/quota-error.ts +49 -0
- package/src/conductor/signal-hub/hub.ts +46 -0
- package/src/conductor/signal-hub/index.ts +2 -0
- package/src/conductor/signal-hub/translate.test.ts +81 -0
- package/src/conductor/signal-hub/translate.ts +74 -0
- package/src/conductor/skill-parse/index.ts +2 -0
- package/src/conductor/skill-parse/parse.ts +108 -0
- package/src/conductor/transcript-store/index.ts +22 -0
- package/src/conductor/transcript-store/serialize.ts +116 -0
- package/src/conductor/transcript-store/store.ts +205 -0
- package/src/console/auth-status.ts +56 -0
- package/src/console/components/AgentsView.ts +165 -0
- package/src/console/components/BackgroundAgents.ts +155 -0
- package/src/console/components/Banner.ts +334 -0
- package/src/console/components/Composer.ts +94 -0
- package/src/console/components/StatusBar.ts +49 -0
- package/src/console/components/TerminalConsole.ts +1090 -0
- package/src/console/components/WorkingIndicator.ts +98 -0
- package/src/console/components/banner-sweep.ts +24 -0
- package/src/console/components/welcome.ts +74 -0
- package/src/console/contract.ts +630 -0
- package/src/console/index.ts +34 -0
- package/src/console/input/complete.ts +127 -0
- package/src/console/input/dir-reader.ts +34 -0
- package/src/console/input/index.ts +23 -0
- package/src/console/input/keymap.ts +159 -0
- package/src/console/input/paste.ts +104 -0
- package/src/console/mount.ts +56 -0
- package/src/console/overlays/approval-queue.ts +57 -0
- package/src/console/overlays/approval.ts +130 -0
- package/src/console/overlays/auth.ts +342 -0
- package/src/console/overlays/boards.ts +308 -0
- package/src/console/overlays/host.ts +36 -0
- package/src/console/overlays/index.ts +26 -0
- package/src/console/overlays/pickers.ts +258 -0
- package/src/console/overlays/sessions.ts +190 -0
- package/src/console/reducer.ts +182 -0
- package/src/console/slash/builtins.ts +81 -0
- package/src/console/slash/commands/dynamic.ts +83 -0
- package/src/console/slash/commands/integrations.ts +695 -0
- package/src/console/slash/commands/shared.ts +75 -0
- package/src/console/slash/commands/transcript.ts +263 -0
- package/src/console/slash/commands/workbench.ts +246 -0
- package/src/console/slash/index.ts +15 -0
- package/src/console/slash/registry.ts +70 -0
- package/src/console/slash/resolve.ts +63 -0
- package/src/console/startup.ts +209 -0
- package/src/console/theme/adapter.ts +45 -0
- package/src/console/theme/index.ts +7 -0
- package/src/console/theme/palette.ts +68 -0
- package/src/console/theme/resolve.ts +39 -0
- package/src/console/theme/tokens.ts +71 -0
- package/src/entry.ts +55 -0
- package/src/guardrails.ts +37 -0
- package/src/index.ts +18 -0
- package/src/insight/channel.ts +88 -0
- package/src/insight/contract.ts +185 -0
- package/src/insight/index.ts +110 -0
- package/src/insight/recorder.ts +213 -0
- package/src/insight/redaction.ts +157 -0
- package/src/insight/replay.ts +158 -0
- package/src/insight/sampling.ts +70 -0
- package/src/insight/serialize.ts +50 -0
- package/src/insight/sinks/console.ts +64 -0
- package/src/insight/sinks/file.ts +40 -0
- package/src/insight/sinks/index.ts +24 -0
- package/src/insight/sinks/stream.ts +54 -0
- package/src/integrations/sarvam/attach.ts +239 -0
- package/src/integrations/sarvam/config.ts +156 -0
- package/src/integrations/sarvam/index.ts +25 -0
- package/src/integrations/sarvam/sarvam.test.ts +60 -0
- package/src/integrations/sarvam/types.ts +27 -0
- package/src/integrations/zoho/attach.ts +342 -0
- package/src/integrations/zoho/config.ts +125 -0
- package/src/integrations/zoho/index.ts +27 -0
- package/src/integrations/zoho/types.ts +21 -0
- package/src/integrations/zoho/zoho.test.ts +50 -0
- package/src/kit/clipboard-image.ts +107 -0
- package/src/kit/external-editor.ts +48 -0
- package/src/kit/image.ts +59 -0
- package/src/kit/index.ts +51 -0
- package/src/kit/shell.ts +19 -0
- package/src/kit/tool-fetch.ts +85 -0
- package/src/launch/catalog.ts +148 -0
- package/src/launch/contract.ts +187 -0
- package/src/launch/credentials.ts +625 -0
- package/src/launch/index.ts +98 -0
- package/src/launch/invocation/attachments.ts +179 -0
- package/src/launch/invocation/flags.ts +196 -0
- package/src/launch/invocation/index.ts +25 -0
- package/src/launch/invocation/read.ts +260 -0
- package/src/launch/invocation/usage.ts +67 -0
- package/src/launch/login.ts +324 -0
- package/src/launch/oauth.test.ts +18 -0
- package/src/launch/oauth.ts +203 -0
- package/src/launch/packages.ts +194 -0
- package/src/launch/pickers.ts +189 -0
- package/src/runtime-bridge/bridges/_drive.ts +96 -0
- package/src/runtime-bridge/bridges/builtins.ts +68 -0
- package/src/runtime-bridge/bridges/claude-cli.ts +123 -0
- package/src/runtime-bridge/bridges/codex-cli.ts +142 -0
- package/src/runtime-bridge/bridges/index.ts +33 -0
- package/src/runtime-bridge/bridges/indusagi-cli.ts +155 -0
- package/src/runtime-bridge/broker.ts +227 -0
- package/src/runtime-bridge/contract.ts +122 -0
- package/src/runtime-bridge/index.ts +79 -0
- package/src/runtime-bridge/sink.ts +180 -0
- package/src/sessions/contract.ts +81 -0
- package/src/sessions/index.ts +13 -0
- package/src/sessions/library.ts +229 -0
- package/src/settings/contract.ts +114 -0
- package/src/settings/index.ts +32 -0
- package/src/settings/manager.ts +117 -0
- package/src/transcript-export/index.ts +45 -0
- package/src/transcript-export/publish.ts +260 -0
- package/src/transcript-export/sgr.ts +315 -0
- package/src/transcript-export/template.ts +272 -0
- package/src/transcript-export/theme-bridge.ts +150 -0
- package/src/window-budget/budget/estimate.ts +135 -0
- package/src/window-budget/budget/gate.ts +33 -0
- package/src/window-budget/budget/index.ts +16 -0
- package/src/window-budget/budget/slice.ts +56 -0
- package/src/window-budget/condenser.ts +58 -0
- package/src/window-budget/contract.ts +184 -0
- package/src/window-budget/index.ts +19 -0
- package/src/window-budget/microcompact.ts +95 -0
- package/src/window-budget/rehydrate.ts +136 -0
- package/src/window-budget/summarize/condense.ts +103 -0
- package/src/window-budget/summarize/index.ts +14 -0
- package/src/window-budget/summarize/prompt.ts +149 -0
- package/src/workflow-engine/agent-runner.ts +181 -0
- package/src/workflow-engine/display.ts +224 -0
- package/src/workflow-engine/engine.ts +294 -0
- package/src/workflow-engine/index.ts +23 -0
- package/src/workflow-engine/parse.ts +172 -0
- package/src/workflow-engine/structured-output.ts +35 -0
- package/src/workspace/brand.ts +29 -0
- package/src/workspace/index.ts +18 -0
- package/src/workspace/locator.ts +103 -0
- package/src/workspace/runtime-detect.ts +64 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slash line resolution — parse a typed line, then match it against the registry.
|
|
3
|
+
*/
|
|
4
|
+
import type { SlashCommand, SlashRegistry } from "../contract.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The leading character that marks a line as a slash invocation.
|
|
8
|
+
*/
|
|
9
|
+
export const SLASH_PREFIX = "/" as const;
|
|
10
|
+
|
|
11
|
+
const COMMAND_TOKEN = /^[a-zA-Z][a-zA-Z0-9:-]*(?:\s|$)/;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The lexical split of a slash line into its command token and argument tail.
|
|
15
|
+
*/
|
|
16
|
+
export interface SlashLine {
|
|
17
|
+
readonly name: string;
|
|
18
|
+
readonly args: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Whether a typed line is shaped like a slash command at all.
|
|
23
|
+
*/
|
|
24
|
+
export function looksLikeSlash(input: string): boolean {
|
|
25
|
+
const trimmed = input.trimStart();
|
|
26
|
+
if (!trimmed.startsWith(SLASH_PREFIX)) return false;
|
|
27
|
+
return COMMAND_TOKEN.test(trimmed.slice(SLASH_PREFIX.length));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Split a slash line into its {@link SlashLine} token/argument pair.
|
|
32
|
+
*/
|
|
33
|
+
export function parseSlash(input: string): SlashLine | undefined {
|
|
34
|
+
if (!looksLikeSlash(input)) return void 0;
|
|
35
|
+
const body = input.trimStart().slice(SLASH_PREFIX.length);
|
|
36
|
+
const gap = body.search(/\s/);
|
|
37
|
+
if (gap === -1) {
|
|
38
|
+
return { name: body.toLowerCase(), args: "" };
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
name: body.slice(0, gap).toLowerCase(),
|
|
42
|
+
args: body.slice(gap + 1).trim()
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The outcome of resolving a typed line against a {@link SlashRegistry}.
|
|
48
|
+
*/
|
|
49
|
+
export type SlashResolution =
|
|
50
|
+
| { readonly kind: "not-slash" }
|
|
51
|
+
| { readonly kind: "match"; readonly command: SlashCommand; readonly args: string }
|
|
52
|
+
| { readonly kind: "miss"; readonly name: string };
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Resolve a raw composer line against the registry to a {@link SlashResolution}.
|
|
56
|
+
*/
|
|
57
|
+
export function resolveSlash(input: string, registry: SlashRegistry): SlashResolution {
|
|
58
|
+
const line = parseSlash(input);
|
|
59
|
+
if (line === void 0) return { kind: "not-slash" };
|
|
60
|
+
const command = registry.index.get(line.name);
|
|
61
|
+
if (command === void 0) return { kind: "miss", name: line.name };
|
|
62
|
+
return { kind: "match", command, args: line.args };
|
|
63
|
+
}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Startup gathering — the pure resource/notices/changelog reader the banner draws.
|
|
3
|
+
*
|
|
4
|
+
* The interactive console opens with a one-shot survey of what the session has to
|
|
5
|
+
* work with: which context documents the agent will read, which capability cards
|
|
6
|
+
* (skills) and prompt templates (commands) were discovered on disk, and a count
|
|
7
|
+
* of each. This module *gathers* that survey and nothing else.
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
import { gatherSkillCards, loadMacros } from "../briefing/index.js";
|
|
12
|
+
|
|
13
|
+
const PROFILE_DIR = ".indusagi";
|
|
14
|
+
const CONTEXT_FILES = ["AGENTS.md", "CLAUDE.md"];
|
|
15
|
+
|
|
16
|
+
function skillRoots(cwd: string, home: string) {
|
|
17
|
+
return [
|
|
18
|
+
{ dir: join(cwd, PROFILE_DIR, "skills"), origin: "project" as const },
|
|
19
|
+
{ dir: join(home, PROFILE_DIR, "skills"), origin: "user" as const }
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function macroRoots(cwd: string, home: string) {
|
|
24
|
+
return [
|
|
25
|
+
{ dir: join(cwd, PROFILE_DIR, "commands"), origin: "project" as const, label: "project" },
|
|
26
|
+
{ dir: join(home, PROFILE_DIR, "commands"), origin: "user" as const, label: "user" }
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function shortenPath(path: string, cwd: string, home: string) {
|
|
31
|
+
if (cwd.length > 0 && path.startsWith(cwd)) {
|
|
32
|
+
const rest = path.slice(cwd.length).replace(/^[/\\]+/, "");
|
|
33
|
+
return rest.length > 0 ? `./${rest}` : ".";
|
|
34
|
+
}
|
|
35
|
+
if (home.length > 0 && path.startsWith(home)) {
|
|
36
|
+
return `~${path.slice(home.length)}`;
|
|
37
|
+
}
|
|
38
|
+
return path;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const MAX_SECTION_LINES = 6;
|
|
42
|
+
|
|
43
|
+
function capLines(lines: string[]) {
|
|
44
|
+
if (lines.length <= MAX_SECTION_LINES) return [...lines];
|
|
45
|
+
const head = lines.slice(0, MAX_SECTION_LINES);
|
|
46
|
+
return [...head, `... ${lines.length - MAX_SECTION_LINES} more`];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function section(title: string, lines: string[]): StartupSection | null {
|
|
50
|
+
const filtered = lines.map((line) => line.trim()).filter((line) => line.length > 0);
|
|
51
|
+
if (filtered.length === 0) return null;
|
|
52
|
+
return { title, lines: capLines(filtered), count: filtered.length };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function gatherContext(cwd: string, home: string) {
|
|
56
|
+
const seen = new Set<string>();
|
|
57
|
+
const out: string[] = [];
|
|
58
|
+
for (const root of [cwd, home]) {
|
|
59
|
+
if (root.length === 0) continue;
|
|
60
|
+
for (const name of CONTEXT_FILES) {
|
|
61
|
+
const path = join(root, name);
|
|
62
|
+
if (seen.has(path)) continue;
|
|
63
|
+
seen.add(path);
|
|
64
|
+
if (existsSync(path)) out.push(shortenPath(path, cwd, home));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return out;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function gatherSkills(cwd: string, home: string) {
|
|
71
|
+
let cards: Array<{ name: string; location: string }> = [];
|
|
72
|
+
try {
|
|
73
|
+
cards = gatherSkillCards(skillRoots(cwd, home)).cards.slice();
|
|
74
|
+
} catch {
|
|
75
|
+
cards = [];
|
|
76
|
+
}
|
|
77
|
+
return cards.map((card) => `${card.name} ${shortenPath(card.location, cwd, home)}`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function gatherPrompts(cwd: string, home: string) {
|
|
81
|
+
const lines: string[] = [];
|
|
82
|
+
const claimed = new Set<string>();
|
|
83
|
+
for (const root of macroRoots(cwd, home)) {
|
|
84
|
+
let loaded: Array<{ name: string; source: string }> = [];
|
|
85
|
+
try {
|
|
86
|
+
loaded = loadMacros(root.dir, { origin: root.origin, label: root.label });
|
|
87
|
+
} catch {
|
|
88
|
+
loaded = [];
|
|
89
|
+
}
|
|
90
|
+
for (const macro of loaded) {
|
|
91
|
+
if (claimed.has(macro.name)) continue;
|
|
92
|
+
claimed.add(macro.name);
|
|
93
|
+
lines.push(`/${macro.name} ${shortenPath(macro.source, cwd, home)}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return lines;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Gather the startup map: context documents, skills, and prompt templates.
|
|
101
|
+
*/
|
|
102
|
+
export function gatherStartup(inputs: StartupInputs): StartupMap {
|
|
103
|
+
const { cwd, home } = inputs;
|
|
104
|
+
const sections: StartupSection[] = [];
|
|
105
|
+
const context = section("Context", gatherContext(cwd, home));
|
|
106
|
+
if (context) sections.push(context);
|
|
107
|
+
const skills = section("Skills", gatherSkills(cwd, home));
|
|
108
|
+
if (skills) sections.push(skills);
|
|
109
|
+
const prompts = section("Prompts", gatherPrompts(cwd, home));
|
|
110
|
+
if (prompts) sections.push(prompts);
|
|
111
|
+
return { sections };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function condenseChangelog(markdown: string, lastSeen?: string) {
|
|
115
|
+
if (lastSeen === void 0 || lastSeen.length === 0) return markdown.trim();
|
|
116
|
+
const lines = markdown.split("\n");
|
|
117
|
+
const kept: string[] = [];
|
|
118
|
+
for (const line of lines) {
|
|
119
|
+
const heading = /^##\s+\[?(\d+\.\d+\.\d+)\]?/.exec(line);
|
|
120
|
+
if (heading && heading[1] === lastSeen) break;
|
|
121
|
+
kept.push(line);
|
|
122
|
+
}
|
|
123
|
+
const joined = kept.join("\n").trim();
|
|
124
|
+
return joined.length > 0 ? joined : markdown.trim();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function reverseChangelogEntries(markdown: string) {
|
|
128
|
+
const isEntryHeading = (line: string) => /^##\s+\[?\d+\.\d+\.\d+\]?/.test(line);
|
|
129
|
+
const lines = markdown.split("\n");
|
|
130
|
+
const firstEntry = lines.findIndex(isEntryHeading);
|
|
131
|
+
if (firstEntry === -1) return markdown.trim();
|
|
132
|
+
const preamble = lines.slice(0, firstEntry).join("\n").trim();
|
|
133
|
+
const blocks: string[][] = [];
|
|
134
|
+
for (const line of lines.slice(firstEntry)) {
|
|
135
|
+
if (isEntryHeading(line)) blocks.push([line]);
|
|
136
|
+
else if (blocks.length > 0) blocks[blocks.length - 1].push(line);
|
|
137
|
+
}
|
|
138
|
+
blocks.reverse();
|
|
139
|
+
const body = blocks.map((block) => block.join("\n").trim()).filter((block) => block.length > 0).join("\n\n");
|
|
140
|
+
return preamble.length > 0 ? `${preamble}\n\n${body}` : body;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Gather the changelog survey for the banner.
|
|
145
|
+
*/
|
|
146
|
+
export function gatherChangelog(inputs: StartupInputs): StartupChangelog {
|
|
147
|
+
const { version, lastSeenVersion, changelogPath } = inputs;
|
|
148
|
+
const none: StartupChangelog = { mode: "none", version };
|
|
149
|
+
if (changelogPath === void 0 || !existsSync(changelogPath)) return none;
|
|
150
|
+
if (lastSeenVersion !== void 0 && lastSeenVersion === version) return none;
|
|
151
|
+
let raw: string;
|
|
152
|
+
try {
|
|
153
|
+
raw = readFileSync(changelogPath, "utf-8");
|
|
154
|
+
} catch {
|
|
155
|
+
return none;
|
|
156
|
+
}
|
|
157
|
+
const condensed = condenseChangelog(raw, lastSeenVersion);
|
|
158
|
+
if (condensed.length === 0) {
|
|
159
|
+
return { mode: "condensed", version };
|
|
160
|
+
}
|
|
161
|
+
if (lastSeenVersion === void 0) {
|
|
162
|
+
return { mode: "condensed", version };
|
|
163
|
+
}
|
|
164
|
+
return { mode: "full", version, markdown: reverseChangelogEntries(condensed) };
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* One labelled group inside the startup map.
|
|
169
|
+
*/
|
|
170
|
+
export interface StartupSection {
|
|
171
|
+
readonly title: string;
|
|
172
|
+
readonly lines: readonly string[];
|
|
173
|
+
readonly count: number;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* The gathered survey the banner renders as the "Startup Map" panel.
|
|
178
|
+
*/
|
|
179
|
+
export interface StartupMap {
|
|
180
|
+
readonly sections: readonly StartupSection[];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* The changelog survey the banner may render as a "What is new" block.
|
|
185
|
+
*/
|
|
186
|
+
export type StartupChangelogMode = "none" | "full" | "condensed";
|
|
187
|
+
|
|
188
|
+
export interface StartupChangelog {
|
|
189
|
+
readonly mode: StartupChangelogMode;
|
|
190
|
+
readonly version: string;
|
|
191
|
+
readonly markdown?: string;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** The per-line tone a startup notice carries. */
|
|
195
|
+
export type StartupNoticeKind = "error" | "warning" | "info";
|
|
196
|
+
|
|
197
|
+
export interface StartupNotice {
|
|
198
|
+
readonly kind: StartupNoticeKind;
|
|
199
|
+
readonly text: string;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** What {@link gatherStartup} is handed to compute the survey. */
|
|
203
|
+
export interface StartupInputs {
|
|
204
|
+
readonly cwd: string;
|
|
205
|
+
readonly home: string;
|
|
206
|
+
readonly version: string;
|
|
207
|
+
readonly lastSeenVersion?: string;
|
|
208
|
+
readonly changelogPath?: string;
|
|
209
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme adapter binding — the single boundary where the console's semantic tokens become concrete terminal colours.
|
|
3
|
+
*/
|
|
4
|
+
import { createThemeAdapter } from "indusagi/react-ink";
|
|
5
|
+
import type { InkThemeAdapter, ThemeTokens } from "../contract.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Project the console's semantic tokens onto the framework's colour-key Record.
|
|
9
|
+
*/
|
|
10
|
+
export function frameworkColors(tokens: ThemeTokens): Record<string, string> {
|
|
11
|
+
return {
|
|
12
|
+
text: tokens.bodyText,
|
|
13
|
+
dim: tokens.mutedText,
|
|
14
|
+
muted: tokens.mutedText,
|
|
15
|
+
accent: tokens.signal,
|
|
16
|
+
borderMuted: tokens.quietFrame,
|
|
17
|
+
bashBorder: tokens.frame,
|
|
18
|
+
userMessage: "",
|
|
19
|
+
customMessage: tokens.cardAccent,
|
|
20
|
+
success: tokens.affirm,
|
|
21
|
+
warning: tokens.caution,
|
|
22
|
+
error: tokens.alarm,
|
|
23
|
+
info: tokens.notice,
|
|
24
|
+
highlight: tokens.inkText,
|
|
25
|
+
codeInline: tokens.codeInline,
|
|
26
|
+
heading: tokens.heading,
|
|
27
|
+
blockquoteBar: tokens.blockquoteBar,
|
|
28
|
+
diffAddedBg: tokens.diffAddedBg,
|
|
29
|
+
diffRemovedBg: tokens.diffRemovedBg,
|
|
30
|
+
diffAddedText: tokens.diffAddedText,
|
|
31
|
+
diffRemovedText: tokens.diffRemovedText,
|
|
32
|
+
synKeyword: tokens.synKeyword,
|
|
33
|
+
synString: tokens.synString,
|
|
34
|
+
synNumber: tokens.synNumber,
|
|
35
|
+
synComment: tokens.synComment,
|
|
36
|
+
synType: tokens.synType
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Build the framework {@link InkThemeAdapter} for a scheme from its tokens.
|
|
42
|
+
*/
|
|
43
|
+
export function themeAdapter(schemeName: string, tokens: ThemeTokens): InkThemeAdapter {
|
|
44
|
+
return createThemeAdapter(schemeName, frameworkColors(tokens));
|
|
45
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Console theme engine — public barrel.
|
|
3
|
+
*/
|
|
4
|
+
export { SAFFRON_PALETTE, MIDNIGHT_PALETTE, DAYLIGHT_PALETTE, MIDNIGHT_CB_PALETTE, DAYLIGHT_CB_PALETTE, PALETTES } from "./palette.js";
|
|
5
|
+
export { deriveTokens } from "./tokens.js";
|
|
6
|
+
export { themeAdapter, frameworkColors } from "./adapter.js";
|
|
7
|
+
export { THEMES, THEME_SCHEMES, resolveTheme } from "./resolve.js";
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme palettes — the console's own re-derived accent ramps.
|
|
3
|
+
*/
|
|
4
|
+
import type { ThemePalette, ThemeScheme } from "../contract.js";
|
|
5
|
+
|
|
6
|
+
/** The dark-terminal ramp. */
|
|
7
|
+
export const MIDNIGHT_PALETTE: ThemePalette = {
|
|
8
|
+
primary: "#3ad6b4",
|
|
9
|
+
secondary: "#f0a24b",
|
|
10
|
+
tertiary: "#7c9fe8",
|
|
11
|
+
ink: "#f4f6fb",
|
|
12
|
+
body: "#c3c8d4",
|
|
13
|
+
muted: "#7e8696",
|
|
14
|
+
affirm: "#46c98a",
|
|
15
|
+
caution: "#e8b341",
|
|
16
|
+
alarm: "#ef6a6a"
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/** The light-terminal ramp. */
|
|
20
|
+
export const DAYLIGHT_PALETTE: ThemePalette = {
|
|
21
|
+
primary: "#0f8f78",
|
|
22
|
+
secondary: "#c26a10",
|
|
23
|
+
tertiary: "#3a5ec0",
|
|
24
|
+
ink: "#1c2230",
|
|
25
|
+
body: "#3a4253",
|
|
26
|
+
muted: "#6b7382",
|
|
27
|
+
affirm: "#1d9d63",
|
|
28
|
+
caution: "#a9740a",
|
|
29
|
+
alarm: "#c4322f"
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/** The "IndusCode Saffron" dark-terminal ramp — the brand scheme. */
|
|
33
|
+
export const SAFFRON_PALETTE: ThemePalette = {
|
|
34
|
+
primary: "#f7a23f",
|
|
35
|
+
secondary: "#3fd9b8",
|
|
36
|
+
tertiary: "#b9a589",
|
|
37
|
+
ink: "#fbf2e6",
|
|
38
|
+
body: "#f3e9dc",
|
|
39
|
+
muted: "#8a7a66",
|
|
40
|
+
affirm: "#7fd8a8",
|
|
41
|
+
caution: "#e8c172",
|
|
42
|
+
alarm: "#e8736b"
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/** The dark-terminal color-blind-safe ramp. */
|
|
46
|
+
export const MIDNIGHT_CB_PALETTE: ThemePalette = {
|
|
47
|
+
...MIDNIGHT_PALETTE,
|
|
48
|
+
affirm: "#4aa3ff",
|
|
49
|
+
caution: "#f2c75c",
|
|
50
|
+
alarm: "#c83232"
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/** The light-terminal color-blind-safe ramp. */
|
|
54
|
+
export const DAYLIGHT_CB_PALETTE: ThemePalette = {
|
|
55
|
+
...DAYLIGHT_PALETTE,
|
|
56
|
+
affirm: "#1f6fd6",
|
|
57
|
+
caution: "#8a5e00",
|
|
58
|
+
alarm: "#b02622"
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/** The raw ramp for each scheme, keyed by {@link ThemeScheme}. */
|
|
62
|
+
export const PALETTES: Readonly<Record<ThemeScheme, ThemePalette>> = {
|
|
63
|
+
saffron: SAFFRON_PALETTE,
|
|
64
|
+
midnight: MIDNIGHT_PALETTE,
|
|
65
|
+
daylight: DAYLIGHT_PALETTE,
|
|
66
|
+
"midnight-cb": MIDNIGHT_CB_PALETTE,
|
|
67
|
+
"daylight-cb": DAYLIGHT_CB_PALETTE
|
|
68
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme resolution — assemble the fully-resolved {@link ConsoleTheme} for each scheme.
|
|
3
|
+
*/
|
|
4
|
+
import { DEFAULT_SCHEME, isThemeScheme, type ConsoleTheme, type ThemeScheme } from "../contract.js";
|
|
5
|
+
import { PALETTES } from "./palette.js";
|
|
6
|
+
import { themeAdapter } from "./adapter.js";
|
|
7
|
+
import { deriveTokens } from "./tokens.js";
|
|
8
|
+
|
|
9
|
+
function assembleTheme(scheme: ThemeScheme, palette = PALETTES[scheme]): ConsoleTheme {
|
|
10
|
+
const tokens = deriveTokens(palette);
|
|
11
|
+
return {
|
|
12
|
+
scheme,
|
|
13
|
+
palette,
|
|
14
|
+
tokens,
|
|
15
|
+
adapter: themeAdapter(scheme, tokens)
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** The built-in themes, fully resolved and keyed by {@link ThemeScheme}. */
|
|
20
|
+
export const THEMES: Readonly<Record<ThemeScheme, ConsoleTheme>> = {
|
|
21
|
+
saffron: assembleTheme("saffron"),
|
|
22
|
+
midnight: assembleTheme("midnight"),
|
|
23
|
+
daylight: assembleTheme("daylight"),
|
|
24
|
+
"midnight-cb": assembleTheme("midnight-cb"),
|
|
25
|
+
"daylight-cb": assembleTheme("daylight-cb")
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Resolve a scheme name to its fully-built {@link ConsoleTheme}.
|
|
30
|
+
*/
|
|
31
|
+
export function resolveTheme(scheme?: string | null): ConsoleTheme {
|
|
32
|
+
if (typeof scheme === "string" && isThemeScheme(scheme)) {
|
|
33
|
+
return THEMES[scheme];
|
|
34
|
+
}
|
|
35
|
+
return THEMES[DEFAULT_SCHEME];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** The schemes the console offers, in picker order. */
|
|
39
|
+
export const THEME_SCHEMES: readonly ThemeScheme[] = Object.keys(THEMES) as ThemeScheme[];
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token derivation — expand a raw {@link ThemePalette} into the semantic {@link ThemeTokens}.
|
|
3
|
+
*/
|
|
4
|
+
import type { ThemePalette, ThemeTokens } from "../contract.js";
|
|
5
|
+
|
|
6
|
+
function parseHex(hex: string): [number, number, number] {
|
|
7
|
+
let h = hex.trim().replace(/^#/, "");
|
|
8
|
+
if (h.length === 3) {
|
|
9
|
+
h = h.split("").map((c) => c + c).join("");
|
|
10
|
+
}
|
|
11
|
+
const n = Number.parseInt(h.slice(0, 6).padEnd(6, "0"), 16);
|
|
12
|
+
return [(n >> 16) & 255, (n >> 8) & 255, n & 255];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function toHex([r, g, b]: [number, number, number]) {
|
|
16
|
+
const clamp = (v: number) => Math.max(0, Math.min(255, Math.round(v)));
|
|
17
|
+
return "#" + [clamp(r), clamp(g), clamp(b)].map((v) => v.toString(16).padStart(2, "0")).join("");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function mixHex(a: string, b: string, t: number) {
|
|
21
|
+
const [ar, ag, ab] = parseHex(a);
|
|
22
|
+
const [br, bg, bb] = parseHex(b);
|
|
23
|
+
return toHex([ar + (br - ar) * t, ag + (bg - ag) * t, ab + (bb - ab) * t]);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function diffBackground(hue: string, anchor: string) {
|
|
27
|
+
return mixHex(hue, anchor, 0.78);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function luminance(hex: string) {
|
|
31
|
+
const [r, g, b] = parseHex(hex);
|
|
32
|
+
return (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function backgroundAnchor(palette: ThemePalette) {
|
|
36
|
+
return luminance(palette.ink) >= 0.5 ? "#000000" : "#ffffff";
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Map a raw accent ramp onto the closed semantic token set.
|
|
41
|
+
*/
|
|
42
|
+
export function deriveTokens(palette: ThemePalette): ThemeTokens {
|
|
43
|
+
const anchor = backgroundAnchor(palette);
|
|
44
|
+
return {
|
|
45
|
+
signal: palette.primary,
|
|
46
|
+
frame: palette.tertiary,
|
|
47
|
+
quietFrame: palette.muted,
|
|
48
|
+
promptSurface: palette.secondary,
|
|
49
|
+
cardAccent: palette.secondary,
|
|
50
|
+
bodyText: palette.body,
|
|
51
|
+
mutedText: palette.muted,
|
|
52
|
+
inkText: palette.ink,
|
|
53
|
+
notice: palette.tertiary,
|
|
54
|
+
affirm: palette.affirm,
|
|
55
|
+
caution: palette.caution,
|
|
56
|
+
alarm: palette.alarm,
|
|
57
|
+
pending: palette.primary,
|
|
58
|
+
codeInline: palette.primary,
|
|
59
|
+
heading: palette.primary,
|
|
60
|
+
blockquoteBar: palette.muted,
|
|
61
|
+
diffAddedBg: diffBackground(palette.affirm, anchor),
|
|
62
|
+
diffRemovedBg: diffBackground(palette.alarm, anchor),
|
|
63
|
+
diffAddedText: palette.affirm,
|
|
64
|
+
diffRemovedText: palette.alarm,
|
|
65
|
+
synKeyword: palette.primary,
|
|
66
|
+
synString: palette.affirm,
|
|
67
|
+
synNumber: palette.caution,
|
|
68
|
+
synComment: palette.muted,
|
|
69
|
+
synType: palette.tertiary
|
|
70
|
+
};
|
|
71
|
+
}
|
package/src/entry.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Thin executable bootstrap for the indusagi coding agent.
|
|
4
|
+
*
|
|
5
|
+
* The real work lives in the `boot/` subsystem; this file just installs the
|
|
6
|
+
* cross-cutting runtime concerns (process title, MCP log noise filter, heap
|
|
7
|
+
* headroom) and hands control to {@link boot}.
|
|
8
|
+
*/
|
|
9
|
+
import { argv as processArgv, env as processEnv } from "node:process";
|
|
10
|
+
// `process` is a Node.js global; do NOT import it from `node:process` (which
|
|
11
|
+
// exports only `argv`, `env`, etc. but not the global `process` itself).
|
|
12
|
+
// Use the global directly throughout this file.
|
|
13
|
+
import { realpathSync } from "node:fs";
|
|
14
|
+
import { fileURLToPath } from "node:url";
|
|
15
|
+
import { BRAND, boot, ensureHeapHeadroom } from "./boot/index.js";
|
|
16
|
+
|
|
17
|
+
const MCP_NOISE_MARKER = "[MCP]";
|
|
18
|
+
|
|
19
|
+
function installMcpNoiseFilter(): void {
|
|
20
|
+
const self = installMcpNoiseFilter as { installed?: boolean };
|
|
21
|
+
if (self.installed) return;
|
|
22
|
+
self.installed = true;
|
|
23
|
+
if (processEnv[BRAND.envDebug]) return;
|
|
24
|
+
const carriesMcpNoise = (args: unknown[]): boolean =>
|
|
25
|
+
typeof args[0] === "string" && (args[0] as string).includes(MCP_NOISE_MARKER);
|
|
26
|
+
const wrap =
|
|
27
|
+
(original: (...args: unknown[]) => void) =>
|
|
28
|
+
(...args: unknown[]): void => {
|
|
29
|
+
if (carriesMcpNoise(args)) return;
|
|
30
|
+
(original as (...a: unknown[]) => void)(...args);
|
|
31
|
+
};
|
|
32
|
+
console.log = wrap(console.log.bind(console)) as typeof console.log;
|
|
33
|
+
console.error = wrap(console.error.bind(console)) as typeof console.error;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function isProgramEntry(): boolean {
|
|
37
|
+
const entryArg = processArgv[1];
|
|
38
|
+
if (!entryArg) return false;
|
|
39
|
+
try {
|
|
40
|
+
return realpathSync(fileURLToPath(import.meta.url)) === realpathSync(entryArg);
|
|
41
|
+
} catch {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
process.title = BRAND.binNames[0];
|
|
47
|
+
installMcpNoiseFilter();
|
|
48
|
+
if (isProgramEntry()) {
|
|
49
|
+
ensureHeapHeadroom();
|
|
50
|
+
void boot(processArgv.slice(2)).then((code) => {
|
|
51
|
+
process.exitCode = code;
|
|
52
|
+
process.stdout.write("", () => process.exit(code));
|
|
53
|
+
setTimeout(() => process.exit(code), 1e3).unref();
|
|
54
|
+
});
|
|
55
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// @ts-nocheck — barrel re-export for guardrails subsystem.
|
|
2
|
+
// Preserves the package's public surface: `indusagi-coding-agent/guardrails`.
|
|
3
|
+
|
|
4
|
+
// Permission gate
|
|
5
|
+
export {
|
|
6
|
+
READ_ONLY_TOOL_NAMES,
|
|
7
|
+
EDIT_TOOL_NAMES,
|
|
8
|
+
makeRule,
|
|
9
|
+
resolveRuleDecision,
|
|
10
|
+
createPermissionGate,
|
|
11
|
+
} from "./conductor/permissions.js";
|
|
12
|
+
|
|
13
|
+
// Catastrophic-command classifier
|
|
14
|
+
export { evaluateCatastrophic, bashSubcommandSubjects } from "./conductor/bash-guard.js";
|
|
15
|
+
|
|
16
|
+
// Briefing
|
|
17
|
+
export { composeBriefing } from "./briefing/compose.js";
|
|
18
|
+
export { gatherContextDocs } from "./briefing/context-docs.js";
|
|
19
|
+
|
|
20
|
+
// Stores
|
|
21
|
+
export {
|
|
22
|
+
READ_STATE_HANDLE_KEY,
|
|
23
|
+
ReadStateStore,
|
|
24
|
+
createReadStateStore,
|
|
25
|
+
} from "./boot/runners/read-state.js";
|
|
26
|
+
export {
|
|
27
|
+
CHECKPOINT_HANDLE_KEY,
|
|
28
|
+
CheckpointStore,
|
|
29
|
+
createCheckpointStore,
|
|
30
|
+
} from "./boot/runners/checkpoint.js";
|
|
31
|
+
|
|
32
|
+
// Deck provisioner
|
|
33
|
+
export { provisionDeck } from "./capability-deck/provision.js";
|
|
34
|
+
|
|
35
|
+
// Stable refusal string (preserved verbatim)
|
|
36
|
+
export const READ_BEFORE_EDIT_MESSAGE =
|
|
37
|
+
"File has not been read yet. Read it first before writing to it.";
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export * as boot from "./boot/index.js";
|
|
2
|
+
export * as workspace from "./workspace/index.js";
|
|
3
|
+
export * as briefing from "./briefing/index.js";
|
|
4
|
+
export * as launch from "./launch/index.js";
|
|
5
|
+
export * as conductor from "./conductor/index.js";
|
|
6
|
+
export * as capabilityDeck from "./capability-deck/index.js";
|
|
7
|
+
export * as workflowEngine from "./workflow-engine/index.js";
|
|
8
|
+
export * as windowBudget from "./window-budget/index.js";
|
|
9
|
+
export * as consoleUi from "./console/index.js";
|
|
10
|
+
export * as settings from "./settings/index.js";
|
|
11
|
+
export * as kit from "./kit/index.js";
|
|
12
|
+
export * as transcriptExport from "./transcript-export/index.js";
|
|
13
|
+
export * as sessions from "./sessions/index.js";
|
|
14
|
+
export * as addons from "./addons/index.js";
|
|
15
|
+
export * as channels from "./channels/index.js";
|
|
16
|
+
export * as runtimeBridge from "./runtime-bridge/index.js";
|
|
17
|
+
export * as insight from "./insight/index.js";
|
|
18
|
+
export { VERSION } from "./workspace/index.js";
|