@aligndottech/cli 0.46.0 → 0.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -8
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +14 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/connect-agents.d.ts.map +1 -1
- package/dist/commands/connect-agents.js +13 -3
- package/dist/commands/connect-agents.js.map +1 -1
- package/dist/commands/default-action.d.ts +5 -5
- package/dist/commands/default-action.d.ts.map +1 -1
- package/dist/commands/default-action.js +40 -13
- package/dist/commands/default-action.js.map +1 -1
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +12 -4
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/registry.d.ts.map +1 -1
- package/dist/commands/registry.js +2 -0
- package/dist/commands/registry.js.map +1 -1
- package/dist/commands/setup.d.ts +2 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +84 -114
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/use.d.ts +32 -0
- package/dist/commands/use.d.ts.map +1 -0
- package/dist/commands/use.js +94 -0
- package/dist/commands/use.js.map +1 -0
- package/dist/lib/agent-rules.d.ts +18 -5
- package/dist/lib/agent-rules.d.ts.map +1 -1
- package/dist/lib/agent-rules.js +81 -22
- package/dist/lib/agent-rules.js.map +1 -1
- package/dist/lib/config.d.ts +14 -10
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +64 -17
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/foreign-env.d.ts +23 -0
- package/dist/lib/foreign-env.d.ts.map +1 -0
- package/dist/lib/foreign-env.js +27 -0
- package/dist/lib/foreign-env.js.map +1 -0
- package/dist/lib/gateway-client.d.ts +5 -1
- package/dist/lib/gateway-client.d.ts.map +1 -1
- package/dist/lib/gateway-client.js +10 -2
- package/dist/lib/gateway-client.js.map +1 -1
- package/dist/lib/launch/adapters/args.d.ts +7 -0
- package/dist/lib/launch/adapters/args.d.ts.map +1 -0
- package/dist/lib/launch/adapters/args.js +10 -0
- package/dist/lib/launch/adapters/args.js.map +1 -0
- package/dist/lib/launch/adapters/claude-code.d.ts +39 -0
- package/dist/lib/launch/adapters/claude-code.d.ts.map +1 -0
- package/dist/lib/launch/adapters/claude-code.js +39 -0
- package/dist/lib/launch/adapters/claude-code.js.map +1 -0
- package/dist/lib/launch/adapters/cursor.d.ts +18 -0
- package/dist/lib/launch/adapters/cursor.d.ts.map +1 -0
- package/dist/lib/launch/adapters/cursor.js +27 -0
- package/dist/lib/launch/adapters/cursor.js.map +1 -0
- package/dist/lib/launch/adapters/opencode.d.ts +21 -0
- package/dist/lib/launch/adapters/opencode.d.ts.map +1 -0
- package/dist/lib/launch/adapters/opencode.js +64 -0
- package/dist/lib/launch/adapters/opencode.js.map +1 -0
- package/dist/lib/launch/adapters/pi.d.ts +23 -0
- package/dist/lib/launch/adapters/pi.d.ts.map +1 -0
- package/dist/lib/launch/adapters/pi.js +35 -0
- package/dist/lib/launch/adapters/pi.js.map +1 -0
- package/dist/lib/launch/agents.d.ts +24 -0
- package/dist/lib/launch/agents.d.ts.map +1 -0
- package/dist/lib/launch/agents.js +22 -0
- package/dist/lib/launch/agents.js.map +1 -0
- package/dist/lib/launch/config-writes.d.ts +37 -0
- package/dist/lib/launch/config-writes.d.ts.map +1 -0
- package/dist/lib/launch/config-writes.js +26 -0
- package/dist/lib/launch/config-writes.js.map +1 -0
- package/dist/lib/launch/cursor-state.d.ts +14 -0
- package/dist/lib/launch/cursor-state.d.ts.map +1 -0
- package/dist/lib/launch/cursor-state.js +26 -0
- package/dist/lib/launch/cursor-state.js.map +1 -0
- package/dist/lib/launch/detect.d.ts +7 -0
- package/dist/lib/launch/detect.d.ts.map +1 -0
- package/dist/lib/launch/detect.js +34 -0
- package/dist/lib/launch/detect.js.map +1 -0
- package/dist/lib/launch/launch-files.d.ts +15 -0
- package/dist/lib/launch/launch-files.d.ts.map +1 -0
- package/dist/lib/launch/launch-files.js +56 -0
- package/dist/lib/launch/launch-files.js.map +1 -0
- package/dist/lib/launch/launch.d.ts +59 -0
- package/dist/lib/launch/launch.d.ts.map +1 -0
- package/dist/lib/launch/launch.js +198 -0
- package/dist/lib/launch/launch.js.map +1 -0
- package/dist/lib/launch/opencode-state.d.ts +16 -0
- package/dist/lib/launch/opencode-state.d.ts.map +1 -0
- package/dist/lib/launch/opencode-state.js +103 -0
- package/dist/lib/launch/opencode-state.js.map +1 -0
- package/dist/lib/launch/pi-state.d.ts +23 -0
- package/dist/lib/launch/pi-state.d.ts.map +1 -0
- package/dist/lib/launch/pi-state.js +112 -0
- package/dist/lib/launch/pi-state.js.map +1 -0
- package/dist/lib/launch/pick-agent.d.ts +28 -0
- package/dist/lib/launch/pick-agent.d.ts.map +1 -0
- package/dist/lib/launch/pick-agent.js +63 -0
- package/dist/lib/launch/pick-agent.js.map +1 -0
- package/dist/lib/launch/project-state.d.ts +21 -0
- package/dist/lib/launch/project-state.d.ts.map +1 -0
- package/dist/lib/launch/project-state.js +100 -0
- package/dist/lib/launch/project-state.js.map +1 -0
- package/dist/lib/launch/run-agent.d.ts +21 -0
- package/dist/lib/launch/run-agent.d.ts.map +1 -0
- package/dist/lib/launch/run-agent.js +69 -0
- package/dist/lib/launch/run-agent.js.map +1 -0
- package/dist/lib/local-gateway-client.d.ts +4 -4
- package/dist/lib/local-gateway-client.d.ts.map +1 -1
- package/dist/lib/local-gateway-client.js +3 -1
- package/dist/lib/local-gateway-client.js.map +1 -1
- package/dist/lib/mcp-setup.d.ts +9 -2
- package/dist/lib/mcp-setup.d.ts.map +1 -1
- package/dist/lib/mcp-setup.js +104 -28
- package/dist/lib/mcp-setup.js.map +1 -1
- package/dist/lib/mcp-timeline-tools.d.ts.map +1 -1
- package/dist/lib/mcp-timeline-tools.js +5 -3
- package/dist/lib/mcp-timeline-tools.js.map +1 -1
- package/dist/lib/safe-config-write.d.ts +140 -0
- package/dist/lib/safe-config-write.d.ts.map +1 -0
- package/dist/lib/safe-config-write.js +701 -0
- package/dist/lib/safe-config-write.js.map +1 -0
- package/dist/lib/setup-route.d.ts +26 -0
- package/dist/lib/setup-route.d.ts.map +1 -0
- package/dist/lib/setup-route.js +36 -0
- package/dist/lib/setup-route.js.map +1 -0
- package/dist/lib/usage-telemetry.d.ts +6 -2
- package/dist/lib/usage-telemetry.d.ts.map +1 -1
- package/dist/lib/usage-telemetry.js +6 -2
- package/dist/lib/usage-telemetry.js.map +1 -1
- package/dist/lib/user-hooks.d.ts +2 -1
- package/dist/lib/user-hooks.d.ts.map +1 -1
- package/dist/lib/user-hooks.js +42 -10
- package/dist/lib/user-hooks.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface OpenCodeProjectState {
|
|
2
|
+
projectHasPlugin: boolean;
|
|
3
|
+
projectHasMcp: boolean;
|
|
4
|
+
projectHasBlock: boolean;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* What OpenCode would already load for this directory, so a per-session injection never doubles
|
|
8
|
+
* it. "Present" means present AND doing the same job: a plugin or server aimed at another graph
|
|
9
|
+
* does not stand in for ours. Unreadable or malformed files count as absent: the cost of a wrong
|
|
10
|
+
* "absent" is a duplicate, the cost of a throw is no session at all. Only `.json` configs are
|
|
11
|
+
* read; a commented `.jsonc` does not parse and reads as absent.
|
|
12
|
+
*/
|
|
13
|
+
export declare function readOpenCodeState(cwd: string, home: string, opts: {
|
|
14
|
+
localIsDefault: boolean;
|
|
15
|
+
}, env?: Record<string, string | undefined>): OpenCodeProjectState;
|
|
16
|
+
//# sourceMappingURL=opencode-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode-state.d.ts","sourceRoot":"","sources":["../../../src/lib/launch/opencode-state.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,oBAAoB;IACnC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,EAAE,OAAO,CAAC;CAC1B;AA+ED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE;IAAE,cAAc,EAAE,OAAO,CAAA;CAAE,EACjC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAM,GAC3C,oBAAoB,CAatB"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { ALIGN_NUDGE_START } from '../agent-rules.js';
|
|
4
|
+
import { readsLocal } from './project-state.js';
|
|
5
|
+
function readText(file) {
|
|
6
|
+
try {
|
|
7
|
+
return readFileSync(file, 'utf8');
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function readJson(file) {
|
|
14
|
+
const text = readText(file);
|
|
15
|
+
if (text === null)
|
|
16
|
+
return null;
|
|
17
|
+
try {
|
|
18
|
+
const parsed = JSON.parse(text);
|
|
19
|
+
return typeof parsed === 'object' && parsed !== null ? parsed : null;
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The cwd and each directory above it, up to and including the git root (OpenCode's own
|
|
27
|
+
* project boundary: it does not read config or AGENTS.md above the worktree). With no .git
|
|
28
|
+
* anywhere, all the way up.
|
|
29
|
+
*/
|
|
30
|
+
function projectDirs(cwd) {
|
|
31
|
+
const dirs = [];
|
|
32
|
+
for (let dir = cwd;; dir = path.dirname(dir)) {
|
|
33
|
+
dirs.push(dir);
|
|
34
|
+
if (existsSync(path.join(dir, '.git')) || path.dirname(dir) === dir)
|
|
35
|
+
return dirs;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** ~/.config/opencode, or $XDG_CONFIG_HOME/opencode when that is absolute (same rule as detectEditors). */
|
|
39
|
+
function globalDir(home, env) {
|
|
40
|
+
const xdg = env['XDG_CONFIG_HOME'];
|
|
41
|
+
return path.join(xdg && path.isAbsolute(xdg) ? xdg : path.join(home, '.config'), 'opencode');
|
|
42
|
+
}
|
|
43
|
+
/** The plugin writer's own output: the check call, and an optional `"--env", "<name>"` pair. */
|
|
44
|
+
function pluginReadsLocal(text, localIsDefault) {
|
|
45
|
+
if (text === null || !text.includes('"check", "--advisory", "--format", "opencode"'))
|
|
46
|
+
return false;
|
|
47
|
+
const env = /"--env",\s*"([^"]+)"/.exec(text)?.[1];
|
|
48
|
+
return readsLocal(env === undefined ? [] : ['--env', env], localIsDefault);
|
|
49
|
+
}
|
|
50
|
+
function isLocalAlignServer(entry, localIsDefault) {
|
|
51
|
+
const e = entry;
|
|
52
|
+
// `enabled: false` means OpenCode will not start it, so it does not do our job: inject align-local.
|
|
53
|
+
if (e?.enabled === false)
|
|
54
|
+
return false;
|
|
55
|
+
if (e?.type !== 'local' || !Array.isArray(e.command))
|
|
56
|
+
return false;
|
|
57
|
+
const tokens = e.command.filter((t) => typeof t === 'string');
|
|
58
|
+
return tokens.includes('mcp') && tokens.some((t) => /^align(\.cmd)?$/.test(path.basename(t))) && readsLocal(tokens, localIsDefault);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* OpenCode 1.18.27 tries AGENTS.md, CLAUDE.md, CONTEXT.md in that order and the FIRST filename
|
|
62
|
+
* found anywhere up to the worktree wins; every match of that one name is read. CLAUDE.md is
|
|
63
|
+
* skipped under OPENCODE_DISABLE_CLAUDE_CODE*.
|
|
64
|
+
*/
|
|
65
|
+
function projectInstructionFiles(dirs, claudeOff) {
|
|
66
|
+
for (const name of ['AGENTS.md', 'CLAUDE.md', 'CONTEXT.md']) {
|
|
67
|
+
if (name === 'CLAUDE.md' && claudeOff)
|
|
68
|
+
continue;
|
|
69
|
+
const found = dirs.map((d) => path.join(d, name)).filter((f) => existsSync(f));
|
|
70
|
+
if (found.length > 0)
|
|
71
|
+
return found;
|
|
72
|
+
}
|
|
73
|
+
return [];
|
|
74
|
+
}
|
|
75
|
+
/** The global AGENTS.md, or ~/.claude/CLAUDE.md only when that is absent (and Claude Code files are not disabled). */
|
|
76
|
+
function globalInstructionFiles(home, global, claudeOff) {
|
|
77
|
+
const agents = path.join(global, 'AGENTS.md');
|
|
78
|
+
if (existsSync(agents))
|
|
79
|
+
return [agents];
|
|
80
|
+
return claudeOff ? [] : [path.join(home, '.claude', 'CLAUDE.md')];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* What OpenCode would already load for this directory, so a per-session injection never doubles
|
|
84
|
+
* it. "Present" means present AND doing the same job: a plugin or server aimed at another graph
|
|
85
|
+
* does not stand in for ours. Unreadable or malformed files count as absent: the cost of a wrong
|
|
86
|
+
* "absent" is a duplicate, the cost of a throw is no session at all. Only `.json` configs are
|
|
87
|
+
* read; a commented `.jsonc` does not parse and reads as absent.
|
|
88
|
+
*/
|
|
89
|
+
export function readOpenCodeState(cwd, home, opts, env = {}) {
|
|
90
|
+
const { localIsDefault } = opts;
|
|
91
|
+
const dirs = projectDirs(cwd);
|
|
92
|
+
const global = globalDir(home, env);
|
|
93
|
+
const configDirs = [...dirs.map((d) => path.join(d, '.opencode')), global];
|
|
94
|
+
const configFiles = [...dirs.map((d) => path.join(d, 'opencode.json')), ...configDirs.map((d) => path.join(d, 'opencode.json'))];
|
|
95
|
+
const claudeOff = Object.entries(env).some(([k, v]) => k.startsWith('OPENCODE_DISABLE_CLAUDE_CODE') && v);
|
|
96
|
+
const instructionFiles = [...projectInstructionFiles(dirs, claudeOff), ...globalInstructionFiles(home, global, claudeOff)];
|
|
97
|
+
return {
|
|
98
|
+
projectHasPlugin: configDirs.some((d) => pluginReadsLocal(readText(path.join(d, 'plugins', 'align.js')), localIsDefault)),
|
|
99
|
+
projectHasMcp: configFiles.some((f) => isLocalAlignServer(readJson(f)?.['mcp']?.['align'], localIsDefault)),
|
|
100
|
+
projectHasBlock: instructionFiles.some((f) => readText(f)?.includes(ALIGN_NUDGE_START) ?? false),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=opencode-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode-state.js","sourceRoot":"","sources":["../../../src/lib/launch/opencode-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface PiProjectState {
|
|
2
|
+
/** The extension would load AND do the same job: global, or project-local in a project pi trusts. */
|
|
3
|
+
projectHasExtension: boolean;
|
|
4
|
+
/** pi's MCP adapter already has a local align server (ours, or the user's own) in a file it reads. */
|
|
5
|
+
projectHasMcp: boolean;
|
|
6
|
+
projectHasBlock: boolean;
|
|
7
|
+
/** pi-mcp-adapter is installed as a pi package, so an MCP entry would be read at all. */
|
|
8
|
+
mcpAdapterInstalled: boolean;
|
|
9
|
+
/** <agentDir>/mcp.json: the file the MCP entry is written to. */
|
|
10
|
+
mcpFile: string;
|
|
11
|
+
}
|
|
12
|
+
/** PI_CODING_AGENT_DIR, else ~/.pi/agent. Read only: align never redirects it (it holds auth and history). */
|
|
13
|
+
export declare function piAgentDir(home: string, env: Record<string, string | undefined>): string;
|
|
14
|
+
/**
|
|
15
|
+
* What pi would already load for this directory, so a per-session injection never doubles it.
|
|
16
|
+
* "Present" means present AND doing the same job: an extension aimed at another graph does not
|
|
17
|
+
* stand in for ours. Unreadable or malformed files count as absent: a wrong "absent" is a
|
|
18
|
+
* duplicate, a throw is no session at all.
|
|
19
|
+
*/
|
|
20
|
+
export declare function readPiState(cwd: string, home: string, opts: {
|
|
21
|
+
localIsDefault: boolean;
|
|
22
|
+
}, env?: Record<string, string | undefined>): PiProjectState;
|
|
23
|
+
//# sourceMappingURL=pi-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pi-state.d.ts","sourceRoot":"","sources":["../../../src/lib/launch/pi-state.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,cAAc;IAC7B,qGAAqG;IACrG,mBAAmB,EAAE,OAAO,CAAC;IAC7B,sGAAsG;IACtG,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,EAAE,OAAO,CAAC;IACzB,yFAAyF;IACzF,mBAAmB,EAAE,OAAO,CAAC;IAC7B,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;CACjB;AAgCD,8GAA8G;AAC9G,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,MAAM,CAGxF;AA+CD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,cAAc,EAAE,OAAO,CAAA;CAAE,EAAE,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAM,GAAG,cAAc,CAmBtJ"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { existsSync, readFileSync, realpathSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { ALIGN_NUDGE_START } from '../agent-rules.js';
|
|
4
|
+
import { isLocalAlignServer, readsLocal } from './project-state.js';
|
|
5
|
+
function readText(file) {
|
|
6
|
+
try {
|
|
7
|
+
return readFileSync(file, 'utf8');
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function readJson(file) {
|
|
14
|
+
const text = readText(file);
|
|
15
|
+
if (text === null)
|
|
16
|
+
return null;
|
|
17
|
+
try {
|
|
18
|
+
const parsed = JSON.parse(text);
|
|
19
|
+
return typeof parsed === 'object' && parsed !== null ? parsed : null;
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/** The cwd and every directory above it, to the filesystem root (pi's context files do not stop at a git root). */
|
|
26
|
+
function ancestors(cwd) {
|
|
27
|
+
const dirs = [];
|
|
28
|
+
for (let dir = cwd;; dir = path.dirname(dir)) {
|
|
29
|
+
dirs.push(dir);
|
|
30
|
+
if (path.dirname(dir) === dir)
|
|
31
|
+
return dirs;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** PI_CODING_AGENT_DIR, else ~/.pi/agent. Read only: align never redirects it (it holds auth and history). */
|
|
35
|
+
export function piAgentDir(home, env) {
|
|
36
|
+
const set = env['PI_CODING_AGENT_DIR'];
|
|
37
|
+
return set ? set : path.join(home, '.pi', 'agent');
|
|
38
|
+
}
|
|
39
|
+
/** The extension writer's own output: the check call for pi, and an optional `"--env", "<name>"` pair. */
|
|
40
|
+
function extensionReadsLocal(text, localIsDefault) {
|
|
41
|
+
if (text === null || !text.includes('"check", "--advisory", "--format", "pi"'))
|
|
42
|
+
return false;
|
|
43
|
+
const env = /"--env",\s*"([^"]+)"/.exec(text)?.[1];
|
|
44
|
+
return readsLocal(env === undefined ? [] : ['--env', env], localIsDefault);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Does pi load project-local extensions for this directory? README "Project Trust": project
|
|
48
|
+
* extensions load only after the project is trusted. The saved decision is the nearest entry
|
|
49
|
+
* (the folder or a parent) in <agentDir>/trust.json; with none, `defaultProjectTrust` in the
|
|
50
|
+
* global settings decides, and only `always` trusts. Anything unreadable is "not trusted":
|
|
51
|
+
* the cost of a wrong "no" is a duplicate check, the cost of a wrong "yes" is no check at all.
|
|
52
|
+
*/
|
|
53
|
+
function projectTrusted(cwd, agentDir) {
|
|
54
|
+
const trust = readJson(path.join(agentDir, 'trust.json')) ?? {};
|
|
55
|
+
let real = cwd;
|
|
56
|
+
try {
|
|
57
|
+
real = realpathSync(cwd);
|
|
58
|
+
}
|
|
59
|
+
catch { /* keep cwd */ }
|
|
60
|
+
for (const dir of [...ancestors(cwd), ...ancestors(real)]) {
|
|
61
|
+
const v = trust[dir];
|
|
62
|
+
if (typeof v === 'boolean')
|
|
63
|
+
return v;
|
|
64
|
+
}
|
|
65
|
+
return readJson(path.join(agentDir, 'settings.json'))?.['defaultProjectTrust'] === 'always';
|
|
66
|
+
}
|
|
67
|
+
/** `packages` entries are strings or `{ source }` objects. */
|
|
68
|
+
function packageSources(settings) {
|
|
69
|
+
const list = settings?.['packages'];
|
|
70
|
+
return Array.isArray(list) ? list.map((p) => (typeof p === 'string' ? p : String(p?.source ?? ''))) : [];
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* pi loads AGENTS.md (or CLAUDE.md) from the agent dir, every parent directory up from cwd, and
|
|
74
|
+
* cwd; a directory's AGENTS.override.md is loaded instead of its AGENTS.md / CLAUDE.md (pi README,
|
|
75
|
+
* "Context Files"). Per directory that is one file; which of AGENTS.md and CLAUDE.md wins when
|
|
76
|
+
* both exist is not stated, so AGENTS.md is taken first.
|
|
77
|
+
*/
|
|
78
|
+
function contextFile(dir) {
|
|
79
|
+
for (const name of ['AGENTS.override.md', 'AGENTS.md', 'CLAUDE.md']) {
|
|
80
|
+
const f = path.join(dir, name);
|
|
81
|
+
if (existsSync(f))
|
|
82
|
+
return f;
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* What pi would already load for this directory, so a per-session injection never doubles it.
|
|
88
|
+
* "Present" means present AND doing the same job: an extension aimed at another graph does not
|
|
89
|
+
* stand in for ours. Unreadable or malformed files count as absent: a wrong "absent" is a
|
|
90
|
+
* duplicate, a throw is no session at all.
|
|
91
|
+
*/
|
|
92
|
+
export function readPiState(cwd, home, opts, env = {}) {
|
|
93
|
+
const { localIsDefault } = opts;
|
|
94
|
+
const dirs = ancestors(cwd);
|
|
95
|
+
const agentDir = piAgentDir(home, env);
|
|
96
|
+
const mcpFile = path.join(agentDir, 'mcp.json');
|
|
97
|
+
const trusted = projectTrusted(cwd, agentDir);
|
|
98
|
+
const globalExt = extensionReadsLocal(readText(path.join(agentDir, 'extensions', 'align.ts')), localIsDefault);
|
|
99
|
+
const projectExt = trusted && dirs.some((d) => extensionReadsLocal(readText(path.join(d, '.pi', 'extensions', 'align.ts')), localIsDefault));
|
|
100
|
+
// pi-mcp-adapter reads the agent-dir file and the project's .mcp.json (agent-rules.ts).
|
|
101
|
+
const servers = [mcpFile, path.join(cwd, '.mcp.json')].map((f) => readJson(f)?.['mcpServers']);
|
|
102
|
+
const contextFiles = [...dirs.map(contextFile), contextFile(agentDir)].filter((f) => f !== null);
|
|
103
|
+
const settings = [readJson(path.join(agentDir, 'settings.json')), ...(trusted ? [readJson(path.join(cwd, '.pi', 'settings.json'))] : [])];
|
|
104
|
+
return {
|
|
105
|
+
projectHasExtension: globalExt || projectExt,
|
|
106
|
+
projectHasMcp: servers.some((s) => s?.['align-local'] !== undefined || isLocalAlignServer(s?.['align'], localIsDefault)),
|
|
107
|
+
projectHasBlock: contextFiles.some((f) => readText(f)?.includes(ALIGN_NUDGE_START) ?? false),
|
|
108
|
+
mcpAdapterInstalled: settings.some((s) => packageSources(s).some((p) => p.includes('pi-mcp-adapter'))),
|
|
109
|
+
mcpFile,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=pi-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pi-state.js","sourceRoot":"","sources":["../../../src/lib/launch/pi-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { AgentName } from '../sessions/types.js';
|
|
2
|
+
import { type LaunchAgent } from './agents.js';
|
|
3
|
+
/**
|
|
4
|
+
* The wizard's "which coding agent?" step (C5). It reads the same table and the same PATH scan
|
|
5
|
+
* the launcher does and stores through the same config key, so what the wizard picks is exactly
|
|
6
|
+
* what bare `align` opens afterwards. Only supported agents that are installed are ever offered.
|
|
7
|
+
*/
|
|
8
|
+
export interface PickAgentDeps {
|
|
9
|
+
env: Record<string, string | undefined>;
|
|
10
|
+
platform: string;
|
|
11
|
+
agents: readonly LaunchAgent[];
|
|
12
|
+
findOnPath(bin: string, env: Record<string, string | undefined>, platform: string): string | null;
|
|
13
|
+
/** Resolves null when the user cancels. Only called on a terminal with several candidates. */
|
|
14
|
+
select(candidates: LaunchAgent[]): Promise<AgentName | null>;
|
|
15
|
+
say(line: string): void;
|
|
16
|
+
}
|
|
17
|
+
/** The user cancelled the picker: the wizard stops, like any other cancelled prompt. */
|
|
18
|
+
export declare const PICK_CANCELLED: "cancelled";
|
|
19
|
+
export interface AgentConfig {
|
|
20
|
+
getAgent(): string | undefined;
|
|
21
|
+
setAgent(agent: string): void;
|
|
22
|
+
isLaunchOff?(): boolean;
|
|
23
|
+
}
|
|
24
|
+
export declare function pickAgent(config: AgentConfig, opts: {
|
|
25
|
+
interactive: boolean;
|
|
26
|
+
approve?: boolean;
|
|
27
|
+
}, overrides?: Partial<PickAgentDeps>): Promise<AgentName | null | typeof PICK_CANCELLED>;
|
|
28
|
+
//# sourceMappingURL=pick-agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pick-agent.d.ts","sourceRoot":"","sources":["../../../src/lib/launch/pick-agent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAe,KAAK,WAAW,EAAoC,MAAM,aAAa,CAAC;AAG9F;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,SAAS,WAAW,EAAE,CAAC;IAC/B,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAClG,8FAA8F;IAC9F,MAAM,CAAC,UAAU,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IAC7D,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,wFAAwF;AACxF,eAAO,MAAM,cAAc,EAAG,WAAoB,CAAC;AAEnD,MAAM,WAAW,WAAW;IAC1B,QAAQ,IAAI,MAAM,GAAG,SAAS,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,WAAW,CAAC,IAAI,OAAO,CAAC;CACzB;AAsBD,wBAAsB,SAAS,CAC7B,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE;IAAE,WAAW,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,EACjD,SAAS,GAAE,OAAO,CAAC,aAAa,CAAM,GACrC,OAAO,CAAC,SAAS,GAAG,IAAI,GAAG,OAAO,cAAc,CAAC,CAoCnD"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { agentByName, resolveAgentBin, supportedAgents } from './agents.js';
|
|
2
|
+
import { findOnPath } from './detect.js';
|
|
3
|
+
/** The user cancelled the picker: the wizard stops, like any other cancelled prompt. */
|
|
4
|
+
export const PICK_CANCELLED = 'cancelled';
|
|
5
|
+
async function clackSelect(candidates) {
|
|
6
|
+
const clack = await import('@clack/prompts');
|
|
7
|
+
const answer = await clack.select({
|
|
8
|
+
message: 'Which coding agent should `align` open?',
|
|
9
|
+
options: candidates.map((a) => ({ value: a.name, label: a.label })),
|
|
10
|
+
});
|
|
11
|
+
return clack.isCancel(answer) ? null : answer;
|
|
12
|
+
}
|
|
13
|
+
function defaultDeps() {
|
|
14
|
+
return {
|
|
15
|
+
env: process.env,
|
|
16
|
+
platform: process.platform,
|
|
17
|
+
agents: supportedAgents(),
|
|
18
|
+
findOnPath,
|
|
19
|
+
select: clackSelect,
|
|
20
|
+
say: (l) => console.log(l),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export async function pickAgent(config, opts, overrides = {}) {
|
|
24
|
+
const d = { ...defaultDeps(), ...overrides };
|
|
25
|
+
const installed = d.agents.filter((a) => resolveAgentBin(a, d.findOnPath, d.env, d.platform) !== null);
|
|
26
|
+
// A re-run keeps the choice, provided it can still be launched; `align use` changes it. A
|
|
27
|
+
// stored agent that has left PATH is treated as no choice at all.
|
|
28
|
+
const stored = agentByName(config.getAgent());
|
|
29
|
+
if (stored && installed.some((a) => a.name === stored.name))
|
|
30
|
+
return stored.name;
|
|
31
|
+
if (installed.length === 0) {
|
|
32
|
+
d.say('No coding agent that Align can open was found on your PATH. Align works with:');
|
|
33
|
+
for (const a of d.agents)
|
|
34
|
+
d.say(` ${a.label}: ${a.install}`);
|
|
35
|
+
d.say('Install one, then run `align` again.');
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
let chosen;
|
|
39
|
+
if (installed.length === 1 || opts.approve) {
|
|
40
|
+
chosen = installed[0];
|
|
41
|
+
}
|
|
42
|
+
else if (opts.interactive) {
|
|
43
|
+
const name = await d.select(installed);
|
|
44
|
+
if (name === null)
|
|
45
|
+
return PICK_CANCELLED;
|
|
46
|
+
chosen = installed.find((a) => a.name === name);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
d.say(`More than one coding agent is installed (${installed.map((a) => a.label).join(', ')}) and there is no terminal to ask in.`);
|
|
50
|
+
d.say(`Choose one: align use <agent> (${installed.map((a) => a.name).join(' | ')})`);
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
if (!chosen)
|
|
54
|
+
return null;
|
|
55
|
+
const wasOff = config.isLaunchOff?.() === true;
|
|
56
|
+
config.setAgent(chosen.name);
|
|
57
|
+
if (wasOff)
|
|
58
|
+
d.say('Launching is on again: `align use --undo` had turned it off.');
|
|
59
|
+
if (installed.length === 1)
|
|
60
|
+
d.say(`Using ${chosen.label}. Switch any time with \`align use\`.`);
|
|
61
|
+
return chosen.name;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=pick-agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pick-agent.js","sourceRoot":"","sources":["../../../src/lib/launch/pick-agent.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface ProjectState {
|
|
2
|
+
projectHasPreHook: boolean;
|
|
3
|
+
projectHasPostHook: boolean;
|
|
4
|
+
projectHasMcp: boolean;
|
|
5
|
+
projectHasBlock: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface ProjectStateOptions {
|
|
8
|
+
/** Whether an align command with no --env reads the local graph on this machine. */
|
|
9
|
+
localIsDefault: boolean;
|
|
10
|
+
}
|
|
11
|
+
/** Does this command line read the LOCAL graph? An env that names another graph does not. */
|
|
12
|
+
export declare function readsLocal(tokens: string[], localIsDefault: boolean): boolean;
|
|
13
|
+
export declare function isLocalAlignServer(entry: unknown, localIsDefault: boolean): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* What Claude Code would already load for this directory, so a per-session injection never
|
|
16
|
+
* doubles it. "Present" means present AND doing the same job: a hook or server aimed at
|
|
17
|
+
* another graph does not stand in for ours. Unreadable or malformed files count as absent:
|
|
18
|
+
* the cost of a wrong "absent" is a duplicate, the cost of a throw is no session at all.
|
|
19
|
+
*/
|
|
20
|
+
export declare function readProjectState(cwd: string, home: string, opts: ProjectStateOptions): ProjectState;
|
|
21
|
+
//# sourceMappingURL=project-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-state.d.ts","sourceRoot":"","sources":["../../../src/lib/launch/project-state.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,YAAY;IAC3B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAClC,oFAAoF;IACpF,cAAc,EAAE,OAAO,CAAC;CACzB;AAoBD,6FAA6F;AAC7F,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,cAAc,EAAE,OAAO,GAAG,OAAO,CAG7E;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,OAAO,GAAG,OAAO,CAInF;AAoCD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,GAAG,YAAY,CAgCnG"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { ALIGN_NUDGE_START, isAlignHookGroup } from '../agent-rules.js';
|
|
4
|
+
function readJson(file) {
|
|
5
|
+
try {
|
|
6
|
+
const parsed = JSON.parse(readFileSync(file, 'utf8'));
|
|
7
|
+
return typeof parsed === 'object' && parsed !== null ? parsed : null;
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/** The --env an align command line names, or undefined when it names none. */
|
|
14
|
+
function envOf(tokens) {
|
|
15
|
+
const i = tokens.indexOf('--env');
|
|
16
|
+
if (i >= 0)
|
|
17
|
+
return tokens[i + 1];
|
|
18
|
+
return tokens.find((t) => t.startsWith('--env='))?.slice('--env='.length);
|
|
19
|
+
}
|
|
20
|
+
/** Does this command line read the LOCAL graph? An env that names another graph does not. */
|
|
21
|
+
export function readsLocal(tokens, localIsDefault) {
|
|
22
|
+
const env = envOf(tokens);
|
|
23
|
+
return env === undefined ? localIsDefault : env === 'local';
|
|
24
|
+
}
|
|
25
|
+
export function isLocalAlignServer(entry, localIsDefault) {
|
|
26
|
+
const e = entry;
|
|
27
|
+
const tokens = [e?.command, ...(Array.isArray(e?.args) ? e.args : [])].filter((t) => typeof t === 'string');
|
|
28
|
+
return tokens.includes('mcp') && tokens.some((t) => /^align(\.cmd)?$/.test(path.basename(t))) && readsLocal(tokens, localIsDefault);
|
|
29
|
+
}
|
|
30
|
+
function hasLocalHook(settings, event, localIsDefault) {
|
|
31
|
+
const groups = settings?.['hooks']?.[event];
|
|
32
|
+
if (!Array.isArray(groups))
|
|
33
|
+
return false;
|
|
34
|
+
return groups.some((g) => {
|
|
35
|
+
if (!isAlignHookGroup(g))
|
|
36
|
+
return false;
|
|
37
|
+
const hooks = g.hooks;
|
|
38
|
+
return hooks.some((h) => {
|
|
39
|
+
const tokens = String(h?.command ?? '').split(/\s+/);
|
|
40
|
+
return String(h?.command ?? '').includes('align check --advisory') && readsLocal(tokens, localIsDefault);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
function fileHasBlock(file) {
|
|
45
|
+
try {
|
|
46
|
+
return readFileSync(file, 'utf8').includes(ALIGN_NUDGE_START);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The cwd and every directory above it. Claude Code loads CLAUDE.md and CLAUDE.local.md "from
|
|
54
|
+
* your current working directory and every directory above it" (code.claude.com/docs/en/memory,
|
|
55
|
+
* "How CLAUDE.md files load"), with no stop at a git root.
|
|
56
|
+
*/
|
|
57
|
+
function ancestorsOf(cwd) {
|
|
58
|
+
const dirs = [];
|
|
59
|
+
for (let dir = cwd;; dir = path.dirname(dir)) {
|
|
60
|
+
dirs.push(dir);
|
|
61
|
+
if (path.dirname(dir) === dir)
|
|
62
|
+
return dirs;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* What Claude Code would already load for this directory, so a per-session injection never
|
|
67
|
+
* doubles it. "Present" means present AND doing the same job: a hook or server aimed at
|
|
68
|
+
* another graph does not stand in for ours. Unreadable or malformed files count as absent:
|
|
69
|
+
* the cost of a wrong "absent" is a duplicate, the cost of a throw is no session at all.
|
|
70
|
+
*/
|
|
71
|
+
export function readProjectState(cwd, home, opts) {
|
|
72
|
+
const { localIsDefault } = opts;
|
|
73
|
+
const claudeJson = readJson(path.join(home, '.claude.json'));
|
|
74
|
+
const projectEntry = claudeJson?.['projects']?.[cwd];
|
|
75
|
+
const settingsFiles = [
|
|
76
|
+
path.join(cwd, '.claude', 'settings.json'),
|
|
77
|
+
path.join(cwd, '.claude', 'settings.local.json'),
|
|
78
|
+
path.join(home, '.claude', 'settings.json'),
|
|
79
|
+
].map(readJson);
|
|
80
|
+
const disabled = [...settingsFiles, projectEntry ?? null].some((s) => {
|
|
81
|
+
const list = s?.['disabledMcpjsonServers'];
|
|
82
|
+
return Array.isArray(list) && list.includes('align');
|
|
83
|
+
});
|
|
84
|
+
const projectMcp = readJson(path.join(cwd, '.mcp.json'))?.['mcpServers']?.['align'];
|
|
85
|
+
const userMcp = claudeJson?.['mcpServers']?.['align'];
|
|
86
|
+
const projectScopedMcp = projectEntry?.['mcpServers']?.['align'];
|
|
87
|
+
const blockFiles = [
|
|
88
|
+
...ancestorsOf(cwd).flatMap((d) => [path.join(d, 'CLAUDE.md'), path.join(d, '.claude', 'CLAUDE.md'), path.join(d, 'CLAUDE.local.md')]),
|
|
89
|
+
path.join(home, '.claude', 'CLAUDE.md'),
|
|
90
|
+
];
|
|
91
|
+
return {
|
|
92
|
+
projectHasPreHook: settingsFiles.some((s) => hasLocalHook(s, 'PreToolUse', localIsDefault)),
|
|
93
|
+
projectHasPostHook: settingsFiles.some((s) => hasLocalHook(s, 'PostToolUse', localIsDefault)),
|
|
94
|
+
projectHasMcp: (!disabled && isLocalAlignServer(projectMcp, localIsDefault)) ||
|
|
95
|
+
isLocalAlignServer(userMcp, localIsDefault) ||
|
|
96
|
+
isLocalAlignServer(projectScopedMcp, localIsDefault),
|
|
97
|
+
projectHasBlock: blockFiles.some(fileHasBlock),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=project-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-state.js","sourceRoot":"","sources":["../../../src/lib/launch/project-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type ChildProcess, type SpawnOptions } from 'node:child_process';
|
|
2
|
+
import type { LaunchSpec } from './adapters/claude-code.js';
|
|
3
|
+
export interface RunDeps {
|
|
4
|
+
spawn: (command: string, args: string[], options: SpawnOptions) => ChildProcess;
|
|
5
|
+
platform: string;
|
|
6
|
+
/** The process whose signals are forwarded. A parameter so tests need not signal themselves. */
|
|
7
|
+
proc: Pick<typeof process, 'on' | 'off'>;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Run the agent with the terminal handed to it and resolve with the exit code align should
|
|
11
|
+
* leave with. align stays alive until the child is gone:
|
|
12
|
+
* - SIGINT: the tty already delivered Ctrl-C to the child's process group, so align only
|
|
13
|
+
* has to not die first (a handler that does nothing keeps it alive). A SIGINT sent to align
|
|
14
|
+
* ALONE (kill -INT <pid>) is deliberately not forwarded: forwarding would double-deliver the
|
|
15
|
+
* far more common tty Ctrl-C, which reaches both processes, and the agent would see two.
|
|
16
|
+
* - SIGTERM / SIGHUP / SIGQUIT: nobody else will tell the child, so forward them rather than
|
|
17
|
+
* orphan it.
|
|
18
|
+
* A child that dies by signal maps to 128+signal, the shell convention.
|
|
19
|
+
*/
|
|
20
|
+
export declare function runAgent(spec: LaunchSpec, deps?: Partial<RunDeps>): Promise<number>;
|
|
21
|
+
//# sourceMappingURL=run-agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-agent.d.ts","sourceRoot":"","sources":["../../../src/lib/launch/run-agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAsB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAG9F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAE5D,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,YAAY,KAAK,YAAY,CAAC;IAChF,QAAQ,EAAE,MAAM,CAAC;IACjB,gGAAgG;IAChG,IAAI,EAAE,IAAI,CAAC,OAAO,OAAO,EAAE,IAAI,GAAG,KAAK,CAAC,CAAC;CAC1C;AAqBD;;;;;;;;;;GAUG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,GAAE,OAAO,CAAC,OAAO,CAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAiC7F"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { spawn as nodeSpawn } from 'node:child_process';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
// cmd.exe re-parses the whole line, so these would run a second command or expand a variable.
|
|
5
|
+
const WIN_SHELL_CHARS = /[&|<>^%"]/;
|
|
6
|
+
/** One CRT-quoted argument: trailing backslashes are doubled so they cannot escape the closing quote. */
|
|
7
|
+
const winQuote = (a) => `"${a.replace(/(\\+)$/, '$1$1')}"`;
|
|
8
|
+
function winShimCommand(spec) {
|
|
9
|
+
const binHit = WIN_SHELL_CHARS.exec(spec.bin);
|
|
10
|
+
if (binHit)
|
|
11
|
+
throw new Error(`the path to ${path.win32.basename(spec.bin)} (${spec.bin}) holds the shell character ${binHit[0]}, which cmd.exe would interpret. Move or reinstall the agent to a path without it.`);
|
|
12
|
+
spec.args.forEach((arg, i) => {
|
|
13
|
+
const hit = WIN_SHELL_CHARS.exec(arg);
|
|
14
|
+
if (hit) {
|
|
15
|
+
throw new Error(`refusing argument ${i + 1} ("${arg}"): it holds the shell character ${hit[0]}, which cmd.exe would interpret. Passing arguments after \`align --\` has this limit on Windows; run the agent directly for this one.`);
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
const line = [spec.bin, ...spec.args].map(winQuote).join(' ');
|
|
19
|
+
return { command: 'cmd.exe', args: ['/d', '/s', '/c', `"${line}"`] };
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Run the agent with the terminal handed to it and resolve with the exit code align should
|
|
23
|
+
* leave with. align stays alive until the child is gone:
|
|
24
|
+
* - SIGINT: the tty already delivered Ctrl-C to the child's process group, so align only
|
|
25
|
+
* has to not die first (a handler that does nothing keeps it alive). A SIGINT sent to align
|
|
26
|
+
* ALONE (kill -INT <pid>) is deliberately not forwarded: forwarding would double-deliver the
|
|
27
|
+
* far more common tty Ctrl-C, which reaches both processes, and the agent would see two.
|
|
28
|
+
* - SIGTERM / SIGHUP / SIGQUIT: nobody else will tell the child, so forward them rather than
|
|
29
|
+
* orphan it.
|
|
30
|
+
* A child that dies by signal maps to 128+signal, the shell convention.
|
|
31
|
+
*/
|
|
32
|
+
export async function runAgent(spec, deps = {}) {
|
|
33
|
+
const spawn = deps.spawn ?? nodeSpawn;
|
|
34
|
+
const platform = deps.platform ?? process.platform;
|
|
35
|
+
const proc = deps.proc ?? process;
|
|
36
|
+
const isShim = platform === 'win32' && /\.(cmd|bat)$/i.test(spec.bin);
|
|
37
|
+
const { command, args } = isShim ? winShimCommand(spec) : { command: spec.bin, args: spec.args };
|
|
38
|
+
const options = { stdio: 'inherit', env: { ...process.env, ...spec.env } };
|
|
39
|
+
if (isShim)
|
|
40
|
+
options.windowsVerbatimArguments = true;
|
|
41
|
+
const child = spawn(command, args, options);
|
|
42
|
+
const forward = (sig) => () => { child.kill(sig); };
|
|
43
|
+
const onTerm = forward('SIGTERM');
|
|
44
|
+
const onHup = forward('SIGHUP');
|
|
45
|
+
const onQuit = forward('SIGQUIT');
|
|
46
|
+
const onInt = () => { };
|
|
47
|
+
proc.on('SIGTERM', onTerm);
|
|
48
|
+
proc.on('SIGHUP', onHup);
|
|
49
|
+
proc.on('SIGQUIT', onQuit);
|
|
50
|
+
proc.on('SIGINT', onInt);
|
|
51
|
+
try {
|
|
52
|
+
return await new Promise((resolve, reject) => {
|
|
53
|
+
child.on('error', reject);
|
|
54
|
+
child.on('exit', (code, signal) => {
|
|
55
|
+
if (signal)
|
|
56
|
+
resolve(128 + (os.constants.signals[signal] ?? 0));
|
|
57
|
+
else
|
|
58
|
+
resolve(code ?? 1);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
proc.off('SIGTERM', onTerm);
|
|
64
|
+
proc.off('SIGHUP', onHup);
|
|
65
|
+
proc.off('SIGQUIT', onQuit);
|
|
66
|
+
proc.off('SIGINT', onInt);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=run-agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-agent.js","sourceRoot":"","sources":["../../../src/lib/launch/run-agent.ts"],"names":[],"mappings":"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"}
|