@qodeca/xezar 0.13.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -39
- package/dist/agent-config/account-identity.d.ts +2 -8
- package/dist/agent-config/account-identity.js +54 -10
- package/dist/agent-config/account-identity.js.map +1 -1
- package/dist/agent-config/catalog.d.ts +49 -7
- package/dist/agent-config/catalog.js +107 -0
- package/dist/agent-config/catalog.js.map +1 -1
- package/dist/agent-config/model-settings/pi.d.ts +12 -6
- package/dist/agent-config/model-settings/pi.js +12 -6
- package/dist/agent-config/model-settings/pi.js.map +1 -1
- package/dist/agent-config/seed.js +10 -0
- package/dist/agent-config/seed.js.map +1 -1
- package/dist/contract/github.d.ts +15 -0
- package/dist/contract/index.d.ts +9 -0
- package/dist/contract/index.js +1527 -895
- package/dist/contract/mcp-api-reference.d.ts +174 -0
- package/dist/contract/mcp-audit.d.ts +103 -0
- package/dist/contract/mcp-discovery.d.ts +257 -0
- package/dist/contract/mcp-event-catalog.d.ts +121 -0
- package/dist/contract/mcp-event-catalog.test.d.ts +1 -0
- package/dist/contract/mcp-idempotency.d.ts +200 -0
- package/dist/contract/mcp-journal.d.ts +268 -0
- package/dist/contract/mcp-leader.d.ts +88 -0
- package/dist/contract/mcp-ownership.d.ts +78 -0
- package/dist/contract/mcp-versioning.d.ts +139 -0
- package/dist/contract/runs.d.ts +81 -0
- package/dist/core/agent-profiles.d.ts +15 -4
- package/dist/core/agent-profiles.js +22 -8
- package/dist/core/agent-profiles.js.map +1 -1
- package/dist/core/opencode-server-runner.js +71 -11
- package/dist/core/opencode-server-runner.js.map +1 -1
- package/dist/core/secret-redaction.d.ts +7 -1
- package/dist/core/secret-redaction.js +44 -10
- package/dist/core/secret-redaction.js.map +1 -1
- package/dist/index.js +138 -27
- package/dist/index.js.map +1 -1
- package/dist/machine-identity.d.ts +66 -0
- package/dist/machine-identity.js +96 -0
- package/dist/machine-identity.js.map +1 -0
- package/dist/mcp/adapters/claude-code.d.ts +41 -0
- package/dist/mcp/adapters/claude-code.js +40 -0
- package/dist/mcp/adapters/claude-code.js.map +1 -0
- package/dist/mcp/adapters/codex.d.ts +140 -0
- package/dist/mcp/adapters/codex.js +323 -0
- package/dist/mcp/adapters/codex.js.map +1 -0
- package/dist/mcp/adapters/opencode.d.ts +148 -0
- package/dist/mcp/adapters/opencode.js +528 -0
- package/dist/mcp/adapters/opencode.js.map +1 -0
- package/dist/mcp/adapters/pi-link.d.ts +102 -0
- package/dist/mcp/adapters/pi-link.js +235 -0
- package/dist/mcp/adapters/pi-link.js.map +1 -0
- package/dist/mcp/adapters/pi.d.ts +188 -0
- package/dist/mcp/adapters/pi.js +418 -0
- package/dist/mcp/adapters/pi.js.map +1 -0
- package/dist/mcp/api-reference.d.ts +26 -0
- package/dist/mcp/api-reference.js +133 -0
- package/dist/mcp/api-reference.js.map +1 -0
- package/dist/mcp/audit-trail.d.ts +162 -0
- package/dist/mcp/audit-trail.js +306 -0
- package/dist/mcp/audit-trail.js.map +1 -0
- package/dist/mcp/bridge.d.ts +81 -0
- package/dist/mcp/bridge.js +407 -0
- package/dist/mcp/bridge.js.map +1 -0
- package/dist/mcp/connection-file.d.ts +49 -0
- package/dist/mcp/connection-file.js +63 -0
- package/dist/mcp/connection-file.js.map +1 -0
- package/dist/mcp/echo-guard.d.ts +94 -0
- package/dist/mcp/echo-guard.js +160 -0
- package/dist/mcp/echo-guard.js.map +1 -0
- package/dist/mcp/event-catalog.d.ts +120 -0
- package/dist/mcp/event-catalog.js +306 -0
- package/dist/mcp/event-catalog.js.map +1 -0
- package/dist/mcp/event-controller.d.ts +230 -0
- package/dist/mcp/event-controller.js +596 -0
- package/dist/mcp/event-controller.js.map +1 -0
- package/dist/mcp/event-journal.d.ts +57 -0
- package/dist/mcp/event-journal.js +423 -0
- package/dist/mcp/event-journal.js.map +1 -0
- package/dist/mcp/index.d.ts +63 -0
- package/dist/mcp/index.js +386 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/ipc.d.ts +202 -0
- package/dist/mcp/ipc.js +206 -0
- package/dist/mcp/ipc.js.map +1 -0
- package/dist/mcp/leader-delivery.d.ts +119 -0
- package/dist/mcp/leader-delivery.js +450 -0
- package/dist/mcp/leader-delivery.js.map +1 -0
- package/dist/mcp/operation-receipts.d.ts +210 -0
- package/dist/mcp/operation-receipts.js +723 -0
- package/dist/mcp/operation-receipts.js.map +1 -0
- package/dist/mcp/project-catalogs.d.ts +23 -0
- package/dist/mcp/project-catalogs.js +25 -0
- package/dist/mcp/project-catalogs.js.map +1 -0
- package/dist/mcp/project-leaders.d.ts +26 -0
- package/dist/mcp/project-leaders.js +17 -0
- package/dist/mcp/project-leaders.js.map +1 -0
- package/dist/mcp/protocol.d.ts +50 -0
- package/dist/mcp/protocol.js +47 -0
- package/dist/mcp/protocol.js.map +1 -0
- package/dist/mcp/reconnect.d.ts +297 -0
- package/dist/mcp/reconnect.js +465 -0
- package/dist/mcp/reconnect.js.map +1 -0
- package/dist/mcp/resource-ownership.d.ts +228 -0
- package/dist/mcp/resource-ownership.js +390 -0
- package/dist/mcp/resource-ownership.js.map +1 -0
- package/dist/mcp/service-adapter.d.ts +16488 -0
- package/dist/mcp/service-adapter.js +148 -0
- package/dist/mcp/service-adapter.js.map +1 -0
- package/dist/mcp/service.d.ts +83 -0
- package/dist/mcp/service.js +233 -0
- package/dist/mcp/service.js.map +1 -0
- package/dist/mcp/session-binding.d.ts +105 -0
- package/dist/mcp/session-binding.js +163 -0
- package/dist/mcp/session-binding.js.map +1 -0
- package/dist/mcp/stale-write.d.ts +145 -0
- package/dist/mcp/stale-write.js +219 -0
- package/dist/mcp/stale-write.js.map +1 -0
- package/dist/mcp/tool.d.ts +48 -0
- package/dist/mcp/tool.js +24 -0
- package/dist/mcp/tool.js.map +1 -0
- package/dist/mcp/tools/discovery.d.ts +40 -0
- package/dist/mcp/tools/discovery.js +232 -0
- package/dist/mcp/tools/discovery.js.map +1 -0
- package/dist/mcp/tools/execution-control.d.ts +171 -0
- package/dist/mcp/tools/execution-control.js +513 -0
- package/dist/mcp/tools/execution-control.js.map +1 -0
- package/dist/mcp/tools/handoff-git.d.ts +26 -0
- package/dist/mcp/tools/handoff-git.js +544 -0
- package/dist/mcp/tools/handoff-git.js.map +1 -0
- package/dist/mcp/tools/index.d.ts +2 -0
- package/dist/mcp/tools/index.js +23 -0
- package/dist/mcp/tools/index.js.map +1 -0
- package/dist/mcp/tools/leader-events.d.ts +46 -0
- package/dist/mcp/tools/leader-events.js +126 -0
- package/dist/mcp/tools/leader-events.js.map +1 -0
- package/dist/mcp/tools/local-handoff.d.ts +102 -0
- package/dist/mcp/tools/local-handoff.js +306 -0
- package/dist/mcp/tools/local-handoff.js.map +1 -0
- package/dist/mcp/tools/project-config.d.ts +340 -0
- package/dist/mcp/tools/project-config.js +1075 -0
- package/dist/mcp/tools/project-config.js.map +1 -0
- package/dist/mcp/tools/results-evidence.d.ts +112 -0
- package/dist/mcp/tools/results-evidence.js +1045 -0
- package/dist/mcp/tools/results-evidence.js.map +1 -0
- package/dist/mcp/tools/task-create.d.ts +70 -0
- package/dist/mcp/tools/task-create.js +473 -0
- package/dist/mcp/tools/task-create.js.map +1 -0
- package/dist/mcp/tools/task-reads.d.ts +102 -0
- package/dist/mcp/tools/task-reads.js +689 -0
- package/dist/mcp/tools/task-reads.js.map +1 -0
- package/dist/mcp/tools/work-organisation.d.ts +2 -0
- package/dist/mcp/tools/work-organisation.js +502 -0
- package/dist/mcp/tools/work-organisation.js.map +1 -0
- package/dist/paths.d.ts +17 -7
- package/dist/paths.js +18 -8
- package/dist/paths.js.map +1 -1
- package/dist/runs/project-writer.js +76 -11
- package/dist/runs/project-writer.js.map +1 -1
- package/dist/runs/retention.d.ts +25 -2
- package/dist/runs/retention.js +63 -2
- package/dist/runs/retention.js.map +1 -1
- package/dist/server/forge/github.js +44 -0
- package/dist/server/forge/github.js.map +1 -1
- package/dist/server/forge/types.d.ts +16 -0
- package/dist/server/project-context.d.ts +81 -8
- package/dist/server/project-context.js +143 -35
- package/dist/server/project-context.js.map +1 -1
- package/dist/server/server.d.ts +1050 -53
- package/dist/server/server.js +326 -120
- package/dist/server/server.js.map +1 -1
- package/dist/server/validators.d.ts +26 -6
- package/dist/server/validators.js +17 -0
- package/dist/server/validators.js.map +1 -1
- package/dist/skills-remote.js +64 -6
- package/dist/skills-remote.js.map +1 -1
- package/dist/workflows/run.d.ts +277 -12
- package/dist/workflows/run.js +599 -79
- package/dist/workflows/run.js.map +1 -1
- package/dist/workspace/agent-profiles.d.ts +30 -3
- package/dist/workspace/agent-profiles.js +39 -4
- package/dist/workspace/agent-profiles.js.map +1 -1
- package/dist/workspace/config.js +25 -4
- package/dist/workspace/config.js.map +1 -1
- package/dist/workspace/project-owner.d.ts +210 -0
- package/dist/workspace/project-owner.js +518 -0
- package/dist/workspace/project-owner.js.map +1 -0
- package/package.json +5 -3
- package/scripts/pi-leader-extension.ts +420 -0
- package/scripts/sync-readme.mjs +83 -2
- package/web/dist/assets/{alert-dialog-BVsVcbFy.js → alert-dialog-D6rP6d39.js} +1 -1
- package/web/dist/assets/arrow-down-DMOfFIzW.js +1 -0
- package/web/dist/assets/arrow-left-C4Ec2BUg.js +1 -0
- package/web/dist/assets/{centered-state-Djgly6Ni.js → centered-state-B0ZqrPaa.js} +12 -12
- package/web/dist/assets/chevron-right-mHJ-crvn.js +1 -0
- package/web/dist/assets/{collapsible-DZ4D-DHG.js → collapsible-DchEHgUM.js} +1 -1
- package/web/dist/assets/{commit-list-B-z1JL9G.js → commit-list-BpMim1Rv.js} +1 -1
- package/web/dist/assets/{compare-variants-CdS8r8E2.js → compare-variants-D5ItQbAq.js} +1 -1
- package/web/dist/assets/{diff-BKew9rQX.js → diff-HqqZ_WDR.js} +2 -2
- package/web/dist/assets/{diff-stat-D0mc5V6Z.js → diff-stat-NsU-3ecr.js} +1 -1
- package/web/dist/assets/{diff-view-xpIcuLIC.js → diff-view-B7c11Xux.js} +1 -1
- package/web/dist/assets/{dropdown-menu-CEQziH7X.js → dropdown-menu-CtTpnyod.js} +1 -1
- package/web/dist/assets/{editable-title-BCX3T2BY.js → editable-title-BXtuGQry.js} +1 -1
- package/web/dist/assets/{ellipsis-vertical-ByVdDc4z.js → ellipsis-vertical-MHtGZSH6.js} +1 -1
- package/web/dist/assets/{file-xBSB5hXO.js → file-DKLw5SOb.js} +1 -1
- package/web/dist/assets/{folder-CldgbZ5A.js → folder-Drw6-ufH.js} +1 -1
- package/web/dist/assets/{git-toolbar-BYlnf4qf.js → git-toolbar-BQH8bORV.js} +1 -1
- package/web/dist/assets/github-ynnpKFCJ.js +1 -0
- package/web/dist/assets/{image-preview-Cv5mZr0n.js → image-preview-DLhMN_R9.js} +1 -1
- package/web/dist/assets/index-BEsrNdXt.js +29 -0
- package/web/dist/assets/index-Da8DOBau.css +2 -0
- package/web/dist/assets/{markdown-CgEEE2ND.js → markdown-q365eN6Y.js} +1 -1
- package/web/dist/assets/{new-task-form-1r2bgsdD.js → new-task-form-CW-hNIWQ.js} +1 -1
- package/web/dist/assets/{pill-q-x22_ej.js → pill-B_TFulXa.js} +1 -1
- package/web/dist/assets/{project-router-VDN4jQM8.js → project-router-CLPc-ImZ.js} +1 -1
- package/web/dist/assets/{prompt-templates-BmZtCe-L.js → prompt-templates-CLc4RxyO.js} +1 -1
- package/web/dist/assets/{repo-git-C2On8SlI.js → repo-git-Is7R6-Tj.js} +1 -1
- package/web/dist/assets/{run-diff-vguEMJzh.js → run-diff-DHMvDlVo.js} +2 -2
- package/web/dist/assets/run-header-DvZJbQ8I.js +1 -0
- package/web/dist/assets/{search-x-QmhaAbg5.js → search-x-Ce2MMetu.js} +1 -1
- package/web/dist/assets/{skill-empty-hint-BrzUwByZ.js → skill-empty-hint-C_xCSvzB.js} +1 -1
- package/web/dist/assets/skills-CivqD4si.js +1 -0
- package/web/dist/assets/{sparkles-CP8QDOgX.js → sparkles-BCqPoj5g.js} +1 -1
- package/web/dist/assets/{square-terminal-CGypshSD.js → square-terminal-ikj5g-oK.js} +1 -1
- package/web/dist/assets/{tab-link-D4lFzzI1.js → tab-link-VsEjFV1Y.js} +1 -1
- package/web/dist/assets/{task-changes-6aopqAmV.js → task-changes-CH-E81-_.js} +1 -1
- package/web/dist/assets/{task-commits-u-dwaCyw.js → task-commits-DqfkMFxp.js} +1 -1
- package/web/dist/assets/{task-files-IMOZnIUK.js → task-files-D_nkHZ_a.js} +2 -2
- package/web/dist/assets/task-thread-bxQompxJ.js +9 -0
- package/web/dist/assets/{textarea-CyBCyKIk.js → textarea-xajuW1L_.js} +1 -1
- package/web/dist/assets/{thread-loading-Cuq2jchC.js → thread-loading-C3JQZbIE.js} +1 -1
- package/web/dist/assets/{trash-2-B6Dp3ZNs.js → trash-2-hJrBhpUD.js} +1 -1
- package/web/dist/assets/{triangle-alert-xBya8FUp.js → triangle-alert-D1u82y1a.js} +1 -1
- package/web/dist/assets/{upload-D6MXEB9p.js → upload-Bn6FBZ59.js} +1 -1
- package/web/dist/assets/{use-desktop-fLDKEJoB.js → use-desktop-DOIMfHfY.js} +1 -1
- package/web/dist/assets/{use-submit-shortcut-JTpNzU-u.js → use-submit-shortcut-Dj4DHTdE.js} +1 -1
- package/web/dist/assets/utils-YwBpOoRN.js +64 -0
- package/web/dist/assets/{workflows-BY3KTkFw.js → workflows-CTaAKz2m.js} +3 -3
- package/web/dist/assets/{zoomable-image-GTYwLtkS.js → zoomable-image-C1-6P3tg.js} +1 -1
- package/web/dist/index.html +23 -23
- package/web/dist/assets/arrow-down-CYgAlZtW.js +0 -1
- package/web/dist/assets/arrow-left-BOqE0a3k.js +0 -1
- package/web/dist/assets/chevron-right-Cc9BWnbN.js +0 -1
- package/web/dist/assets/github-CqGK62Lw.js +0 -1
- package/web/dist/assets/index-3nxVmdn5.css +0 -2
- package/web/dist/assets/index-qX7n11FX.js +0 -9
- package/web/dist/assets/refresh-cw-DcNCj2nu.js +0 -1
- package/web/dist/assets/run-header-DM7MiKj9.js +0 -1
- package/web/dist/assets/skills-Bj-uG_Hz.js +0 -1
- package/web/dist/assets/task-thread-CbMPmrWq.js +0 -9
- package/web/dist/assets/utils--z9hRtl3.js +0 -64
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { MCP_JOURNAL_RETAINED_ROWS, mcpJournalOperationIdSchema, mcpJournalProjectIdSchema, mcpJournalRowSchema, } from '../contract/index.js';
|
|
2
|
+
import { RECEIPT_MAX_KEPT } from './operation-receipts.js';
|
|
3
|
+
/**
|
|
4
|
+
* The leader-side echo guard (#106, F-13): what stands between the project's event journal and a
|
|
5
|
+
* project-bound leader, so the leader sees human changes and new outcomes and never its own echoes.
|
|
6
|
+
*
|
|
7
|
+
* WHY IT EXISTS. A leader that reacts to every row would react to the row its OWN mutation
|
|
8
|
+
* produced, mutate again, and read that echo too — a loop that costs a model turn per lap and never
|
|
9
|
+
* ends. The compatibility report states the rule: do not react recursively to the leader's own
|
|
10
|
+
* operation acknowledgements; keep causal origin so real new outcomes stay actionable while echoes,
|
|
11
|
+
* duplicate delivery and presentation updates do not trigger loops.
|
|
12
|
+
*
|
|
13
|
+
* THE SOURCE. The same state source as the cockpit, after project filtering (requirements § 8):
|
|
14
|
+
* the per-project journal (#103), fed from the shared services an MCP write goes through. Never the
|
|
15
|
+
* workspace stream — `/api/v1/workspace/events` carries every project and the registry news, and an
|
|
16
|
+
* unfiltered workspace stream reaching MCP is exactly what § 8 prohibits (D-05 § 6.4).
|
|
17
|
+
*
|
|
18
|
+
* THE RULES, in the order `admit` applies them. A row is delivered only when it survives all six:
|
|
19
|
+
* 1. `invalid` — it does not parse as a journal row (`mcpJournalRowSchema`).
|
|
20
|
+
* 2. `foreign-project` — it names a project other than the one this session is bound to (N-01).
|
|
21
|
+
* 3. `workspace-only` — its `kind` is a workspace-only event name. `project-added`,
|
|
22
|
+
* `project-removed` and `checkout-progress` name OTHER projects; N-01 forbids a project-bound
|
|
23
|
+
* session ever receiving one, whatever category an emitter filed it under.
|
|
24
|
+
* 4. `presentation` — its `kind` is presentation, a log line or a counter: D-05 § 6.3's
|
|
25
|
+
* closed negative list plus the SSE stream's own `usage` and `ping`. The journal should never
|
|
26
|
+
* hold one (issue #104's catalog excludes them); this is the leader's own floor under that.
|
|
27
|
+
* 5. `own-echo` — `origin` is `leader` AND `causedBy` is an operation THIS guard issued.
|
|
28
|
+
* Exactly D-05 § 6.3's rule. Never "I recognise the run": a task the leader started still
|
|
29
|
+
* reports its completion (`origin: system`) and a human's edit to it (`origin: human`), and a
|
|
30
|
+
* `leader` row caused by an operation this guard never issued — another session's — is news.
|
|
31
|
+
* 6. `duplicate` — its `eventId` was already delivered. Delivery is at-least-once (D-05
|
|
32
|
+
* § 6.6), and a replay overlapping the live feed must not wake the leader twice.
|
|
33
|
+
*
|
|
34
|
+
* ORDERING IS THE WHOLE TRICK. The service writes the echo while the operation is still in flight:
|
|
35
|
+
* `PATCH /runs/:id` updates the store synchronously inside the route, so the row can reach the
|
|
36
|
+
* journal before the tool result reaches the leader. An operation id recorded on ACKNOWLEDGEMENT
|
|
37
|
+
* would therefore miss its own echo. `issue` records the id first and only then dispatches, so no
|
|
38
|
+
* interleaving can deliver an echo of an operation the guard does not yet know about.
|
|
39
|
+
*
|
|
40
|
+
* WHAT IT IS NOT. Not the journal (#103), not the catalog emitter (#104), not replay/reconnect
|
|
41
|
+
* (#105) and not the event controller (#107): those produce, page and dispatch rows, and each of
|
|
42
|
+
* them hands rows to `admit`. It grants nothing, persists nothing and opens no file.
|
|
43
|
+
*/
|
|
44
|
+
/** The workspace-only names N-01 keeps away from a project-bound session: each names other projects. */
|
|
45
|
+
export const WORKSPACE_ONLY_EVENT_NAMES = ['project-added', 'project-removed', 'checkout-progress'];
|
|
46
|
+
/**
|
|
47
|
+
* Presentation, log lines and counters (requirements § 6): D-05 § 6.3's decided-negative list, plus
|
|
48
|
+
* the two stream signals the brief names as the traffic that must not become leader events.
|
|
49
|
+
*/
|
|
50
|
+
export const PRESENTATION_EVENT_KINDS = [
|
|
51
|
+
'item.started',
|
|
52
|
+
'item.completed',
|
|
53
|
+
'tool-call',
|
|
54
|
+
'tool-result',
|
|
55
|
+
'text',
|
|
56
|
+
'token-usage',
|
|
57
|
+
'cost',
|
|
58
|
+
'usage',
|
|
59
|
+
'ping',
|
|
60
|
+
];
|
|
61
|
+
const WORKSPACE_ONLY = new Set(WORKSPACE_ONLY_EVENT_NAMES);
|
|
62
|
+
const PRESENTATION = new Set(PRESENTATION_EVENT_KINDS);
|
|
63
|
+
/**
|
|
64
|
+
* A remembered set that forgets its oldest entry past `max`. Both bounds below are REUSED, not
|
|
65
|
+
* chosen: an operation can only echo while its receipt is kept (D-09 B-21), and a row can only be
|
|
66
|
+
* redelivered while the journal retains it (B-19).
|
|
67
|
+
*/
|
|
68
|
+
class BoundedSet {
|
|
69
|
+
max;
|
|
70
|
+
#items = new Set();
|
|
71
|
+
constructor(max) {
|
|
72
|
+
this.max = max;
|
|
73
|
+
}
|
|
74
|
+
has(value) {
|
|
75
|
+
return this.#items.has(value);
|
|
76
|
+
}
|
|
77
|
+
add(value) {
|
|
78
|
+
if (this.#items.has(value))
|
|
79
|
+
return;
|
|
80
|
+
this.#items.add(value);
|
|
81
|
+
if (this.#items.size > this.max)
|
|
82
|
+
this.#items.delete(this.#items.values().next().value);
|
|
83
|
+
}
|
|
84
|
+
clear() {
|
|
85
|
+
this.#items.clear();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
export class EchoGuard {
|
|
89
|
+
projectId;
|
|
90
|
+
#own = new BoundedSet(RECEIPT_MAX_KEPT);
|
|
91
|
+
#delivered = new BoundedSet(MCP_JOURNAL_RETAINED_ROWS);
|
|
92
|
+
constructor(options) {
|
|
93
|
+
// A resolved slug only: the `default` alias names no journal, and a guard on it would compare
|
|
94
|
+
// every row against a project id no row can carry.
|
|
95
|
+
this.projectId = mcpJournalProjectIdSchema.parse(options.projectId);
|
|
96
|
+
if (this.projectId === 'default')
|
|
97
|
+
throw new Error('an echo guard needs a resolved project id, not the boot alias');
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Record `operationId` as this leader's own, THEN run `dispatch`. The only way to issue an
|
|
101
|
+
* operation through the guard, so the id is always known before its echo can exist.
|
|
102
|
+
*/
|
|
103
|
+
async issue(operationId, dispatch) {
|
|
104
|
+
this.#own.add(mcpJournalOperationIdSchema.parse(operationId));
|
|
105
|
+
return dispatch();
|
|
106
|
+
}
|
|
107
|
+
/** Whether `operationId` is one this guard issued. */
|
|
108
|
+
isOwn(operationId) {
|
|
109
|
+
return this.#own.has(operationId);
|
|
110
|
+
}
|
|
111
|
+
/** Decide one row. Pure apart from remembering what it delivered; never throws. */
|
|
112
|
+
admit(candidate) {
|
|
113
|
+
const parsed = mcpJournalRowSchema.safeParse(candidate);
|
|
114
|
+
if (!parsed.success)
|
|
115
|
+
return { deliver: false, reason: 'invalid' };
|
|
116
|
+
const row = parsed.data;
|
|
117
|
+
if (row.projectId !== this.projectId)
|
|
118
|
+
return { deliver: false, reason: 'foreign-project' };
|
|
119
|
+
if (WORKSPACE_ONLY.has(row.kind))
|
|
120
|
+
return { deliver: false, reason: 'workspace-only' };
|
|
121
|
+
if (PRESENTATION.has(row.kind))
|
|
122
|
+
return { deliver: false, reason: 'presentation' };
|
|
123
|
+
if (row.origin === 'leader' && row.causedBy !== null && this.#own.has(row.causedBy)) {
|
|
124
|
+
return { deliver: false, reason: 'own-echo' };
|
|
125
|
+
}
|
|
126
|
+
if (this.#delivered.has(row.eventId))
|
|
127
|
+
return { deliver: false, reason: 'duplicate' };
|
|
128
|
+
this.#delivered.add(row.eventId);
|
|
129
|
+
return { deliver: true, row };
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Forget which rows were delivered — for a journal that was recreated (`cursor_too_old` after a
|
|
133
|
+
* new epoch restarts `journalSeq`, and therefore `eventId`, at 1). The operations this leader
|
|
134
|
+
* issued are kept: an echo of one is still an echo after the journal changed.
|
|
135
|
+
*/
|
|
136
|
+
forgetDelivered() {
|
|
137
|
+
this.#delivered.clear();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Attach a guarded leader feed to the bound project's journal. `deliver` sees only admitted rows;
|
|
142
|
+
* `onDrop`, when given, sees every refusal (for tests and diagnostics — never for the leader).
|
|
143
|
+
* Returns the unsubscribe, which the caller must keep: a feed nobody detaches is a listener the
|
|
144
|
+
* journal holds for ever.
|
|
145
|
+
*/
|
|
146
|
+
export function attachLeaderFeed(options) {
|
|
147
|
+
const { journal, guard, deliver, onDrop } = options;
|
|
148
|
+
if (journal.projectId !== guard.projectId) {
|
|
149
|
+
// Refused without naming either project: the session knows its own, the other is not its business.
|
|
150
|
+
throw new Error("a leader feed attaches only to its own project's journal");
|
|
151
|
+
}
|
|
152
|
+
return journal.subscribe((row) => {
|
|
153
|
+
const verdict = guard.admit(row);
|
|
154
|
+
if (verdict.deliver)
|
|
155
|
+
deliver(verdict.row);
|
|
156
|
+
else
|
|
157
|
+
onDrop?.(verdict.reason, row);
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=echo-guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"echo-guard.js","sourceRoot":"","sources":["../../src/mcp/echo-guard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { type McpJournalAppendInput, type McpJournalOrigin, type McpJournalRow, type ProviderStatus } from '../contract/index.js';
|
|
2
|
+
import type { RunStore } from '../runs/store.ts';
|
|
3
|
+
/**
|
|
4
|
+
* The significant-event catalog E-01–E-06 (#104): what enters the project journal (#103), and —
|
|
5
|
+
* equally binding — what never does. Kinds and categories are `packages/contract/src/
|
|
6
|
+
* mcp-event-catalog.ts`; the journal is `./event-journal.ts`.
|
|
7
|
+
*
|
|
8
|
+
* WHERE THE ROWS COME FROM. N-02: nothing here is an MCP-only path. The catalog LISTENS to the
|
|
9
|
+
* shared services the cockpit already drives — the `RunStore` bus (`'run'` snapshots and `'event'`
|
|
10
|
+
* lines, the same two the SSE streams relay) and the workspace bus (`provider-status`) — so a
|
|
11
|
+
* change caused through the cockpit and one caused through MCP reach the same derivation and
|
|
12
|
+
* produce the same row. The two changes that have no in-process signal today (a configuration
|
|
13
|
+
* write and a workflow write, E-05) are reported by their writer through `configChanged` /
|
|
14
|
+
* `workflowChanged` / `agentConfigChanged`.
|
|
15
|
+
*
|
|
16
|
+
* WHAT ENTERS, derived rather than forwarded (D-05 § 5.1 — a terminal status is not an event type):
|
|
17
|
+
* - E-01 a run status transition to `done` / `failed` / `cancelled`, or to `waiting` WITHOUT a
|
|
18
|
+
* structured question (`task.blocked` — the run cannot go on without input);
|
|
19
|
+
* - E-02 a transition to `waiting` that follows an `ask.requested` line (`question.asked`), and a
|
|
20
|
+
* human `user-message` to a run that was `waiting` (`question.answered`);
|
|
21
|
+
* - E-03 a CHECK step settling `done`/`failed` (a quality gate), and a transition to `review` —
|
|
22
|
+
* F-11 keeps the optional review a different kind from a mandatory gate;
|
|
23
|
+
* - E-04 a HUMAN edit of a queued run's prompt (`goal.changed`), a human message to a run that
|
|
24
|
+
* was not waiting (`instruction.added`), and a human add/edit/remove of a queued message;
|
|
25
|
+
* - E-05 the writer-reported configuration, workflow and agent-config changes, minus the keys
|
|
26
|
+
* that only change presentation (`liveTitleUpdates`, `namerModel` only name tasks);
|
|
27
|
+
* - E-06 a provider's availability (`connected` and not disabled) flipping.
|
|
28
|
+
*
|
|
29
|
+
* WHAT NEVER ENTERS. Every other `'event'` type — `item.*`, `tool-call`, `tool-result`, `text`,
|
|
30
|
+
* `note` and `check-output` (log lines), `token-usage`, `cost`, `usage.updated` (token counters),
|
|
31
|
+
* `lifecycle`, `step-*`, `turn.*`, `session.*`, and every ephemeral live frame. Every other record
|
|
32
|
+
* change — token/cost/RSS counters, `diffStat`, titles and `titleSummary`, `seenAt`, pin, archive,
|
|
33
|
+
* the `monitoring` activity, `queued`→`running`. Every other workspace event — `checkout-progress`,
|
|
34
|
+
* `project-*`, `automation-change`. The SSE `ping` keepalive is never on a bus at all. None of
|
|
35
|
+
* these start a model turn: no heartbeat, transport retry, acknowledgement or deduplication does.
|
|
36
|
+
* There is no coalescing either (D-05 § 8 N3): one qualifying change is exactly one row.
|
|
37
|
+
*
|
|
38
|
+
* ORIGIN (D-05 § 6.3: `human | leader | system`). Derived from the door a change came through,
|
|
39
|
+
* never from anything a client says. The MCP door marks its dispatch with `withEventOrigin`
|
|
40
|
+
* (`leader` + the operation id); a change made synchronously inside that call inherits it through
|
|
41
|
+
* `AsyncLocalStorage`. A change that lands LATER — cancelling a running task interrupts its agent,
|
|
42
|
+
* and the `cancelled` status is written when the process exits — cannot inherit it, so the call
|
|
43
|
+
* also leaves an INTENT on the run it names, consumed by that run's next status transition. With
|
|
44
|
+
* neither, each derivation has its own honest default: an engine transition is `system`; a
|
|
45
|
+
* cancellation, a message and a queued-prompt edit only ever start at a person's request, so they
|
|
46
|
+
* are `human` (the cockpit is the only other door that issues them). E-04 is a HUMAN change by
|
|
47
|
+
* definition: a leader's own edit writes no E-04 row, and neither does a leader's answer to a
|
|
48
|
+
* question — while a cancellation, whoever issued it, writes the SAME E-01 row, distinguishable
|
|
49
|
+
* only by `origin` and `causedBy`, which is what the F-13 echo guard needs.
|
|
50
|
+
*
|
|
51
|
+
* Never throws into the service that emitted the change: the store emits from inside its own
|
|
52
|
+
* write, and a journal problem must not fail a task. A row that cannot be written is warned about
|
|
53
|
+
* once and dropped — the journal keeps its sequence gapless by not spending a number (#103).
|
|
54
|
+
*
|
|
55
|
+
* NOT READ HERE: nothing private to `RunManager`, in particular no `ActiveRun` field — `ActiveRun`
|
|
56
|
+
* is built in both `execute` and `runContinuation`, and this module depends on neither. A Continue
|
|
57
|
+
* and a restart recovery reach the same store calls, and therefore the same rows, as a first run.
|
|
58
|
+
*/
|
|
59
|
+
/** Who caused a change, as the door it came through knows it. */
|
|
60
|
+
export interface EventOriginContext {
|
|
61
|
+
readonly origin: McpJournalOrigin;
|
|
62
|
+
/** The leader operation id (D-06 § 5.2) — required for `leader`, `null` otherwise. */
|
|
63
|
+
readonly causedBy: string | null;
|
|
64
|
+
/** The run the operation targets, when it has one: the intent a later transition consumes. */
|
|
65
|
+
readonly runId?: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Run `fn` as a change caused by `context`. The MCP door wraps each dispatched operation in this;
|
|
69
|
+
* nothing else needs to. Throws only on a caller bug: a `leader` context without a valid
|
|
70
|
+
* operation id would defeat the echo guard it exists for.
|
|
71
|
+
*/
|
|
72
|
+
export declare function withEventOrigin<T>(context: EventOriginContext, fn: () => T): T;
|
|
73
|
+
/** The journal as the catalog writes it — `EventJournal` satisfies it. */
|
|
74
|
+
export interface CatalogJournal {
|
|
75
|
+
append(input: McpJournalAppendInput): McpJournalRow | undefined;
|
|
76
|
+
}
|
|
77
|
+
/** The workspace bus as the catalog reads it — `WorkspaceEventBus` satisfies it. */
|
|
78
|
+
export interface WorkspaceEventSource {
|
|
79
|
+
on(listener: (event: string, data: unknown) => void): () => void;
|
|
80
|
+
}
|
|
81
|
+
export interface EventCatalogOptions {
|
|
82
|
+
journal: CatalogJournal;
|
|
83
|
+
/** The project's store. Runs already in it are the baseline: attaching writes no row. */
|
|
84
|
+
store: RunStore;
|
|
85
|
+
/** Host-wide `provider-status` (E-06). Absent: no executor rows, nothing else changes. */
|
|
86
|
+
workspaceEvents?: WorkspaceEventSource;
|
|
87
|
+
/** Provider rows as they are at attach time (`ProviderAuth.status()`), the E-06 baseline. A
|
|
88
|
+
* provider seen for the first time without one counts as a change. */
|
|
89
|
+
providerBaseline?: readonly ProviderStatus[];
|
|
90
|
+
/** Where the one warning about an unwritable row goes. */
|
|
91
|
+
warn?: (message: string) => void;
|
|
92
|
+
}
|
|
93
|
+
export declare class EventCatalog {
|
|
94
|
+
#private;
|
|
95
|
+
private constructor();
|
|
96
|
+
/** Start deriving rows from the project's services. Returns the catalog; `detach` stops it. */
|
|
97
|
+
static attach(options: EventCatalogOptions): EventCatalog;
|
|
98
|
+
/** Stop listening. Every subscription `attach` made is released — none outlives the catalog. */
|
|
99
|
+
detach(): void;
|
|
100
|
+
/**
|
|
101
|
+
* E-05: the project configuration was written (`PUT /config`). `keys` are the fields the write
|
|
102
|
+
* set or cleared — names only, never values. A write that touched nothing but presentation
|
|
103
|
+
* writes no row.
|
|
104
|
+
*/
|
|
105
|
+
configChanged(input: {
|
|
106
|
+
keys: readonly string[];
|
|
107
|
+
version?: string | null;
|
|
108
|
+
}): McpJournalRow | undefined;
|
|
109
|
+
/** E-05: a project workflow was saved or deleted (`POST /workflows`, `DELETE /workflows/:name`). */
|
|
110
|
+
workflowChanged(input: {
|
|
111
|
+
name: string;
|
|
112
|
+
change: 'saved' | 'deleted';
|
|
113
|
+
version?: string | null;
|
|
114
|
+
}): McpJournalRow | undefined;
|
|
115
|
+
/** E-05: an agent configuration file was written (`PUT /agent-config/:id`), by catalog id. */
|
|
116
|
+
agentConfigChanged(input: {
|
|
117
|
+
id: string;
|
|
118
|
+
version?: string | null;
|
|
119
|
+
}): McpJournalRow | undefined;
|
|
120
|
+
}
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
import { MCP_EVENT_KIND_CATEGORY, mcpJournalOperationIdSchema, providerStatusSchema, } from '../contract/index.js';
|
|
3
|
+
import { runVersion } from './stale-write.js';
|
|
4
|
+
/**
|
|
5
|
+
* The origin of the call in flight, and whether that call is still in flight. `AsyncLocalStorage`
|
|
6
|
+
* alone would also hand the context to every async chain the call merely STARTED — a task started
|
|
7
|
+
* through MCP runs for minutes on the promise chain its start created, and its completion would read
|
|
8
|
+
* as the leader's own change, which the echo guard then hides from the leader (#243). `live` ends
|
|
9
|
+
* that at the call's own settlement, so only a change made within the call inherits its origin.
|
|
10
|
+
*/
|
|
11
|
+
const originScope = new AsyncLocalStorage();
|
|
12
|
+
/** The origin of the change being made right now, if an origin-marked call is still making it. */
|
|
13
|
+
function currentOrigin() {
|
|
14
|
+
const scope = originScope.getStore();
|
|
15
|
+
return scope?.live ? scope.context : undefined;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Intents left by an origin-marked call for a run whose effect lands after the call returned. One
|
|
19
|
+
* per run; consumed by the run's next status transition, whether or not that transition writes a
|
|
20
|
+
* row, so an intent never outlives the change it was for by more than one transition.
|
|
21
|
+
*/
|
|
22
|
+
const pendingIntents = new Map();
|
|
23
|
+
/**
|
|
24
|
+
* Run `fn` as a change caused by `context`. The MCP door wraps each dispatched operation in this;
|
|
25
|
+
* nothing else needs to. Throws only on a caller bug: a `leader` context without a valid
|
|
26
|
+
* operation id would defeat the echo guard it exists for.
|
|
27
|
+
*/
|
|
28
|
+
export function withEventOrigin(context, fn) {
|
|
29
|
+
if (context.origin === 'leader' && !mcpJournalOperationIdSchema.safeParse(context.causedBy).success) {
|
|
30
|
+
throw new Error('a leader change must name the operation that caused it');
|
|
31
|
+
}
|
|
32
|
+
if (context.origin !== 'leader' && context.causedBy !== null) {
|
|
33
|
+
throw new Error('only a leader change carries an operation id');
|
|
34
|
+
}
|
|
35
|
+
if (context.runId !== undefined)
|
|
36
|
+
pendingIntents.set(context.runId, context);
|
|
37
|
+
const scope = { context, live: true };
|
|
38
|
+
const end = () => {
|
|
39
|
+
scope.live = false;
|
|
40
|
+
};
|
|
41
|
+
let result;
|
|
42
|
+
try {
|
|
43
|
+
result = originScope.run(scope, fn);
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
end();
|
|
47
|
+
throw err;
|
|
48
|
+
}
|
|
49
|
+
const pending = result;
|
|
50
|
+
// Observed, never rethrown from here: the caller still receives `result` itself, rejection and all.
|
|
51
|
+
if (pending !== null && typeof pending === 'object' && typeof pending.then === 'function') {
|
|
52
|
+
result.then(end, end);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
end();
|
|
56
|
+
}
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
/** Configuration keys whose only effect is how tasks are NAMED — presentation, not execution. */
|
|
60
|
+
const PRESENTATION_CONFIG_KEYS = new Set(['liveTitleUpdates', 'namerModel']);
|
|
61
|
+
const SUBJECT_ID_MAX = 256;
|
|
62
|
+
function remember(run, askedQuestions) {
|
|
63
|
+
return {
|
|
64
|
+
status: run.status,
|
|
65
|
+
task: run.task,
|
|
66
|
+
queued: new Map((run.queuedMessages ?? []).map((message) => [message.id, message.text])),
|
|
67
|
+
steps: new Map(run.steps.map((step) => [step.id, step.status])),
|
|
68
|
+
...(askedQuestions === undefined ? {} : { askedQuestions }),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
export class EventCatalog {
|
|
72
|
+
#journal;
|
|
73
|
+
#store;
|
|
74
|
+
#warn;
|
|
75
|
+
#runs = new Map();
|
|
76
|
+
#executors = new Map();
|
|
77
|
+
#unsubscribe = [];
|
|
78
|
+
#warned = false;
|
|
79
|
+
constructor(options) {
|
|
80
|
+
this.#journal = options.journal;
|
|
81
|
+
this.#store = options.store;
|
|
82
|
+
this.#warn = options.warn ?? ((message) => console.warn(message));
|
|
83
|
+
}
|
|
84
|
+
/** Start deriving rows from the project's services. Returns the catalog; `detach` stops it. */
|
|
85
|
+
static attach(options) {
|
|
86
|
+
const catalog = new EventCatalog(options);
|
|
87
|
+
for (const run of options.store.listRuns())
|
|
88
|
+
catalog.#runs.set(run.id, remember(run));
|
|
89
|
+
for (const row of options.providerBaseline ?? [])
|
|
90
|
+
catalog.#executors.set(executorId(row), isAvailable(row));
|
|
91
|
+
const onRun = (run) => catalog.#guard(() => catalog.#onRun(run));
|
|
92
|
+
const onEvent = (payload) => catalog.#guard(() => catalog.#onEvent(payload.runId, payload.event));
|
|
93
|
+
const onDeleted = (runId) => {
|
|
94
|
+
catalog.#runs.delete(runId);
|
|
95
|
+
pendingIntents.delete(runId);
|
|
96
|
+
};
|
|
97
|
+
options.store.on('run', onRun);
|
|
98
|
+
options.store.on('event', onEvent);
|
|
99
|
+
options.store.on('deleted', onDeleted);
|
|
100
|
+
catalog.#unsubscribe.push(() => options.store.off('run', onRun), () => options.store.off('event', onEvent), () => options.store.off('deleted', onDeleted));
|
|
101
|
+
if (options.workspaceEvents) {
|
|
102
|
+
catalog.#unsubscribe.push(options.workspaceEvents.on((event, data) => {
|
|
103
|
+
if (event === 'provider-status')
|
|
104
|
+
catalog.#guard(() => catalog.#onProviderStatus(data));
|
|
105
|
+
}));
|
|
106
|
+
}
|
|
107
|
+
return catalog;
|
|
108
|
+
}
|
|
109
|
+
/** Stop listening. Every subscription `attach` made is released — none outlives the catalog. */
|
|
110
|
+
detach() {
|
|
111
|
+
for (const unsubscribe of this.#unsubscribe.splice(0))
|
|
112
|
+
unsubscribe();
|
|
113
|
+
this.#runs.clear();
|
|
114
|
+
this.#executors.clear();
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* E-05: the project configuration was written (`PUT /config`). `keys` are the fields the write
|
|
118
|
+
* set or cleared — names only, never values. A write that touched nothing but presentation
|
|
119
|
+
* writes no row.
|
|
120
|
+
*/
|
|
121
|
+
configChanged(input) {
|
|
122
|
+
const keys = [...new Set(input.keys)].filter((key) => !PRESENTATION_CONFIG_KEYS.has(key)).sort();
|
|
123
|
+
if (keys.length === 0)
|
|
124
|
+
return undefined;
|
|
125
|
+
return this.#guard(() => this.#append('config.changed', { type: 'config', id: 'project', version: input.version ?? null }, this.#originOr('human'), `project configuration changed: ${keys.join(', ')}`));
|
|
126
|
+
}
|
|
127
|
+
/** E-05: a project workflow was saved or deleted (`POST /workflows`, `DELETE /workflows/:name`). */
|
|
128
|
+
workflowChanged(input) {
|
|
129
|
+
const kind = input.change === 'saved' ? 'workflow.saved' : 'workflow.deleted';
|
|
130
|
+
return this.#guard(() => this.#append(kind, { type: 'workflow', id: input.name.slice(0, SUBJECT_ID_MAX), version: input.version ?? null }, this.#originOr('human'), `workflow "${clip(input.name, 120)}" ${input.change}`));
|
|
131
|
+
}
|
|
132
|
+
/** E-05: an agent configuration file was written (`PUT /agent-config/:id`), by catalog id. */
|
|
133
|
+
agentConfigChanged(input) {
|
|
134
|
+
return this.#guard(() => this.#append('agent-config.changed', { type: 'agent-config', id: input.id.slice(0, SUBJECT_ID_MAX), version: input.version ?? null }, this.#originOr('human'), `agent configuration ${clip(input.id, 120)} changed`));
|
|
135
|
+
}
|
|
136
|
+
// ---- runs -----------------------------------------------------------------------------------
|
|
137
|
+
#onRun(run) {
|
|
138
|
+
const before = this.#runs.get(run.id);
|
|
139
|
+
// A run seen for the first time — created, or first touched after attach — is the baseline.
|
|
140
|
+
if (!before) {
|
|
141
|
+
this.#runs.set(run.id, remember(run));
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const statusChanged = before.status !== run.status;
|
|
145
|
+
// An unmatched question survives only until the run's status next moves.
|
|
146
|
+
this.#runs.set(run.id, remember(run, statusChanged ? undefined : before.askedQuestions));
|
|
147
|
+
// E-03 — a quality gate settled. Before the status row, which is the order it happened in.
|
|
148
|
+
for (const step of run.steps) {
|
|
149
|
+
if (step.kind !== 'check' || before.steps.get(step.id) === step.status)
|
|
150
|
+
continue;
|
|
151
|
+
if (step.status === 'done' || step.status === 'failed') {
|
|
152
|
+
const passed = step.status === 'done';
|
|
153
|
+
this.#appendRun(passed ? 'gate.passed' : 'gate.failed', run.id, this.#originOr('system'), `quality gate ${clip(step.id, 80)} ${passed ? 'passed' : 'failed'}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// E-04 — the prompt and its stack change only through the queued-prompt edits (#472).
|
|
157
|
+
if (before.task !== run.task)
|
|
158
|
+
this.#humanChange('goal.changed', run.id, 'the queued task prompt was edited');
|
|
159
|
+
const queued = remember(run).queued;
|
|
160
|
+
for (const [id, text] of queued) {
|
|
161
|
+
if (!before.queued.has(id))
|
|
162
|
+
this.#humanChange('instruction.queued', run.id, 'a message was queued onto the task');
|
|
163
|
+
else if (before.queued.get(id) !== text)
|
|
164
|
+
this.#humanChange('instruction.edited', run.id, 'a queued message was edited');
|
|
165
|
+
}
|
|
166
|
+
for (const id of before.queued.keys()) {
|
|
167
|
+
if (!queued.has(id))
|
|
168
|
+
this.#humanChange('instruction.removed', run.id, 'a queued message was removed');
|
|
169
|
+
}
|
|
170
|
+
if (statusChanged)
|
|
171
|
+
this.#onStatus(run, before);
|
|
172
|
+
}
|
|
173
|
+
#onStatus(run, before) {
|
|
174
|
+
const origin = this.#transitionOrigin(run.id, run.status === 'cancelled' ? 'human' : 'system');
|
|
175
|
+
switch (run.status) {
|
|
176
|
+
case 'done':
|
|
177
|
+
this.#appendRun('task.done', run.id, origin, 'task finished: done');
|
|
178
|
+
return;
|
|
179
|
+
case 'failed': {
|
|
180
|
+
const step = run.steps.find((candidate) => candidate.status === 'failed');
|
|
181
|
+
this.#appendRun('task.failed', run.id, origin, step ? `task finished: failed at step ${clip(step.id, 80)}` : 'task finished: failed');
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
case 'cancelled':
|
|
185
|
+
this.#appendRun('task.cancelled', run.id, origin, 'task finished: cancelled');
|
|
186
|
+
return;
|
|
187
|
+
case 'review':
|
|
188
|
+
this.#appendRun('result.ready', run.id, origin, 'result ready for assessment (review)');
|
|
189
|
+
return;
|
|
190
|
+
case 'waiting':
|
|
191
|
+
if (before.askedQuestions !== undefined) {
|
|
192
|
+
this.#appendRun('question.asked', run.id, origin, questionSummary(before.askedQuestions));
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
this.#appendRun('task.blocked', run.id, origin, 'task is waiting for input');
|
|
196
|
+
}
|
|
197
|
+
return;
|
|
198
|
+
default:
|
|
199
|
+
// `queued` and `running` are the engine doing its job, not something to reason about.
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
#onEvent(runId, event) {
|
|
204
|
+
const memory = this.#runs.get(runId);
|
|
205
|
+
if (!memory)
|
|
206
|
+
return;
|
|
207
|
+
if (event.type === 'ask.requested') {
|
|
208
|
+
const count = Array.isArray(event.questions) ? event.questions.length : 1;
|
|
209
|
+
// The engine raises the question and THEN parks the run; a backend that parks first gets
|
|
210
|
+
// its row here instead. Either way: one question, one row.
|
|
211
|
+
if (memory.status === 'waiting') {
|
|
212
|
+
this.#appendRun('question.asked', runId, this.#originOr('system'), questionSummary(count));
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
memory.askedQuestions = count;
|
|
216
|
+
}
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
if (event.type === 'user-message') {
|
|
220
|
+
const origin = this.#originOr('human');
|
|
221
|
+
// A leader's own answer or instruction is its operation, not a human change (E-02/E-04).
|
|
222
|
+
if (origin.origin !== 'human')
|
|
223
|
+
return;
|
|
224
|
+
if (memory.status === 'waiting')
|
|
225
|
+
this.#appendRun('question.answered', runId, origin, 'a human answered the waiting task');
|
|
226
|
+
else
|
|
227
|
+
this.#appendRun('instruction.added', runId, origin, 'a human sent the task a new instruction');
|
|
228
|
+
}
|
|
229
|
+
// Everything else is transcript: log lines, token counters, tool traffic. Never a row.
|
|
230
|
+
}
|
|
231
|
+
#humanChange(kind, runId, summary) {
|
|
232
|
+
const origin = this.#originOr('human');
|
|
233
|
+
if (origin.origin === 'human')
|
|
234
|
+
this.#appendRun(kind, runId, origin, summary);
|
|
235
|
+
}
|
|
236
|
+
/** The origin of a status transition: the current call, else an intent left for this run, else
|
|
237
|
+
* the default. Consumes the intent either way — it was for this transition. */
|
|
238
|
+
#transitionOrigin(runId, fallback) {
|
|
239
|
+
const current = currentOrigin();
|
|
240
|
+
const intent = pendingIntents.get(runId);
|
|
241
|
+
pendingIntents.delete(runId);
|
|
242
|
+
return current ?? intent ?? { origin: fallback, causedBy: null };
|
|
243
|
+
}
|
|
244
|
+
#originOr(fallback) {
|
|
245
|
+
return currentOrigin() ?? { origin: fallback, causedBy: null };
|
|
246
|
+
}
|
|
247
|
+
#appendRun(kind, runId, origin, summary) {
|
|
248
|
+
this.#append(kind, { type: 'run', id: runId, version: runVersion(this.#store, runId) ?? null }, origin, summary);
|
|
249
|
+
}
|
|
250
|
+
// ---- executors --------------------------------------------------------------------------------
|
|
251
|
+
#onProviderStatus(data) {
|
|
252
|
+
const parsed = providerStatusSchema.safeParse(data);
|
|
253
|
+
if (!parsed.success)
|
|
254
|
+
return;
|
|
255
|
+
const id = executorId(parsed.data);
|
|
256
|
+
const available = isAvailable(parsed.data);
|
|
257
|
+
if (this.#executors.get(id) === available)
|
|
258
|
+
return;
|
|
259
|
+
this.#executors.set(id, available);
|
|
260
|
+
this.#append(available ? 'executor.available' : 'executor.unavailable', { type: 'executor', id, version: null }, this.#originOr('system'), available ? `executor ${id} is available` : `executor ${id} is unavailable (${describeUnavailable(parsed.data)})`);
|
|
261
|
+
}
|
|
262
|
+
// ---- writing ------------------------------------------------------------------------------------
|
|
263
|
+
#append(kind, subject, origin, summary) {
|
|
264
|
+
return this.#journal.append({
|
|
265
|
+
category: MCP_EVENT_KIND_CATEGORY[kind],
|
|
266
|
+
kind,
|
|
267
|
+
subject,
|
|
268
|
+
origin: origin.origin,
|
|
269
|
+
causedBy: origin.causedBy,
|
|
270
|
+
summary,
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
#guard(fn) {
|
|
274
|
+
try {
|
|
275
|
+
return fn();
|
|
276
|
+
}
|
|
277
|
+
catch (err) {
|
|
278
|
+
if (!this.#warned) {
|
|
279
|
+
this.#warned = true;
|
|
280
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
281
|
+
this.#warn(`[xez] MCP event catalog could not record an event (${message}) — continuing without it`);
|
|
282
|
+
}
|
|
283
|
+
return undefined;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
function executorId(row) {
|
|
288
|
+
return row.profileId ? `${row.provider}:${row.profileId}` : row.provider;
|
|
289
|
+
}
|
|
290
|
+
/** An executor can take work when it is connected and not switched off in Settings. */
|
|
291
|
+
function isAvailable(row) {
|
|
292
|
+
return row.status === 'connected' && row.enabled !== false;
|
|
293
|
+
}
|
|
294
|
+
/** The coarse state only — never `hint`, which is prose from the CLI. */
|
|
295
|
+
function describeUnavailable(row) {
|
|
296
|
+
if (row.enabled === false)
|
|
297
|
+
return 'disabled';
|
|
298
|
+
return row.status;
|
|
299
|
+
}
|
|
300
|
+
function questionSummary(count) {
|
|
301
|
+
return count === 1 ? 'the agent asked a question and is waiting for an answer' : `the agent asked ${count} questions and is waiting for an answer`;
|
|
302
|
+
}
|
|
303
|
+
function clip(text, max) {
|
|
304
|
+
return text.length <= max ? text : `${text.slice(0, max - 1)}…`;
|
|
305
|
+
}
|
|
306
|
+
//# sourceMappingURL=event-catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-catalog.js","sourceRoot":"","sources":["../../src/mcp/event-catalog.ts"],"names":[],"mappings":"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"}
|