@layorixinc/axterm 0.7.0 → 0.8.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/dist/cli.js +489 -129
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -50,6 +50,11 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
|
50
50
|
function descriptor(surfaceClass, lane, required, defaultEnabled, sizePolicy) {
|
|
51
51
|
return { class: surfaceClass, lane, required, defaultEnabled, sizePolicy };
|
|
52
52
|
}
|
|
53
|
+
function progressGlyph(status) {
|
|
54
|
+
if (status === undefined)
|
|
55
|
+
return "\uD83D\uDCCC";
|
|
56
|
+
return PROGRESS_GLYPHS[status] ?? "\uD83D\uDCCC";
|
|
57
|
+
}
|
|
53
58
|
|
|
54
59
|
class SurfaceCommitter {
|
|
55
60
|
options;
|
|
@@ -125,7 +130,7 @@ function remember(entries, key, limit) {
|
|
|
125
130
|
if (oldest !== undefined)
|
|
126
131
|
entries.delete(oldest);
|
|
127
132
|
}
|
|
128
|
-
var SURFACE_KINDS, SURFACE_DESCRIPTORS, OPTIONAL_SURFACE_KINDS;
|
|
133
|
+
var SURFACE_KINDS, SURFACE_DESCRIPTORS, OPTIONAL_SURFACE_KINDS, PROGRESS_GLYPHS, CONVERSATION_CHANGE_CAUSES;
|
|
129
134
|
var init_agent_surface = __esm(() => {
|
|
130
135
|
SURFACE_KINDS = [
|
|
131
136
|
"state.agent",
|
|
@@ -200,10 +205,10 @@ var init_agent_surface = __esm(() => {
|
|
|
200
205
|
"notice.auth": descriptor("notice", "immediate", true, true, "telemetry"),
|
|
201
206
|
"notice.warning": descriptor("notice", "digest", false, true, "telemetry"),
|
|
202
207
|
"notice.info": descriptor("notice", "digest", false, false, "telemetry"),
|
|
203
|
-
"context.session": descriptor("context", "
|
|
208
|
+
"context.session": descriptor("context", "immediate", true, true, "telemetry"),
|
|
204
209
|
"context.compaction": descriptor("context", "snapshot", false, true, "telemetry"),
|
|
205
210
|
"context.handoff": descriptor("context", "snapshot", false, true, "telemetry"),
|
|
206
|
-
"context.branch": descriptor("context", "
|
|
211
|
+
"context.branch": descriptor("context", "immediate", true, true, "telemetry"),
|
|
207
212
|
"context.tree": descriptor("context", "digest", false, false, "telemetry"),
|
|
208
213
|
"artifact.image": descriptor("artifact", "artifact", false, false, "channelArtifact"),
|
|
209
214
|
"artifact.file": descriptor("artifact", "artifact", false, false, "channelArtifact"),
|
|
@@ -212,6 +217,15 @@ var init_agent_surface = __esm(() => {
|
|
|
212
217
|
"artifact.link": descriptor("artifact", "digest", false, false, "telemetry")
|
|
213
218
|
};
|
|
214
219
|
OPTIONAL_SURFACE_KINDS = SURFACE_KINDS.filter((kind) => !SURFACE_DESCRIPTORS[kind].required);
|
|
220
|
+
PROGRESS_GLYPHS = {
|
|
221
|
+
pending: "\u23F3",
|
|
222
|
+
active: "\uD83D\uDD04",
|
|
223
|
+
blocked: "\u26D4",
|
|
224
|
+
done: "\u2705",
|
|
225
|
+
failed: "\u274C",
|
|
226
|
+
skipped: "\u23E9"
|
|
227
|
+
};
|
|
228
|
+
CONVERSATION_CHANGE_CAUSES = ["new", "resume", "fork", "handoff"];
|
|
215
229
|
});
|
|
216
230
|
|
|
217
231
|
// packages/core/src/menu-keys.ts
|
|
@@ -1816,6 +1830,7 @@ locale: set AXTERM_LANG=en|ko, or \`axterm config set locale ko\`
|
|
|
1816
1830
|
"sl.command.unknownKey": 'Unknown key "{name}" \u2014 nothing was sent. Accepted: {keys}',
|
|
1817
1831
|
"sl.command.keysSent": "\u2328\uFE0F sent: {keys}",
|
|
1818
1832
|
"sl.command.typed": "\u2328\uFE0F typed without Enter:\n```text\n{screen}\n```",
|
|
1833
|
+
"sl.passthrough.sent": "\u2328\uFE0F typed `/{command}` for the agent. Nothing was submitted \u2014 use the `key` control command with `keys:enter` if it needs Enter:\n```text\n{screen}\n```",
|
|
1819
1834
|
"sl.command.failed": "Failed: {error}",
|
|
1820
1835
|
"sl.state.working": "working",
|
|
1821
1836
|
"sl.state.blocked": "waiting for approval",
|
|
@@ -1863,6 +1878,8 @@ locale: set AXTERM_LANG=en|ko, or \`axterm config set locale ko\`
|
|
|
1863
1878
|
"tg.agent.retry": "\u23F3 The agent is rate limited and will retry in {wait}: {error}",
|
|
1864
1879
|
"tg.raw.keysSent": "\u2328\uFE0F sent: {keys}",
|
|
1865
1880
|
"tg.raw.unknownKey": 'unknown key "{name}" \u2014 nothing was sent. Accepted: {keys}',
|
|
1881
|
+
"tg.passthrough.sent": `sent <code>/{command}</code> to the agent. Nothing was submitted \u2014 use the key buttons or <code>/key enter</code> if it needs Enter:
|
|
1882
|
+
{screen}`,
|
|
1866
1883
|
"tg.raw.typed": `\u2328\uFE0F typed (not submitted \u2014 /key enter to send):
|
|
1867
1884
|
<pre>{screen}</pre>`,
|
|
1868
1885
|
"tg.raw.needText": "usage: /type <text> \u2014 written verbatim, without Enter. Then /key enter.",
|
|
@@ -1910,6 +1927,7 @@ locale: set AXTERM_LANG=en|ko, or \`axterm config set locale ko\`
|
|
|
1910
1927
|
"dc.secret.submitted": "\uD83D\uDD10 The secret was submitted and the source message was removed if permissions allowed.",
|
|
1911
1928
|
"dc.ask.tooMany": "This question has too many options for Discord; answer it in the attached terminal.",
|
|
1912
1929
|
"dc.ask.resolvedElsewhere": "\u231B This question was answered elsewhere.",
|
|
1930
|
+
"dc.ask.conversationChanged": "\u231B The conversation changed, so this question no longer exists.",
|
|
1913
1931
|
"dc.command.noProjects": "No projects configured.",
|
|
1914
1932
|
"dc.command.noSessions": "No sessions.",
|
|
1915
1933
|
"dc.command.unknownProject": "Unknown project: {project}",
|
|
@@ -1947,6 +1965,7 @@ locale: set AXTERM_LANG=en|ko, or \`axterm config set locale ko\`
|
|
|
1947
1965
|
"dc.command.unknownKey": 'Unknown key "{name}" \u2014 nothing was sent. Accepted: {keys}',
|
|
1948
1966
|
"dc.command.keysSent": "\u2328\uFE0F sent: {keys}",
|
|
1949
1967
|
"dc.command.typed": "\u2328\uFE0F typed without Enter:\n```text\n{screen}\n```",
|
|
1968
|
+
"dc.passthrough.sent": "\u2328\uFE0F typed `/{command}` for the agent. Nothing was submitted \u2014 use `/ax-key` with `enter` if it needs Enter:\n```text\n{screen}\n```",
|
|
1950
1969
|
"dc.command.tooLong": "Raw input is limited to {limit} characters; send a normal prompt instead.",
|
|
1951
1970
|
"dc.inbound.empty": "\u26A0\uFE0F The attachment is empty.",
|
|
1952
1971
|
"err.discord.noThread": "Discord has no thread for session {session}",
|
|
@@ -2064,6 +2083,12 @@ usage: /fanout <project> <count|branches> <prompt>`,
|
|
|
2064
2083
|
"err.claude.conversationBusy": "session {session} is already in conversation {id} \u2014 two sessions writing one transcript would corrupt it; kill that one first",
|
|
2065
2084
|
"err.claude.noConversation": "claude has no conversation {id} in its store on this machine \u2014 a conversation lives on the machine it ran on, so this one cannot be resumed here",
|
|
2066
2085
|
"agent.approval.denied": "Denied from the axterm channel",
|
|
2086
|
+
"agent.conversation.switch.new": "\uD83D\uDD00 A new conversation was started under this topic \u2014 your next prompt goes to it, not the previous one.",
|
|
2087
|
+
"agent.conversation.switch.resume": "\uD83D\uDD00 This topic resumed a different conversation \u2014 your next prompt goes to the resumed one, not the previous one.",
|
|
2088
|
+
"agent.conversation.switch.fork": "\uD83D\uDD00 The conversation was forked \u2014 this topic now follows the fork, and your next prompt goes to it.",
|
|
2089
|
+
"agent.conversation.switch.handoff": "\uD83D\uDD00 The conversation was handed off \u2014 this topic now follows the new conversation, and your next prompt goes to it.",
|
|
2090
|
+
"agent.conversation.switch.unknown": "\uD83D\uDD00 The conversation under this topic changed \u2014 your next prompt goes to the new conversation, not the previous one.",
|
|
2091
|
+
"agent.conversation.branch": "\uD83C\uDF31 The conversation branched \u2014 this topic now follows the branch, and your next prompt goes to it.",
|
|
2067
2092
|
"err.codex.noAuth": "codex is not logged in ({authFile} not found) \u2014 run `codex login` once, then start the session again",
|
|
2068
2093
|
"err.codex.authLink": "could not link codex credentials into axterm's CODEX_HOME ({reason}) \u2014 refusing to start a logged-out agent",
|
|
2069
2094
|
"health.config.invalid": "the configuration file could not be understood",
|
|
@@ -2104,6 +2129,8 @@ usage: /fanout <project> <count|branches> <prompt>`,
|
|
|
2104
2129
|
"wizard.review.header": "Review",
|
|
2105
2130
|
"wizard.cancelled": "nothing was saved",
|
|
2106
2131
|
"wizard.saved": "configuration saved",
|
|
2132
|
+
"wizard.telegramDiscovering": "looking up the group and user ids this bot can see\u2026",
|
|
2133
|
+
"wizard.telegramDiscoverFailed": "automatic Telegram discovery failed: {error} \u2014 enter the ids manually below or retry setup after stopping the active Telegram channel",
|
|
2107
2134
|
"wizard.checking": "checking the Telegram setup\u2026",
|
|
2108
2135
|
"wizard.telegramOk": "Telegram is ready",
|
|
2109
2136
|
"wizard.needed": "axterm is not configured yet.",
|
|
@@ -2310,6 +2337,7 @@ usage: /fanout <project> <count|branches> <prompt>`,
|
|
|
2310
2337
|
"sl.command.unknownKey": '\uC54C \uC218 \uC5C6\uB294 \uD0A4 "{name}" \u2014 \uC544\uBB34\uAC83\uB3C4 \uBCF4\uB0B4\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uAC00\uB2A5\uD55C \uD0A4: {keys}',
|
|
2311
2338
|
"sl.command.keysSent": "\u2328\uFE0F \uC804\uC1A1: {keys}",
|
|
2312
2339
|
"sl.command.typed": "\u2328\uFE0F Enter \uC5C6\uC774 \uC785\uB825\uD588\uC2B5\uB2C8\uB2E4:\n```text\n{screen}\n```",
|
|
2340
|
+
"sl.passthrough.sent": "\u2328\uFE0F \uC5D0\uC774\uC804\uD2B8\uC5D0 `/{command}` \uB97C \uC785\uB825\uD588\uC2B5\uB2C8\uB2E4. \uC81C\uCD9C\uC740 \uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4 \u2014 Enter\uAC00 \uD544\uC694\uD558\uBA74 `key` \uC81C\uC5B4 \uBA85\uB839\uC5D0 `keys:enter` \uB97C \uC4F0\uC138\uC694:\n```text\n{screen}\n```",
|
|
2313
2341
|
"sl.command.failed": "\uC2E4\uD328: {error}",
|
|
2314
2342
|
"sl.state.working": "\uC791\uC5C5 \uC911",
|
|
2315
2343
|
"sl.state.blocked": "\uC2B9\uC778 \uB300\uAE30 \uC911",
|
|
@@ -2371,6 +2399,8 @@ usage: /fanout <project> <count|branches> <prompt>`,
|
|
|
2371
2399
|
"tg.agent.retry": "\u23F3 \uC5D0\uC774\uC804\uD2B8\uAC00 \uC694\uCCAD \uD55C\uB3C4\uC5D0 \uAC78\uB824 {wait} \uD6C4 \uC7AC\uC2DC\uB3C4\uD569\uB2C8\uB2E4: {error}",
|
|
2372
2400
|
"tg.raw.keysSent": "\u2328\uFE0F \uC804\uC1A1: {keys}",
|
|
2373
2401
|
"tg.raw.unknownKey": '\uC54C \uC218 \uC5C6\uB294 \uD0A4 "{name}" \u2014 \uC544\uBB34\uAC83\uB3C4 \uBCF4\uB0B4\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uAC00\uB2A5\uD55C \uD0A4: {keys}',
|
|
2402
|
+
"tg.passthrough.sent": `<code>/{command}</code> \uB97C \uC5D0\uC774\uC804\uD2B8\uC5D0 \uC785\uB825\uD588\uC2B5\uB2C8\uB2E4. \uC81C\uCD9C\uC740 \uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4 \u2014 Enter\uAC00 \uD544\uC694\uD558\uBA74 \uD0A4 \uBC84\uD2BC\uC774\uB098 <code>/key enter</code> \uB97C \uC4F0\uC138\uC694:
|
|
2403
|
+
{screen}`,
|
|
2374
2404
|
"tg.raw.typed": `\u2328\uFE0F \uC785\uB825\uD588\uC2B5\uB2C8\uB2E4 (\uC544\uC9C1 \uC81C\uCD9C \uC548 \uD568 \u2014 \uBCF4\uB0B4\uB824\uBA74 /key enter):
|
|
2375
2405
|
<pre>{screen}</pre>`,
|
|
2376
2406
|
"tg.raw.needText": "\uC0AC\uC6A9\uBC95: /type <\uD14D\uC2A4\uD2B8> \u2014 Enter \uC5C6\uC774 \uADF8\uB300\uB85C \uC785\uB825\uB429\uB2C8\uB2E4. \uC774\uD6C4 /key enter.",
|
|
@@ -2418,6 +2448,7 @@ usage: /fanout <project> <count|branches> <prompt>`,
|
|
|
2418
2448
|
"dc.secret.submitted": "\uD83D\uDD10 \uBE44\uBC00\uC744 \uC804\uB2EC\uD588\uC73C\uBA70 \uAD8C\uD55C\uC774 \uD5C8\uC6A9\uD55C \uACBD\uC6B0 \uC6D0\uBCF8 \uBA54\uC2DC\uC9C0\uB97C \uC0AD\uC81C\uD588\uC2B5\uB2C8\uB2E4.",
|
|
2419
2449
|
"dc.ask.tooMany": "Discord\uC5D0 \uD45C\uC2DC\uD558\uAE30\uC5D0\uB294 \uC120\uD0DD\uC9C0\uAC00 \uB108\uBB34 \uB9CE\uC2B5\uB2C8\uB2E4. \uC5F0\uACB0\uB41C \uD130\uBBF8\uB110\uC5D0\uC11C \uB2F5\uD558\uC138\uC694.",
|
|
2420
2450
|
"dc.ask.resolvedElsewhere": "\u231B \uC774 \uC9C8\uBB38\uC740 \uB2E4\uB978 \uACF3\uC5D0\uC11C \uB2F5\uBCC0\uB418\uC5C8\uC2B5\uB2C8\uB2E4.",
|
|
2451
|
+
"dc.ask.conversationChanged": "\u231B \uB300\uD654\uAC00 \uBC14\uB00C\uC5B4 \uC774 \uC9C8\uBB38\uC740 \uB354 \uC774\uC0C1 \uC874\uC7AC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
|
|
2421
2452
|
"dc.command.noProjects": "\uC124\uC815\uB41C \uD504\uB85C\uC81D\uD2B8\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
2422
2453
|
"dc.command.noSessions": "\uC138\uC158\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
2423
2454
|
"dc.command.unknownProject": "\uC54C \uC218 \uC5C6\uB294 \uD504\uB85C\uC81D\uD2B8: {project}",
|
|
@@ -2462,6 +2493,7 @@ usage: /fanout <project> <count|branches> <prompt>`,
|
|
|
2462
2493
|
"dc.command.unknownKey": '\uC54C \uC218 \uC5C6\uB294 \uD0A4 "{name}" \u2014 \uC544\uBB34\uAC83\uB3C4 \uBCF4\uB0B4\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uAC00\uB2A5\uD55C \uD0A4: {keys}',
|
|
2463
2494
|
"dc.command.keysSent": "\u2328\uFE0F \uC804\uC1A1: {keys}",
|
|
2464
2495
|
"dc.command.typed": "\u2328\uFE0F Enter \uC5C6\uC774 \uC785\uB825\uD588\uC2B5\uB2C8\uB2E4:\n```text\n{screen}\n```",
|
|
2496
|
+
"dc.passthrough.sent": "\u2328\uFE0F \uC5D0\uC774\uC804\uD2B8\uC5D0 `/{command}` \uB97C \uC785\uB825\uD588\uC2B5\uB2C8\uB2E4. \uC81C\uCD9C\uC740 \uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4 \u2014 Enter\uAC00 \uD544\uC694\uD558\uBA74 `/ax-key` \uC5D0 `enter` \uB97C \uC4F0\uC138\uC694:\n```text\n{screen}\n```",
|
|
2465
2497
|
"dc.command.tooLong": "\uC6D0\uC2DC \uC785\uB825\uC740 \uCD5C\uB300 {limit}\uC790\uC785\uB2C8\uB2E4. \uC77C\uBC18 \uD504\uB86C\uD504\uD2B8\uB85C \uBCF4\uB0B4\uC138\uC694.",
|
|
2466
2498
|
"dc.state.shell": "\uC178",
|
|
2467
2499
|
"dc.state.exited": "\uC885\uB8CC\uB428",
|
|
@@ -2572,6 +2604,12 @@ usage: /fanout <project> <count|branches> <prompt>`,
|
|
|
2572
2604
|
"err.claude.conversationBusy": "\uC138\uC158 {session} \uC774(\uAC00) \uC774\uBBF8 \uB300\uD654 {id} \uC5D0 \uB4E4\uC5B4\uAC00 \uC788\uC2B5\uB2C8\uB2E4. \uD55C transcript\uC5D0 \uB450 \uC138\uC158\uC774 \uC4F0\uBA74 \uC190\uC0C1\uB418\uBBC0\uB85C \uBA3C\uC800 \uADF8 \uC138\uC158\uC744 \uC885\uB8CC\uD558\uC138\uC694",
|
|
2573
2605
|
"err.claude.noConversation": "\uC774 \uBA38\uC2E0\uC758 claude \uC800\uC7A5\uC18C\uC5D0 \uB300\uD654 {id} \uC774(\uAC00) \uC5C6\uC2B5\uB2C8\uB2E4. \uB300\uD654\uB294 \uC2E4\uD589\uB41C \uBA38\uC2E0\uC5D0 \uB0A8\uC73C\uBBC0\uB85C \uC5EC\uAE30\uC11C\uB294 \uC774\uC5B4\uAC08 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4",
|
|
2574
2606
|
"agent.approval.denied": "axterm \uCC44\uB110\uC5D0\uC11C \uAC70\uBD80\uB418\uC5C8\uC2B5\uB2C8\uB2E4",
|
|
2607
|
+
"agent.conversation.switch.new": "\uD83D\uDD00 \uC774 \uD1A0\uD53D \uC544\uB798\uC5D0 \uC0C8 \uB300\uD654\uAC00 \uC2DC\uC791\uB418\uC5C8\uC2B5\uB2C8\uB2E4 \u2014 \uB2E4\uC74C \uD504\uB86C\uD504\uD2B8\uB294 \uC774\uC804 \uB300\uD654\uAC00 \uC544\uB2C8\uB77C \uC0C8 \uB300\uD654\uB85C \uAC11\uB2C8\uB2E4.",
|
|
2608
|
+
"agent.conversation.switch.resume": "\uD83D\uDD00 \uC774 \uD1A0\uD53D\uC774 \uB2E4\uB978 \uB300\uD654\uB97C \uC774\uC5B4\uBC1B\uC558\uC2B5\uB2C8\uB2E4 \u2014 \uB2E4\uC74C \uD504\uB86C\uD504\uD2B8\uB294 \uC774\uC804 \uB300\uD654\uAC00 \uC544\uB2C8\uB77C \uC774\uC5B4\uC9C4 \uB300\uD654\uB85C \uAC11\uB2C8\uB2E4.",
|
|
2609
|
+
"agent.conversation.switch.fork": "\uD83D\uDD00 \uB300\uD654\uAC00 \uD3EC\uD06C\uB418\uC5C8\uC2B5\uB2C8\uB2E4 \u2014 \uC774 \uD1A0\uD53D\uC740 \uC774\uC81C \uD3EC\uD06C\uB41C \uB300\uD654\uB97C \uB530\uB974\uBA70, \uB2E4\uC74C \uD504\uB86C\uD504\uD2B8\uB294 \uADF8\uCABD\uC73C\uB85C \uAC11\uB2C8\uB2E4.",
|
|
2610
|
+
"agent.conversation.switch.handoff": "\uD83D\uDD00 \uB300\uD654\uAC00 \uC778\uACC4\uB418\uC5C8\uC2B5\uB2C8\uB2E4 \u2014 \uC774 \uD1A0\uD53D\uC740 \uC774\uC81C \uC0C8 \uB300\uD654\uB97C \uB530\uB974\uBA70, \uB2E4\uC74C \uD504\uB86C\uD504\uD2B8\uB294 \uADF8\uCABD\uC73C\uB85C \uAC11\uB2C8\uB2E4.",
|
|
2611
|
+
"agent.conversation.switch.unknown": "\uD83D\uDD00 \uC774 \uD1A0\uD53D\uC758 \uB300\uD654\uAC00 \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4 \u2014 \uB2E4\uC74C \uD504\uB86C\uD504\uD2B8\uB294 \uC774\uC804 \uB300\uD654\uAC00 \uC544\uB2C8\uB77C \uC0C8 \uB300\uD654\uB85C \uAC11\uB2C8\uB2E4.",
|
|
2612
|
+
"agent.conversation.branch": "\uD83C\uDF31 \uB300\uD654\uAC00 \uBD84\uAE30\uB418\uC5C8\uC2B5\uB2C8\uB2E4 \u2014 \uC774 \uD1A0\uD53D\uC740 \uC774\uC81C \uBD84\uAE30\uB41C \uB300\uD654\uB97C \uB530\uB974\uBA70, \uB2E4\uC74C \uD504\uB86C\uD504\uD2B8\uB294 \uADF8\uCABD\uC73C\uB85C \uAC11\uB2C8\uB2E4.",
|
|
2575
2613
|
"err.codex.noAuth": "codex\uC5D0 \uB85C\uADF8\uC778\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 ({authFile} \uC5C6\uC74C). `codex login` \uC744 \uD55C \uBC88 \uC2E4\uD589\uD55C \uB4A4 \uC138\uC158\uC744 \uB2E4\uC2DC \uC2DC\uC791\uD558\uC138\uC694",
|
|
2576
2614
|
"err.codex.authLink": "codex \uC790\uACA9 \uC99D\uBA85\uC744 axterm\uC758 CODEX_HOME\uC5D0 \uC5F0\uACB0\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 ({reason}). \uB85C\uADF8\uC544\uC6C3 \uC0C1\uD0DC\uC758 \uC5D0\uC774\uC804\uD2B8\uB294 \uC2DC\uC791\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4",
|
|
2577
2615
|
"health.config.invalid": "\uC124\uC815 \uD30C\uC77C\uC744 \uC774\uD574\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4",
|
|
@@ -2612,6 +2650,8 @@ usage: /fanout <project> <count|branches> <prompt>`,
|
|
|
2612
2650
|
"wizard.review.header": "\uD655\uC778",
|
|
2613
2651
|
"wizard.cancelled": "\uC800\uC7A5\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4",
|
|
2614
2652
|
"wizard.saved": "\uC124\uC815\uC744 \uC800\uC7A5\uD588\uC2B5\uB2C8\uB2E4",
|
|
2653
|
+
"wizard.telegramDiscovering": "\uC774 \uBD07\uC774 \uBCFC \uC218 \uC788\uB294 \uADF8\uB8F9 id\uC640 \uC0AC\uC6A9\uC790 id\uB97C \uC870\uD68C\uD558\uB294 \uC911\u2026",
|
|
2654
|
+
"wizard.telegramDiscoverFailed": "Telegram \uC790\uB3D9 \uC870\uD68C \uC2E4\uD328: {error} \u2014 \uC544\uB798\uC5D0\uC11C id\uB97C \uC9C1\uC811 \uC785\uB825\uD558\uAC70\uB098, \uC2E4\uD589 \uC911\uC778 Telegram \uCC44\uB110\uC744 \uC911\uC9C0\uD55C \uB4A4 setup\uC744 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694",
|
|
2615
2655
|
"wizard.checking": "Telegram \uC124\uC815\uC744 \uC810\uAC80\uD558\uB294 \uC911\u2026",
|
|
2616
2656
|
"wizard.telegramOk": "Telegram \uC900\uBE44 \uC644\uB8CC",
|
|
2617
2657
|
"wizard.needed": "axterm\uC774 \uC544\uC9C1 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.",
|
|
@@ -2780,6 +2820,25 @@ var init_setup_wizard = __esm(() => {
|
|
|
2780
2820
|
});
|
|
2781
2821
|
|
|
2782
2822
|
// packages/core/src/agent-resume.ts
|
|
2823
|
+
function repairPersistedResumeSource(profile, source) {
|
|
2824
|
+
if (profile.id !== "omp" || source.agentSessionFile === undefined)
|
|
2825
|
+
return source;
|
|
2826
|
+
const file = source.agentSessionFile;
|
|
2827
|
+
const lastSeparator = Math.max(file.lastIndexOf("/"), file.lastIndexOf("\\"));
|
|
2828
|
+
if (lastSeparator < 0 || !file.slice(lastSeparator + 1).toLowerCase().endsWith(".jsonl"))
|
|
2829
|
+
return source;
|
|
2830
|
+
const parent = file.slice(0, lastSeparator);
|
|
2831
|
+
const parentSeparator = Math.max(parent.lastIndexOf("/"), parent.lastIndexOf("\\"));
|
|
2832
|
+
const parentName = parent.slice(parentSeparator + 1);
|
|
2833
|
+
const match2 = OMP_SESSION_ID_SUFFIX.exec(parentName);
|
|
2834
|
+
if (match2 === null)
|
|
2835
|
+
return source;
|
|
2836
|
+
return {
|
|
2837
|
+
...source,
|
|
2838
|
+
agentSessionFile: `${parent}.jsonl`,
|
|
2839
|
+
agentSessionId: match2[1]
|
|
2840
|
+
};
|
|
2841
|
+
}
|
|
2783
2842
|
function resumeReference(profile, source) {
|
|
2784
2843
|
const reported = profile.resume?.ref === "sessionId" ? source.agentSessionId : source.agentSessionFile;
|
|
2785
2844
|
if (reported !== undefined && reported.length > 0)
|
|
@@ -2831,9 +2890,10 @@ function buildResumeCommand(command, profile, reference) {
|
|
|
2831
2890
|
const fragment = template.map((token) => token.replaceAll(REF, reference));
|
|
2832
2891
|
return resume.form === "subcommand" ? [base[0], ...fragment, ...base.slice(1)] : [...base, ...fragment];
|
|
2833
2892
|
}
|
|
2834
|
-
var REF = "{ref}", COMMAND_ALIASES;
|
|
2893
|
+
var REF = "{ref}", OMP_SESSION_ID_SUFFIX, COMMAND_ALIASES;
|
|
2835
2894
|
var init_agent_resume = __esm(() => {
|
|
2836
2895
|
init_agent_registry();
|
|
2896
|
+
OMP_SESSION_ID_SUFFIX = /_([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i;
|
|
2837
2897
|
COMMAND_ALIASES = new Map(REGISTERED_AGENTS.flatMap((id) => {
|
|
2838
2898
|
const profile = agentProfile(id);
|
|
2839
2899
|
return profile.command === undefined ? [] : [[profile.command, id]];
|
|
@@ -3698,15 +3758,45 @@ function next(prev, state, now) {
|
|
|
3698
3758
|
stateStartedAt: prev?.state === state ? prev.stateStartedAt : now
|
|
3699
3759
|
};
|
|
3700
3760
|
}
|
|
3761
|
+
function delegationSurface(event, subagentId) {
|
|
3762
|
+
const done = event.event === "agent_end" || event.event === "agent_settled";
|
|
3763
|
+
const prompt = event.prompt?.split(`
|
|
3764
|
+
`, 1)[0]?.trim().slice(0, MAX_DELEGATION_TITLE);
|
|
3765
|
+
return {
|
|
3766
|
+
event: "surface",
|
|
3767
|
+
surface: {
|
|
3768
|
+
class: "progress",
|
|
3769
|
+
kind: "progress.delegation",
|
|
3770
|
+
key: subagentId,
|
|
3771
|
+
sourceEvent: event.event,
|
|
3772
|
+
payload: {
|
|
3773
|
+
scope: "delegation",
|
|
3774
|
+
title: event.tool_name ?? (prompt !== undefined && prompt !== "" ? prompt : subagentId),
|
|
3775
|
+
status: done ? "done" : "active"
|
|
3776
|
+
}
|
|
3777
|
+
}
|
|
3778
|
+
};
|
|
3779
|
+
}
|
|
3780
|
+
function withoutConversationIdentity(event) {
|
|
3781
|
+
if (event.session_id === undefined && event.session_file === undefined && event.session_name === undefined) {
|
|
3782
|
+
return event;
|
|
3783
|
+
}
|
|
3784
|
+
const { session_id: _id, session_file: _file, session_name: _name, ...rest } = event;
|
|
3785
|
+
return rest;
|
|
3786
|
+
}
|
|
3701
3787
|
function withConversationId(events, identity) {
|
|
3702
3788
|
const id = identity.sessionId;
|
|
3703
3789
|
const subagent = identity.subagentId;
|
|
3704
|
-
if (typeof
|
|
3705
|
-
return
|
|
3790
|
+
if (typeof subagent === "string" && subagent !== "") {
|
|
3791
|
+
return events.map((event) => LEAD_ONLY_EVENTS.has(event.event) ? delegationSurface(event, subagent) : withoutConversationIdentity(event));
|
|
3706
3792
|
}
|
|
3793
|
+
if (typeof id !== "string" || id === "")
|
|
3794
|
+
return [...events];
|
|
3707
3795
|
return events.map((event) => ({ session_id: id, ...event }));
|
|
3708
3796
|
}
|
|
3709
|
-
function mayReplaceConversationIdentity(agentId, current, reported, event) {
|
|
3797
|
+
function mayReplaceConversationIdentity(agentId, current, reported, event, fromSubagent = false) {
|
|
3798
|
+
if (fromSubagent)
|
|
3799
|
+
return false;
|
|
3710
3800
|
if (reported === current)
|
|
3711
3801
|
return false;
|
|
3712
3802
|
if (current === undefined)
|
|
@@ -3802,8 +3892,15 @@ function isAgentSendable(probe, now) {
|
|
|
3802
3892
|
return probe.occupied;
|
|
3803
3893
|
return now - probe.spawnedAt < BOOT_GRACE_MS;
|
|
3804
3894
|
}
|
|
3805
|
-
var AGENT_ACTIVITY, WORKING_HOOK_STALE_MS = 30000, OUTPUT_QUIET_MS = 1e4, BOOT_GRACE_MS = 60000;
|
|
3895
|
+
var LEAD_ONLY_EVENTS, MAX_DELEGATION_TITLE = 80, AGENT_ACTIVITY, WORKING_HOOK_STALE_MS = 30000, OUTPUT_QUIET_MS = 1e4, BOOT_GRACE_MS = 60000;
|
|
3806
3896
|
var init_agent_status = __esm(() => {
|
|
3897
|
+
LEAD_ONLY_EVENTS = new Set([
|
|
3898
|
+
"before_agent_start",
|
|
3899
|
+
"agent_start",
|
|
3900
|
+
"agent_settled",
|
|
3901
|
+
"agent_end",
|
|
3902
|
+
"message_end"
|
|
3903
|
+
]);
|
|
3807
3904
|
AGENT_ACTIVITY = new Set([
|
|
3808
3905
|
"agent_start",
|
|
3809
3906
|
"before_agent_start",
|
|
@@ -3824,6 +3921,42 @@ var init_agent_status = __esm(() => {
|
|
|
3824
3921
|
]);
|
|
3825
3922
|
});
|
|
3826
3923
|
|
|
3924
|
+
// packages/core/src/agent-passthrough.ts
|
|
3925
|
+
function parseAgentPassthrough(text) {
|
|
3926
|
+
if (text.includes(`
|
|
3927
|
+
`) || text.includes("\r"))
|
|
3928
|
+
return;
|
|
3929
|
+
if (!text.startsWith("."))
|
|
3930
|
+
return;
|
|
3931
|
+
const rest = text.slice(1);
|
|
3932
|
+
const match2 = /^([A-Za-z][A-Za-z0-9_.-]*)(\s.*)?$/.exec(rest);
|
|
3933
|
+
if (!match2)
|
|
3934
|
+
return;
|
|
3935
|
+
const name = match2[1];
|
|
3936
|
+
if (name.length > MAX_NAME)
|
|
3937
|
+
return;
|
|
3938
|
+
if (match2[2] === undefined && DOTFILE_NAMES.has(name.toLowerCase()))
|
|
3939
|
+
return;
|
|
3940
|
+
return { keystrokes: `/${rest}`, name };
|
|
3941
|
+
}
|
|
3942
|
+
var MAX_NAME = 32, DOTFILE_NAMES;
|
|
3943
|
+
var init_agent_passthrough = __esm(() => {
|
|
3944
|
+
DOTFILE_NAMES = new Set([
|
|
3945
|
+
"env",
|
|
3946
|
+
"gitignore",
|
|
3947
|
+
"gitattributes",
|
|
3948
|
+
"npmrc",
|
|
3949
|
+
"nvmrc",
|
|
3950
|
+
"editorconfig",
|
|
3951
|
+
"dockerignore",
|
|
3952
|
+
"gitmodules",
|
|
3953
|
+
"bashrc",
|
|
3954
|
+
"zshrc",
|
|
3955
|
+
"profile",
|
|
3956
|
+
"tool-versions"
|
|
3957
|
+
]);
|
|
3958
|
+
});
|
|
3959
|
+
|
|
3827
3960
|
// packages/core/src/surface-policy.ts
|
|
3828
3961
|
function resolveSurfacePolicy(agentId, kind, config) {
|
|
3829
3962
|
const descriptor2 = SURFACE_DESCRIPTORS[kind];
|
|
@@ -4003,15 +4136,15 @@ function planMaterialisedPath(stagingDir, sessionId, remotePath) {
|
|
|
4003
4136
|
let name = base.replace(/[\u0000-\u001f<>:"|?*]/g, "_").replace(/^\.+$/, "");
|
|
4004
4137
|
if (name.length === 0)
|
|
4005
4138
|
name = "file";
|
|
4006
|
-
if (name.length >
|
|
4139
|
+
if (name.length > MAX_NAME2) {
|
|
4007
4140
|
const dot = name.lastIndexOf(".");
|
|
4008
4141
|
const ext = dot > 0 && name.length - dot <= 16 ? name.slice(dot) : "";
|
|
4009
|
-
name = name.slice(0,
|
|
4142
|
+
name = name.slice(0, MAX_NAME2 - ext.length) + ext;
|
|
4010
4143
|
}
|
|
4011
4144
|
return `${stagingDir}/${sessionId}/${name}`;
|
|
4012
4145
|
}
|
|
4013
4146
|
var SCRATCH_DIR_NAME = ".axterm", SCRATCH_IGNORE_NAME = ".gitignore", SCRATCH_IGNORE_BODY = `*
|
|
4014
|
-
`,
|
|
4147
|
+
`, MAX_NAME2 = 120;
|
|
4015
4148
|
|
|
4016
4149
|
// packages/core/src/claude-hooks.ts
|
|
4017
4150
|
function resultText(response) {
|
|
@@ -6654,6 +6787,7 @@ var init_src = __esm(() => {
|
|
|
6654
6787
|
init_choice();
|
|
6655
6788
|
init_agent_status();
|
|
6656
6789
|
init_activity();
|
|
6790
|
+
init_agent_passthrough();
|
|
6657
6791
|
init_agent_surface();
|
|
6658
6792
|
init_surface_policy();
|
|
6659
6793
|
init_pty_protocol();
|
|
@@ -6747,14 +6881,20 @@ function renderSlackSurface(surface) {
|
|
|
6747
6881
|
const progress = surface.payload.current !== undefined && surface.payload.total !== undefined ? ` (${surface.payload.current}/${surface.payload.total})` : "";
|
|
6748
6882
|
const items = surface.payload.items?.map((item) => `${item.status === "done" ? "\u2611" : item.status === "active" ? "\u25B6" : "\u2022"} ${item.label}`).join(`
|
|
6749
6883
|
`);
|
|
6750
|
-
|
|
6884
|
+
const glyph = surface.payload.status === undefined ? "\uD83D\uDCCB" : progressGlyph(surface.payload.status);
|
|
6885
|
+
return `${glyph} **${surface.payload.title}**${progress}${items ? `
|
|
6751
6886
|
${items}` : ""}`;
|
|
6752
6887
|
}
|
|
6753
6888
|
case "activity":
|
|
6754
6889
|
return `${surface.payload.isError ? "\u26A0\uFE0F" : "\uD83D\uDD27"} **${surface.payload.label}**${surface.payload.summary ? `
|
|
6755
6890
|
${surface.payload.summary}` : ""}`;
|
|
6756
|
-
case "context":
|
|
6891
|
+
case "context": {
|
|
6892
|
+
if (surface.kind === "context.session" || surface.kind === "context.branch") {
|
|
6893
|
+
const key2 = surface.payload.action === "branch" ? "agent.conversation.branch" : `agent.conversation.switch.${surface.payload.cause ?? "unknown"}`;
|
|
6894
|
+
return `${t(key2)}${surface.payload.reason ? ` (${surface.payload.reason})` : ""}`;
|
|
6895
|
+
}
|
|
6757
6896
|
return `\uD83E\uDDED ${surface.payload.action}${surface.payload.reason ? ` \xB7 ${surface.payload.reason}` : ""}`;
|
|
6897
|
+
}
|
|
6758
6898
|
case "artifact":
|
|
6759
6899
|
return `\uD83D\uDCCE ${surface.payload.name ?? surface.payload.path ?? surface.payload.url ?? "artifact"}${surface.payload.caption ? `
|
|
6760
6900
|
${surface.payload.caption}` : ""}${surface.payload.text ? `
|
|
@@ -7242,7 +7382,7 @@ ${screen}
|
|
|
7242
7382
|
if (this.#secretPrompts.get(surface.sessionId) === surface.payload.seq) {
|
|
7243
7383
|
this.#secretPrompts.delete(surface.sessionId);
|
|
7244
7384
|
}
|
|
7245
|
-
await this.#resolveFlow(surface.sessionId, surface.payload.seq);
|
|
7385
|
+
await this.#resolveFlow(surface.sessionId, surface.payload.seq, surface.source.event === "conversation_change");
|
|
7246
7386
|
} else {
|
|
7247
7387
|
await this.#openFlow(surface);
|
|
7248
7388
|
}
|
|
@@ -7401,15 +7541,19 @@ ${screen}
|
|
|
7401
7541
|
if (ts)
|
|
7402
7542
|
await this.api.updateMessage(this.config.channelId, ts, { text, blocks: [] });
|
|
7403
7543
|
}
|
|
7404
|
-
async#resolveFlow(sessionId, seq) {
|
|
7544
|
+
async#resolveFlow(sessionId, seq, retracted) {
|
|
7405
7545
|
const flow = this.#flows.get(sessionId);
|
|
7406
7546
|
if (flow !== undefined && flow.seq !== seq)
|
|
7407
7547
|
return;
|
|
7408
7548
|
this.#flows.delete(sessionId);
|
|
7409
|
-
if (flow?.messageTs)
|
|
7410
|
-
await this.api.updateMessage(this.config.channelId, flow.messageTs, {
|
|
7549
|
+
if (flow?.messageTs) {
|
|
7550
|
+
await this.api.updateMessage(this.config.channelId, flow.messageTs, {
|
|
7551
|
+
text: t(retracted ? "dc.ask.conversationChanged" : "dc.ask.resolvedElsewhere"),
|
|
7552
|
+
blocks: []
|
|
7553
|
+
}).catch(() => {
|
|
7411
7554
|
return;
|
|
7412
7555
|
});
|
|
7556
|
+
}
|
|
7413
7557
|
}
|
|
7414
7558
|
async#handleMessage(message) {
|
|
7415
7559
|
if (message.channel !== this.config.channelId || message.bot_id || message.subtype || !message.user || !this.#allowedUsers.has(message.user) || !message.thread_ts)
|
|
@@ -7430,6 +7574,16 @@ ${screen}
|
|
|
7430
7574
|
await this.#renderFlow(binding.sessionId);
|
|
7431
7575
|
return;
|
|
7432
7576
|
}
|
|
7577
|
+
const passthrough = parseAgentPassthrough(message.text ?? "");
|
|
7578
|
+
if (passthrough) {
|
|
7579
|
+
this.host.write(binding.sessionId, passthrough.keystrokes);
|
|
7580
|
+
this.#log(`session ${binding.sessionId} passthrough .${passthrough.name}`);
|
|
7581
|
+
await this.#sendToSession(binding.sessionId, t("sl.passthrough.sent", {
|
|
7582
|
+
command: passthrough.name,
|
|
7583
|
+
screen: this.host.screen(binding.sessionId, RAW_SCREEN_LINES)
|
|
7584
|
+
}));
|
|
7585
|
+
return;
|
|
7586
|
+
}
|
|
7433
7587
|
const staged = [];
|
|
7434
7588
|
if (this.config.inbound?.enabled) {
|
|
7435
7589
|
for (const file of message.files ?? []) {
|
|
@@ -9012,14 +9166,20 @@ function renderDiscordSurface(surface) {
|
|
|
9012
9166
|
const progress = surface.payload.current !== undefined && surface.payload.total !== undefined ? ` (${surface.payload.current}/${surface.payload.total})` : "";
|
|
9013
9167
|
const items = surface.payload.items?.map((item) => `${item.status === "done" ? "\u2611" : item.status === "active" ? "\u25B6" : "\u2022"} ${item.label}`).join(`
|
|
9014
9168
|
`);
|
|
9015
|
-
|
|
9169
|
+
const glyph = surface.payload.status === undefined ? "\uD83D\uDCCB" : progressGlyph(surface.payload.status);
|
|
9170
|
+
return `${glyph} **${surface.payload.title}**${progress}${items ? `
|
|
9016
9171
|
${items}` : ""}`;
|
|
9017
9172
|
}
|
|
9018
9173
|
case "activity":
|
|
9019
9174
|
return `${surface.payload.isError ? "\u26A0\uFE0F" : "\uD83D\uDD27"} **${surface.payload.label}**${surface.payload.summary ? `
|
|
9020
9175
|
${surface.payload.summary}` : ""}`;
|
|
9021
|
-
case "context":
|
|
9176
|
+
case "context": {
|
|
9177
|
+
if (surface.kind === "context.session" || surface.kind === "context.branch") {
|
|
9178
|
+
const key2 = surface.payload.action === "branch" ? "agent.conversation.branch" : `agent.conversation.switch.${surface.payload.cause ?? "unknown"}`;
|
|
9179
|
+
return `${t(key2)}${surface.payload.reason ? ` (${surface.payload.reason})` : ""}`;
|
|
9180
|
+
}
|
|
9022
9181
|
return `\uD83E\uDDED ${surface.payload.action}${surface.payload.reason ? ` \xB7 ${surface.payload.reason}` : ""}`;
|
|
9182
|
+
}
|
|
9023
9183
|
case "artifact":
|
|
9024
9184
|
return `\uD83D\uDCCE ${surface.payload.name ?? surface.payload.path ?? surface.payload.url ?? "artifact"}${surface.payload.caption ? `
|
|
9025
9185
|
${surface.payload.caption}` : ""}${surface.payload.text ? `
|
|
@@ -9243,9 +9403,9 @@ ${screen}
|
|
|
9243
9403
|
}
|
|
9244
9404
|
async onSurface(surface) {
|
|
9245
9405
|
if (surface.class === "decision") {
|
|
9246
|
-
if (surface.payload.state === "resolved")
|
|
9247
|
-
await this.resolveFlow(surface.sessionId, surface.payload.seq);
|
|
9248
|
-
else
|
|
9406
|
+
if (surface.payload.state === "resolved") {
|
|
9407
|
+
await this.resolveFlow(surface.sessionId, surface.payload.seq, surface.source.event === "conversation_change");
|
|
9408
|
+
} else
|
|
9249
9409
|
await this.openFlow(surface);
|
|
9250
9410
|
return;
|
|
9251
9411
|
}
|
|
@@ -9413,7 +9573,7 @@ ${screen}
|
|
|
9413
9573
|
});
|
|
9414
9574
|
}
|
|
9415
9575
|
}
|
|
9416
|
-
async resolveFlow(sessionId, seq) {
|
|
9576
|
+
async resolveFlow(sessionId, seq, retracted) {
|
|
9417
9577
|
const flow = this.flows.get(sessionId);
|
|
9418
9578
|
const matchingFlow = flow?.seq === seq ? flow : undefined;
|
|
9419
9579
|
if (matchingFlow !== undefined)
|
|
@@ -9423,7 +9583,7 @@ ${screen}
|
|
|
9423
9583
|
const binding = this.host.findBindingBySession("discord", sessionId);
|
|
9424
9584
|
if (matchingFlow?.messageId && binding) {
|
|
9425
9585
|
await this.api.editMessage(binding.containerId, matchingFlow.messageId, {
|
|
9426
|
-
content: t("dc.ask.resolvedElsewhere"),
|
|
9586
|
+
content: t(retracted ? "dc.ask.conversationChanged" : "dc.ask.resolvedElsewhere"),
|
|
9427
9587
|
components: []
|
|
9428
9588
|
}).catch(() => {
|
|
9429
9589
|
return;
|
|
@@ -9683,6 +9843,16 @@ ${screen}
|
|
|
9683
9843
|
await this.handleAttachments(binding.sessionId, attachments, text);
|
|
9684
9844
|
return;
|
|
9685
9845
|
}
|
|
9846
|
+
const passthrough = parseAgentPassthrough(message.content);
|
|
9847
|
+
if (passthrough) {
|
|
9848
|
+
this.host.write(binding.sessionId, passthrough.keystrokes);
|
|
9849
|
+
this.log(`session ${binding.sessionId} passthrough .${passthrough.name}`);
|
|
9850
|
+
await this.sendToSession(binding.sessionId, t("dc.passthrough.sent", {
|
|
9851
|
+
command: passthrough.name,
|
|
9852
|
+
screen: this.host.screen(binding.sessionId, RAW_SCREEN_LINES)
|
|
9853
|
+
}));
|
|
9854
|
+
return;
|
|
9855
|
+
}
|
|
9686
9856
|
if (text)
|
|
9687
9857
|
await this.host.prompt(binding.sessionId, text);
|
|
9688
9858
|
}
|
|
@@ -10915,6 +11085,10 @@ export default function axtermAgentStatus(pi: PiLike): void {\r
|
|
|
10915
11085
|
// how omp instantiates the module, which is why the PID guard above uses it\r
|
|
10916
11086
|
// too.\r
|
|
10917
11087
|
const LEAD_KEY = "AXTERM_LEAD_SESSION";\r
|
|
11088
|
+
// Counts \`session_start\`s, not ids. The gate must distinguish "this build\r
|
|
11089
|
+
// exposes no session ids" from "this event happens to have no id" \u2014 the\r
|
|
11090
|
+
// count is what tells those apart (see isLeadSession).\r
|
|
11091
|
+
const STARTS_KEY = "AXTERM_LEAD_STARTS";\r
|
|
10918
11092
|
\r
|
|
10919
11093
|
function sessionIdOf(ctx: unknown): string | undefined {\r
|
|
10920
11094
|
const manager = (ctx as { sessionManager?: { getSessionId?: () => string } } | undefined)?.sessionManager;\r
|
|
@@ -10953,24 +11127,39 @@ export default function axtermAgentStatus(pi: PiLike): void {\r
|
|
|
10953
11127
|
* cannot begin before its parent, so first is the lead \u2014 and recording it\r
|
|
10954
11128
|
* here rather than lazily on the first judgement matters: a subagent's\r
|
|
10955
11129
|
* completion would otherwise be the first caller and crown itself.\r
|
|
11130
|
+
*\r
|
|
11131
|
+
* Only the FIRST start may crown. "First id-bearing start wins" let a\r
|
|
11132
|
+
* subagent crown itself one step removed \u2014 the lead's start exposed no id,\r
|
|
11133
|
+
* the subagent's did, and its settled then passed the gate as the lead.\r
|
|
11134
|
+
* That is the operator's report (omp x telegram): the done message and the\r
|
|
11135
|
+
* topic rename arrived while the lead was still working.\r
|
|
10956
11136
|
*/\r
|
|
10957
11137
|
function rememberLead(ctx: unknown): void {\r
|
|
11138
|
+
const starts = Number(process.env[STARTS_KEY] ?? "0") + 1;\r
|
|
11139
|
+
process.env[STARTS_KEY] = String(starts);\r
|
|
10958
11140
|
const id = sessionIdOf(ctx);\r
|
|
10959
|
-
if (
|
|
10960
|
-
if (!process.env[LEAD_KEY]) process.env[LEAD_KEY] = id;\r
|
|
11141
|
+
if (starts === 1 && id !== undefined) process.env[LEAD_KEY] = id;\r
|
|
10961
11142
|
}\r
|
|
10962
11143
|
\r
|
|
10963
11144
|
/**\r
|
|
10964
|
-
*
|
|
10965
|
-
*
|
|
10966
|
-
*
|
|
10967
|
-
|
|
11145
|
+
* Whether this event may claim the SESSION's lifecycle (turn start/end,\r
|
|
11146
|
+
* prompt, reply). Two different unknowns meet here and must not be\r
|
|
11147
|
+
* conflated \u2014 conflating them was the reported bug:\r
|
|
11148
|
+
*\r
|
|
11149
|
+
* - Lead id known: exact match only. An event with no id is not "probably\r
|
|
11150
|
+
* the lead", it is unidentified \u2014 a false \`done\` sends the message and\r
|
|
11151
|
+
* renames the topic, and nothing repairs that; a LATE turn end is what\r
|
|
11152
|
+
* stall forwarding (\xA74.75) exists for.\r
|
|
11153
|
+
* - No lead id and ONE session started: this build exposes no ids and there\r
|
|
11154
|
+
* is nothing to confuse \u2014 fail open, or the session sits at \`working\`\r
|
|
11155
|
+
* forever; the shutdown path makes the same choice (\xA74.42).\r
|
|
11156
|
+
* - No lead id and SEVERAL sessions started: any of them could be the one\r
|
|
11157
|
+
* finishing, so nobody may claim the turn end.\r
|
|
10968
11158
|
*/\r
|
|
10969
11159
|
function isLeadSession(ctx: unknown): boolean {\r
|
|
10970
11160
|
const lead = process.env[LEAD_KEY];\r
|
|
10971
|
-
if (
|
|
10972
|
-
|
|
10973
|
-
return id === undefined || id === lead;\r
|
|
11161
|
+
if (lead) return sessionIdOf(ctx) === lead;\r
|
|
11162
|
+
return Number(process.env[STARTS_KEY] ?? "0") <= 1;\r
|
|
10974
11163
|
}\r
|
|
10975
11164
|
\r
|
|
10976
11165
|
/**\r
|
|
@@ -11069,12 +11258,8 @@ export default function axtermAgentStatus(pi: PiLike): void {\r
|
|
|
11069
11258
|
const activityQueue: Array<{ event: string; extra: Record<string, unknown> }> = [];\r
|
|
11070
11259
|
let activityDropped = 0;\r
|
|
11071
11260
|
\r
|
|
11072
|
-
function
|
|
11073
|
-
|
|
11074
|
-
extra["dropped"] = activityDropped;\r
|
|
11075
|
-
activityDropped = 0;\r
|
|
11076
|
-
}\r
|
|
11077
|
-
activityQueue.push({ event: "activity", extra });\r
|
|
11261
|
+
function enqueue(event: string, extra: Record<string, unknown>): void {\r
|
|
11262
|
+
activityQueue.push({ event, extra });\r
|
|
11078
11263
|
if (activityQueue.length > MAX_ACTIVITY_QUEUE) {\r
|
|
11079
11264
|
activityQueue.shift();\r
|
|
11080
11265
|
// Counted so the next item can admit the gap rather than hide it.\r
|
|
@@ -11082,18 +11267,42 @@ export default function axtermAgentStatus(pi: PiLike): void {\r
|
|
|
11082
11267
|
}\r
|
|
11083
11268
|
drain();\r
|
|
11084
11269
|
}\r
|
|
11270
|
+
\r
|
|
11271
|
+
function postActivity(extra: Record<string, unknown>): void {\r
|
|
11272
|
+
if (activityDropped > 0) {\r
|
|
11273
|
+
extra["dropped"] = activityDropped;\r
|
|
11274
|
+
activityDropped = 0;\r
|
|
11275
|
+
}\r
|
|
11276
|
+
enqueue("activity", extra);\r
|
|
11277
|
+
}\r
|
|
11085
11278
|
\r
|
|
11086
11279
|
function postSurface(surface: Record<string, unknown>, immediate = false): void {\r
|
|
11087
11280
|
if (immediate) {\r
|
|
11088
11281
|
post("surface", { surface });\r
|
|
11089
11282
|
return;\r
|
|
11090
11283
|
}\r
|
|
11091
|
-
|
|
11092
|
-
|
|
11093
|
-
|
|
11094
|
-
|
|
11095
|
-
|
|
11096
|
-
|
|
11284
|
+
enqueue("surface", { surface });\r
|
|
11285
|
+
}\r
|
|
11286
|
+
\r
|
|
11287
|
+
/**\r
|
|
11288
|
+
* A subagent's lifecycle, labelled instead of dropped. Suppressing it was\r
|
|
11289
|
+
* the first fix, and it traded one failure for another: a silent subagent\r
|
|
11290
|
+
* looks like a hang (\xA74.51). So the event still goes out, but carrying the\r
|
|
11291
|
+
* subagent's id under \`agent_id\` \u2014 the field claude already marks its\r
|
|
11292
|
+
* subagents with and the daemon's delivery point keys on \u2014 so downstream it\r
|
|
11293
|
+
* renders as delegation telemetry, never as the session's turn.\r
|
|
11294
|
+
*\r
|
|
11295
|
+
* Queued, not \`post()\`: the status slot is latest-only, so a subagent's end\r
|
|
11296
|
+
* racing the lead's real turn-end would overwrite one or the other \u2014 either\r
|
|
11297
|
+
* the delegation vanishes or the session never leaves \`working\`.\r
|
|
11298
|
+
*\r
|
|
11299
|
+
* No id means unidentified, not "subagent": an unlabelled \`agent_end\` IS\r
|
|
11300
|
+
* the reported bug, so nothing is posted rather than something wrong.\r
|
|
11301
|
+
*/\r
|
|
11302
|
+
function postDelegation(event: string, ctx: unknown, extra: Record<string, unknown> = {}): void {\r
|
|
11303
|
+
const id = sessionIdOf(ctx);\r
|
|
11304
|
+
if (id === undefined) return;\r
|
|
11305
|
+
enqueue(event, { ...extra, agent_id: id });\r
|
|
11097
11306
|
}\r
|
|
11098
11307
|
\r
|
|
11099
11308
|
async function postOnce(event: string, extra: Record<string, unknown>): Promise<void> {\r
|
|
@@ -11310,8 +11519,19 @@ export default function axtermAgentStatus(pi: PiLike): void {\r
|
|
|
11310
11519
|
\r
|
|
11311
11520
|
/* ------------------------------ handlers ------------------------------ */\r
|
|
11312
11521
|
pi.on("session_start", (_event, ctx) => {\r
|
|
11313
|
-
//
|
|
11522
|
+
// \`rememberLead\` first: first-wins, and a subagent cannot begin before its\r
|
|
11523
|
+
// parent, so the lead is decided here for every later judgement.\r
|
|
11314
11524
|
rememberLead(ctx);\r
|
|
11525
|
+
// Then the same rule as every other lead-only event (\xA74.114). This one was\r
|
|
11526
|
+
// missed, and it is the one that carries identity: every AgentSession\r
|
|
11527
|
+
// announced its own session_id and session_file, so a subagent's start\r
|
|
11528
|
+
// could become the session's conversation and \`axterm resume\` reopened it.\r
|
|
11529
|
+
// Labelled rather than dropped \u2014 the daemon strips a marked payload's\r
|
|
11530
|
+
// identity and still renders the subagent as delegation.\r
|
|
11531
|
+
if (!isLeadSession(ctx)) {\r
|
|
11532
|
+
postDelegation("session_start", ctx);\r
|
|
11533
|
+
return;\r
|
|
11534
|
+
}\r
|
|
11315
11535
|
post("session_start", sessionIdentityOf(ctx));\r
|
|
11316
11536
|
});\r
|
|
11317
11537
|
\r
|
|
@@ -11331,10 +11551,15 @@ export default function axtermAgentStatus(pi: PiLike): void {\r
|
|
|
11331
11551
|
});\r
|
|
11332
11552
|
\r
|
|
11333
11553
|
// Lead only: this sets the run's starting prompt, which the channel shows in\r
|
|
11334
|
-
// the topic title. A subagent's
|
|
11554
|
+
// the topic title. A subagent's prompt is labelled instead \u2014 downstream it\r
|
|
11555
|
+
// becomes the delegation surface's title, not the topic's.\r
|
|
11335
11556
|
pi.on("before_agent_start", (event, ctx) => {\r
|
|
11336
|
-
|
|
11337
|
-
|
|
11557
|
+
const prompt = (event as { prompt?: string } | undefined)?.prompt ?? "";\r
|
|
11558
|
+
if (!isLeadSession(ctx)) {\r
|
|
11559
|
+
postDelegation("before_agent_start", ctx, { prompt });\r
|
|
11560
|
+
return;\r
|
|
11561
|
+
}\r
|
|
11562
|
+
post("before_agent_start", { prompt });\r
|
|
11338
11563
|
});\r
|
|
11339
11564
|
\r
|
|
11340
11565
|
/* -------- completion: agent_settled preferred, isIdle fallback -------- */\r
|
|
@@ -11380,8 +11605,12 @@ export default function axtermAgentStatus(pi: PiLike): void {\r
|
|
|
11380
11605
|
\r
|
|
11381
11606
|
// Lead only: a subagent starting is not the session's turn restarting, and\r
|
|
11382
11607
|
// resetting \`endReported\` here on its behalf would arm a second completion.\r
|
|
11608
|
+
// But it IS news (\xA74.51) \u2014 labelled, it marks the delegation active.\r
|
|
11383
11609
|
pi.on("agent_start", (_event, ctx) => {\r
|
|
11384
|
-
if (!isLeadSession(ctx))
|
|
11610
|
+
if (!isLeadSession(ctx)) {\r
|
|
11611
|
+
postDelegation("agent_start", ctx);\r
|
|
11612
|
+
return;\r
|
|
11613
|
+
}\r
|
|
11385
11614
|
clearPendingCheck();\r
|
|
11386
11615
|
endReported = false;\r
|
|
11387
11616
|
post("agent_start");\r
|
|
@@ -11625,9 +11854,16 @@ export default function axtermAgentStatus(pi: PiLike): void {\r
|
|
|
11625
11854
|
\r
|
|
11626
11855
|
// Lead only, and this is the one the report was about: a finishing subagent\r
|
|
11627
11856
|
// announced the turn as done and renamed the topic while the lead worked on.\r
|
|
11857
|
+
// Labelled with its id, a subagent's end is delegation telemetry instead.\r
|
|
11628
11858
|
pi.on("agent_settled", (_event, ctx) => {\r
|
|
11629
|
-
|
|
11859
|
+
// A build that emits agent_settled emits it for every AgentSession, so\r
|
|
11860
|
+
// this is a build property: record it before the gate, or a subagent's\r
|
|
11861
|
+
// settled would leave the isIdle fallback armed for a second end.\r
|
|
11630
11862
|
settledSupported = true;\r
|
|
11863
|
+
if (!isLeadSession(ctx)) {\r
|
|
11864
|
+
postDelegation("agent_end", ctx);\r
|
|
11865
|
+
return;\r
|
|
11866
|
+
}\r
|
|
11631
11867
|
clearPendingCheck();\r
|
|
11632
11868
|
postEndOnce();\r
|
|
11633
11869
|
});\r
|
|
@@ -11635,8 +11871,14 @@ export default function axtermAgentStatus(pi: PiLike): void {\r
|
|
|
11635
11871
|
// The other route to a turn end, for builds without \`agent_settled\`. Gated the\r
|
|
11636
11872
|
// same way, or a subagent whose own work is idle ends the session's turn.\r
|
|
11637
11873
|
pi.on("agent_end", (_event, ctx) => {\r
|
|
11638
|
-
if (!isLeadSession(ctx)) return;\r
|
|
11639
11874
|
if (settledSupported) return;\r
|
|
11875
|
+
if (!isLeadSession(ctx)) {\r
|
|
11876
|
+
// No isIdle wait for a delegation: the single pending-check slot\r
|
|
11877
|
+
// belongs to the lead's real turn, and a slightly early "done" on a\r
|
|
11878
|
+
// delegation surface is cosmetic where a stolen slot is not.\r
|
|
11879
|
+
postDelegation("agent_end", ctx);\r
|
|
11880
|
+
return;\r
|
|
11881
|
+
}\r
|
|
11640
11882
|
const c = ctx as { isIdle?: () => boolean } | undefined;\r
|
|
11641
11883
|
if (!c || typeof c.isIdle !== "function") {\r
|
|
11642
11884
|
postEndOnce();\r
|
|
@@ -12308,10 +12550,12 @@ AXTERM_HOOK_TOKEN=${this.token}
|
|
|
12308
12550
|
return;
|
|
12309
12551
|
}
|
|
12310
12552
|
res.writeHead(200).end();
|
|
12311
|
-
|
|
12312
|
-
|
|
12313
|
-
|
|
12314
|
-
|
|
12553
|
+
for (const delivered of withConversationId([payload], { subagentId: payload.agent_id })) {
|
|
12554
|
+
try {
|
|
12555
|
+
session.onEvent(delivered);
|
|
12556
|
+
} catch (err) {
|
|
12557
|
+
log(`hook handler failed: ${String(err)}`);
|
|
12558
|
+
}
|
|
12315
12559
|
}
|
|
12316
12560
|
}
|
|
12317
12561
|
handleAsk(sessionId, askId, questions, _req, res) {
|
|
@@ -20532,6 +20776,60 @@ ${result.stderr}`);
|
|
|
20532
20776
|
}
|
|
20533
20777
|
});
|
|
20534
20778
|
}
|
|
20779
|
+
applyConversationChange(id, runtime, info, change) {
|
|
20780
|
+
const previousId = runtime.mainAgentSessionId;
|
|
20781
|
+
if (change.nextId !== undefined) {
|
|
20782
|
+
runtime.mainAgentSessionId = change.nextId;
|
|
20783
|
+
info.agentSessionId = change.nextId;
|
|
20784
|
+
this.store.setAgentSessionId(id, change.nextId);
|
|
20785
|
+
}
|
|
20786
|
+
if (runtime.dialogOpen) {
|
|
20787
|
+
this.publishSurface({
|
|
20788
|
+
v: 1,
|
|
20789
|
+
sessionId: id,
|
|
20790
|
+
agentId: change.agentId,
|
|
20791
|
+
class: "decision",
|
|
20792
|
+
kind: `decision.${runtime.decisionKind ?? "ask"}`,
|
|
20793
|
+
source: { transport: "extension", event: "conversation_change", authoritative: true },
|
|
20794
|
+
payload: { state: "resolved", choiceKind: runtime.decisionKind ?? "ask", seq: runtime.choiceSeq }
|
|
20795
|
+
});
|
|
20796
|
+
}
|
|
20797
|
+
runtime.choiceSeq += 1;
|
|
20798
|
+
runtime.dialogOpen = false;
|
|
20799
|
+
runtime.decisionKind = undefined;
|
|
20800
|
+
this.pendingPrompt.delete(id);
|
|
20801
|
+
runtime.entry = undefined;
|
|
20802
|
+
runtime.stallReported = undefined;
|
|
20803
|
+
runtime.telemetryReported = undefined;
|
|
20804
|
+
runtime.antigravitySubagentActive = undefined;
|
|
20805
|
+
clearTimeout(runtime.exitTimer);
|
|
20806
|
+
runtime.exitTimer = undefined;
|
|
20807
|
+
runtime.agentExited = false;
|
|
20808
|
+
const action = change.event === "session_branch" ? "branch" : "switch";
|
|
20809
|
+
log(`session ${info.shortId} conversation ${action}: ${previousId ?? "(none)"} -> ${change.nextId ?? "(unknown)"}`);
|
|
20810
|
+
if (previousId === undefined)
|
|
20811
|
+
return;
|
|
20812
|
+
const cause = CONVERSATION_CHANGE_CAUSES.includes(change.reason ?? "") ? change.reason : undefined;
|
|
20813
|
+
const detail2 = cause === undefined ? change.reason ?? change.nextId ?? change.nextFile : undefined;
|
|
20814
|
+
this.publishSurface({
|
|
20815
|
+
v: 1,
|
|
20816
|
+
sessionId: id,
|
|
20817
|
+
agentId: change.agentId,
|
|
20818
|
+
class: "context",
|
|
20819
|
+
kind: change.event === "session_branch" ? "context.branch" : "context.session",
|
|
20820
|
+
key: "session",
|
|
20821
|
+
source: {
|
|
20822
|
+
transport: change.agentId === "omp" ? "extension" : "hook",
|
|
20823
|
+
event: change.event,
|
|
20824
|
+
authoritative: true
|
|
20825
|
+
},
|
|
20826
|
+
payload: {
|
|
20827
|
+
action,
|
|
20828
|
+
...cause === undefined ? {} : { cause },
|
|
20829
|
+
...detail2 === undefined ? {} : { reason: detail2 }
|
|
20830
|
+
}
|
|
20831
|
+
});
|
|
20832
|
+
}
|
|
20535
20833
|
resolvePendingScreenDecision(id) {
|
|
20536
20834
|
const session = this.live.get(id);
|
|
20537
20835
|
const runtime = this.agentRuntime.get(id);
|
|
@@ -21425,37 +21723,20 @@ ${result.stderr}`);
|
|
|
21425
21723
|
}
|
|
21426
21724
|
const reportedId = fromAntigravitySubagent ? undefined : result.meta?.agentSessionId;
|
|
21427
21725
|
const previousId = runtime.mainAgentSessionId;
|
|
21428
|
-
const replacesId = reportedId !== undefined && mayReplaceConversationIdentity(agentId, previousId, reportedId, payload.event);
|
|
21726
|
+
const replacesId = reportedId !== undefined && mayReplaceConversationIdentity(agentId, previousId, reportedId, payload.event, fromAntigravitySubagent);
|
|
21429
21727
|
const explicitOmpChange = agentId === "omp" && (payload.event === "session_switch" || payload.event === "session_branch");
|
|
21430
|
-
const acceptsFile = previousId === undefined || reportedId === previousId || replacesId || explicitOmpChange;
|
|
21728
|
+
const acceptsFile = !fromAntigravitySubagent && (previousId === undefined || reportedId === previousId || replacesId || explicitOmpChange);
|
|
21431
21729
|
if (result.meta?.agentSessionFile !== undefined && acceptsFile) {
|
|
21432
21730
|
info.agentSessionFile = result.meta.agentSessionFile;
|
|
21433
21731
|
this.store.setAgentSessionFile(id, result.meta.agentSessionFile);
|
|
21434
21732
|
}
|
|
21435
|
-
if (reportedId !== undefined && replacesId) {
|
|
21436
|
-
|
|
21437
|
-
info.agentSessionId = reportedId;
|
|
21438
|
-
this.store.setAgentSessionId(id, reportedId);
|
|
21439
|
-
}
|
|
21440
|
-
if (previousId !== undefined && (reportedId !== undefined && replacesId || explicitOmpChange)) {
|
|
21441
|
-
const action = payload.event === "session_branch" ? "branch" : "switch";
|
|
21442
|
-
log(`session ${info.shortId} conversation ${action}: ${previousId} -> ${reportedId ?? "(unknown)"}`);
|
|
21443
|
-
this.publishSurface({
|
|
21444
|
-
v: 1,
|
|
21445
|
-
sessionId: id,
|
|
21733
|
+
if (reportedId !== undefined && replacesId || explicitOmpChange) {
|
|
21734
|
+
this.applyConversationChange(id, runtime, info, {
|
|
21446
21735
|
agentId,
|
|
21447
|
-
|
|
21448
|
-
|
|
21449
|
-
|
|
21450
|
-
|
|
21451
|
-
transport: agentId === "omp" ? "extension" : "hook",
|
|
21452
|
-
event: payload.event,
|
|
21453
|
-
authoritative: true
|
|
21454
|
-
},
|
|
21455
|
-
payload: {
|
|
21456
|
-
action,
|
|
21457
|
-
reason: payload.switch_reason ?? reportedId ?? result.meta?.agentSessionFile
|
|
21458
|
-
}
|
|
21736
|
+
event: payload.event,
|
|
21737
|
+
...reportedId !== undefined && replacesId ? { nextId: reportedId } : {},
|
|
21738
|
+
...payload.switch_reason === undefined ? {} : { reason: payload.switch_reason },
|
|
21739
|
+
...result.meta?.agentSessionFile === undefined ? {} : { nextFile: result.meta.agentSessionFile }
|
|
21459
21740
|
});
|
|
21460
21741
|
}
|
|
21461
21742
|
if (agentId === "codex" && runtime.mainAgentSessionId !== undefined && payload.event !== "activity") {
|
|
@@ -21553,7 +21834,8 @@ ${result.stderr}`);
|
|
|
21553
21834
|
if (this.live.has(stored.id))
|
|
21554
21835
|
throw new AxtermError("err.session.running", { id: stored.shortId });
|
|
21555
21836
|
const profile = agentProfile(agentIdFromCommand(stored.agentCommand));
|
|
21556
|
-
const
|
|
21837
|
+
const resumeSource = repairPersistedResumeSource(profile, { ...stored, ownSessionId: stored.id });
|
|
21838
|
+
const reference = resumeReference(profile, resumeSource);
|
|
21557
21839
|
if (reference === undefined) {
|
|
21558
21840
|
throw new AxtermError("err.session.noConversation", {
|
|
21559
21841
|
id: stored.shortId,
|
|
@@ -21566,7 +21848,20 @@ ${result.stderr}`);
|
|
|
21566
21848
|
}
|
|
21567
21849
|
if (!fs26.existsSync(stored.cwd))
|
|
21568
21850
|
throw new AxtermError("err.session.cwdGone", { cwd: stored.cwd });
|
|
21569
|
-
|
|
21851
|
+
if (resumeSource.agentSessionFile !== undefined && resumeSource.agentSessionFile !== stored.agentSessionFile) {
|
|
21852
|
+
this.store.setAgentSessionFile(stored.id, resumeSource.agentSessionFile);
|
|
21853
|
+
log(`session ${stored.shortId} repaired OMP resume transcript to its parent conversation`);
|
|
21854
|
+
}
|
|
21855
|
+
if (resumeSource.agentSessionId !== undefined && resumeSource.agentSessionId !== stored.agentSessionId) {
|
|
21856
|
+
this.store.setAgentSessionId(stored.id, resumeSource.agentSessionId);
|
|
21857
|
+
}
|
|
21858
|
+
const info = {
|
|
21859
|
+
...stored,
|
|
21860
|
+
...resumeSource.agentSessionFile === undefined ? {} : { agentSessionFile: resumeSource.agentSessionFile },
|
|
21861
|
+
...resumeSource.agentSessionId === undefined ? {} : { agentSessionId: resumeSource.agentSessionId },
|
|
21862
|
+
agentCommand,
|
|
21863
|
+
state: "running"
|
|
21864
|
+
};
|
|
21570
21865
|
delete info.exitCode;
|
|
21571
21866
|
delete info.exitedAt;
|
|
21572
21867
|
delete info.agentState;
|
|
@@ -22740,7 +23035,7 @@ class TelegramChannel {
|
|
|
22740
23035
|
case "immediate":
|
|
22741
23036
|
if (surface.class === "decision") {
|
|
22742
23037
|
if (surface.payload.state === "resolved") {
|
|
22743
|
-
await this.onChoiceResolved(surface.sessionId, surface.payload.seq);
|
|
23038
|
+
await this.onChoiceResolved(surface.sessionId, surface.payload.seq, surface.source.event === "conversation_change");
|
|
22744
23039
|
} else if (surface.payload.choiceKind === "shellPrompt") {
|
|
22745
23040
|
await this.onShellPrompt(surface.sessionId, surface.payload.seq, surface.payload.shellPrompt);
|
|
22746
23041
|
} else {
|
|
@@ -22748,6 +23043,8 @@ class TelegramChannel {
|
|
|
22748
23043
|
}
|
|
22749
23044
|
} else if (surface.class === "notice") {
|
|
22750
23045
|
await this.onNotice(surface);
|
|
23046
|
+
} else if (surface.class === "context") {
|
|
23047
|
+
await this.onConversationChange(surface);
|
|
22751
23048
|
}
|
|
22752
23049
|
return;
|
|
22753
23050
|
case "snapshot":
|
|
@@ -22777,6 +23074,11 @@ class TelegramChannel {
|
|
|
22777
23074
|
const retryMs = surface.payload.retryAt === undefined ? surface.payload.durationMs : Math.max(0, surface.payload.retryAt - Date.now());
|
|
22778
23075
|
await this.onAgentError(surface.sessionId, kind, surface.payload.detail, retryMs, surface.id);
|
|
22779
23076
|
}
|
|
23077
|
+
async onConversationChange(surface) {
|
|
23078
|
+
const key2 = surface.payload.action === "branch" ? "agent.conversation.branch" : `agent.conversation.switch.${surface.payload.cause ?? "unknown"}`;
|
|
23079
|
+
const detail2 = surface.payload.reason;
|
|
23080
|
+
await this.sendToSession(surface.sessionId, tHtml(key2) + (detail2 === undefined ? "" : ` (${code(detail2)})`));
|
|
23081
|
+
}
|
|
22780
23082
|
bufferDigest(surface) {
|
|
22781
23083
|
const settings = this.deliverySettings;
|
|
22782
23084
|
let digest = this.digests.get(surface.sessionId);
|
|
@@ -22842,7 +23144,8 @@ class TelegramChannel {
|
|
|
22842
23144
|
return;
|
|
22843
23145
|
const lines = [...snapshot2.items.values()].map((surface) => {
|
|
22844
23146
|
const text = surface.class === "progress" ? surface.payload.title : surface.class === "state" ? `${surface.payload.name}: ${String(surface.payload.value)}` : surface.class === "context" ? `${surface.payload.action}${surface.payload.reason ? `: ${surface.payload.reason}` : ""}` : surface.kind;
|
|
22845
|
-
|
|
23147
|
+
const glyph = progressGlyph(surface.class === "progress" ? surface.payload.status : undefined);
|
|
23148
|
+
return `${glyph} ${clipText(text, settings.maxChars)}`;
|
|
22846
23149
|
});
|
|
22847
23150
|
this.snapshots.delete(sessionId);
|
|
22848
23151
|
const body = clipText(lines.join(`
|
|
@@ -23028,7 +23331,7 @@ ${t("tg.status.inferred")}` : "");
|
|
|
23028
23331
|
${code(prompt.line)}`);
|
|
23029
23332
|
return;
|
|
23030
23333
|
}
|
|
23031
|
-
await this.api.call("sendMessage", {
|
|
23334
|
+
const sent = await this.api.call("sendMessage", {
|
|
23032
23335
|
chat_id: binding.chatId,
|
|
23033
23336
|
message_thread_id: binding.topicId,
|
|
23034
23337
|
parse_mode: "HTML",
|
|
@@ -23043,7 +23346,9 @@ ${code(prompt.line)}`,
|
|
|
23043
23346
|
]
|
|
23044
23347
|
}
|
|
23045
23348
|
});
|
|
23349
|
+
this.promptKeyboards.set(sessionId, { seq, messageId: sent.message_id });
|
|
23046
23350
|
}
|
|
23351
|
+
promptKeyboards = new Map;
|
|
23047
23352
|
awaitingSecret = new Map;
|
|
23048
23353
|
async captureSecret(sessionId, msg, text) {
|
|
23049
23354
|
const seq = this.awaitingSecret.get(sessionId);
|
|
@@ -23108,12 +23413,13 @@ ${code(prompt.line)}`,
|
|
|
23108
23413
|
}
|
|
23109
23414
|
if (extras.length > 0)
|
|
23110
23415
|
rows2.push(extras);
|
|
23111
|
-
await this.api.call("sendMessage", {
|
|
23416
|
+
const sent = await this.api.call("sendMessage", {
|
|
23112
23417
|
chat_id: binding.chatId,
|
|
23113
23418
|
message_thread_id: binding.topicId,
|
|
23114
23419
|
text: t("tg.ask.question", { question: question.question, progress }) + (question.multi ? t("tg.ask.multiHint") : ""),
|
|
23115
23420
|
reply_markup: { inline_keyboard: rows2 }
|
|
23116
23421
|
});
|
|
23422
|
+
flow.messageId = sent.message_id;
|
|
23117
23423
|
}
|
|
23118
23424
|
async finishFlow(sessionId, flow, binding) {
|
|
23119
23425
|
const summary = flow.questions.map((q, i) => {
|
|
@@ -23133,7 +23439,7 @@ ${code(prompt.line)}`,
|
|
|
23133
23439
|
return;
|
|
23134
23440
|
}
|
|
23135
23441
|
if (flow.questions.length > 1) {
|
|
23136
|
-
await this.api.call("sendMessage", {
|
|
23442
|
+
const sent = await this.api.call("sendMessage", {
|
|
23137
23443
|
chat_id: binding.chatId,
|
|
23138
23444
|
message_thread_id: binding.topicId,
|
|
23139
23445
|
text: t("tg.ask.review", { summary }),
|
|
@@ -23141,11 +23447,29 @@ ${code(prompt.line)}`,
|
|
|
23141
23447
|
inline_keyboard: [[{ text: t("tg.ask.submit"), callback_data: encodeSubmitCallback(flow.shortId, flow.seq) }]]
|
|
23142
23448
|
}
|
|
23143
23449
|
});
|
|
23450
|
+
flow.messageId = sent.message_id;
|
|
23144
23451
|
}
|
|
23145
23452
|
}
|
|
23146
|
-
async onChoiceResolved(sessionId, seq) {
|
|
23147
|
-
|
|
23453
|
+
async onChoiceResolved(sessionId, seq, retracted) {
|
|
23454
|
+
const messageIds = [];
|
|
23455
|
+
const flow = this.flows.get(sessionId);
|
|
23456
|
+
if (flow?.seq === seq) {
|
|
23148
23457
|
this.flows.delete(sessionId);
|
|
23458
|
+
if (flow.messageId !== undefined)
|
|
23459
|
+
messageIds.push(flow.messageId);
|
|
23460
|
+
}
|
|
23461
|
+
const prompt = this.promptKeyboards.get(sessionId);
|
|
23462
|
+
if (prompt?.seq === seq) {
|
|
23463
|
+
this.promptKeyboards.delete(sessionId);
|
|
23464
|
+
messageIds.push(prompt.messageId);
|
|
23465
|
+
}
|
|
23466
|
+
const binding = this.control.findBindingBySession(sessionId);
|
|
23467
|
+
if (!binding)
|
|
23468
|
+
return;
|
|
23469
|
+
for (const messageId of messageIds) {
|
|
23470
|
+
const edit = retracted ? this.api.call("editMessageText", { chat_id: binding.chatId, message_id: messageId, text: t("dc.ask.conversationChanged") }) : this.api.call("editMessageReplyMarkup", { chat_id: binding.chatId, message_id: messageId, reply_markup: { inline_keyboard: [] } });
|
|
23471
|
+
await edit.catch(() => {});
|
|
23472
|
+
}
|
|
23149
23473
|
}
|
|
23150
23474
|
async onAgentError(sessionId, kind, error, retryMs, surfaceId) {
|
|
23151
23475
|
const reason = clipText(error, AGENT_ERROR_CHARS);
|
|
@@ -23299,6 +23623,16 @@ ${code(prompt.line)}`,
|
|
|
23299
23623
|
return;
|
|
23300
23624
|
if (await this.captureFreeText(binding.sessionId, text))
|
|
23301
23625
|
return;
|
|
23626
|
+
const passthrough = parseAgentPassthrough(msg.text ?? "");
|
|
23627
|
+
if (passthrough) {
|
|
23628
|
+
this.control.write(binding.sessionId, passthrough.keystrokes);
|
|
23629
|
+
this.log(`session ${binding.sessionId} passthrough .${passthrough.name}`);
|
|
23630
|
+
await this.sendToSession(binding.sessionId, tHtml("tg.passthrough.sent", {
|
|
23631
|
+
command: passthrough.name,
|
|
23632
|
+
screen: this.control.screen(binding.sessionId, RAW_SCREEN_LINES)
|
|
23633
|
+
}));
|
|
23634
|
+
return;
|
|
23635
|
+
}
|
|
23302
23636
|
const chatId = msg.chat.id;
|
|
23303
23637
|
await this.react(chatId, msg.message_id, "received");
|
|
23304
23638
|
try {
|
|
@@ -25622,19 +25956,19 @@ function readLine(secret) {
|
|
|
25622
25956
|
stdin.on("data", onData);
|
|
25623
25957
|
});
|
|
25624
25958
|
}
|
|
25625
|
-
function renderPrompt(state) {
|
|
25626
|
-
|
|
25959
|
+
function renderPrompt(state, write) {
|
|
25960
|
+
write(`
|
|
25627
25961
|
${bold(t(state.promptKey))}
|
|
25628
25962
|
`);
|
|
25629
25963
|
if (state.choices) {
|
|
25630
25964
|
for (const [index, choice2] of state.choices.entries()) {
|
|
25631
25965
|
const marker = choice2 === state.default ? green("\u25CF") : "\u25CB";
|
|
25632
|
-
|
|
25966
|
+
write(` ${marker} ${index + 1}) ${choice2}
|
|
25633
25967
|
`);
|
|
25634
25968
|
}
|
|
25635
25969
|
}
|
|
25636
25970
|
const hint = state.default.length > 0 ? dim(` [${state.default}]`) : "";
|
|
25637
|
-
|
|
25971
|
+
write(`${dim("\u203A")}${hint} `);
|
|
25638
25972
|
}
|
|
25639
25973
|
function interpret(state, input) {
|
|
25640
25974
|
if (!state.choices)
|
|
@@ -25645,44 +25979,85 @@ function interpret(state, input) {
|
|
|
25645
25979
|
}
|
|
25646
25980
|
return input;
|
|
25647
25981
|
}
|
|
25648
|
-
function renderReview(state) {
|
|
25649
|
-
|
|
25982
|
+
function renderReview(state, write) {
|
|
25983
|
+
write(`
|
|
25650
25984
|
${bold(t("wizard.review.header"))}
|
|
25651
25985
|
`);
|
|
25652
25986
|
for (const [key, value] of Object.entries(state.answers)) {
|
|
25653
25987
|
const shown = key === "telegramToken" ? `${value.slice(0, 4)}\u2026` : value;
|
|
25654
|
-
|
|
25988
|
+
write(` ${key.padEnd(16)} ${shown}
|
|
25655
25989
|
`);
|
|
25656
25990
|
}
|
|
25657
25991
|
}
|
|
25658
|
-
|
|
25659
|
-
|
|
25992
|
+
function telegramDiscoveryLines(found) {
|
|
25993
|
+
const lines = [];
|
|
25994
|
+
if (found.chats.length > 0) {
|
|
25995
|
+
lines.push(t("cli.telegram.discoverChats"));
|
|
25996
|
+
for (const chat of found.chats) {
|
|
25997
|
+
const marks = [chat.type, chat.isForum ? undefined : t("cli.telegram.topicsOff")].filter((mark) => mark !== undefined).join(" \u2014 ");
|
|
25998
|
+
lines.push(` ${String(chat.id).padEnd(16)} ${(chat.title ?? "").padEnd(24)} ${marks}`);
|
|
25999
|
+
}
|
|
26000
|
+
} else {
|
|
26001
|
+
lines.push(t("cli.telegram.discoverNone"), t("cli.telegram.discoverHint"));
|
|
26002
|
+
}
|
|
26003
|
+
if (found.users.length > 0) {
|
|
26004
|
+
lines.push(t("cli.telegram.discoverUsers"));
|
|
26005
|
+
for (const user of found.users) {
|
|
26006
|
+
const label = [user.username !== undefined ? `@${user.username}` : undefined, user.name].filter((part) => part !== undefined).join(" ");
|
|
26007
|
+
lines.push(` ${String(user.id).padEnd(16)} ${label}`);
|
|
26008
|
+
}
|
|
26009
|
+
}
|
|
26010
|
+
return lines;
|
|
26011
|
+
}
|
|
26012
|
+
async function runSetup(client, current = DEFAULT_CONFIG, injectedIO) {
|
|
26013
|
+
const io = injectedIO ?? {
|
|
26014
|
+
hostname: os2.hostname().split(".")[0] ?? "",
|
|
26015
|
+
readLine,
|
|
26016
|
+
write: (text) => stdout.write(text)
|
|
26017
|
+
};
|
|
26018
|
+
io.write(`${bold("axterm setup")}
|
|
25660
26019
|
${dim(t("wizard.intro"))}
|
|
25661
26020
|
`);
|
|
25662
|
-
let state = startWizard(current,
|
|
26021
|
+
let state = startWizard(current, io.hostname);
|
|
25663
26022
|
for (;; ) {
|
|
25664
26023
|
if (state.kind === "review") {
|
|
25665
|
-
renderReview(state);
|
|
25666
|
-
|
|
26024
|
+
renderReview(state, io.write);
|
|
26025
|
+
io.write(`
|
|
25667
26026
|
${bold(t(state.promptKey))} ${dim("[yes]")} `);
|
|
25668
|
-
const confirm = (await readLine(false)).trim().toLowerCase();
|
|
26027
|
+
const confirm = (await io.readLine(false)).trim().toLowerCase();
|
|
25669
26028
|
if (confirm.length > 0 && !["y", "yes"].includes(confirm)) {
|
|
25670
|
-
|
|
26029
|
+
io.write(`${dim(t("wizard.cancelled"))}
|
|
25671
26030
|
`);
|
|
25672
26031
|
return { saved: false };
|
|
25673
26032
|
}
|
|
25674
26033
|
break;
|
|
25675
26034
|
}
|
|
25676
|
-
renderPrompt(state);
|
|
25677
|
-
const answer = interpret(state, await readLine(state.secret));
|
|
26035
|
+
renderPrompt(state, io.write);
|
|
26036
|
+
const answer = interpret(state, await io.readLine(state.secret));
|
|
25678
26037
|
const result = advance(state, answer);
|
|
25679
26038
|
if ("error" in result) {
|
|
25680
|
-
|
|
26039
|
+
io.write(` ${red("\u2717")} ${t(result.error)}
|
|
25681
26040
|
`);
|
|
25682
26041
|
continue;
|
|
25683
26042
|
}
|
|
25684
26043
|
if ("done" in result)
|
|
25685
26044
|
break;
|
|
26045
|
+
if (state.step === "telegramToken" && result.state.step === "telegramGroup") {
|
|
26046
|
+
io.write(`${dim(t("wizard.telegramDiscovering"))}
|
|
26047
|
+
`);
|
|
26048
|
+
try {
|
|
26049
|
+
const found = await client.call("telegram.discover", {
|
|
26050
|
+
botToken: result.state.answers["telegramToken"]
|
|
26051
|
+
});
|
|
26052
|
+
for (const line of telegramDiscoveryLines(found))
|
|
26053
|
+
io.write(`${line}
|
|
26054
|
+
`);
|
|
26055
|
+
} catch (error) {
|
|
26056
|
+
const detail2 = error instanceof Error ? error.message : String(error);
|
|
26057
|
+
io.write(`${red("\u2717")} ${t("wizard.telegramDiscoverFailed", { error: detail2 })}
|
|
26058
|
+
`);
|
|
26059
|
+
}
|
|
26060
|
+
}
|
|
25686
26061
|
state = result.state;
|
|
25687
26062
|
if (state.answers["locale"] !== undefined)
|
|
25688
26063
|
setLocale(state.answers["locale"]);
|
|
@@ -25696,19 +26071,19 @@ ${bold(t(state.promptKey))} ${dim("[yes]")} `);
|
|
|
25696
26071
|
for (const [path4, value] of finished.done.secrets) {
|
|
25697
26072
|
await client.call("config.set", { path: path4, value });
|
|
25698
26073
|
}
|
|
25699
|
-
|
|
26074
|
+
io.write(`
|
|
25700
26075
|
${green("\u2713")} ${t("wizard.saved")}
|
|
25701
26076
|
`);
|
|
25702
26077
|
if (finished.done.settings.some(([k, v]) => k === "channels.telegram.enabled" && v === "true")) {
|
|
25703
|
-
|
|
26078
|
+
io.write(`${dim(t("wizard.checking"))}
|
|
25704
26079
|
`);
|
|
25705
26080
|
const report = await client.call("telegram.doctor");
|
|
25706
26081
|
if (report.ok)
|
|
25707
|
-
|
|
26082
|
+
io.write(`${green("\u2713")} ${t("wizard.telegramOk")}
|
|
25708
26083
|
`);
|
|
25709
26084
|
else
|
|
25710
26085
|
for (const problem of report.problems)
|
|
25711
|
-
|
|
26086
|
+
io.write(`${red("\u2717")} ${problem}
|
|
25712
26087
|
`);
|
|
25713
26088
|
}
|
|
25714
26089
|
return { saved: true };
|
|
@@ -26452,7 +26827,7 @@ import { stdin as stdin2, stdout as stdout2 } from "process";
|
|
|
26452
26827
|
// packages/cli/package.json
|
|
26453
26828
|
var package_default = {
|
|
26454
26829
|
name: "@layorixinc/axterm",
|
|
26455
|
-
version: "0.
|
|
26830
|
+
version: "0.8.0",
|
|
26456
26831
|
type: "module",
|
|
26457
26832
|
bin: {
|
|
26458
26833
|
axterm: "dist/cli.js"
|
|
@@ -28978,23 +29353,8 @@ async function main2() {
|
|
|
28978
29353
|
const found = await client.call("telegram.discover", {
|
|
28979
29354
|
...token !== undefined ? { botToken: token } : {}
|
|
28980
29355
|
});
|
|
28981
|
-
|
|
28982
|
-
console.log(
|
|
28983
|
-
for (const chat of found.chats) {
|
|
28984
|
-
const marks = [chat.type, chat.isForum ? undefined : t("cli.telegram.topicsOff")].filter((m) => m !== undefined).join(" \u2014 ");
|
|
28985
|
-
console.log(` ${String(chat.id).padEnd(16)} ${(chat.title ?? "").padEnd(24)} ${marks}`);
|
|
28986
|
-
}
|
|
28987
|
-
} else {
|
|
28988
|
-
console.log(t("cli.telegram.discoverNone"));
|
|
28989
|
-
console.log(t("cli.telegram.discoverHint"));
|
|
28990
|
-
}
|
|
28991
|
-
if (found.users.length > 0) {
|
|
28992
|
-
console.log(t("cli.telegram.discoverUsers"));
|
|
28993
|
-
for (const user of found.users) {
|
|
28994
|
-
const label = [user.username !== undefined ? `@${user.username}` : undefined, user.name].filter((part) => part !== undefined).join(" ");
|
|
28995
|
-
console.log(` ${String(user.id).padEnd(16)} ${label}`);
|
|
28996
|
-
}
|
|
28997
|
-
}
|
|
29356
|
+
for (const line of telegramDiscoveryLines(found))
|
|
29357
|
+
console.log(line);
|
|
28998
29358
|
} else {
|
|
28999
29359
|
throw new Error(t("cli.usage.telegram"));
|
|
29000
29360
|
}
|