@aligndottech/cli 0.67.1 → 0.68.1
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/README.md +28 -7
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +5 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/capture.d.ts.map +1 -1
- package/dist/commands/capture.js +4 -0
- package/dist/commands/capture.js.map +1 -1
- package/dist/commands/check.d.ts +1 -5
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +1 -33
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/connect-agents.d.ts +8 -18
- package/dist/commands/connect-agents.d.ts.map +1 -1
- package/dist/commands/connect-agents.js +32 -19
- package/dist/commands/connect-agents.js.map +1 -1
- package/dist/commands/default-action.d.ts.map +1 -1
- package/dist/commands/default-action.js +18 -7
- package/dist/commands/default-action.js.map +1 -1
- package/dist/commands/local.js +2 -2
- package/dist/commands/local.js.map +1 -1
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +4 -2
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +24 -15
- package/dist/commands/setup.js.map +1 -1
- package/dist/lib/agent/agent-guidance.d.ts +8 -0
- package/dist/lib/agent/agent-guidance.d.ts.map +1 -0
- package/dist/lib/agent/agent-guidance.js +8 -0
- package/dist/lib/agent/agent-guidance.js.map +1 -0
- package/dist/lib/agent/edit-gate.d.ts +30 -0
- package/dist/lib/agent/edit-gate.d.ts.map +1 -0
- package/dist/lib/agent/edit-gate.js +67 -0
- package/dist/lib/agent/edit-gate.js.map +1 -0
- package/dist/lib/agent/edit-text.d.ts +14 -0
- package/dist/lib/agent/edit-text.d.ts.map +1 -0
- package/dist/lib/agent/edit-text.js +34 -0
- package/dist/lib/agent/edit-text.js.map +1 -0
- package/dist/lib/agent/engines/claude-code-protocol.d.ts +24 -0
- package/dist/lib/agent/engines/claude-code-protocol.d.ts.map +1 -0
- package/dist/lib/agent/engines/claude-code-protocol.js +127 -0
- package/dist/lib/agent/engines/claude-code-protocol.js.map +1 -0
- package/dist/lib/agent/engines/claude-code.d.ts +17 -0
- package/dist/lib/agent/engines/claude-code.d.ts.map +1 -0
- package/dist/lib/agent/engines/claude-code.js +122 -0
- package/dist/lib/agent/engines/claude-code.js.map +1 -0
- package/dist/lib/agent/engines/pi-models.d.ts +46 -0
- package/dist/lib/agent/engines/pi-models.d.ts.map +1 -0
- package/dist/lib/agent/engines/pi-models.js +91 -0
- package/dist/lib/agent/engines/pi-models.js.map +1 -0
- package/dist/lib/agent/engines/pi-sdk.d.ts +39 -0
- package/dist/lib/agent/engines/pi-sdk.d.ts.map +1 -0
- package/dist/lib/agent/engines/pi-sdk.js +105 -0
- package/dist/lib/agent/engines/pi-sdk.js.map +1 -0
- package/dist/lib/agent/engines/pi.d.ts +44 -0
- package/dist/lib/agent/engines/pi.d.ts.map +1 -0
- package/dist/lib/agent/engines/pi.js +189 -0
- package/dist/lib/agent/engines/pi.js.map +1 -0
- package/dist/lib/agent/failure-tail.d.ts +9 -0
- package/dist/lib/agent/failure-tail.d.ts.map +1 -0
- package/dist/lib/agent/failure-tail.js +42 -0
- package/dist/lib/agent/failure-tail.js.map +1 -0
- package/dist/lib/agent/git-runs-programs.d.ts +11 -0
- package/dist/lib/agent/git-runs-programs.d.ts.map +1 -0
- package/dist/lib/agent/git-runs-programs.js +25 -0
- package/dist/lib/agent/git-runs-programs.js.map +1 -0
- package/dist/lib/agent/graph-tools.d.ts +23 -0
- package/dist/lib/agent/graph-tools.d.ts.map +1 -0
- package/dist/lib/agent/graph-tools.js +33 -0
- package/dist/lib/agent/graph-tools.js.map +1 -0
- package/dist/lib/agent/permission-broker.d.ts +27 -0
- package/dist/lib/agent/permission-broker.d.ts.map +1 -0
- package/dist/lib/agent/permission-broker.js +56 -0
- package/dist/lib/agent/permission-broker.js.map +1 -0
- package/dist/lib/agent/read-only-command.d.ts +15 -0
- package/dist/lib/agent/read-only-command.d.ts.map +1 -0
- package/dist/lib/agent/read-only-command.js +102 -0
- package/dist/lib/agent/read-only-command.js.map +1 -0
- package/dist/lib/agent/run-agent-session.d.ts +45 -0
- package/dist/lib/agent/run-agent-session.d.ts.map +1 -0
- package/dist/lib/agent/run-agent-session.js +139 -0
- package/dist/lib/agent/run-agent-session.js.map +1 -0
- package/dist/lib/agent/select-engine.d.ts +28 -0
- package/dist/lib/agent/select-engine.d.ts.map +1 -0
- package/dist/lib/agent/select-engine.js +14 -0
- package/dist/lib/agent/select-engine.js.map +1 -0
- package/dist/lib/agent/tui/app.d.ts +12 -0
- package/dist/lib/agent/tui/app.d.ts.map +1 -0
- package/dist/lib/agent/tui/app.js +122 -0
- package/dist/lib/agent/tui/app.js.map +1 -0
- package/dist/lib/agent/tui/cards.d.ts +17 -0
- package/dist/lib/agent/tui/cards.d.ts.map +1 -0
- package/dist/lib/agent/tui/cards.js +48 -0
- package/dist/lib/agent/tui/cards.js.map +1 -0
- package/dist/lib/agent/tui/controller.d.ts +21 -0
- package/dist/lib/agent/tui/controller.d.ts.map +1 -0
- package/dist/lib/agent/tui/controller.js +29 -0
- package/dist/lib/agent/tui/controller.js.map +1 -0
- package/dist/lib/agent/tui/theme.d.ts +11 -0
- package/dist/lib/agent/tui/theme.d.ts.map +1 -0
- package/dist/lib/agent/tui/theme.js +13 -0
- package/dist/lib/agent/tui/theme.js.map +1 -0
- package/dist/lib/agent/types.d.ts +84 -0
- package/dist/lib/agent/types.d.ts.map +1 -0
- package/dist/lib/agent/types.js +2 -0
- package/dist/lib/agent/types.js.map +1 -0
- package/dist/lib/config.d.ts +4 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +17 -0
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/doctor.d.ts +1 -1
- package/dist/lib/doctor.js +2 -2
- package/dist/lib/launch/config-writes.d.ts +5 -3
- package/dist/lib/launch/config-writes.d.ts.map +1 -1
- package/dist/lib/launch/config-writes.js +39 -8
- package/dist/lib/launch/config-writes.js.map +1 -1
- package/dist/lib/launch/launch.d.ts +4 -0
- package/dist/lib/launch/launch.d.ts.map +1 -1
- package/dist/lib/launch/launch.js +14 -6
- package/dist/lib/launch/launch.js.map +1 -1
- package/dist/lib/launch/mcp-child-env.js +1 -1
- package/dist/lib/launch/mcp-child-env.js.map +1 -1
- package/dist/lib/launch/prompts.d.ts +6 -0
- package/dist/lib/launch/prompts.d.ts.map +1 -1
- package/dist/lib/launch/prompts.js +12 -0
- package/dist/lib/launch/prompts.js.map +1 -1
- package/dist/lib/personal-import.d.ts +4 -0
- package/dist/lib/personal-import.d.ts.map +1 -1
- package/dist/lib/personal-import.js +4 -0
- package/dist/lib/personal-import.js.map +1 -1
- package/dist/lib/scope-real.d.ts +12 -0
- package/dist/lib/scope-real.d.ts.map +1 -1
- package/dist/lib/sync/real-env.d.ts +12 -0
- package/dist/lib/sync/real-env.d.ts.map +1 -1
- package/dist/lib/usage-telemetry.d.ts +1 -1
- package/dist/lib/usage-telemetry.d.ts.map +1 -1
- package/dist/lib/usage-telemetry.js +20 -2
- package/dist/lib/usage-telemetry.js.map +1 -1
- package/dist/lib/write-confirm.d.ts +14 -5
- package/dist/lib/write-confirm.d.ts.map +1 -1
- package/dist/lib/write-confirm.js +29 -10
- package/dist/lib/write-confirm.js.map +1 -1
- package/package.json +5 -2
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which shell commands the broker lets through without asking. The rule is an allowlist over a
|
|
3
|
+
* parse that fails toward asking: anything this file cannot positively read as read-only is not.
|
|
4
|
+
*
|
|
5
|
+
* A command is one or more segments joined by `;`, `&&`, `||` or `|`. EVERY segment must be a
|
|
6
|
+
* known read-only command, so an allowed `git status` cannot approve what follows it. Characters
|
|
7
|
+
* that run or write something else (substitution, redirects, background jobs, newlines, escapes)
|
|
8
|
+
* reject the whole line. A quoted `;` splits wrongly, and that only ever produces a segment that
|
|
9
|
+
* fails the allowlist, so the mistake costs a question and never a pass.
|
|
10
|
+
*/
|
|
11
|
+
const SHELL_SYNTAX = /[`$<>(){}\\\n\r]/;
|
|
12
|
+
const PLAIN = new Set(['ls', 'pwd', 'head', 'tail', 'wc', 'echo', 'true', 'grep', 'which', 'test']);
|
|
13
|
+
const GIT_READ = new Set(['status', 'log', 'show', 'diff', 'blame', 'rev-parse', 'ls-files', 'ls-tree', 'shortlog', 'describe']);
|
|
14
|
+
const GIT_FLAGS_THAT_RUN_OR_WRITE = ['--output', '--ext-diff', '--textconv', '--exec'];
|
|
15
|
+
const FIND_FLAGS_THAT_RUN_OR_WRITE = ['-exec', '-execdir', '-ok', '-okdir', '-delete', '-fprint', '-fprint0', '-fprintf', '-fls'];
|
|
16
|
+
/** What the shell hands the program: every quote removed, so `-d""elete` reads as `-delete`. */
|
|
17
|
+
const unquote = (t) => t.replace(/["']/g, '');
|
|
18
|
+
/**
|
|
19
|
+
* A git option that runs or writes, including git's unambiguous abbreviations of it
|
|
20
|
+
* (`--outp=x` is `--output=x`). Four characters is the shortest prefix, so `--out` counts.
|
|
21
|
+
*/
|
|
22
|
+
function isRiskyGitFlag(token) {
|
|
23
|
+
const name = token.split('=')[0] ?? '';
|
|
24
|
+
return name.length >= 4 && GIT_FLAGS_THAT_RUN_OR_WRITE.some((f) => f.startsWith(name));
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Splits on `;`, `&&`, `||` and `|` that sit outside quotes, so `grep 'a;b' f` stays one command.
|
|
28
|
+
* Returns undefined for an unbalanced quote: a line this cannot read is a line that asks.
|
|
29
|
+
*/
|
|
30
|
+
function splitOutsideQuotes(command) {
|
|
31
|
+
const segments = [];
|
|
32
|
+
let current = '';
|
|
33
|
+
let quote;
|
|
34
|
+
for (let i = 0; i < command.length; i++) {
|
|
35
|
+
const c = command[i];
|
|
36
|
+
if (quote !== undefined) {
|
|
37
|
+
if (c === quote)
|
|
38
|
+
quote = undefined;
|
|
39
|
+
current += c;
|
|
40
|
+
}
|
|
41
|
+
else if (c === "'" || c === '"') {
|
|
42
|
+
quote = c;
|
|
43
|
+
current += c;
|
|
44
|
+
}
|
|
45
|
+
else if (c === ';' || c === '|' || c === '&') {
|
|
46
|
+
const double = command[i + 1] === c && c !== ';';
|
|
47
|
+
// A lone & is a background job. Keep it in the segment so the segment check rejects it.
|
|
48
|
+
if (c === '&' && !double) {
|
|
49
|
+
current += c;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
segments.push(current);
|
|
53
|
+
current = '';
|
|
54
|
+
if (double)
|
|
55
|
+
i++;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
current += c;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (quote !== undefined)
|
|
62
|
+
return undefined;
|
|
63
|
+
segments.push(current);
|
|
64
|
+
return segments;
|
|
65
|
+
}
|
|
66
|
+
/** True when this one command, with no chaining, can only read. */
|
|
67
|
+
function segmentIsReadOnly(segment) {
|
|
68
|
+
if (segment.includes('&'))
|
|
69
|
+
return false;
|
|
70
|
+
const tokens = segment.trim().split(/\s+/).map(unquote).filter((t) => t !== '');
|
|
71
|
+
const [head, second, ...rest] = tokens;
|
|
72
|
+
if (head === undefined)
|
|
73
|
+
return false;
|
|
74
|
+
if (PLAIN.has(head))
|
|
75
|
+
return true;
|
|
76
|
+
if (head === 'command')
|
|
77
|
+
return second === '-v';
|
|
78
|
+
if (head === 'node')
|
|
79
|
+
return second === '--version' || second === '-v';
|
|
80
|
+
if (head === 'find')
|
|
81
|
+
return ![second, ...rest].some((t) => t !== undefined && FIND_FLAGS_THAT_RUN_OR_WRITE.includes(t));
|
|
82
|
+
if (head === 'git') {
|
|
83
|
+
// The subcommand must come first: `git -c core.pager=sh log` would run a program.
|
|
84
|
+
if (second === undefined || !GIT_READ.has(second))
|
|
85
|
+
return false;
|
|
86
|
+
return !rest.some(isRiskyGitFlag);
|
|
87
|
+
}
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
/** True when any segment of the line runs git, which can run programs the repo's config names. */
|
|
91
|
+
export function commandUsesGit(command) {
|
|
92
|
+
const segments = splitOutsideQuotes(command) ?? [];
|
|
93
|
+
return segments.some((s) => unquote(s.trim().split(/\s+/)[0] ?? '') === 'git');
|
|
94
|
+
}
|
|
95
|
+
/** True only when every segment of the line is a known read-only command. */
|
|
96
|
+
export function isReadOnlyCommand(command) {
|
|
97
|
+
if (command.trim() === '' || SHELL_SYNTAX.test(command))
|
|
98
|
+
return false;
|
|
99
|
+
const segments = splitOutsideQuotes(command);
|
|
100
|
+
return segments !== undefined && segments.every(segmentIsReadOnly);
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=read-only-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-only-command.js","sourceRoot":"","sources":["../../../src/lib/agent/read-only-command.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { type ClaudeCodeOpts } from './engines/claude-code.js';
|
|
2
|
+
import { type ResolvedPiModel } from './engines/pi-models.js';
|
|
3
|
+
import { type GraphToolSpec } from './graph-tools.js';
|
|
4
|
+
import { type EngineName } from './select-engine.js';
|
|
5
|
+
import { type AgentUiOptions } from './tui/app.js';
|
|
6
|
+
import type { AgentEngine, GateOutcome, ToolAsk } from './types.js';
|
|
7
|
+
/**
|
|
8
|
+
* The composition root for Align's own agent: picks the engine, builds the edit gate over the
|
|
9
|
+
* local graph, and hands both to Align's UI. Everything with a side effect is a dependency, so
|
|
10
|
+
* the wiring is tested without a terminal, a provider or a `claude` binary.
|
|
11
|
+
*/
|
|
12
|
+
export interface SessionDeps {
|
|
13
|
+
cwd: string;
|
|
14
|
+
env: Record<string, string | undefined>;
|
|
15
|
+
startupEnv: Readonly<Record<string, string | undefined>>;
|
|
16
|
+
out: (line: string) => void;
|
|
17
|
+
getRemembered: () => EngineName | undefined;
|
|
18
|
+
remember: (engine: EngineName) => void;
|
|
19
|
+
resolveModel: () => Promise<ResolvedPiModel | undefined>;
|
|
20
|
+
findClaude: () => string | null;
|
|
21
|
+
projectState: () => {
|
|
22
|
+
projectHasMcp: boolean;
|
|
23
|
+
projectHasBlock: boolean;
|
|
24
|
+
};
|
|
25
|
+
makeGate: () => (ask: ToolAsk) => Promise<GateOutcome>;
|
|
26
|
+
gitRunsPrograms: () => Promise<boolean>;
|
|
27
|
+
graphTools: () => GraphToolSpec[];
|
|
28
|
+
countDecisions: () => number;
|
|
29
|
+
loadPiEngine: () => Promise<{
|
|
30
|
+
createPiEngine: (o: {
|
|
31
|
+
cwd: string;
|
|
32
|
+
stateDir: string;
|
|
33
|
+
model: ResolvedPiModel;
|
|
34
|
+
tools: GraphToolSpec[];
|
|
35
|
+
}) => Promise<AgentEngine>;
|
|
36
|
+
}>;
|
|
37
|
+
createClaudeCodeEngine: (o: ClaudeCodeOpts) => AgentEngine;
|
|
38
|
+
runAgentUi: (o: AgentUiOptions) => Promise<number>;
|
|
39
|
+
record: (agent: 'align' | 'claude-code') => void;
|
|
40
|
+
}
|
|
41
|
+
export declare function runAgentSession(opts: {
|
|
42
|
+
engine?: EngineName;
|
|
43
|
+
}, deps?: SessionDeps): Promise<number>;
|
|
44
|
+
export declare function defaultSessionDeps(): SessionDeps;
|
|
45
|
+
//# sourceMappingURL=run-agent-session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-agent-session.d.ts","sourceRoot":"","sources":["../../../src/lib/agent/run-agent-session.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,KAAK,cAAc,EAA0B,MAAM,0BAA0B,CAAC;AACvF,OAAO,EAAE,KAAK,eAAe,EAAkB,MAAM,wBAAwB,CAAC;AAC9E,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,KAAK,UAAU,EAAgB,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,KAAK,cAAc,EAAc,MAAM,cAAc,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAEpE;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACxC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IACzD,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,aAAa,EAAE,MAAM,UAAU,GAAG,SAAS,CAAC;IAC5C,QAAQ,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACvC,YAAY,EAAE,MAAM,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC,CAAC;IACzD,UAAU,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IAChC,YAAY,EAAE,MAAM;QAAE,aAAa,EAAE,OAAO,CAAC;QAAC,eAAe,EAAE,OAAO,CAAA;KAAE,CAAC;IACzE,QAAQ,EAAE,MAAM,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IACvD,eAAe,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACxC,UAAU,EAAE,MAAM,aAAa,EAAE,CAAC;IAClC,cAAc,EAAE,MAAM,MAAM,CAAC;IAC7B,YAAY,EAAE,MAAM,OAAO,CAAC;QAAE,cAAc,EAAE,CAAC,CAAC,EAAE;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,eAAe,CAAC;YAAC,KAAK,EAAE,aAAa,EAAE,CAAA;SAAE,KAAK,OAAO,CAAC,WAAW,CAAC,CAAA;KAAE,CAAC,CAAC;IAChK,sBAAsB,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,WAAW,CAAC;IAC3D,UAAU,EAAE,CAAC,CAAC,EAAE,cAAc,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACnD,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,GAAG,aAAa,KAAK,IAAI,CAAC;CAClD;AAsBD,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAA;CAAE,EAAE,IAAI,GAAE,WAAkC,GAAG,OAAO,CAAC,MAAM,CAAC,CAwC9H;AAED,wBAAgB,kBAAkB,IAAI,WAAW,CA+ChD"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { confirm, isCancel } from '@clack/prompts';
|
|
4
|
+
import { alignNudgeBody } from '../agent-rules.js';
|
|
5
|
+
import { createConfigStore, savedLlmConfig } from '../config.js';
|
|
6
|
+
import { createGatewayClient } from '../gateway-client.js';
|
|
7
|
+
import { findOnPath } from '../launch/detect.js';
|
|
8
|
+
import { isLocalDefault } from '../launch/launch.js';
|
|
9
|
+
import { readProjectState } from '../launch/project-state.js';
|
|
10
|
+
import { childEnv } from '../launch/run-agent.js';
|
|
11
|
+
import { createLocalDb } from '../local-db.js';
|
|
12
|
+
import { hasConfiguredProvider, probeOllama } from '../local-llm.js';
|
|
13
|
+
import { alignConfigDir } from '../private-files.js';
|
|
14
|
+
import { STARTUP_ENV } from '../startup-env.js';
|
|
15
|
+
import { launchAlignEntry } from '../trusted-align-bin.js';
|
|
16
|
+
import { ASK_ONCE_GUIDANCE } from './agent-guidance.js';
|
|
17
|
+
import { gateEdit } from './edit-gate.js';
|
|
18
|
+
import { decisionsThatWroteTheseLines } from './edit-text.js';
|
|
19
|
+
import { gitConfigRunsPrograms } from './git-runs-programs.js';
|
|
20
|
+
import { createClaudeCodeEngine } from './engines/claude-code.js';
|
|
21
|
+
import { resolvePiModel } from './engines/pi-models.js';
|
|
22
|
+
import { createGraphTools } from './graph-tools.js';
|
|
23
|
+
import { selectEngine } from './select-engine.js';
|
|
24
|
+
import { runAgentUi } from './tui/app.js';
|
|
25
|
+
const NOTHING_TO_RUN = [
|
|
26
|
+
'Align needs a model to run its own agent, or your own Claude Code.',
|
|
27
|
+
' Add an API key: align ai',
|
|
28
|
+
' Use a local model: ollama pull qwen2.5:7b',
|
|
29
|
+
' Or install Claude Code (your subscription works): https://claude.com/claude-code',
|
|
30
|
+
];
|
|
31
|
+
const CANNOT_RUN = {
|
|
32
|
+
align: 'Align\'s own engine has no model. Add a key with `align ai`, or start Ollama.',
|
|
33
|
+
claude: 'Claude Code is not installed (no `claude` on PATH).',
|
|
34
|
+
};
|
|
35
|
+
function claudeArgs(state) {
|
|
36
|
+
const args = [];
|
|
37
|
+
args.push('--append-system-prompt', [...(state.projectHasBlock ? [] : [alignNudgeBody()]), ASK_ONCE_GUIDANCE].join('\n\n'));
|
|
38
|
+
// Last, because claude's --mcp-config is variadic. Named align-local so it never replaces a
|
|
39
|
+
// server the user configured as `align` (see adapters/claude-code.ts).
|
|
40
|
+
if (!state.projectHasMcp)
|
|
41
|
+
args.push('--mcp-config', JSON.stringify({ mcpServers: { 'align-local': launchAlignEntry('mcpServers') } }));
|
|
42
|
+
return args;
|
|
43
|
+
}
|
|
44
|
+
export async function runAgentSession(opts, deps = defaultSessionDeps()) {
|
|
45
|
+
const model = await deps.resolveModel();
|
|
46
|
+
const claudeBin = deps.findClaude();
|
|
47
|
+
const choice = selectEngine({ flag: opts.engine, remembered: deps.getRemembered(), hasModel: model !== undefined, claudeOnPath: claudeBin !== null });
|
|
48
|
+
if (choice.engine === 'none') {
|
|
49
|
+
(choice.unavailable ? [CANNOT_RUN[choice.unavailable]] : NOTHING_TO_RUN).forEach((l) => deps.out(l));
|
|
50
|
+
return 1;
|
|
51
|
+
}
|
|
52
|
+
if (opts.engine)
|
|
53
|
+
deps.remember(opts.engine);
|
|
54
|
+
const claude = () => deps.createClaudeCodeEngine({
|
|
55
|
+
cwd: deps.cwd,
|
|
56
|
+
bin: claudeBin ?? 'claude',
|
|
57
|
+
extraArgs: claudeArgs(deps.projectState()),
|
|
58
|
+
// The user's own environment, not Align's: a key Align saved stays out of `claude`, and
|
|
59
|
+
// ALIGN_WRAPPED stops an `align` run inside it from opening a second agent.
|
|
60
|
+
env: childEnv(deps.env, deps.startupEnv, { ALIGN_WRAPPED: '1' }),
|
|
61
|
+
});
|
|
62
|
+
let engine;
|
|
63
|
+
let agent = choice.engine === 'align' ? 'align' : 'claude-code';
|
|
64
|
+
if (choice.engine === 'align' && model) {
|
|
65
|
+
try {
|
|
66
|
+
const { createPiEngine } = await deps.loadPiEngine();
|
|
67
|
+
engine = await createPiEngine({ cwd: deps.cwd, stateDir: alignConfigDir(), model, tools: deps.graphTools() });
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
if (!claudeBin || opts.engine === 'align') {
|
|
71
|
+
deps.out(`Align's own engine could not start: ${err.message}`);
|
|
72
|
+
return 1;
|
|
73
|
+
}
|
|
74
|
+
deps.out(`Align's own engine could not start (${err.message}). Using your Claude Code instead.`);
|
|
75
|
+
engine = claude();
|
|
76
|
+
agent = 'claude-code';
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
engine = claude();
|
|
81
|
+
}
|
|
82
|
+
deps.record(agent);
|
|
83
|
+
return deps.runAgentUi({ engine, decisionCount: deps.countDecisions(), gate: deps.makeGate(), gitRunsPrograms: deps.gitRunsPrograms });
|
|
84
|
+
}
|
|
85
|
+
export function defaultSessionDeps() {
|
|
86
|
+
const config = createConfigStore();
|
|
87
|
+
const localEnv = config.getEnvironment('local');
|
|
88
|
+
const client = createGatewayClient(localEnv);
|
|
89
|
+
const cwd = process.cwd();
|
|
90
|
+
return {
|
|
91
|
+
cwd,
|
|
92
|
+
env: process.env,
|
|
93
|
+
startupEnv: STARTUP_ENV,
|
|
94
|
+
out: (l) => process.stderr.write(`${l}\n`),
|
|
95
|
+
getRemembered: () => config.getAgentEngine(),
|
|
96
|
+
remember: (e) => config.setAgentEngine(e),
|
|
97
|
+
resolveModel: () => resolvePiModel({ saved: savedLlmConfig(config), probeOllama }),
|
|
98
|
+
findClaude: () => findOnPath('claude', process.env, process.platform),
|
|
99
|
+
projectState: () => readProjectState(cwd, os.homedir(), { localIsDefault: isLocalDefault() }),
|
|
100
|
+
makeGate: () => (ask) => gateEdit(ask, {
|
|
101
|
+
client,
|
|
102
|
+
cwd,
|
|
103
|
+
canAdjudicate: () => hasConfiguredProvider(),
|
|
104
|
+
blame: (input, at) => decisionsThatWroteTheseLines(client, input, at),
|
|
105
|
+
}),
|
|
106
|
+
gitRunsPrograms: () => gitConfigRunsPrograms(cwd),
|
|
107
|
+
graphTools: () => createGraphTools({ client, env: localEnv }),
|
|
108
|
+
countDecisions: () => {
|
|
109
|
+
if (!localEnv.localDbPath)
|
|
110
|
+
return 0;
|
|
111
|
+
const db = createLocalDb(localEnv.localDbPath);
|
|
112
|
+
try {
|
|
113
|
+
return db.getStats().decisions;
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
db.close();
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
// The engine is a one-time download on first use (pi-sdk.ts says why), asked for here, before
|
|
120
|
+
// the screen opens. A no or a failure falls back like any engine that cannot start.
|
|
121
|
+
loadPiEngine: async () => {
|
|
122
|
+
const { defaultPiSdkDeps, loadPiSdk, PI_ENGINE_VERSION } = await import('./engines/pi-sdk.js');
|
|
123
|
+
const sdk = await loadPiSdk(defaultPiSdkDeps({
|
|
124
|
+
engineDir: path.join(alignConfigDir(), 'engine', PI_ENGINE_VERSION),
|
|
125
|
+
confirm: async (message) => { const yes = await confirm({ message, initialValue: true }); return !isCancel(yes) && yes === true; },
|
|
126
|
+
}));
|
|
127
|
+
const { createPiEngine } = await import('./engines/pi.js');
|
|
128
|
+
return { createPiEngine: (o) => createPiEngine(o, { sdk }) };
|
|
129
|
+
},
|
|
130
|
+
createClaudeCodeEngine,
|
|
131
|
+
runAgentUi,
|
|
132
|
+
record: (agent) => {
|
|
133
|
+
void import('../usage-telemetry.js')
|
|
134
|
+
.then((m) => m.recordFunnelStage(localEnv, 'agent_launched', 'align', { agent }))
|
|
135
|
+
.catch(() => undefined);
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=run-agent-session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-agent-session.js","sourceRoot":"","sources":["../../../src/lib/agent/run-agent-session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which engine bare `align` runs behind Align's UI.
|
|
3
|
+
*
|
|
4
|
+
* An explicit `--engine` is obeyed or refused, never swapped for the other: a person who typed
|
|
5
|
+
* `--engine claude` and got a different model would not know which one answered. A remembered
|
|
6
|
+
* choice is softer, because the machine may have changed since it was saved (Claude Code
|
|
7
|
+
* uninstalled, a key removed), so it falls back to the default. The default prefers Align's own
|
|
8
|
+
* engine when a model is configured, then the user's own Claude Code, which keeps a subscription
|
|
9
|
+
* user on their subscription with no key to buy.
|
|
10
|
+
*/
|
|
11
|
+
export type EngineName = 'align' | 'claude';
|
|
12
|
+
export interface EngineFacts {
|
|
13
|
+
flag?: EngineName;
|
|
14
|
+
remembered?: EngineName;
|
|
15
|
+
/** A model the Align engine can run on: a saved or exported key, or a reachable Ollama. */
|
|
16
|
+
hasModel: boolean;
|
|
17
|
+
claudeOnPath: boolean;
|
|
18
|
+
}
|
|
19
|
+
export type EngineChoice = {
|
|
20
|
+
engine: 'align';
|
|
21
|
+
} | {
|
|
22
|
+
engine: 'claude-code';
|
|
23
|
+
} | {
|
|
24
|
+
engine: 'none';
|
|
25
|
+
unavailable?: EngineName;
|
|
26
|
+
};
|
|
27
|
+
export declare function selectEngine(f: EngineFacts): EngineChoice;
|
|
28
|
+
//# sourceMappingURL=select-engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select-engine.d.ts","sourceRoot":"","sources":["../../../src/lib/agent/select-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE5C,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,2FAA2F;IAC3F,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,MAAM,YAAY,GAAG;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,aAAa,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,UAAU,CAAA;CAAE,CAAC;AAO1H,wBAAgB,YAAY,CAAC,CAAC,EAAE,WAAW,GAAG,YAAY,CAKzD"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
function runnable(name, f) {
|
|
2
|
+
if (name === 'align')
|
|
3
|
+
return f.hasModel ? { engine: 'align' } : undefined;
|
|
4
|
+
return f.claudeOnPath ? { engine: 'claude-code' } : undefined;
|
|
5
|
+
}
|
|
6
|
+
export function selectEngine(f) {
|
|
7
|
+
if (f.flag)
|
|
8
|
+
return runnable(f.flag, f) ?? { engine: 'none', unavailable: f.flag };
|
|
9
|
+
const remembered = f.remembered && runnable(f.remembered, f);
|
|
10
|
+
if (remembered)
|
|
11
|
+
return remembered;
|
|
12
|
+
return runnable('align', f) ?? runnable('claude', f) ?? { engine: 'none' };
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=select-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select-engine.js","sourceRoot":"","sources":["../../../src/lib/agent/select-engine.ts"],"names":[],"mappings":"AAsBA,SAAS,QAAQ,CAAC,IAAgB,EAAE,CAAc;IAChD,IAAI,IAAI,KAAK,OAAO;QAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAC1E,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,CAAc;IACzC,IAAI,CAAC,CAAC,IAAI;QAAE,OAAO,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAClF,MAAM,UAAU,GAAG,CAAC,CAAC,UAAU,IAAI,QAAQ,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;IAC7D,IAAI,UAAU;QAAE,OAAO,UAAU,CAAC;IAClC,OAAO,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC7E,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type Terminal } from '@earendil-works/pi-tui';
|
|
2
|
+
import type { AgentEngine, GateOutcome, ToolAsk } from '../types.js';
|
|
3
|
+
/** The only file that names pi-tui, so a breaking change there stays in one place. */
|
|
4
|
+
export interface AgentUiOptions {
|
|
5
|
+
engine: AgentEngine;
|
|
6
|
+
decisionCount: number;
|
|
7
|
+
gate: (ask: ToolAsk) => Promise<GateOutcome>;
|
|
8
|
+
gitRunsPrograms?: () => Promise<boolean>;
|
|
9
|
+
terminal?: Terminal;
|
|
10
|
+
}
|
|
11
|
+
export declare function runAgentUi(opts: AgentUiOptions): Promise<number>;
|
|
12
|
+
//# sourceMappingURL=app.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../../../src/lib/agent/tui/app.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0G,KAAK,QAAQ,EAAuB,MAAM,wBAAwB,CAAC;AAGpL,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAe,OAAO,EAAE,MAAM,aAAa,CAAC;AAKlF,sFAAsF;AACtF,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,WAAW,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAC7C,eAAe,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACzC,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAaD,wBAAsB,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAgGtE"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { Container, Editor, Markdown, matchesKey, ProcessTerminal, Spacer, Text, TuiMainScreen } from '@earendil-works/pi-tui';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { createBroker } from '../permission-broker.js';
|
|
4
|
+
import { commandCard, gateCard, gateNote, headerLine, toolLine } from './cards.js';
|
|
5
|
+
import { answerForKey, createController } from './controller.js';
|
|
6
|
+
import { theme } from './theme.js';
|
|
7
|
+
const markdownTheme = {
|
|
8
|
+
heading: theme.title, link: theme.link, linkUrl: theme.dim, code: theme.key, codeBlock: (s) => s,
|
|
9
|
+
codeBlockBorder: theme.dim, quote: theme.dim, quoteBorder: theme.dim, hr: theme.dim, listBullet: theme.key,
|
|
10
|
+
bold: chalk.bold, italic: chalk.italic, strikethrough: chalk.strikethrough, underline: chalk.underline,
|
|
11
|
+
};
|
|
12
|
+
const editorTheme = {
|
|
13
|
+
borderColor: theme.dim,
|
|
14
|
+
selectList: { selectedPrefix: theme.key, selectedText: theme.title, description: theme.dim, scrollInfo: theme.dim, noMatch: theme.dim },
|
|
15
|
+
};
|
|
16
|
+
export async function runAgentUi(opts) {
|
|
17
|
+
const { engine } = opts;
|
|
18
|
+
const tui = new TuiMainScreen(opts.terminal ?? new ProcessTerminal());
|
|
19
|
+
const transcript = new Container();
|
|
20
|
+
const editor = new Editor(tui, editorTheme);
|
|
21
|
+
const controller = createController();
|
|
22
|
+
let streaming;
|
|
23
|
+
let pending;
|
|
24
|
+
let finish = () => { };
|
|
25
|
+
const addLines = (lines) => {
|
|
26
|
+
streaming = undefined;
|
|
27
|
+
for (const l of lines)
|
|
28
|
+
transcript.addChild(new Text(l, 1, 0));
|
|
29
|
+
tui.requestRender();
|
|
30
|
+
};
|
|
31
|
+
const endTurn = () => { controller.turnEnded(); editor.disableSubmit = false; tui.requestRender(); };
|
|
32
|
+
const askHuman = (q) => {
|
|
33
|
+
addLines(['', ...(q.kind === 'gate' ? gateCard(q) : commandCard(q)), '']);
|
|
34
|
+
controller.beginAsk();
|
|
35
|
+
return new Promise((resolve) => { pending = { kind: q.kind, resolve }; });
|
|
36
|
+
};
|
|
37
|
+
const broker = createBroker({ gate: opts.gate, gitRunsPrograms: opts.gitRunsPrograms, askHuman, onGate: (outcome) => addLines(gateNote(outcome)) });
|
|
38
|
+
const onKey = (data) => {
|
|
39
|
+
if (matchesKey(data, 'ctrl+c')) {
|
|
40
|
+
if (controller.ctrlC() === 'exit')
|
|
41
|
+
finish(0);
|
|
42
|
+
else
|
|
43
|
+
addLines([theme.dim('Press Ctrl+C again to leave.')]);
|
|
44
|
+
return { consume: true };
|
|
45
|
+
}
|
|
46
|
+
controller.otherKey();
|
|
47
|
+
if (matchesKey(data, 'ctrl+d') && controller.ctrlD(editor.getText() === '') === 'exit') {
|
|
48
|
+
finish(0);
|
|
49
|
+
return { consume: true };
|
|
50
|
+
}
|
|
51
|
+
if (pending) {
|
|
52
|
+
const answer = answerForKey(pending.kind, data);
|
|
53
|
+
if (answer) {
|
|
54
|
+
const { resolve } = pending;
|
|
55
|
+
pending = undefined;
|
|
56
|
+
controller.endAsk();
|
|
57
|
+
resolve(answer);
|
|
58
|
+
}
|
|
59
|
+
return { consume: true };
|
|
60
|
+
}
|
|
61
|
+
if (matchesKey(data, 'escape') && controller.escape() === 'abort') {
|
|
62
|
+
engine.abort();
|
|
63
|
+
return { consume: true };
|
|
64
|
+
}
|
|
65
|
+
return undefined;
|
|
66
|
+
};
|
|
67
|
+
editor.onSubmit = (text) => {
|
|
68
|
+
const line = controller.submit(text);
|
|
69
|
+
if (line === undefined)
|
|
70
|
+
return;
|
|
71
|
+
editor.setText('');
|
|
72
|
+
editor.disableSubmit = true;
|
|
73
|
+
addLines(['', `${theme.brand('>')} ${line}`]);
|
|
74
|
+
engine.prompt(line).catch((e) => addLines([theme.error(e instanceof Error ? e.message : String(e))])).finally(endTurn);
|
|
75
|
+
};
|
|
76
|
+
tui.addChild(new Text(headerLine({ label: engine.label, decisionCount: opts.decisionCount }), 1, 0));
|
|
77
|
+
tui.addChild(new Spacer(1));
|
|
78
|
+
tui.addChild(transcript);
|
|
79
|
+
tui.addChild(editor);
|
|
80
|
+
tui.setFocus(editor);
|
|
81
|
+
tui.addInputListener(onKey);
|
|
82
|
+
const closed = new Promise((resolve) => { finish = resolve; });
|
|
83
|
+
let failed;
|
|
84
|
+
try {
|
|
85
|
+
tui.start();
|
|
86
|
+
// An engine that cannot start (no `claude`, a bad key) ends the run with its reason, printed
|
|
87
|
+
// after the screen is restored, rather than throwing out of a cleared terminal.
|
|
88
|
+
await engine.start((e) => {
|
|
89
|
+
if (e.type === 'text') {
|
|
90
|
+
if (!streaming) {
|
|
91
|
+
streaming = { md: new Markdown('', 1, 0, markdownTheme), text: '' };
|
|
92
|
+
transcript.addChild(streaming.md);
|
|
93
|
+
}
|
|
94
|
+
streaming.text += e.delta;
|
|
95
|
+
streaming.md.setText(streaming.text);
|
|
96
|
+
}
|
|
97
|
+
else if (e.type === 'gate') {
|
|
98
|
+
addLines(gateNote(e.outcome));
|
|
99
|
+
}
|
|
100
|
+
else if (e.type === 'error') {
|
|
101
|
+
addLines([theme.error(e.message)]);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
addLines(toolLine(e));
|
|
105
|
+
if (e.type === 'turn-end')
|
|
106
|
+
endTurn();
|
|
107
|
+
}
|
|
108
|
+
tui.requestRender();
|
|
109
|
+
}, broker).catch((err) => { failed = err instanceof Error ? err.message : String(err); });
|
|
110
|
+
if (failed === undefined) {
|
|
111
|
+
const code = await closed;
|
|
112
|
+
await engine.close();
|
|
113
|
+
return code;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
tui.stop();
|
|
118
|
+
}
|
|
119
|
+
process.stderr.write(`${failed}\n`);
|
|
120
|
+
return 1;
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=app.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../../../src/lib/agent/tui/app.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { HumanQuestion } from '../permission-broker.js';
|
|
2
|
+
import type { AgentUiEvent, GateOutcome } from '../types.js';
|
|
3
|
+
export declare function headerLine(o: {
|
|
4
|
+
label: string;
|
|
5
|
+
decisionCount: number;
|
|
6
|
+
}): string;
|
|
7
|
+
export declare function gateCard(q: Extract<HumanQuestion, {
|
|
8
|
+
kind: 'gate';
|
|
9
|
+
}>): string[];
|
|
10
|
+
export declare function commandCard(q: Extract<HumanQuestion, {
|
|
11
|
+
kind: 'command';
|
|
12
|
+
}>): string[];
|
|
13
|
+
/** What an allowed edit leaves in the transcript. Never silent when the gate could not check. */
|
|
14
|
+
export declare function gateNote(outcome: GateOutcome): string[];
|
|
15
|
+
/** The transcript line for a tool starting, or for one that failed (with why, when it said). */
|
|
16
|
+
export declare function toolLine(e: AgentUiEvent): string[];
|
|
17
|
+
//# sourceMappingURL=cards.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cards.d.ts","sourceRoot":"","sources":["../../../../src/lib/agent/tui/cards.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAgB,WAAW,EAAE,MAAM,aAAa,CAAC;AAG3E,wBAAgB,UAAU,CAAC,CAAC,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAG9E;AAUD,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC,aAAa,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,MAAM,EAAE,CAY9E;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,CAAC,aAAa,EAAE;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC,GAAG,MAAM,EAAE,CAEpF;AAED,iGAAiG;AACjG,wBAAgB,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,EAAE,CAKvD;AAED,gGAAgG;AAChG,wBAAgB,QAAQ,CAAC,CAAC,EAAE,YAAY,GAAG,MAAM,EAAE,CAMlD"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { theme } from './theme.js';
|
|
2
|
+
export function headerLine(o) {
|
|
3
|
+
const n = `${o.decisionCount} ${o.decisionCount === 1 ? 'decision' : 'decisions'}`;
|
|
4
|
+
return [theme.brand('Align'), o.label, n].join(theme.dim(' · '));
|
|
5
|
+
}
|
|
6
|
+
function decisionLines(d) {
|
|
7
|
+
return [
|
|
8
|
+
` ${theme.title(d.title)}`,
|
|
9
|
+
...(d.why ? [` ${d.why}`] : []),
|
|
10
|
+
...(d.url ? [` ${theme.link(d.url)}`] : []),
|
|
11
|
+
];
|
|
12
|
+
}
|
|
13
|
+
export function gateCard(q) {
|
|
14
|
+
const lead = {
|
|
15
|
+
conflict: 'This edit conflicts with a decision',
|
|
16
|
+
'rewrites-decided-lines': 'This edit changes lines written by a decision',
|
|
17
|
+
unchecked: 'Align could not read this edit, so it was not checked against your decisions',
|
|
18
|
+
}[q.outcome.reason];
|
|
19
|
+
return [
|
|
20
|
+
theme.warn(lead),
|
|
21
|
+
...q.outcome.cards.flatMap((d) => ['', ...decisionLines(d)]),
|
|
22
|
+
'',
|
|
23
|
+
theme.key('[a] allow once [s] stop'),
|
|
24
|
+
];
|
|
25
|
+
}
|
|
26
|
+
export function commandCard(q) {
|
|
27
|
+
return [theme.warn('Run this command?'), ` ${q.command}`, '', theme.key('[y] yes [s] yes for this session [n] no')];
|
|
28
|
+
}
|
|
29
|
+
/** What an allowed edit leaves in the transcript. Never silent when the gate could not check. */
|
|
30
|
+
export function gateNote(outcome) {
|
|
31
|
+
if (outcome.kind !== 'allow')
|
|
32
|
+
return [];
|
|
33
|
+
if (outcome.note === 'not-checked')
|
|
34
|
+
return [theme.dim('not checked against the decision graph')];
|
|
35
|
+
if (outcome.cards.length === 0)
|
|
36
|
+
return [];
|
|
37
|
+
return [theme.dim(`checked against: ${outcome.cards.map((d) => d.title).join(', ')}`)];
|
|
38
|
+
}
|
|
39
|
+
/** The transcript line for a tool starting, or for one that failed (with why, when it said). */
|
|
40
|
+
export function toolLine(e) {
|
|
41
|
+
if (e.type === 'tool-start')
|
|
42
|
+
return [`${theme.dim('•')} ${theme.title(e.tool)} ${theme.dim(e.summary)}`];
|
|
43
|
+
if (e.type === 'tool-end' && !e.ok) {
|
|
44
|
+
return [theme.error(' that tool call failed'), ...(e.detail ?? '').split('\n').filter((l) => l !== '').map((l) => theme.dim(` ${l}`))];
|
|
45
|
+
}
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=cards.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cards.js","sourceRoot":"","sources":["../../../../src/lib/agent/tui/cards.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { HumanAnswer } from '../types.js';
|
|
2
|
+
/** The screen's state machine, with no terminal in it so it can be tested on its own. */
|
|
3
|
+
export type Phase = 'idle' | 'running' | 'awaiting-answer';
|
|
4
|
+
export interface Controller {
|
|
5
|
+
phase(): Phase;
|
|
6
|
+
/** Returns the text to send, or undefined when the line is empty or a turn is already running. */
|
|
7
|
+
submit(text: string): string | undefined;
|
|
8
|
+
turnEnded(): void;
|
|
9
|
+
beginAsk(): void;
|
|
10
|
+
endAsk(): void;
|
|
11
|
+
/** Esc: abort only while a turn runs (not while a question is open). */
|
|
12
|
+
escape(): 'abort' | 'none';
|
|
13
|
+
/** Two in a row exit. */
|
|
14
|
+
ctrlC(): 'hint' | 'exit';
|
|
15
|
+
/** Any key that is not Ctrl+C resets the exit count. */
|
|
16
|
+
otherKey(): void;
|
|
17
|
+
ctrlD(editorEmpty: boolean): 'exit' | 'none';
|
|
18
|
+
}
|
|
19
|
+
export declare function createController(): Controller;
|
|
20
|
+
export declare function answerForKey(kind: 'gate' | 'command', key: string): HumanAnswer | undefined;
|
|
21
|
+
//# sourceMappingURL=controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../src/lib/agent/tui/controller.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,yFAAyF;AACzF,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,SAAS,GAAG,iBAAiB,CAAC;AAE3D,MAAM,WAAW,UAAU;IACzB,KAAK,IAAI,KAAK,CAAC;IACf,kGAAkG;IAClG,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACzC,SAAS,IAAI,IAAI,CAAC;IAClB,QAAQ,IAAI,IAAI,CAAC;IACjB,MAAM,IAAI,IAAI,CAAC;IACf,wEAAwE;IACxE,MAAM,IAAI,OAAO,GAAG,MAAM,CAAC;IAC3B,yBAAyB;IACzB,KAAK,IAAI,MAAM,GAAG,MAAM,CAAC;IACzB,wDAAwD;IACxD,QAAQ,IAAI,IAAI,CAAC;IACjB,KAAK,CAAC,WAAW,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;CAC9C;AAED,wBAAgB,gBAAgB,IAAI,UAAU,CAmB7C;AAOD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAE3F"}
|