@cursor/july 0.1.2 → 0.1.4
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/AGENTS.md +16 -5
- package/README.md +8 -9
- package/dist/bin/agent-serve.d.ts +3 -1
- package/dist/bin/agent-serve.d.ts.map +1 -1
- package/dist/bin/agent-serve.js +416 -155
- package/dist/channels/slack/log.d.ts +1 -1
- package/dist/channels/slack/log.d.ts.map +1 -1
- package/dist/channels/slack/log.js +4 -5
- package/dist/channels/slack/setup.js +1 -1
- package/dist/channels/slack/socket-mode.d.ts.map +1 -1
- package/dist/channels/slack/socket-mode.js +10 -9
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +3 -3
- package/dist/docs/assets/{app.Oje4vhlk.js → app.DF-Yx4OP.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.0XrheBv2.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.H5XZ2zCB.js → VPLocalSearchBox.DSeJSudL.js} +1 -1
- package/dist/docs/assets/chunks/{theme.CTR_TuaE.js → theme.DZVLTXOC.js} +2 -2
- package/dist/docs/assets/{index.md.m81y7TY7.js → index.md.Cylk70gg.js} +1 -1
- package/dist/docs/assets/{quickstart.md.CfU8_uTC.js → quickstart.md.BU6Iwi_9.js} +18 -6
- package/dist/docs/assets/{reference_cli.md.DA730zCu.js → reference_cli.md.Bv6pOxcF.js} +11 -6
- package/dist/docs/assets/{reference_cli.md.DA730zCu.lean.js → reference_cli.md.Bv6pOxcF.lean.js} +1 -1
- package/dist/docs/building-with-agents.html +3 -3
- package/dist/docs/concepts.html +3 -3
- package/dist/docs/deployment.html +3 -3
- package/dist/docs/evals.html +3 -3
- package/dist/docs/guides/agent-to-agent.html +3 -3
- package/dist/docs/guides/cloud-runtime.html +3 -3
- package/dist/docs/guides/github.html +3 -3
- package/dist/docs/guides/human-in-the-loop.html +3 -3
- package/dist/docs/guides/slack.html +3 -3
- package/dist/docs/guides/webhooks.html +3 -3
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +3 -3
- package/dist/docs/index.html +5 -5
- package/dist/docs/quickstart.html +22 -10
- package/dist/docs/reference/agent-config.html +3 -3
- package/dist/docs/reference/channels.html +3 -3
- package/dist/docs/reference/cli.html +14 -9
- package/dist/docs/reference/connections.html +3 -3
- package/dist/docs/reference/hooks.html +3 -3
- package/dist/docs/reference/http-api.html +3 -3
- package/dist/docs/reference/instructions.html +3 -3
- package/dist/docs/reference/playground.html +3 -3
- package/dist/docs/reference/project-layout.html +3 -3
- package/dist/docs/reference/schedules.html +3 -3
- package/dist/docs/reference/sessions.html +3 -3
- package/dist/docs/reference/skills.html +3 -3
- package/dist/docs/reference/subagents.html +3 -3
- package/dist/docs/reference/tools.html +3 -3
- package/dist/docs/scaffolding-agents.html +3 -3
- package/dist/docs/storage.html +3 -3
- package/dist/docs/troubleshooting.html +3 -3
- package/dist/internal/ab-collector.js +3 -3
- package/dist/internal/ab-fold.js +1 -1
- package/dist/internal/chat-client.d.ts +29 -3
- package/dist/internal/chat-client.d.ts.map +1 -1
- package/dist/internal/chat-client.js +180 -27
- package/dist/internal/cli-ax.d.ts +83 -2
- package/dist/internal/cli-ax.d.ts.map +1 -1
- package/dist/internal/cli-ax.js +626 -52
- package/dist/internal/cli-cursor.d.ts.map +1 -1
- package/dist/internal/cli-cursor.js +8 -36
- package/dist/internal/cli-deploy.d.ts +59 -3
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +316 -38
- package/dist/internal/cli-github.js +13 -13
- package/dist/internal/cursor/account-mcp.js +3 -3
- package/dist/internal/cursor/backend-client.js +1 -1
- package/dist/internal/cursor/credentials.d.ts +14 -3
- package/dist/internal/cursor/credentials.d.ts.map +1 -1
- package/dist/internal/cursor/credentials.js +21 -6
- package/dist/internal/cursor/github-credentials.js +3 -3
- package/dist/internal/cursor-event-relay.js +1 -1
- package/dist/internal/cursor-relay-core.d.ts +1 -1
- package/dist/internal/cursor-relay-core.d.ts.map +1 -1
- package/dist/internal/cursor-relay-core.js +2 -1
- package/dist/internal/cursor-slack-relay.js +1 -1
- package/dist/internal/deploy-client.d.ts +9 -1
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +23 -3
- package/dist/internal/deploy-source.d.ts +35 -0
- package/dist/internal/deploy-source.d.ts.map +1 -0
- package/dist/internal/deploy-source.js +118 -0
- package/dist/internal/discovery.d.ts +11 -0
- package/dist/internal/discovery.d.ts.map +1 -1
- package/dist/internal/discovery.js +43 -14
- package/dist/internal/distribution.d.ts +7 -0
- package/dist/internal/distribution.d.ts.map +1 -1
- package/dist/internal/distribution.js +7 -0
- package/dist/internal/docs-site.js +3 -3
- package/dist/internal/eval-run-store.d.ts.map +1 -1
- package/dist/internal/eval-run-store.js +10 -9
- package/dist/internal/eval-runner.d.ts +2 -0
- package/dist/internal/eval-runner.d.ts.map +1 -1
- package/dist/internal/eval-runner.js +2 -0
- package/dist/internal/event-mapper.d.ts +54 -1
- package/dist/internal/event-mapper.d.ts.map +1 -1
- package/dist/internal/event-mapper.js +151 -41
- package/dist/internal/github-fanout.js +2 -2
- package/dist/internal/host-platforms.js +5 -5
- package/dist/internal/init-project.d.ts +88 -1
- package/dist/internal/init-project.d.ts.map +1 -1
- package/dist/internal/init-project.js +221 -31
- package/dist/internal/install-cursor-skills.d.ts +64 -0
- package/dist/internal/install-cursor-skills.d.ts.map +1 -0
- package/dist/internal/install-cursor-skills.js +274 -0
- package/dist/internal/logs-client.d.ts +60 -0
- package/dist/internal/logs-client.d.ts.map +1 -0
- package/dist/internal/logs-client.js +311 -0
- package/dist/internal/mcp-endpoint.d.ts.map +1 -1
- package/dist/internal/mcp-endpoint.js +1 -1
- package/dist/internal/open-browser.d.ts +5 -0
- package/dist/internal/open-browser.d.ts.map +1 -0
- package/dist/internal/open-browser.js +34 -0
- package/dist/internal/playground/toolchain.d.ts.map +1 -1
- package/dist/internal/playground/toolchain.js +19 -14
- package/dist/internal/playground-proxy.d.ts +69 -0
- package/dist/internal/playground-proxy.d.ts.map +1 -0
- package/dist/internal/playground-proxy.js +468 -0
- package/dist/internal/prompt-context.d.ts +35 -0
- package/dist/internal/prompt-context.d.ts.map +1 -0
- package/dist/internal/prompt-context.js +71 -0
- package/dist/internal/reminder-runner.d.ts.map +1 -1
- package/dist/internal/reminder-runner.js +11 -11
- package/dist/internal/request-headers.d.ts +11 -0
- package/dist/internal/request-headers.d.ts.map +1 -0
- package/dist/internal/request-headers.js +14 -0
- package/dist/internal/resolve-prod-target.d.ts +44 -0
- package/dist/internal/resolve-prod-target.d.ts.map +1 -0
- package/dist/internal/resolve-prod-target.js +134 -0
- package/dist/internal/resolved-connections.js +5 -5
- package/dist/internal/run-client.d.ts +2 -2
- package/dist/internal/run-client.d.ts.map +1 -1
- package/dist/internal/run-client.js +38 -23
- package/dist/internal/schedule-runner.js +1 -1
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +23 -17
- package/dist/internal/session-engine.d.ts +1 -1
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +34 -19
- package/dist/internal/sessions-client.d.ts +34 -0
- package/dist/internal/sessions-client.d.ts.map +1 -0
- package/dist/internal/sessions-client.js +193 -0
- package/dist/internal/storage-coordinator.js +6 -6
- package/dist/internal/stream-progress.d.ts.map +1 -1
- package/dist/internal/stream-progress.js +31 -3
- package/dist/internal/terminal-style.d.ts +22 -0
- package/dist/internal/terminal-style.d.ts.map +1 -0
- package/dist/internal/terminal-style.js +49 -0
- package/dist/internal/trajectory.d.ts +10 -5
- package/dist/internal/trajectory.d.ts.map +1 -1
- package/dist/internal/trajectory.js +82 -10
- package/dist/internal/update-check.d.ts +93 -0
- package/dist/internal/update-check.d.ts.map +1 -0
- package/dist/internal/update-check.js +431 -0
- package/dist/internal/workspace.d.ts +11 -0
- package/dist/internal/workspace.d.ts.map +1 -1
- package/dist/internal/workspace.js +38 -4
- package/dist/playground/assets/index-Ct_Usdm8.css +1 -0
- package/dist/playground/assets/index-Dsyb-Vaj.js +319 -0
- package/dist/playground/index.html +2 -2
- package/dist/types.d.ts +29 -2
- package/dist/types.d.ts.map +1 -1
- package/docs/README.md +0 -1
- package/docs/quickstart.md +22 -7
- package/docs/reference/cli.md +51 -3
- package/package.json +4 -1
- package/skills/ab/SKILL.md +8 -8
- package/skills/create-agent/SKILL.md +28 -22
- package/skills/debug/SKILL.md +11 -11
- package/skills/evals/SKILL.md +16 -16
- package/skills/framework-map/SKILL.md +6 -6
- package/skills/github/SKILL.md +13 -13
- package/skills/hillclimb/SKILL.md +10 -10
- package/skills/setup-slack/SKILL.md +14 -14
- package/src/bin/agent-serve.ts +451 -191
- package/src/channels/slack/log.ts +5 -5
- package/src/channels/slack/setup.ts +1 -1
- package/src/channels/slack/socket-mode.ts +11 -9
- package/src/internal/ab-collector.ts +3 -3
- package/src/internal/ab-fold.ts +1 -1
- package/src/internal/chat-client.ts +252 -37
- package/src/internal/cli-ax.ts +761 -72
- package/src/internal/cli-cursor.ts +14 -42
- package/src/internal/cli-deploy.ts +428 -49
- package/src/internal/cli-github.ts +13 -15
- package/src/internal/cursor/account-mcp.ts +3 -3
- package/src/internal/cursor/backend-client.ts +1 -1
- package/src/internal/cursor/credentials.ts +26 -7
- package/src/internal/cursor/github-credentials.ts +3 -3
- package/src/internal/cursor-event-relay.ts +1 -1
- package/src/internal/cursor-relay-core.ts +4 -2
- package/src/internal/cursor-slack-relay.ts +1 -1
- package/src/internal/deploy-client.ts +45 -4
- package/src/internal/deploy-source.ts +133 -0
- package/src/internal/discovery.ts +53 -16
- package/src/internal/distribution.ts +8 -0
- package/src/internal/docs-site.ts +3 -3
- package/src/internal/eval-run-store.ts +10 -11
- package/src/internal/eval-runner.ts +5 -0
- package/src/internal/event-mapper.ts +222 -42
- package/src/internal/github-fanout.ts +2 -2
- package/src/internal/host-platforms.ts +5 -5
- package/src/internal/init-project.ts +333 -51
- package/src/internal/install-cursor-skills.ts +327 -0
- package/src/internal/logs-client.ts +442 -0
- package/src/internal/mcp-endpoint.ts +1 -3
- package/src/internal/open-browser.ts +41 -0
- package/src/internal/playground/toolchain.ts +18 -16
- package/src/internal/playground-proxy.ts +576 -0
- package/src/internal/prompt-context.ts +95 -0
- package/src/internal/reminder-runner.ts +11 -17
- package/src/internal/request-headers.ts +23 -0
- package/src/internal/resolve-prod-target.ts +182 -0
- package/src/internal/resolved-connections.ts +5 -5
- package/src/internal/run-client.ts +39 -36
- package/src/internal/schedule-runner.ts +1 -1
- package/src/internal/server.ts +25 -16
- package/src/internal/session-engine.ts +35 -18
- package/src/internal/sessions-client.ts +216 -0
- package/src/internal/storage-coordinator.ts +6 -6
- package/src/internal/stream-progress.ts +36 -2
- package/src/internal/terminal-style.ts +74 -0
- package/src/internal/trajectory.ts +91 -13
- package/src/internal/update-check.ts +552 -0
- package/src/internal/workspace.ts +42 -4
- package/src/types.ts +45 -7
- package/dist/docs/assets/chunks/@localSearchIndexroot.zwQ9RCQ7.js +0 -1
- package/dist/playground/assets/index-B1Qc9h2u.css +0 -1
- package/dist/playground/assets/index-CpDYCj8W.js +0 -79
- /package/dist/docs/assets/{index.md.m81y7TY7.lean.js → index.md.Cylk70gg.lean.js} +0 -0
- /package/dist/docs/assets/{quickstart.md.CfU8_uTC.lean.js → quickstart.md.BU6Iwi_9.lean.js} +0 -0
|
@@ -54,6 +54,7 @@ import { type ABSnapshot, buildABSnapshot } from "./ab-snapshot.js";
|
|
|
54
54
|
import { ApprovalGate } from "./approval-gate.js";
|
|
55
55
|
import { samePrincipal } from "./auth.js";
|
|
56
56
|
import { mergeCloudOptions, resolveSessionRuntime } from "./cloud-merge.js";
|
|
57
|
+
import { isDevMode } from "./dev-mode.js";
|
|
57
58
|
import { EventLogStore } from "./event-log.js";
|
|
58
59
|
import { TurnEventMapper } from "./event-mapper.js";
|
|
59
60
|
import { createHostPlatforms, type HostPlatforms } from "./host-platforms.js";
|
|
@@ -65,6 +66,11 @@ import {
|
|
|
65
66
|
} from "./ids.js";
|
|
66
67
|
import { validateToolInput } from "./json-schema.js";
|
|
67
68
|
import { McpHost } from "./mcp-host.js";
|
|
69
|
+
import {
|
|
70
|
+
buildIdentitySection,
|
|
71
|
+
buildSessionContextBlock,
|
|
72
|
+
SCHEDULE_CHANNEL_PREFIX,
|
|
73
|
+
} from "./prompt-context.js";
|
|
68
74
|
import { assertCloudCanHonorAccountServersFilters } from "./resolved-connections.js";
|
|
69
75
|
import type { AgentRunner } from "./sdk-runner.js";
|
|
70
76
|
import { SessionStore } from "./session-store.js";
|
|
@@ -77,7 +83,7 @@ import {
|
|
|
77
83
|
} from "./workspace.js";
|
|
78
84
|
|
|
79
85
|
export const HTTP_CHANNEL_ID = "http";
|
|
80
|
-
export
|
|
86
|
+
export { SCHEDULE_CHANNEL_PREFIX } from "./prompt-context.js";
|
|
81
87
|
|
|
82
88
|
export class SessionBusyError extends Error {
|
|
83
89
|
constructor(sessionId: string) {
|
|
@@ -243,7 +249,7 @@ export class SessionEngine {
|
|
|
243
249
|
(sessionId) => this.sessions.eventFilePath(sessionId),
|
|
244
250
|
(sessionId, error) =>
|
|
245
251
|
this.logger(
|
|
246
|
-
`[
|
|
252
|
+
`[agentkit] failed to persist events for ${sessionId}: ${describeError(error)}`
|
|
247
253
|
)
|
|
248
254
|
);
|
|
249
255
|
this.storage =
|
|
@@ -439,7 +445,7 @@ export class SessionEngine {
|
|
|
439
445
|
}
|
|
440
446
|
} catch (error) {
|
|
441
447
|
this.logger(
|
|
442
|
-
`[
|
|
448
|
+
`[agentkit] ab "${experiment.name}" enrollment failed (sticky skip): ${describeError(error)}`
|
|
443
449
|
);
|
|
444
450
|
variant = null;
|
|
445
451
|
}
|
|
@@ -706,7 +712,7 @@ export class SessionEngine {
|
|
|
706
712
|
this.queueDispatch(sessionId, event);
|
|
707
713
|
} catch (error) {
|
|
708
714
|
this.logger(
|
|
709
|
-
`[
|
|
715
|
+
`[agentkit] failed to record event for ${sessionId}: ${describeError(error)}`
|
|
710
716
|
);
|
|
711
717
|
}
|
|
712
718
|
};
|
|
@@ -744,7 +750,10 @@ export class SessionEngine {
|
|
|
744
750
|
// events while sibling parallel tools are still executing.
|
|
745
751
|
if (
|
|
746
752
|
update.type === "tool-call-started" ||
|
|
747
|
-
update.type === "tool-call-completed"
|
|
753
|
+
update.type === "tool-call-completed" ||
|
|
754
|
+
// Nested subagent progress (newer SDKs); string check keeps
|
|
755
|
+
// typecheck green against older published `@cursor/sdk` pins.
|
|
756
|
+
(update as { type: string }).type === "tool-call-delta"
|
|
748
757
|
) {
|
|
749
758
|
await yieldEventLoop();
|
|
750
759
|
}
|
|
@@ -847,14 +856,24 @@ export class SessionEngine {
|
|
|
847
856
|
})
|
|
848
857
|
: undefined;
|
|
849
858
|
let turnPrompt = prompt;
|
|
859
|
+
if (isFirstTurn) {
|
|
860
|
+
const contextBlock = buildSessionContextBlock({
|
|
861
|
+
sessionId: record.sessionId,
|
|
862
|
+
channelId: record.channelId,
|
|
863
|
+
channelKind: this.channelsById.get(record.channelId)?.meta?.kind,
|
|
864
|
+
environment: isDevMode() ? "local dev server" : "hosted deployment",
|
|
865
|
+
});
|
|
866
|
+
turnPrompt = `${contextBlock}\n\n${prompt}`;
|
|
867
|
+
}
|
|
850
868
|
if (runtime === "cloud" && isFirstTurn) {
|
|
851
869
|
const preamble = [
|
|
852
870
|
agent.instructions?.trim() ?? "",
|
|
871
|
+
buildIdentitySection(agent),
|
|
853
872
|
buildAgentToolsCatalog(agent.tools, { includeScripts: true }),
|
|
854
873
|
]
|
|
855
874
|
.filter((part) => part !== "")
|
|
856
875
|
.join("\n\n");
|
|
857
|
-
turnPrompt =
|
|
876
|
+
turnPrompt = `${preamble}\n\n${turnPrompt}`;
|
|
858
877
|
}
|
|
859
878
|
return {
|
|
860
879
|
sessionId: record.sessionId,
|
|
@@ -1382,7 +1401,7 @@ export class SessionEngine {
|
|
|
1382
1401
|
.then(() => this.dispatchEvent(sessionId, event))
|
|
1383
1402
|
.catch((error) => {
|
|
1384
1403
|
this.logger(
|
|
1385
|
-
`[
|
|
1404
|
+
`[agentkit] event dispatch failed for ${sessionId}: ${describeError(error)}`
|
|
1386
1405
|
);
|
|
1387
1406
|
})
|
|
1388
1407
|
.then(() => {
|
|
@@ -1427,7 +1446,7 @@ export class SessionEngine {
|
|
|
1427
1446
|
await handler(event, channelCtx, sessionCtx);
|
|
1428
1447
|
} catch (error) {
|
|
1429
1448
|
this.logger(
|
|
1430
|
-
`[
|
|
1449
|
+
`[agentkit] channel "${record.channelId}" handler for ${event.type} threw: ${describeError(error)}`
|
|
1431
1450
|
);
|
|
1432
1451
|
}
|
|
1433
1452
|
}
|
|
@@ -1455,7 +1474,7 @@ export class SessionEngine {
|
|
|
1455
1474
|
});
|
|
1456
1475
|
} catch (error) {
|
|
1457
1476
|
this.logger(
|
|
1458
|
-
`[
|
|
1477
|
+
`[agentkit] hook "${hook.name}" handler for ${event.type} threw: ${describeError(error)}`
|
|
1459
1478
|
);
|
|
1460
1479
|
}
|
|
1461
1480
|
}
|
|
@@ -1597,7 +1616,7 @@ export class SessionEngine {
|
|
|
1597
1616
|
});
|
|
1598
1617
|
} catch (error) {
|
|
1599
1618
|
this.logger(
|
|
1600
|
-
`[
|
|
1619
|
+
`[agentkit] ab persistSnapshots.save threw: ${describeError(error)}`
|
|
1601
1620
|
);
|
|
1602
1621
|
}
|
|
1603
1622
|
} else {
|
|
@@ -1806,9 +1825,7 @@ export class SessionEngine {
|
|
|
1806
1825
|
try {
|
|
1807
1826
|
await this.runBulkRestore(storage, policy);
|
|
1808
1827
|
} catch (error) {
|
|
1809
|
-
this.logger(
|
|
1810
|
-
`[agent-serve] session restore failed: ${describeError(error)}`
|
|
1811
|
-
);
|
|
1828
|
+
this.logger(`[agentkit] session restore failed: ${describeError(error)}`);
|
|
1812
1829
|
}
|
|
1813
1830
|
}
|
|
1814
1831
|
|
|
@@ -1865,7 +1882,7 @@ export class SessionEngine {
|
|
|
1865
1882
|
return { record, events };
|
|
1866
1883
|
} catch (error) {
|
|
1867
1884
|
this.logger(
|
|
1868
|
-
`[
|
|
1885
|
+
`[agentkit] failed to restore session ${record.sessionId}: ${describeError(error)}`
|
|
1869
1886
|
);
|
|
1870
1887
|
return undefined;
|
|
1871
1888
|
}
|
|
@@ -1884,7 +1901,7 @@ export class SessionEngine {
|
|
|
1884
1901
|
(ndjson === undefined ? 0 : Buffer.byteLength(ndjson, "utf8"));
|
|
1885
1902
|
if (bytes > budget) {
|
|
1886
1903
|
this.logger(
|
|
1887
|
-
`[
|
|
1904
|
+
`[agentkit] session restore stopped at the ${policy.maxTotalBytes}-byte budget after ${restored} session(s); remaining sessions restore lazily on resume`
|
|
1888
1905
|
);
|
|
1889
1906
|
break outer;
|
|
1890
1907
|
}
|
|
@@ -1894,13 +1911,13 @@ export class SessionEngine {
|
|
|
1894
1911
|
restored += 1;
|
|
1895
1912
|
} catch (error) {
|
|
1896
1913
|
this.logger(
|
|
1897
|
-
`[
|
|
1914
|
+
`[agentkit] failed to restore session ${item.record.sessionId}: ${describeError(error)}`
|
|
1898
1915
|
);
|
|
1899
1916
|
}
|
|
1900
1917
|
}
|
|
1901
1918
|
}
|
|
1902
1919
|
if (restored > 0) {
|
|
1903
|
-
this.logger(`[
|
|
1920
|
+
this.logger(`[agentkit] restored ${restored} session(s) from storage`);
|
|
1904
1921
|
}
|
|
1905
1922
|
}
|
|
1906
1923
|
|
|
@@ -1956,7 +1973,7 @@ export class SessionEngine {
|
|
|
1956
1973
|
const events = await storage.listSessionEvents(record.sessionId);
|
|
1957
1974
|
await this.materializeSession(record, eventsNdjson(events));
|
|
1958
1975
|
this.logger(
|
|
1959
|
-
`[
|
|
1976
|
+
`[agentkit] lazily restored session ${record.sessionId} from storage`
|
|
1960
1977
|
);
|
|
1961
1978
|
return record;
|
|
1962
1979
|
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session list / event fetch for CLI (`sessions`, `session`, chat reattach).
|
|
3
|
+
*
|
|
4
|
+
* Customer-facing errors never include hosting URLs or infra jargon.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { SessionEvent, SessionSummary } from "../types.js";
|
|
8
|
+
import { sanitizeCustomerError } from "./logs-client.js";
|
|
9
|
+
import { mergeRequestHeaders, type RequestAuth } from "./request-headers.js";
|
|
10
|
+
|
|
11
|
+
export async function listSessions(args: {
|
|
12
|
+
baseUrl: string;
|
|
13
|
+
auth?: RequestAuth;
|
|
14
|
+
fetchImpl?: typeof fetch;
|
|
15
|
+
}): Promise<SessionSummary[]> {
|
|
16
|
+
const baseUrl = args.baseUrl.replace(/\/$/, "");
|
|
17
|
+
const fetchImpl = args.fetchImpl ?? fetch;
|
|
18
|
+
let resp: Response;
|
|
19
|
+
try {
|
|
20
|
+
resp = await fetchImpl(`${baseUrl}/v1/sessions`, {
|
|
21
|
+
headers: mergeRequestHeaders(args.auth),
|
|
22
|
+
});
|
|
23
|
+
} catch (error) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
sanitizeCustomerError(
|
|
26
|
+
error instanceof Error ? error.message : "Could not list sessions."
|
|
27
|
+
)
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
if (!resp.ok) {
|
|
31
|
+
throw new Error(`Could not list sessions (HTTP ${resp.status}).`);
|
|
32
|
+
}
|
|
33
|
+
const body = (await resp.json()) as { sessions?: unknown };
|
|
34
|
+
if (!Array.isArray(body.sessions)) {
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
const out: SessionSummary[] = [];
|
|
38
|
+
for (const row of body.sessions) {
|
|
39
|
+
const parsed = parseSessionSummary(row);
|
|
40
|
+
if (parsed !== undefined) {
|
|
41
|
+
out.push(parsed);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function fetchSessionEvents(args: {
|
|
48
|
+
baseUrl: string;
|
|
49
|
+
sessionId: string;
|
|
50
|
+
auth?: RequestAuth;
|
|
51
|
+
fetchImpl?: typeof fetch;
|
|
52
|
+
}): Promise<SessionEvent[]> {
|
|
53
|
+
const baseUrl = args.baseUrl.replace(/\/$/, "");
|
|
54
|
+
const fetchImpl = args.fetchImpl ?? fetch;
|
|
55
|
+
const path = `/v1/session/${encodeURIComponent(args.sessionId)}/events`;
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
const jsonResp = await fetchImpl(`${baseUrl}${path}?format=json`, {
|
|
59
|
+
headers: mergeRequestHeaders(args.auth),
|
|
60
|
+
});
|
|
61
|
+
if (jsonResp.ok) {
|
|
62
|
+
const body = (await jsonResp.json()) as { events?: unknown };
|
|
63
|
+
if (Array.isArray(body.events)) {
|
|
64
|
+
return body.events as SessionEvent[];
|
|
65
|
+
}
|
|
66
|
+
} else if (jsonResp.status === 404) {
|
|
67
|
+
throw new Error(`Session ${args.sessionId} not found.`);
|
|
68
|
+
} else if (jsonResp.status === 403) {
|
|
69
|
+
throw new Error(
|
|
70
|
+
`Session ${args.sessionId} is not readable by this caller.`
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
} catch (error) {
|
|
74
|
+
if (error instanceof Error && error.message.startsWith("Session ")) {
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
// Fall through to NDJSON.
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
const resp = await fetchImpl(`${baseUrl}${path}`, {
|
|
82
|
+
headers: mergeRequestHeaders(args.auth),
|
|
83
|
+
});
|
|
84
|
+
if (resp.status === 404) {
|
|
85
|
+
throw new Error(`Session ${args.sessionId} not found.`);
|
|
86
|
+
}
|
|
87
|
+
if (resp.status === 403) {
|
|
88
|
+
throw new Error(
|
|
89
|
+
`Session ${args.sessionId} is not readable by this caller.`
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
if (!resp.ok) {
|
|
93
|
+
throw new Error(`Could not fetch session events (HTTP ${resp.status}).`);
|
|
94
|
+
}
|
|
95
|
+
const text = await resp.text();
|
|
96
|
+
const events: SessionEvent[] = [];
|
|
97
|
+
for (const line of text.split("\n")) {
|
|
98
|
+
if (line.trim() === "") {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
events.push(JSON.parse(line) as SessionEvent);
|
|
103
|
+
} catch {
|
|
104
|
+
// skip malformed lines
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return events;
|
|
108
|
+
} catch (error) {
|
|
109
|
+
if (error instanceof Error && error.message.startsWith("Session ")) {
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
if (error instanceof Error && error.message.startsWith("Could not fetch")) {
|
|
113
|
+
throw new Error(sanitizeCustomerError(error.message));
|
|
114
|
+
}
|
|
115
|
+
throw new Error(
|
|
116
|
+
sanitizeCustomerError(
|
|
117
|
+
error instanceof Error
|
|
118
|
+
? error.message
|
|
119
|
+
: "Could not fetch session events."
|
|
120
|
+
)
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** Lenient parse so partial stubs / older servers still list by sessionId. */
|
|
126
|
+
function parseSessionSummary(value: unknown): SessionSummary | undefined {
|
|
127
|
+
if (typeof value !== "object" || value === null) {
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
const row = value as Record<string, unknown>;
|
|
131
|
+
if (typeof row.sessionId !== "string" || row.sessionId === "") {
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
const continuationToken =
|
|
135
|
+
typeof row.continuationToken === "string"
|
|
136
|
+
? row.continuationToken
|
|
137
|
+
: row.continuationToken === null
|
|
138
|
+
? null
|
|
139
|
+
: null;
|
|
140
|
+
return {
|
|
141
|
+
sessionId: row.sessionId,
|
|
142
|
+
channelId: typeof row.channelId === "string" ? row.channelId : "",
|
|
143
|
+
mode: row.mode === "task" ? "task" : "chat",
|
|
144
|
+
title: typeof row.title === "string" ? row.title : undefined,
|
|
145
|
+
turnCount: typeof row.turnCount === "number" ? row.turnCount : 0,
|
|
146
|
+
running: row.running === true,
|
|
147
|
+
createdAt: typeof row.createdAt === "string" ? row.createdAt : "",
|
|
148
|
+
updatedAt: typeof row.updatedAt === "string" ? row.updatedAt : "",
|
|
149
|
+
continuationToken,
|
|
150
|
+
externalUrl:
|
|
151
|
+
typeof row.externalUrl === "string" ? row.externalUrl : undefined,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Pick the previous (most recently updated) followable session for
|
|
157
|
+
* `resume` / `chat --resume` when no session id was passed.
|
|
158
|
+
* Followable = has a non-empty continuation token (task sessions without
|
|
159
|
+
* one are skipped).
|
|
160
|
+
*/
|
|
161
|
+
export function pickPreviousSession(
|
|
162
|
+
sessions: readonly SessionSummary[]
|
|
163
|
+
): SessionSummary | undefined {
|
|
164
|
+
const followable = sessions.filter(
|
|
165
|
+
(s) => typeof s.continuationToken === "string" && s.continuationToken !== ""
|
|
166
|
+
);
|
|
167
|
+
if (followable.length === 0) {
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
170
|
+
return [...followable].sort((a, b) =>
|
|
171
|
+
b.updatedAt.localeCompare(a.updatedAt)
|
|
172
|
+
)[0];
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** Look up the most recently updated followable session id. */
|
|
176
|
+
export async function resolvePreviousSessionId(args: {
|
|
177
|
+
baseUrl: string;
|
|
178
|
+
auth?: RequestAuth;
|
|
179
|
+
fetchImpl?: typeof fetch;
|
|
180
|
+
}): Promise<string | undefined> {
|
|
181
|
+
const sessions = await listSessions({
|
|
182
|
+
baseUrl: args.baseUrl,
|
|
183
|
+
auth: args.auth,
|
|
184
|
+
fetchImpl: args.fetchImpl,
|
|
185
|
+
});
|
|
186
|
+
return pickPreviousSession(sessions)?.sessionId;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** Format a sessions table (id, channel, mode, turns, running, updated). */
|
|
190
|
+
export function formatSessionsTable(sessions: SessionSummary[]): string {
|
|
191
|
+
if (sessions.length === 0) {
|
|
192
|
+
return "No sessions.\n";
|
|
193
|
+
}
|
|
194
|
+
const header = ["SESSION", "CHANNEL", "MODE", "TURNS", "RUNNING", "UPDATED"];
|
|
195
|
+
const rows = sessions.map((s) => [
|
|
196
|
+
s.sessionId,
|
|
197
|
+
s.channelId,
|
|
198
|
+
s.mode,
|
|
199
|
+
String(s.turnCount),
|
|
200
|
+
s.running ? "yes" : "no",
|
|
201
|
+
s.updatedAt,
|
|
202
|
+
]);
|
|
203
|
+
return `${renderTable(header, rows)}\n`;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function renderTable(header: string[], rows: string[][]): string {
|
|
207
|
+
const widths = header.map((h, i) =>
|
|
208
|
+
Math.max(h.length, ...rows.map((row) => (row[i] ?? "").length))
|
|
209
|
+
);
|
|
210
|
+
const renderRow = (row: string[]): string =>
|
|
211
|
+
row
|
|
212
|
+
.map((cell, i) => cell.padEnd(widths[i] ?? 0))
|
|
213
|
+
.join(" ")
|
|
214
|
+
.trimEnd();
|
|
215
|
+
return [renderRow(header), ...rows.map(renderRow)].join("\n");
|
|
216
|
+
}
|
|
@@ -317,7 +317,7 @@ export class StorageCoordinator {
|
|
|
317
317
|
// under at-most-once). The session is unrecoverable; treat as a miss
|
|
318
318
|
// so the conversation can continue rather than failing forever.
|
|
319
319
|
this.logger(
|
|
320
|
-
`[
|
|
320
|
+
`[agentkit] storage continuation entry points at missing session ${sessionId}; treating as a miss`
|
|
321
321
|
);
|
|
322
322
|
return undefined;
|
|
323
323
|
}
|
|
@@ -488,7 +488,7 @@ export class StorageCoordinator {
|
|
|
488
488
|
return value == null ? undefined : (value as unknown as ABSnapshot);
|
|
489
489
|
} catch (error) {
|
|
490
490
|
this.logger(
|
|
491
|
-
`[
|
|
491
|
+
`[agentkit] storage get(ab-snapshot) failed: ${describeError(error)}`
|
|
492
492
|
);
|
|
493
493
|
return undefined;
|
|
494
494
|
}
|
|
@@ -521,7 +521,7 @@ export class StorageCoordinator {
|
|
|
521
521
|
clearTimeout(timer);
|
|
522
522
|
if (!drained) {
|
|
523
523
|
this.logger(
|
|
524
|
-
`[
|
|
524
|
+
`[agentkit] storage shutdown drain timed out after ${CLOSE_DRAIN_TIMEOUT_MS}ms with ${this.pending} write(s) undelivered`
|
|
525
525
|
);
|
|
526
526
|
}
|
|
527
527
|
}
|
|
@@ -569,7 +569,7 @@ export class StorageCoordinator {
|
|
|
569
569
|
return Array.isArray(entries) ? entries : [];
|
|
570
570
|
} catch (error) {
|
|
571
571
|
this.logger(
|
|
572
|
-
`[
|
|
572
|
+
`[agentkit] storage list(${prefix}) failed: ${describeError(error)}`
|
|
573
573
|
);
|
|
574
574
|
return [];
|
|
575
575
|
}
|
|
@@ -583,7 +583,7 @@ export class StorageCoordinator {
|
|
|
583
583
|
this.dropped += ops.length;
|
|
584
584
|
if (this.dropped <= ops.length || this.dropped % 1_000 < ops.length) {
|
|
585
585
|
this.logger(
|
|
586
|
-
`[
|
|
586
|
+
`[agentkit] storage queue full (${MAX_PENDING_OPS} pending writes); dropped ${this.dropped} write(s) so far — the sink is too slow for the traffic`
|
|
587
587
|
);
|
|
588
588
|
}
|
|
589
589
|
return;
|
|
@@ -600,7 +600,7 @@ export class StorageCoordinator {
|
|
|
600
600
|
}
|
|
601
601
|
} catch (error) {
|
|
602
602
|
this.logger(
|
|
603
|
-
`[
|
|
603
|
+
`[agentkit] storage ${op.op}(${op.key}) failed: ${describeError(error)}`
|
|
604
604
|
);
|
|
605
605
|
} finally {
|
|
606
606
|
this.pending -= 1;
|
|
@@ -64,6 +64,9 @@ export function createStreamProgress(options?: {
|
|
|
64
64
|
break;
|
|
65
65
|
}
|
|
66
66
|
case "reasoning.appended": {
|
|
67
|
+
if (event.data.parentCallId !== undefined) {
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
67
70
|
if (!thinkingShown) {
|
|
68
71
|
thinkingShown = true;
|
|
69
72
|
write(c.dim(" · thinking…\n"));
|
|
@@ -71,6 +74,11 @@ export function createStreamProgress(options?: {
|
|
|
71
74
|
break;
|
|
72
75
|
}
|
|
73
76
|
case "message.appended": {
|
|
77
|
+
// Nested subagent deltas stay inside the task chip/indent, not
|
|
78
|
+
// the parent agent stream.
|
|
79
|
+
if (event.data.parentCallId !== undefined) {
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
74
82
|
if (!assistantOpen) {
|
|
75
83
|
write(`${c.green("‹ agent")} `);
|
|
76
84
|
assistantOpen = true;
|
|
@@ -79,6 +87,9 @@ export function createStreamProgress(options?: {
|
|
|
79
87
|
break;
|
|
80
88
|
}
|
|
81
89
|
case "message.completed": {
|
|
90
|
+
if (event.data.parentCallId !== undefined) {
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
82
93
|
closeAssistant();
|
|
83
94
|
break;
|
|
84
95
|
}
|
|
@@ -98,9 +109,18 @@ export function createStreamProgress(options?: {
|
|
|
98
109
|
closeAssistant();
|
|
99
110
|
const now = Date.now();
|
|
100
111
|
for (const call of event.data.calls) {
|
|
112
|
+
if (call.toolName === "task" && call.parentCallId === undefined) {
|
|
113
|
+
// Covered by subagent.called; avoid a duplicate bare `task` line.
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
101
116
|
toolStartedAt.set(call.callId, now);
|
|
117
|
+
const indent =
|
|
118
|
+
call.parentCallId !== undefined ||
|
|
119
|
+
event.data.parentCallId !== undefined
|
|
120
|
+
? " "
|
|
121
|
+
: " ";
|
|
102
122
|
write(
|
|
103
|
-
|
|
123
|
+
`${indent}${c.magenta("⚙")} ${c.bold(call.toolName)}${c.dim(
|
|
104
124
|
formatArgs(call.args)
|
|
105
125
|
)}\n`
|
|
106
126
|
);
|
|
@@ -127,13 +147,21 @@ export function createStreamProgress(options?: {
|
|
|
127
147
|
break;
|
|
128
148
|
}
|
|
129
149
|
case "action.result": {
|
|
150
|
+
if (
|
|
151
|
+
event.data.toolName === "task" &&
|
|
152
|
+
event.data.parentCallId === undefined
|
|
153
|
+
) {
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
130
156
|
const started = toolStartedAt.get(event.data.callId);
|
|
131
157
|
toolStartedAt.delete(event.data.callId);
|
|
132
158
|
const dur =
|
|
133
159
|
started === undefined ? "" : c.dim(` ${elapsed(started)}`);
|
|
134
160
|
const mark = event.data.isError ? c.red("✗") : c.magenta("✓");
|
|
161
|
+
const indent =
|
|
162
|
+
event.data.parentCallId !== undefined ? " " : " ";
|
|
135
163
|
write(
|
|
136
|
-
|
|
164
|
+
`${indent}${mark} ${c.bold(event.data.toolName)}${dur} ${c.dim(
|
|
137
165
|
truncate(stringify(event.data.output), 90)
|
|
138
166
|
)}\n`
|
|
139
167
|
);
|
|
@@ -149,6 +177,12 @@ export function createStreamProgress(options?: {
|
|
|
149
177
|
);
|
|
150
178
|
break;
|
|
151
179
|
}
|
|
180
|
+
case "subagent.completed": {
|
|
181
|
+
write(
|
|
182
|
+
` ${c.magenta("✓")} ${c.bold(event.data.name ?? "subagent")} ${c.dim("done")}\n`
|
|
183
|
+
);
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
152
186
|
case "turn.completed": {
|
|
153
187
|
closeAssistant();
|
|
154
188
|
const usage = event.data.usage;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tiny ANSI helpers for CLI progress output. Respects `NO_COLOR` and
|
|
3
|
+
* only enables when the target stream is a TTY.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { clearScreenDown, cursorTo } from "node:readline";
|
|
7
|
+
|
|
8
|
+
export interface TerminalPalette {
|
|
9
|
+
dim: (s: string) => string;
|
|
10
|
+
bold: (s: string) => string;
|
|
11
|
+
cyan: (s: string) => string;
|
|
12
|
+
green: (s: string) => string;
|
|
13
|
+
red: (s: string) => string;
|
|
14
|
+
magenta: (s: string) => string;
|
|
15
|
+
yellow: (s: string) => string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const IDENTITY = (s: string): string => s;
|
|
19
|
+
|
|
20
|
+
const PLAIN: TerminalPalette = {
|
|
21
|
+
dim: IDENTITY,
|
|
22
|
+
bold: IDENTITY,
|
|
23
|
+
cyan: IDENTITY,
|
|
24
|
+
green: IDENTITY,
|
|
25
|
+
red: IDENTITY,
|
|
26
|
+
magenta: IDENTITY,
|
|
27
|
+
yellow: IDENTITY,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export function colorEnabledFor(
|
|
31
|
+
stream: NodeJS.WriteStream = process.stdout
|
|
32
|
+
): boolean {
|
|
33
|
+
return stream.isTTY === true && process.env.NO_COLOR === undefined;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function makePalette(enabled: boolean): TerminalPalette {
|
|
37
|
+
if (!enabled) {
|
|
38
|
+
return PLAIN;
|
|
39
|
+
}
|
|
40
|
+
const wrap =
|
|
41
|
+
(code: string) =>
|
|
42
|
+
(s: string): string =>
|
|
43
|
+
`\u001b[${code}m${s}\u001b[0m`;
|
|
44
|
+
return {
|
|
45
|
+
dim: wrap("2"),
|
|
46
|
+
bold: wrap("1"),
|
|
47
|
+
cyan: wrap("36"),
|
|
48
|
+
green: wrap("32"),
|
|
49
|
+
red: wrap("31"),
|
|
50
|
+
magenta: wrap("35"),
|
|
51
|
+
yellow: wrap("33"),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Palette for human-facing stdout (init summaries, next steps). */
|
|
56
|
+
export function stdoutPalette(): TerminalPalette {
|
|
57
|
+
return makePalette(colorEnabledFor(process.stdout));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Palette for human-facing stderr (login progress, warnings). */
|
|
61
|
+
export function stderrPalette(): TerminalPalette {
|
|
62
|
+
return makePalette(colorEnabledFor(process.stderr));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Wipe the terminal before a `dev` Enter-to-restart cycle. */
|
|
66
|
+
export function clearTerminal(
|
|
67
|
+
stream: NodeJS.WriteStream = process.stdout
|
|
68
|
+
): void {
|
|
69
|
+
if (stream.isTTY !== true) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
cursorTo(stream, 0, 0);
|
|
73
|
+
clearScreenDown(stream);
|
|
74
|
+
}
|