@anhlp/alp 0.0.1-beta.4 → 0.0.1-beta.6
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 +14 -412
- package/bin/alp.js +5 -0
- package/lib/launcher.js +136 -0
- package/package.json +18 -105
- package/dist/THIRD-PARTY-NOTICES.txt +0 -626
- package/dist/acp.js +0 -19936
- package/dist/alpd.js +0 -49562
- package/docs/modular-monorepo.md +0 -214
- package/packages/cli/README.md +0 -7
- package/packages/cli/dist/THIRD-PARTY-NOTICES.txt +0 -651
- package/packages/cli/dist/acp/agent.d.ts +0 -37
- package/packages/cli/dist/acp/agent.js +0 -489
- package/packages/cli/dist/acp/main.d.ts +0 -4
- package/packages/cli/dist/acp/main.js +0 -23
- package/packages/cli/dist/acp.js +0 -19936
- package/packages/cli/dist/alp-web/THIRD-PARTY-NOTICES.txt +0 -2590
- package/packages/cli/dist/alp-web/alp-boundary.json +0 -15
- package/packages/cli/dist/alp-web/apple-touch-icon.png +0 -0
- package/packages/cli/dist/alp-web/assets/TerminalPanel-DLuoa74B.css +0 -1
- package/packages/cli/dist/alp-web/assets/TerminalPanel-PrU2l3u5.js +0 -16
- package/packages/cli/dist/alp-web/assets/index-BJdBTDFX.css +0 -1
- package/packages/cli/dist/alp-web/assets/index-DpfiPv5s.js +0 -52
- package/packages/cli/dist/alp-web/favicon-attention.svg +0 -6
- package/packages/cli/dist/alp-web/favicon-running.svg +0 -6
- package/packages/cli/dist/alp-web/favicon.svg +0 -5
- package/packages/cli/dist/alp-web/index.html +0 -20
- package/packages/cli/dist/alp-web.js +0 -9640
- package/packages/cli/dist/alpd.js +0 -49562
- package/packages/cli/dist/backup.d.ts +0 -4
- package/packages/cli/dist/backup.js +0 -146
- package/packages/cli/dist/build-manifest.json +0 -240
- package/packages/cli/dist/cli.d.ts +0 -2
- package/packages/cli/dist/cli.js +0 -30
- package/packages/cli/dist/daemon.d.ts +0 -35
- package/packages/cli/dist/daemon.js +0 -126
- package/packages/cli/dist/index.d.ts +0 -1
- package/packages/cli/dist/index.js +0 -5
- package/packages/cli/dist/interfaces.d.ts +0 -24
- package/packages/cli/dist/interfaces.js +0 -156
- package/packages/cli/dist/library.d.ts +0 -140
- package/packages/cli/dist/library.js +0 -319
- package/packages/cli/dist/paths.d.ts +0 -3
- package/packages/cli/dist/paths.js +0 -18
- package/packages/cli/dist/projects.d.ts +0 -9
- package/packages/cli/dist/projects.js +0 -159
- package/packages/cli/dist/schedules.d.ts +0 -2
- package/packages/cli/dist/schedules.js +0 -45
- package/packages/cli/dist/sessions.d.ts +0 -43
- package/packages/cli/dist/sessions.js +0 -458
- package/packages/cli/dist/tasks.d.ts +0 -29
- package/packages/cli/dist/tasks.js +0 -345
- package/packages/cli/dist/terminal.d.ts +0 -8
- package/packages/cli/dist/terminal.js +0 -79
- package/packages/cli/dist/usage.d.ts +0 -3
- package/packages/cli/dist/usage.js +0 -78
- package/packages/cli/dist/web-service.d.ts +0 -38
- package/packages/cli/dist/web-service.js +0 -119
- package/packages/client/README.md +0 -29
- package/packages/client/dist/acp-probe.d.ts +0 -44
- package/packages/client/dist/acp-probe.js +0 -37
- package/packages/client/dist/antigravity-probe.d.ts +0 -34
- package/packages/client/dist/antigravity-probe.js +0 -95
- package/packages/client/dist/command.d.ts +0 -5
- package/packages/client/dist/command.js +0 -33
- package/packages/client/dist/doctor.d.ts +0 -13
- package/packages/client/dist/doctor.js +0 -587
- package/packages/client/dist/index.d.ts +0 -151
- package/packages/client/dist/index.js +0 -533
- package/packages/client/dist/integration-lock.d.ts +0 -35
- package/packages/client/dist/integration-lock.js +0 -179
- package/packages/client/dist/ipc.d.ts +0 -42
- package/packages/client/dist/ipc.js +0 -69
- package/packages/client/dist/library-test.d.ts +0 -94
- package/packages/client/dist/library-test.js +0 -37
- package/packages/client/dist/mcp-probe.d.ts +0 -24
- package/packages/client/dist/mcp-probe.js +0 -147
- package/packages/client/dist/portable.d.ts +0 -19
- package/packages/client/dist/portable.js +0 -33
- package/packages/client/dist/prompt.d.ts +0 -32
- package/packages/client/dist/prompt.js +0 -59
- package/packages/client/dist/render.d.ts +0 -6
- package/packages/client/dist/render.js +0 -120
- package/packages/client/dist/rpc/client.d.ts +0 -82
- package/packages/client/dist/rpc/client.js +0 -292
- package/packages/client/dist/rpc/errors.d.ts +0 -42
- package/packages/client/dist/rpc/errors.js +0 -34
- package/packages/client/dist/rpc/framing.d.ts +0 -21
- package/packages/client/dist/rpc/framing.js +0 -57
- package/packages/client/dist/rpc/handshake.d.ts +0 -19
- package/packages/client/dist/rpc/handshake.js +0 -8
- package/packages/client/dist/rpc/reconnect.d.ts +0 -97
- package/packages/client/dist/rpc/reconnect.js +0 -227
- package/packages/client/dist/rpc/registry.d.ts +0 -211
- package/packages/client/dist/rpc/registry.js +0 -145
- package/packages/client/dist/rpc/timers.d.ts +0 -11
- package/packages/client/dist/rpc/timers.js +0 -11
- package/packages/client/dist/service.d.ts +0 -50
- package/packages/client/dist/service.js +0 -143
- package/packages/client/dist/setup.d.ts +0 -2
- package/packages/client/dist/setup.js +0 -146
- package/packages/client/dist/supervise.d.ts +0 -14
- package/packages/client/dist/supervise.js +0 -87
- package/packages/client/dist/websocket.d.ts +0 -51
- package/packages/client/dist/websocket.js +0 -190
- package/packages/core/README.md +0 -7
- package/packages/core/dist/adapter.d.ts +0 -20
- package/packages/core/dist/adapter.js +0 -30
- package/packages/core/dist/atomic.d.ts +0 -2
- package/packages/core/dist/atomic.js +0 -28
- package/packages/core/dist/backup.d.ts +0 -27
- package/packages/core/dist/backup.js +0 -681
- package/packages/core/dist/beads.d.ts +0 -65
- package/packages/core/dist/beads.js +0 -213
- package/packages/core/dist/delegation.d.ts +0 -2
- package/packages/core/dist/delegation.js +0 -32
- package/packages/core/dist/errors.d.ts +0 -4
- package/packages/core/dist/errors.js +0 -11
- package/packages/core/dist/formulas.d.ts +0 -25
- package/packages/core/dist/formulas.js +0 -201
- package/packages/core/dist/hook-run.d.ts +0 -44
- package/packages/core/dist/hook-run.js +0 -60
- package/packages/core/dist/hooks.d.ts +0 -35
- package/packages/core/dist/hooks.js +0 -30
- package/packages/core/dist/index.d.ts +0 -31
- package/packages/core/dist/index.js +0 -65
- package/packages/core/dist/init.d.ts +0 -30
- package/packages/core/dist/init.js +0 -89
- package/packages/core/dist/library-edit.d.ts +0 -93
- package/packages/core/dist/library-edit.js +0 -368
- package/packages/core/dist/library.d.ts +0 -28
- package/packages/core/dist/library.js +0 -108
- package/packages/core/dist/log.d.ts +0 -37
- package/packages/core/dist/log.js +0 -156
- package/packages/core/dist/migrations.d.ts +0 -9
- package/packages/core/dist/migrations.js +0 -95
- package/packages/core/dist/models.d.ts +0 -11
- package/packages/core/dist/models.js +0 -44
- package/packages/core/dist/permissions.d.ts +0 -14
- package/packages/core/dist/permissions.js +0 -229
- package/packages/core/dist/profiles.d.ts +0 -27
- package/packages/core/dist/profiles.js +0 -122
- package/packages/core/dist/promptsafe.d.ts +0 -1
- package/packages/core/dist/promptsafe.js +0 -13
- package/packages/core/dist/providers.d.ts +0 -90
- package/packages/core/dist/providers.js +0 -101
- package/packages/core/dist/resolver.d.ts +0 -41
- package/packages/core/dist/resolver.js +0 -240
- package/packages/core/dist/safe-path.d.ts +0 -2
- package/packages/core/dist/safe-path.js +0 -24
- package/packages/core/dist/shell.d.ts +0 -16
- package/packages/core/dist/shell.js +0 -22
- package/packages/core/dist/state-schema.d.ts +0 -9
- package/packages/core/dist/state-schema.js +0 -54
- package/packages/core/dist/task-rows.d.ts +0 -47
- package/packages/core/dist/task-rows.js +0 -45
- package/packages/core/dist/tasks.d.ts +0 -128
- package/packages/core/dist/tasks.js +0 -835
- package/packages/core/dist/teams.d.ts +0 -80
- package/packages/core/dist/teams.js +0 -159
- package/packages/core/dist/template-path.d.ts +0 -2
- package/packages/core/dist/template-path.js +0 -10
- package/packages/core/dist/trust.d.ts +0 -8
- package/packages/core/dist/trust.js +0 -47
- package/packages/core/dist/types.d.ts +0 -51
- package/packages/core/dist/upgrade.d.ts +0 -10
- package/packages/core/dist/upgrade.js +0 -200
- package/packages/core/dist/user-settings.d.ts +0 -6
- package/packages/core/dist/user-settings.js +0 -72
- package/packages/core/dist/user-worktree.d.ts +0 -29
- package/packages/core/dist/user-worktree.js +0 -242
- package/packages/core/dist/validation.d.ts +0 -17
- package/packages/core/dist/validation.js +0 -296
- package/packages/core/dist/verify.d.ts +0 -15
- package/packages/core/dist/verify.js +0 -123
- package/packages/core/dist/workflow.d.ts +0 -45
- package/packages/core/dist/workflow.js +0 -33
- package/templates/ALP.md +0 -52
- package/templates/agents/lead/AGENT.md +0 -90
- package/templates/agents/main/AGENT.md +0 -150
- package/templates/agents/oracle/AGENT.md +0 -44
- package/templates/agents/peer/AGENT.md +0 -55
- package/templates/agents/reviewer/AGENT.md +0 -80
- package/templates/agents/supervisor/AGENT.md +0 -72
- package/templates/providers/antigravity.json +0 -6
- package/templates/providers/opencode.json +0 -7
- package/templates/role-skills.json +0 -8
- package/templates/skills/bug-loop/SKILL.md +0 -44
- package/templates/skills/bug-loop/references/test-proof.md +0 -25
- package/templates/skills/goal-griller/SKILL.md +0 -49
- package/templates/skills/prompt-leverage/SKILL.md +0 -37
- package/templates/skills/prompt-leverage/references/brief-template.md +0 -27
- package/templates/skills/sequence-execution-plan/SKILL.md +0 -42
- package/templates/skills/sequence-execution-plan/references/plan-template.md +0 -22
- package/templates/skills/smart-commits/SKILL.md +0 -40
- package/templates/skills/xia/SKILL.md +0 -42
- package/templates/teams/cafe/HOUSE_RULES.md +0 -1
- package/templates/teams/cafe/team.json +0 -15
- package/templates/teams/pho/HOUSE_RULES.md +0 -1
- package/templates/teams/pho/team.json +0 -14
|
@@ -1,458 +0,0 @@
|
|
|
1
|
-
// packages/cli/src/sessions.js
|
|
2
|
-
import { randomUUID } from "node:crypto";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { createInterface } from "node:readline";
|
|
5
|
-
import { parseArgs } from "node:util";
|
|
6
|
-
import { ago, duration, renderLog, renderPs } from "@anhlp/alp-client/render";
|
|
7
|
-
import { isTaskId } from "@anhlp/alp-core/tasks";
|
|
8
|
-
import { connect } from "@anhlp/alp-client/index";
|
|
9
|
-
import { UsageError } from "./usage.js";
|
|
10
|
-
import { start, running, stop } from "./daemon.js";
|
|
11
|
-
import { taskProject } from "./tasks.js";
|
|
12
|
-
function toolLine(item) {
|
|
13
|
-
const detail = item.detail ?? {};
|
|
14
|
-
const first = (text) => String(text ?? "").split("\n")[0].slice(0, 200);
|
|
15
|
-
switch (detail.type) {
|
|
16
|
-
case "shell":
|
|
17
|
-
return detail.command;
|
|
18
|
-
case "read":
|
|
19
|
-
case "edit":
|
|
20
|
-
case "write":
|
|
21
|
-
return `${item.name} ${detail.filePath}`;
|
|
22
|
-
case "search":
|
|
23
|
-
return `${item.name} ${first(detail.query)}`;
|
|
24
|
-
case "fetch":
|
|
25
|
-
return `${item.name} ${detail.url}`;
|
|
26
|
-
case "sub_agent":
|
|
27
|
-
return `${item.name}${detail.description ? ` ${first(detail.description)}` : ""}`;
|
|
28
|
-
case "plain_text":
|
|
29
|
-
return `${item.name}${detail.label ? ` ${detail.label}` : ""}`;
|
|
30
|
-
}
|
|
31
|
-
return item.name === "alp_delegate" ? `delegate \u2192 ${detail.input?.agent}` : item.name;
|
|
32
|
-
}
|
|
33
|
-
function printer(json) {
|
|
34
|
-
const depth = /* @__PURE__ */ new Map();
|
|
35
|
-
const agents = /* @__PURE__ */ new Map();
|
|
36
|
-
const printed = /* @__PURE__ */ new Set();
|
|
37
|
-
const latest = /* @__PURE__ */ new Map();
|
|
38
|
-
const line = (sessionId, text) => console.log(`${" ".repeat(depth.get(sessionId) ?? 0)}${text}`);
|
|
39
|
-
return (envelope) => {
|
|
40
|
-
if (json) {
|
|
41
|
-
console.log(JSON.stringify(envelope));
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
const { sessionId, event } = envelope;
|
|
45
|
-
if (event.type === "session.opened") {
|
|
46
|
-
const { session } = event;
|
|
47
|
-
depth.set(sessionId, session.parentId ? (depth.get(session.parentId) ?? 0) + 1 : 0);
|
|
48
|
-
agents.set(sessionId, session.agent);
|
|
49
|
-
line(sessionId, `\u25B8 ${session.agent} (${session.runtime}:${session.model}, ${session.mode}) ${sessionId}`);
|
|
50
|
-
} else if (event.type === "item") {
|
|
51
|
-
const { item } = event;
|
|
52
|
-
latest.set(item.id, { sessionId, item });
|
|
53
|
-
if (item.kind === "tool_call" && item.status !== "running" && !printed.has(item.id)) {
|
|
54
|
-
printed.add(item.id);
|
|
55
|
-
const detail = toolLine(item);
|
|
56
|
-
line(sessionId, ` ${item.status === "failed" ? "\u2717" : "\u2713"} ${detail}`);
|
|
57
|
-
}
|
|
58
|
-
if (item.kind === "notice") line(sessionId, ` ${item.level === "error" ? "\u203C" : item.level === "warning" ? "!" : "\u2139"} ${item.text}`);
|
|
59
|
-
if (item.kind === "todo") {
|
|
60
|
-
line(sessionId, " tasks:");
|
|
61
|
-
for (const entry of item.items) line(sessionId, ` ${entry.status === "completed" ? "\u2611" : entry.status === "in_progress" ? "\u25D0" : "\u2610"} ${entry.text}`);
|
|
62
|
-
}
|
|
63
|
-
} else if (event.type === "mail") {
|
|
64
|
-
line(sessionId, ` \u2709 ${event.mail.kind} from ${event.mail.from}`);
|
|
65
|
-
} else if (event.type === "question") {
|
|
66
|
-
const { question } = event;
|
|
67
|
-
line(sessionId, ` ? ${question.agent} asks you [${question.id}]: ${question.body}${question.options?.length ? ` (${question.options.join(" | ")})` : ""}`);
|
|
68
|
-
line(sessionId, ` answer here, or with: alp answer ${question.id} <text>`);
|
|
69
|
-
} else if (event.type === "question.resolved") {
|
|
70
|
-
line(sessionId, ` \u21B3 ${event.questionId} ${event.outcome}${event.answer !== void 0 ? `: ${event.answer}` : ""}`);
|
|
71
|
-
} else if (event.type === "turn.ended") {
|
|
72
|
-
for (const [id, entry] of latest) {
|
|
73
|
-
if (entry.sessionId !== sessionId || printed.has(id) || entry.item.kind !== "assistant_message") continue;
|
|
74
|
-
printed.add(id);
|
|
75
|
-
line(sessionId, ` ${agents.get(sessionId) ?? "agent"}: ${entry.item.text.replace(/\n/g, `
|
|
76
|
-
${" ".repeat((depth.get(sessionId) ?? 0) + 2)}`)}`);
|
|
77
|
-
}
|
|
78
|
-
if (event.state !== "completed") line(sessionId, ` turn ${event.state}${event.error ? `: ${event.error.message}` : ""}`);
|
|
79
|
-
} else if (event.type === "prompt.failed") {
|
|
80
|
-
line(sessionId, ` prompt failed: ${event.error.message}`);
|
|
81
|
-
} else if (event.type === "session.failed") {
|
|
82
|
-
line(sessionId, ` runtime failed: ${event.error.message}`);
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
function answerer(client) {
|
|
87
|
-
const waiting = [];
|
|
88
|
-
let rl;
|
|
89
|
-
const ask = () => {
|
|
90
|
-
if (rl || !waiting.length) return;
|
|
91
|
-
const question = waiting[0];
|
|
92
|
-
rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
93
|
-
rl.question(`answer ${question.id}> `, (text) => {
|
|
94
|
-
rl.close();
|
|
95
|
-
rl = void 0;
|
|
96
|
-
waiting.shift();
|
|
97
|
-
if (text.trim()) client.request("question.answer", { questionId: question.id, text }).catch((error) => console.error(`alp: ${error.message}`));
|
|
98
|
-
ask();
|
|
99
|
-
});
|
|
100
|
-
};
|
|
101
|
-
return {
|
|
102
|
-
accept(event) {
|
|
103
|
-
if (event.type === "question") {
|
|
104
|
-
waiting.push(event.question);
|
|
105
|
-
ask();
|
|
106
|
-
}
|
|
107
|
-
if (event.type === "question.resolved") {
|
|
108
|
-
const index = waiting.findIndex((question) => question.id === event.questionId);
|
|
109
|
-
if (index === 0 && rl) {
|
|
110
|
-
rl.close();
|
|
111
|
-
rl = void 0;
|
|
112
|
-
console.error("");
|
|
113
|
-
}
|
|
114
|
-
if (index >= 0) waiting.splice(index, 1);
|
|
115
|
-
ask();
|
|
116
|
-
}
|
|
117
|
-
},
|
|
118
|
-
close() {
|
|
119
|
-
rl?.close();
|
|
120
|
-
rl = void 0;
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
function follow(client, rootId, print, { untilIdle, interactive = false, targetOnly = false, promptId }) {
|
|
125
|
-
const answering = interactive ? answerer(client) : void 0;
|
|
126
|
-
const done = new Promise((resolve, reject) => {
|
|
127
|
-
let failed = false;
|
|
128
|
-
let interrupted = false;
|
|
129
|
-
const finish = () => {
|
|
130
|
-
process.off("SIGINT", onSignal);
|
|
131
|
-
answering?.close();
|
|
132
|
-
resolve(!failed);
|
|
133
|
-
};
|
|
134
|
-
const onSignal = () => {
|
|
135
|
-
if (interrupted) {
|
|
136
|
-
finish();
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
interrupted = true;
|
|
140
|
-
console.error("Interrupting\u2026 press Ctrl-C again to detach.");
|
|
141
|
-
client.request("session.interrupt", { sessionId: rootId }).catch(() => {
|
|
142
|
-
});
|
|
143
|
-
};
|
|
144
|
-
process.on("SIGINT", onSignal);
|
|
145
|
-
client.onClose((error) => {
|
|
146
|
-
process.off("SIGINT", onSignal);
|
|
147
|
-
answering?.close();
|
|
148
|
-
reject(error);
|
|
149
|
-
});
|
|
150
|
-
let rootEnded = false;
|
|
151
|
-
client.onEvent((envelope) => {
|
|
152
|
-
if (targetOnly && envelope.sessionId !== rootId) return;
|
|
153
|
-
if (promptId && envelope.event.type === "prompt.failed" && envelope.event.clientMessageId !== promptId) return;
|
|
154
|
-
print(envelope);
|
|
155
|
-
answering?.accept(envelope.event);
|
|
156
|
-
const { sessionId, event } = envelope;
|
|
157
|
-
if (event.type === "turn.ended") {
|
|
158
|
-
if (sessionId === rootId) {
|
|
159
|
-
failed = event.state !== "completed";
|
|
160
|
-
rootEnded = true;
|
|
161
|
-
}
|
|
162
|
-
if (!untilIdle || !rootEnded) return;
|
|
163
|
-
setTimeout(() => {
|
|
164
|
-
client.request("session.get", { sessionId: rootId }).then(({ session }) => {
|
|
165
|
-
if (!session.busy) finish();
|
|
166
|
-
}, finish);
|
|
167
|
-
}, 50);
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
if (sessionId !== rootId) return;
|
|
171
|
-
if (event.type === "turn.started") {
|
|
172
|
-
rootEnded = false;
|
|
173
|
-
} else if (event.type === "session.closed" || event.type === "session.failed" || event.type === "prompt.failed") {
|
|
174
|
-
failed ||= event.type !== "session.closed";
|
|
175
|
-
finish();
|
|
176
|
-
}
|
|
177
|
-
});
|
|
178
|
-
});
|
|
179
|
-
done.catch(() => {
|
|
180
|
-
});
|
|
181
|
-
return done;
|
|
182
|
-
}
|
|
183
|
-
async function run(args) {
|
|
184
|
-
const { values, positionals } = parseArgs({ args, allowPositionals: true, options: {
|
|
185
|
-
agent: { type: "string" },
|
|
186
|
-
team: { type: "string" },
|
|
187
|
-
profile: { type: "string" },
|
|
188
|
-
workflow: { type: "string" },
|
|
189
|
-
model: { type: "string" },
|
|
190
|
-
mode: { type: "string" },
|
|
191
|
-
thinking: { type: "string" },
|
|
192
|
-
project: { type: "string" },
|
|
193
|
-
json: { type: "boolean" }
|
|
194
|
-
} });
|
|
195
|
-
const text = positionals.join(" ").trim();
|
|
196
|
-
if (!text) throw new UsageError();
|
|
197
|
-
const teams = [values.team, values.profile, values.workflow].filter(Boolean);
|
|
198
|
-
if (new Set(teams).size > 1) throw new UsageError();
|
|
199
|
-
const client = await connect(await start(), { name: "alp-cli", version: "1" });
|
|
200
|
-
try {
|
|
201
|
-
const spec = { cwd: path.resolve(values.project ?? process.cwd()), persist: true, agent: values.agent, workflow: teams[0], model: values.model, mode: values.mode, thinking: values.thinking };
|
|
202
|
-
const sessionId = `cli-${randomUUID()}`;
|
|
203
|
-
const done = follow(client, sessionId, printer(values.json), { untilIdle: true, interactive: !values.json && process.stdin.isTTY });
|
|
204
|
-
await client.request("session.create", { sessionId, spec });
|
|
205
|
-
await client.request("session.prompt", { sessionId, clientMessageId: randomUUID(), content: [{ type: "text", text }] });
|
|
206
|
-
if (!await done) process.exitCode = 1;
|
|
207
|
-
await client.request("session.release", { sessionId }).catch(() => {
|
|
208
|
-
});
|
|
209
|
-
} finally {
|
|
210
|
-
client.close();
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
async function ps(args) {
|
|
214
|
-
const { values, positionals } = parseArgs({ args, allowPositionals: true, options: { all: { type: "boolean" } } });
|
|
215
|
-
if (positionals.length) throw new UsageError();
|
|
216
|
-
const client = await running();
|
|
217
|
-
const [{ sessions }, pauses] = await Promise.all([client.request("session.list", { includeClosed: values.all }), client.request("daemon.pauses")]).finally(() => client.close());
|
|
218
|
-
printPauses(pauses, false);
|
|
219
|
-
if (!sessions.length) {
|
|
220
|
-
console.log(values.all ? "No sessions" : "No live sessions");
|
|
221
|
-
return;
|
|
222
|
-
}
|
|
223
|
-
for (const line of renderPs(sessions)) console.log(line);
|
|
224
|
-
}
|
|
225
|
-
async function attach(args) {
|
|
226
|
-
const { values, positionals } = parseArgs({ args, allowPositionals: true, options: { json: { type: "boolean" } } });
|
|
227
|
-
if (positionals.length !== 1) throw new UsageError();
|
|
228
|
-
const client = await running();
|
|
229
|
-
try {
|
|
230
|
-
const done = follow(client, positionals[0], printer(values.json), { untilIdle: false, interactive: !values.json && process.stdin.isTTY });
|
|
231
|
-
const { session } = await client.request("session.attach", { sessionId: positionals[0] });
|
|
232
|
-
if (session.id !== positionals[0]) console.error(`Following root ${session.id}`);
|
|
233
|
-
if (session.status === "idle" || session.status === "running") await done;
|
|
234
|
-
else console.error(`Session is ${session.lastError?.code ?? session.status}; resume it with: alp send ${session.id} <text>`);
|
|
235
|
-
} finally {
|
|
236
|
-
client.close();
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
async function send(args) {
|
|
240
|
-
const { values, positionals: [sessionId, ...words] } = parseArgs({ args, allowPositionals: true, options: { json: { type: "boolean" }, prompt: { type: "boolean" } } });
|
|
241
|
-
const text = words.join(" ").trim();
|
|
242
|
-
if (!sessionId || !text) throw new UsageError();
|
|
243
|
-
const client = await connect(await start(), { name: "alp-cli", version: "1" });
|
|
244
|
-
let subscriptionId;
|
|
245
|
-
try {
|
|
246
|
-
const { session } = await client.request("session.get", { sessionId });
|
|
247
|
-
if (session.parentId && !values.prompt) {
|
|
248
|
-
await client.request("session.message", { sessionId, text });
|
|
249
|
-
if (!values.json) console.error(`Sent to ${session.agent} as mail from the user`);
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
const live = session.status === "idle" || session.status === "running";
|
|
253
|
-
if (values.prompt && !live) throw new Error("Explicit prompts require a live session; use default alp send to reopen a root");
|
|
254
|
-
const clientMessageId = randomUUID();
|
|
255
|
-
const done = follow(client, sessionId, printer(values.json), { untilIdle: true, interactive: !values.json && process.stdin.isTTY, targetOnly: !!session.parentId, promptId: clientMessageId });
|
|
256
|
-
if (live) {
|
|
257
|
-
const attached = await client.request("session.attach", { sessionId, replay: false });
|
|
258
|
-
subscriptionId = attached.session.id;
|
|
259
|
-
} else {
|
|
260
|
-
await client.request("session.create", { sessionId, spec: { cwd: session.projectRoot } });
|
|
261
|
-
subscriptionId = sessionId;
|
|
262
|
-
}
|
|
263
|
-
const steer = !values.prompt && live && !!session.activeTurnId;
|
|
264
|
-
await client.request("session.prompt", { sessionId, clientMessageId, delivery: steer ? "steer" : "auto", content: [{ type: "text", text }] });
|
|
265
|
-
if (!values.json) console.error(values.prompt ? "Submitted an explicit prompt" : steer ? "Steered the running turn" : live ? "Started a turn" : "Resumed the session");
|
|
266
|
-
if (!await done) process.exitCode = 1;
|
|
267
|
-
} finally {
|
|
268
|
-
if (subscriptionId) await client.request("session.release", { sessionId: subscriptionId }).catch(() => {
|
|
269
|
-
});
|
|
270
|
-
client.close();
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
async function questions(args) {
|
|
274
|
-
const { values, positionals } = parseArgs({ args, allowPositionals: true, options: { json: { type: "boolean" } } });
|
|
275
|
-
if (positionals.length) throw new UsageError();
|
|
276
|
-
const client = await running();
|
|
277
|
-
const { questions: pending } = await client.request("question.list").finally(() => client.close());
|
|
278
|
-
if (values.json) {
|
|
279
|
-
console.log(JSON.stringify(pending));
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
if (!pending.length) {
|
|
283
|
-
console.log("No questions wait for you");
|
|
284
|
-
return;
|
|
285
|
-
}
|
|
286
|
-
for (const question of pending) {
|
|
287
|
-
console.log(`${question.id} ${question.agent} ${ago(question.askedAt)} ago root ${question.rootId}`);
|
|
288
|
-
console.log(` ${question.body.replace(/\n/g, "\n ")}`);
|
|
289
|
-
if (question.options?.length) console.log(` options: ${question.options.join(" | ")}`);
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
async function answer(args) {
|
|
293
|
-
const { values, positionals: [questionId, ...words] } = parseArgs({ args, allowPositionals: true, options: { dismiss: { type: "boolean" }, reason: { type: "string" } } });
|
|
294
|
-
const text = words.join(" ").trim();
|
|
295
|
-
if (!questionId || (values.dismiss ? text : !text)) throw new UsageError();
|
|
296
|
-
const client = await running();
|
|
297
|
-
const result = await client.request("question.answer", values.dismiss ? { questionId, dismiss: true, reason: values.reason } : { questionId, text }).finally(() => client.close());
|
|
298
|
-
console.log(`${values.dismiss ? "Dismissed" : "Answered"} ${result.questionId}`);
|
|
299
|
-
}
|
|
300
|
-
function renderStatus(status, root) {
|
|
301
|
-
const lines = [`${root?.title ? `"${root.title}" ` : ""}${status.rootId} ${status.sessions[0]?.projectRoot ?? ""}`];
|
|
302
|
-
const depth = /* @__PURE__ */ new Map();
|
|
303
|
-
const assignments = new Map(status.assignments.map((assignment) => [assignment.id, assignment]));
|
|
304
|
-
for (const session of status.sessions) {
|
|
305
|
-
depth.set(session.id, session.parentId ? (depth.get(session.parentId) ?? 0) + 1 : 0);
|
|
306
|
-
const assignment = assignments.get(session.id);
|
|
307
|
-
const where = assignment?.worktree ? ` worktree ${assignment.worktree.branch}` : "";
|
|
308
|
-
const mail = session.unreadMail ? ` \u2709${session.unreadMail}` : "";
|
|
309
|
-
lines.push(`${" ".repeat(depth.get(session.id) + 1)}${session.agent.padEnd(9)} ${session.state.padEnd(14)} idle ${duration(session.idleMs).padEnd(7)} ${session.runtime}:${session.model} ${session.mode}${where}${mail}`);
|
|
310
|
-
}
|
|
311
|
-
for (const question of status.questions) lines.push(` ? ${question.id} ${question.agent} asks (${ago(question.askedAt)}): ${question.body.split("\n")[0]}`);
|
|
312
|
-
for (const worktree of status.worktrees) lines.push(` \u2387 unmerged ${worktree.branch} from ${worktree.agent}: ${worktree.files.length} files${worktree.stat ? ` (${worktree.stat.trim()})` : ""}`);
|
|
313
|
-
for (const lease of status.leases) lines.push(` \u26BF ${lease.agent} holds the write lease on ${lease.checkout}`);
|
|
314
|
-
for (const claim of status.claims ?? []) lines.push(` \u2691 ${claim.agent} claims ${claim.paths.join(", ")}${claim.task ? ` for ${claim.task}` : ""}: ${claim.body.split("\n")[0].slice(0, 100)}`);
|
|
315
|
-
return lines.join("\n");
|
|
316
|
-
}
|
|
317
|
-
async function top(args) {
|
|
318
|
-
const { values, positionals } = parseArgs({ args, allowPositionals: true, options: { once: { type: "boolean" } } });
|
|
319
|
-
if (positionals.length > 1) throw new UsageError();
|
|
320
|
-
const client = await running();
|
|
321
|
-
const frame = async () => {
|
|
322
|
-
const { sessions } = await client.request("session.list", { rootsOnly: true });
|
|
323
|
-
const roots = positionals.length ? sessions.filter((session) => session.id === positionals[0]) : sessions;
|
|
324
|
-
if (positionals.length && !roots.length) throw new Error(`Session ${positionals[0]} is not a live root`);
|
|
325
|
-
const blocks = [];
|
|
326
|
-
for (const root of roots) {
|
|
327
|
-
const { status } = await client.request("session.status", { sessionId: root.id }).catch(() => ({}));
|
|
328
|
-
if (status) blocks.push(renderStatus(status, root));
|
|
329
|
-
}
|
|
330
|
-
return `alp top ${(/* @__PURE__ */ new Date()).toLocaleTimeString()} ${roots.length} live ${roots.length === 1 ? "tree" : "trees"}
|
|
331
|
-
|
|
332
|
-
${blocks.join("\n\n") || "No live sessions"}`;
|
|
333
|
-
};
|
|
334
|
-
try {
|
|
335
|
-
if (values.once || !process.stdout.isTTY) {
|
|
336
|
-
console.log(await frame());
|
|
337
|
-
return;
|
|
338
|
-
}
|
|
339
|
-
let stop2 = false;
|
|
340
|
-
process.once("SIGINT", () => {
|
|
341
|
-
stop2 = true;
|
|
342
|
-
});
|
|
343
|
-
while (!stop2) {
|
|
344
|
-
const text = await frame();
|
|
345
|
-
process.stdout.write(`\x1B[2J\x1B[H${text}
|
|
346
|
-
|
|
347
|
-
(Ctrl-C to exit)
|
|
348
|
-
`);
|
|
349
|
-
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
350
|
-
}
|
|
351
|
-
} finally {
|
|
352
|
-
client.close();
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
async function log(args) {
|
|
356
|
-
const { values, positionals } = parseArgs({ args, allowPositionals: true, options: { json: { type: "boolean" } } });
|
|
357
|
-
if (positionals.length !== 1) throw new UsageError();
|
|
358
|
-
const client = await running();
|
|
359
|
-
const { rootId, entries } = await client.request("session.log", { sessionId: positionals[0] }).finally(() => client.close());
|
|
360
|
-
if (values.json) {
|
|
361
|
-
for (const entry of entries) console.log(JSON.stringify(entry));
|
|
362
|
-
return;
|
|
363
|
-
}
|
|
364
|
-
if (!entries.length) {
|
|
365
|
-
console.log(`No assignment log for ${rootId}`);
|
|
366
|
-
return;
|
|
367
|
-
}
|
|
368
|
-
for (const line of renderLog(rootId, entries)) console.log(line);
|
|
369
|
-
}
|
|
370
|
-
async function board(args) {
|
|
371
|
-
const { values, positionals } = parseArgs({ args, allowPositionals: true, options: { project: { type: "string" }, json: { type: "boolean" } } });
|
|
372
|
-
if (positionals.length) throw new UsageError();
|
|
373
|
-
const projectRoot = path.resolve(values.project ?? process.cwd());
|
|
374
|
-
const client = await running();
|
|
375
|
-
const { pins } = await client.request("board.list", { projectRoot }).finally(() => client.close());
|
|
376
|
-
if (values.json) {
|
|
377
|
-
console.log(JSON.stringify(pins));
|
|
378
|
-
return;
|
|
379
|
-
}
|
|
380
|
-
if (!pins.length) {
|
|
381
|
-
console.log(`The board for ${projectRoot} is empty`);
|
|
382
|
-
return;
|
|
383
|
-
}
|
|
384
|
-
console.log(`Project board ${projectRoot}`);
|
|
385
|
-
for (const pin of pins) {
|
|
386
|
-
const mark = pin.kind === "claim" ? "\u2691" : pin.kind === "decision" ? "\u25C6" : "\u2022";
|
|
387
|
-
console.log(`${mark} ${pin.kind.padEnd(8)} ${pin.id} ${pin.agent} ${ago(pin.at)} ago${pin.paths ? ` [${pin.paths.join(", ")}]` : ""}`);
|
|
388
|
-
console.log(` ${pin.body.replace(/\n/g, "\n ")}`);
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
function printPauses({ all, runtimes, parked }, always = true) {
|
|
392
|
-
const line = (name, pause2) => console.log(`\u23F8 ${name} paused since ${pause2.since.slice(0, 16).replace("T", " ")} by ${pause2.by}: ${pause2.reason}${pause2.resetsAt ? `; the limit resets ${pause2.resetsAt}` : ""}${pause2.checkedAt ? `; ${name} last asked ${ago(pause2.checkedAt)} ago` : ""}`);
|
|
393
|
-
if (all) line("ALP", all);
|
|
394
|
-
for (const [kind, pause2] of Object.entries(runtimes)) line(kind, pause2);
|
|
395
|
-
for (const entry of parked) console.log(` parked ${entry.agent} ${entry.assignmentId} (${entry.runtime}): ${entry.reason}`);
|
|
396
|
-
if (always && !all && !Object.keys(runtimes).length) console.log("Nothing is paused");
|
|
397
|
-
}
|
|
398
|
-
async function pause(args) {
|
|
399
|
-
const { values, positionals } = parseArgs({ args, allowPositionals: true, options: { now: { type: "boolean" }, message: { type: "string", short: "m" }, json: { type: "boolean" } } });
|
|
400
|
-
if (positionals.length > 1 || positionals[0] && !["codex", "claude", "status"].includes(positionals[0])) throw new UsageError();
|
|
401
|
-
const client = await running();
|
|
402
|
-
const state = await (positionals[0] === "status" ? client.request("daemon.pauses") : client.request("daemon.pause", { ...positionals[0] ? { runtime: positionals[0] } : {}, now: !!values.now, ...values.message ? { reason: values.message } : {} })).finally(() => client.close());
|
|
403
|
-
if (values.json) console.log(JSON.stringify(state));
|
|
404
|
-
else printPauses(state);
|
|
405
|
-
}
|
|
406
|
-
async function resume(args) {
|
|
407
|
-
const { values, positionals } = parseArgs({ args, allowPositionals: true, options: { json: { type: "boolean" } } });
|
|
408
|
-
if (positionals.length > 1 || positionals[0] && !["codex", "claude"].includes(positionals[0])) throw new UsageError();
|
|
409
|
-
const client = await running();
|
|
410
|
-
const state = await client.request("daemon.resume", positionals[0] ? { runtime: positionals[0] } : {}).finally(() => client.close());
|
|
411
|
-
if (values.json) console.log(JSON.stringify(state));
|
|
412
|
-
else printPauses(state);
|
|
413
|
-
}
|
|
414
|
-
async function recall(args) {
|
|
415
|
-
const { values, positionals } = parseArgs({ args, allowPositionals: true, options: { project: { type: "string" }, json: { type: "boolean" } } });
|
|
416
|
-
const [target, ...words] = positionals;
|
|
417
|
-
const question = words.join(" ").trim();
|
|
418
|
-
if (!target || !question) throw new UsageError();
|
|
419
|
-
const byTask = isTaskId(target);
|
|
420
|
-
const client = await running();
|
|
421
|
-
const answer2 = await client.request("assignment.recall", {
|
|
422
|
-
...byTask ? { taskId: target, projectRoot: await taskProject(values.project) } : { assignmentId: target },
|
|
423
|
-
question
|
|
424
|
-
}).finally(() => client.close());
|
|
425
|
-
if (values.json) {
|
|
426
|
-
console.log(JSON.stringify(answer2));
|
|
427
|
-
return;
|
|
428
|
-
}
|
|
429
|
-
console.log(`${answer2.agent} (assignment ${answer2.assignmentId}${answer2.taskId ? `, task ${answer2.taskId}` : ""}, finished ${ago(answer2.finishedAt)} ago):`);
|
|
430
|
-
console.log(answer2.answer);
|
|
431
|
-
}
|
|
432
|
-
async function interrupt(args) {
|
|
433
|
-
if (args.length !== 1) throw new UsageError();
|
|
434
|
-
const client = await running();
|
|
435
|
-
await client.request("session.interrupt", { sessionId: args[0] }).finally(() => client.close());
|
|
436
|
-
console.log("Interrupted");
|
|
437
|
-
}
|
|
438
|
-
export {
|
|
439
|
-
answer,
|
|
440
|
-
answerer,
|
|
441
|
-
attach,
|
|
442
|
-
board,
|
|
443
|
-
follow,
|
|
444
|
-
interrupt,
|
|
445
|
-
log,
|
|
446
|
-
pause,
|
|
447
|
-
printPauses,
|
|
448
|
-
printer,
|
|
449
|
-
ps,
|
|
450
|
-
questions,
|
|
451
|
-
recall,
|
|
452
|
-
renderStatus,
|
|
453
|
-
resume,
|
|
454
|
-
run,
|
|
455
|
-
send,
|
|
456
|
-
toolLine,
|
|
457
|
-
top
|
|
458
|
-
};
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
export namespace STATUS_MARK {
|
|
2
|
-
let open: string;
|
|
3
|
-
let in_progress: string;
|
|
4
|
-
let review: string;
|
|
5
|
-
let closed: string;
|
|
6
|
-
}
|
|
7
|
-
/** The ALP project a task command works on: --project, or the current directory. */
|
|
8
|
-
/** alp permissions: the profile each agent runs with, from .alp/settings.json and $ALP_HOME/settings.json. */
|
|
9
|
-
export function taskProject(directory: any): Promise<string>;
|
|
10
|
-
export function taskRow(task: any, tasks: any): string;
|
|
11
|
-
export function warnUnreadable(errors: any): void;
|
|
12
|
-
/** The project's tasks: open, in progress and in review by default; ready lists what nothing blocks. */
|
|
13
|
-
export function tasksCommand(args: any): Promise<void>;
|
|
14
|
-
/** The GitHub CLI, for gh:pr and gh:run gates. */
|
|
15
|
-
export function gh(args: any, { cwd }: {
|
|
16
|
-
cwd: any;
|
|
17
|
-
}): Promise<any>;
|
|
18
|
-
/** alp tasks gates: clears GitHub gates that are done and lists the open ones. alp tasks compact: shrinks old closed tasks. */
|
|
19
|
-
export function taskMaintenance([command]: [any], args: any): Promise<void>;
|
|
20
|
-
/** alp tasks export / import: interchange with beads through its JSONL issue format. */
|
|
21
|
-
export function beads(command: any, args: any): Promise<void>;
|
|
22
|
-
/** alp formula: workflow templates that pour into an epic with a task per step. */
|
|
23
|
-
export function formulaCommand([action, ...args]: [any, ...any[]]): Promise<void>;
|
|
24
|
-
export namespace repeated {
|
|
25
|
-
let type: string;
|
|
26
|
-
let multiple: boolean;
|
|
27
|
-
}
|
|
28
|
-
export function taskCommand([action, ...args]: [any, ...any[]]): Promise<void>;
|
|
29
|
-
export function printTask(task: any, tasks: any): void;
|