@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,518 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { closeSync, fstatSync, ftruncateSync, mkdirSync, openSync, readFileSync, readdirSync, rmdirSync, statSync, unlinkSync, writeSync } from 'node:fs';
|
|
3
|
+
import { hostname } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { MCP_PROJECT_OCCUPIED_CODE, MCP_PROJECT_OCCUPIED_REASON, MCP_SESSION_EXPIRED_CODE, MCP_SESSION_EXPIRED_REASON, } from '../contract/index.js';
|
|
7
|
+
/**
|
|
8
|
+
* Exclusive per-project MCP ownership (#99), implementing decision D-02
|
|
9
|
+
* (`docs/features/mcp-server/mcp-d02-session-binding-decision.md`). Every number and rule below
|
|
10
|
+
* was fixed there, or adopted by D-09 as B-13 to B-15; none is a knob.
|
|
11
|
+
*
|
|
12
|
+
* One logical MCP session owns a project. The xezar SERVICE holds the owner record on that
|
|
13
|
+
* session's behalf (D-02.1), because the service is where every write is gated — a claim held by
|
|
14
|
+
* something that does not check it before a mutation is decoration. Cross-process exclusion of the
|
|
15
|
+
* service itself is already `ownProjectData`'s job (`runs/project-writer.ts`); this module decides
|
|
16
|
+
* which session INSIDE the owning service may write, and what a returning client is told.
|
|
17
|
+
*
|
|
18
|
+
* Mechanism, in the order a session meets it:
|
|
19
|
+
*
|
|
20
|
+
* - **Acquire** (D-02.2): publish a uniquely named claim with `openSync(path, 'wx', 0o600)`, THEN
|
|
21
|
+
* scan for peers. A live peer means "not the owner", always; dead or expired peers are reaped,
|
|
22
|
+
* which is safe only because the reaper has already published its own claim. Two simultaneous
|
|
23
|
+
* contenders may both refuse, never both succeed, so a refusal retries: 5 attempts, full-jitter
|
|
24
|
+
* backoff over a doubling window capped at 200 ms. Exhaustion answers *project-occupied*.
|
|
25
|
+
* NOT the `mergeWriteWorkspaceConfig` read-modify-write shape, and NOT the unlink-and-retry
|
|
26
|
+
* stale reclaim of `AutomationStore.acquireLease`: D-02 measured both admitting two owners.
|
|
27
|
+
* - **Fence** (D-02.3): acquisition MINTS a token, `<wall-clock ms>-<UUIDv4>`, and every mutation
|
|
28
|
+
* is checked for EQUALITY against the current live owner's token (`checkMutation`). Never
|
|
29
|
+
* derived from what is on disk — reaping deletes exactly what a `max + 1` counter would read, so
|
|
30
|
+
* a derived generation hands the next owner the number the previous owner still holds. The
|
|
31
|
+
* wall-clock prefix is for humans reading logs; nothing fences on it.
|
|
32
|
+
* - **Renew** (D-02.5): a background timer rewrites the claim every 5 s; the lease is 30 s. The
|
|
33
|
+
* timer consumes no model turn, so MODEL SILENCE IS NOT SESSION DEATH — an owner that says
|
|
34
|
+
* nothing for an hour is still the owner.
|
|
35
|
+
* - **Resumed owner** (D-02.5): a renewal that finds the lease already lapsed — a frozen process,
|
|
36
|
+
* a suspended laptop, a claim that vanished — must NOT renew. Renewing a lease that may already
|
|
37
|
+
* have been reclaimed is how two owners are made. It drops its claim and re-runs acquisition
|
|
38
|
+
* from scratch under a NEW token; if it loses, its session is expired.
|
|
39
|
+
* - **Release** (D-02.4, D-02.7): only on confirmed termination (`release`, fired by the transport
|
|
40
|
+
* when the bridge's connection closes — never by one request ending or one stream closing) or
|
|
41
|
+
* expiry. Releasing touches the claim file and this object's own memory, and NOTHING else: this
|
|
42
|
+
* module imports nothing that can reach a run, so a started task keeps running across every
|
|
43
|
+
* handover (N-05). The inverse holds too — a task ending or parking at `waiting` releases
|
|
44
|
+
* nothing.
|
|
45
|
+
*
|
|
46
|
+
* There is no manual disconnect and no forced takeover (F-18): nothing here lets one session evict
|
|
47
|
+
* another. `occupied` is left only by the real owner ending or expiring.
|
|
48
|
+
*
|
|
49
|
+
* ## Every state, and who fires each exit
|
|
50
|
+
*
|
|
51
|
+
* No exit below is a human action, so no state is a dead end.
|
|
52
|
+
*
|
|
53
|
+
* | State | Exit | Who fires it | If nobody fires it |
|
|
54
|
+
* | --- | --- | --- | --- |
|
|
55
|
+
* | unowned | → owned | a client's `initialize`, via `acquire` | stays unowned — the correct resting state; nothing is blocked |
|
|
56
|
+
* | acquiring | → owned / → occupied | the acquiring call itself | bounded: 5 attempts, ≤ 200 ms per backoff |
|
|
57
|
+
* | owned | → unowned | the transport, on connection close (`release`) | falls through to expiry |
|
|
58
|
+
* | owned | → expired | lease arithmetic at every read (`checkMutation`, `state`, the next `acquire`) | no timer is needed: expiry is derived, not stored |
|
|
59
|
+
* | owned, process frozen | → expired | nothing but the lease | the lease IS the exit — the reason it exists |
|
|
60
|
+
* | owner resumed after lost time | → owned (new token) / → expired | the owner's own renewal tick | mandatory, not best-effort: skipping it renews a lost lease |
|
|
61
|
+
* | expired | → unowned / → owned by another | the next `acquire`, which reaps the claim | nothing waits on an expired claim except a would-be owner, whose arrival is the trigger |
|
|
62
|
+
* | fenced session | → a fresh session | the bridge, automatically, on the session-expired error | not a dead end: reconnecting is the client's own protocol obligation |
|
|
63
|
+
* | occupied (a refused second client) | → owned by it, later | that client retrying | the real owner and the cockpit keep working |
|
|
64
|
+
*
|
|
65
|
+
* What reaches a terminal state BECAUSE of this lease: an MCP session (fenced or expired), and
|
|
66
|
+
* nothing else. No run, queue, worktree or executor does.
|
|
67
|
+
*
|
|
68
|
+
* ## Known limits, named rather than hidden
|
|
69
|
+
*
|
|
70
|
+
* - **The wall clock, on purpose.** Leases compare `Date.now()` values, because a monotonic clock
|
|
71
|
+
* stops while a laptop sleeps and would hide exactly the suspension the resumed-owner rule
|
|
72
|
+
* exists for. The cost: a clock set BACKWARDS makes a claim read as fresh until the clock
|
|
73
|
+
* catches up. A dead holder is still freed by the pid probe; only a frozen-but-alive holder
|
|
74
|
+
* waits longer.
|
|
75
|
+
* - **Check, then act.** The fence runs before a mutation starts. A mutation that passed it is not
|
|
76
|
+
* re-checked part-way through its own asynchronous work.
|
|
77
|
+
* - **The lease boundary between processes.** A peer that reads a claim a microsecond after its
|
|
78
|
+
* lease lapsed may reap it while the owner is mid-renewal. The owner detects an unlinked claim
|
|
79
|
+
* after writing (`nlink === 0`) and re-acquires; a reap landing after that check is caught on
|
|
80
|
+
* the next tick. Two services cannot both hold a project's data anyway (`ownProjectData`).
|
|
81
|
+
* - **A connected but wedged bridge** keeps ownership until its transport closes: D-02.4 leaves an
|
|
82
|
+
* application-level `ping` Open, and this module implements the three signals D-02 decided.
|
|
83
|
+
*
|
|
84
|
+
* ## Where the claim lives (D-02.8)
|
|
85
|
+
*
|
|
86
|
+
* `<dataDir>/mcp-owner-claims/<pid>-<uuid>.json`, `0600`, in the bound project's own `.local/xezar`
|
|
87
|
+
* — gitignored, per project, deletable at any moment (the next acquisition rebuilds it, and the
|
|
88
|
+
* minted token keeps a pre-deletion owner fenced). Not in `~/.xezar/config.json`: that file merges
|
|
89
|
+
* additively, and mutual exclusion is not additive. D-02 left the exact directory name open and
|
|
90
|
+
* D-04 did not claim it; `mcp-owner-claims` is the smallest name that says what it holds.
|
|
91
|
+
*/
|
|
92
|
+
/** Renewal interval. D-02.5; D-09 B-13. */
|
|
93
|
+
export const OWNER_RENEW_INTERVAL_MS = 5_000;
|
|
94
|
+
/** Owner lease. D-02.5; D-09 B-14. */
|
|
95
|
+
export const OWNER_LEASE_MS = 30_000;
|
|
96
|
+
/** Acquisition attempts before answering project-occupied. D-02.2; D-09 B-15. */
|
|
97
|
+
export const OWNER_ACQUIRE_ATTEMPTS = 5;
|
|
98
|
+
/** Cap on the doubling full-jitter backoff window. D-02.2; D-09 B-15. */
|
|
99
|
+
export const OWNER_BACKOFF_CAP_MS = 200;
|
|
100
|
+
/**
|
|
101
|
+
* The window the doubling starts from. D-02 fixed the attempts and the cap but not the start;
|
|
102
|
+
* 25 ms doubles to the cap at the last retry (25, 50, 100, 200), so the whole budget waits at most
|
|
103
|
+
* 375 ms — inside the same order as the 98 ms worst case D-02 measured at eight contenders.
|
|
104
|
+
*/
|
|
105
|
+
const OWNER_BACKOFF_BASE_MS = 25;
|
|
106
|
+
/** The claim directory's name inside the project's data directory. */
|
|
107
|
+
export const OWNER_CLAIM_DIR = 'mcp-owner-claims';
|
|
108
|
+
const CLAIM_NAME = /^([1-9]\d*)-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.json$/;
|
|
109
|
+
/** The on-disk claim — local runtime state, never an API shape, so it lives here. It holds no
|
|
110
|
+
* session key: the file identifies a holder process and a lease, not a client. */
|
|
111
|
+
const claimSchema = z.object({
|
|
112
|
+
v: z.literal(1),
|
|
113
|
+
token: z.string(),
|
|
114
|
+
pid: z.number().int().positive(),
|
|
115
|
+
host: z.string(),
|
|
116
|
+
acquiredAt: z.number(),
|
|
117
|
+
renewedAt: z.number(),
|
|
118
|
+
});
|
|
119
|
+
/** The project-occupied error. Carries the project's own id and nothing about the owner (N-01). */
|
|
120
|
+
export function projectOccupiedError(projectId) {
|
|
121
|
+
return {
|
|
122
|
+
code: MCP_PROJECT_OCCUPIED_CODE,
|
|
123
|
+
message: 'This project is occupied: it is already connected to another MCP client. It becomes available when that client disconnects or its session expires; try again then.',
|
|
124
|
+
data: { reason: MCP_PROJECT_OCCUPIED_REASON, projectId, retryable: true },
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/** The session-expired error a fenced or expired owner receives on any later call. */
|
|
128
|
+
export function sessionExpiredError(projectId) {
|
|
129
|
+
return {
|
|
130
|
+
code: MCP_SESSION_EXPIRED_CODE,
|
|
131
|
+
message: 'This MCP session no longer owns the project. Reconnect to start a new session.',
|
|
132
|
+
data: { reason: MCP_SESSION_EXPIRED_REASON, projectId, retryable: true },
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
/** `process.kill(pid, 0)`: only `ESRCH` confirms death. `EPERM` is a live process we may not
|
|
136
|
+
* signal, and anything else is not proof of death either. */
|
|
137
|
+
function processAlive(pid) {
|
|
138
|
+
try {
|
|
139
|
+
process.kill(pid, 0);
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
return error.code !== 'ESRCH';
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function isNotFound(error) {
|
|
147
|
+
return error?.code === 'ENOENT';
|
|
148
|
+
}
|
|
149
|
+
function unlinkIfPresent(path) {
|
|
150
|
+
try {
|
|
151
|
+
unlinkSync(path);
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
if (!isNotFound(error))
|
|
155
|
+
throw error;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/** One project's owner slot. The service keeps one per bound project. */
|
|
159
|
+
export class ProjectOwnership {
|
|
160
|
+
projectId;
|
|
161
|
+
dir;
|
|
162
|
+
now;
|
|
163
|
+
random;
|
|
164
|
+
sleep;
|
|
165
|
+
pid;
|
|
166
|
+
host;
|
|
167
|
+
isAlive;
|
|
168
|
+
autoRenew;
|
|
169
|
+
holding;
|
|
170
|
+
timer;
|
|
171
|
+
/** Serialises this object's acquisitions, so two sessions in one process never interleave an
|
|
172
|
+
* attempt. Cross-process exclusion is the claim file's job, not this chain's. */
|
|
173
|
+
tail = Promise.resolve();
|
|
174
|
+
pending = new Set();
|
|
175
|
+
warnedRenewal = false;
|
|
176
|
+
disposed = false;
|
|
177
|
+
constructor(options) {
|
|
178
|
+
this.projectId = options.projectId;
|
|
179
|
+
this.dir = join(options.dataDir, OWNER_CLAIM_DIR);
|
|
180
|
+
this.now = options.now ?? Date.now;
|
|
181
|
+
this.random = options.random ?? Math.random;
|
|
182
|
+
this.sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
183
|
+
this.pid = options.pid ?? process.pid;
|
|
184
|
+
this.host = options.host ?? hostname();
|
|
185
|
+
this.isAlive = options.isAlive ?? processAlive;
|
|
186
|
+
this.autoRenew = options.autoRenew ?? true;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Make `sessionKey` the owner, or say why not. Idempotent for the owner: every request and
|
|
190
|
+
* stream of the SAME logical session gets the same token back, because they are not additional
|
|
191
|
+
* clients. A different session is refused with the project-occupied error.
|
|
192
|
+
*/
|
|
193
|
+
acquire(sessionKey) {
|
|
194
|
+
// After `dispose` the service is going away: nothing may claim on its behalf any more.
|
|
195
|
+
const ticket = { sessionKey, closed: this.disposed };
|
|
196
|
+
this.pending.add(ticket);
|
|
197
|
+
const run = this.tail.then(() => this.acquireSerial(ticket));
|
|
198
|
+
this.tail = run.catch(() => undefined);
|
|
199
|
+
return run.finally(() => this.pending.delete(ticket));
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* The fence. Call it before EVERY mutation with the token the request was bound to; proceed
|
|
203
|
+
* only on `ok: true`. Equality with the current live owner's token, and nothing weaker: a stale
|
|
204
|
+
* token is refused even when its process is alive and even when its lease has not lapsed in its
|
|
205
|
+
* own memory.
|
|
206
|
+
*/
|
|
207
|
+
checkMutation(token) {
|
|
208
|
+
const holding = this.liveHolding();
|
|
209
|
+
if (!holding || holding.token !== token)
|
|
210
|
+
return { ok: false, error: sessionExpiredError(this.projectId) };
|
|
211
|
+
return { ok: true };
|
|
212
|
+
}
|
|
213
|
+
/** The token a new request from `sessionKey` binds to, or `undefined` when that session does not
|
|
214
|
+
* own the project (never did, released, fenced or expired) — the transport answers
|
|
215
|
+
* session-expired then. */
|
|
216
|
+
sessionToken(sessionKey) {
|
|
217
|
+
const holding = this.liveHolding();
|
|
218
|
+
return holding?.sessionKey === sessionKey ? holding.token : undefined;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Confirmed termination of `sessionKey`: the transport observed its connection close. Frees the
|
|
222
|
+
* project at once. Touches the claim file and this object's memory only — never a run (N-05).
|
|
223
|
+
* Not to be called when one request completes or one stream closes; those are not session death.
|
|
224
|
+
*/
|
|
225
|
+
release(sessionKey) {
|
|
226
|
+
for (const ticket of this.pending)
|
|
227
|
+
if (ticket.sessionKey === sessionKey)
|
|
228
|
+
ticket.closed = true;
|
|
229
|
+
if (this.holding?.sessionKey === sessionKey)
|
|
230
|
+
this.dropHolding();
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Occupancy as the cockpit renders it, derived at read time by the same classifier acquisition
|
|
234
|
+
* uses — a dead owner's claim reads `expired` the moment it is true, never a stale `owned`.
|
|
235
|
+
* Reads only; reaping stays with the next acquirer, who has published its own claim first.
|
|
236
|
+
*/
|
|
237
|
+
state() {
|
|
238
|
+
if (this.holding)
|
|
239
|
+
return this.liveHolding() ? 'owned' : 'expired';
|
|
240
|
+
let names;
|
|
241
|
+
try {
|
|
242
|
+
names = readdirSync(this.dir);
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
245
|
+
if (isNotFound(error))
|
|
246
|
+
return 'unowned';
|
|
247
|
+
throw error;
|
|
248
|
+
}
|
|
249
|
+
let sawStale = false;
|
|
250
|
+
for (const name of names) {
|
|
251
|
+
const match = CLAIM_NAME.exec(name);
|
|
252
|
+
if (!match)
|
|
253
|
+
continue;
|
|
254
|
+
const pid = Number(match[1]);
|
|
255
|
+
// Our own process's only real ownership is `holding`; any other claim of ours is an
|
|
256
|
+
// acquisition in flight, which must not flicker the display to `owned`.
|
|
257
|
+
if (pid === this.pid)
|
|
258
|
+
continue;
|
|
259
|
+
const verdict = this.classify(join(this.dir, name), pid);
|
|
260
|
+
if (verdict === 'live')
|
|
261
|
+
return 'owned';
|
|
262
|
+
if (verdict === 'dead' || verdict === 'expired')
|
|
263
|
+
sawStale = true;
|
|
264
|
+
}
|
|
265
|
+
return sawStale ? 'expired' : 'unowned';
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* One renewal. The timer fires it every `OWNER_RENEW_INTERVAL_MS`; tests call it directly.
|
|
269
|
+
* The resumed-owner rule lives here: a lease that has already lapsed is NEVER renewed.
|
|
270
|
+
*/
|
|
271
|
+
renewalTick() {
|
|
272
|
+
const holding = this.holding;
|
|
273
|
+
if (!holding) {
|
|
274
|
+
this.stopTimer();
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const at = this.now();
|
|
278
|
+
if (at - holding.renewedAt > OWNER_LEASE_MS) {
|
|
279
|
+
this.reacquire(holding.sessionKey);
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
let descriptor;
|
|
283
|
+
try {
|
|
284
|
+
// `r+`, never a create: a claim that was reaped while we were away must not be resurrected
|
|
285
|
+
// beside the owner that reaped it.
|
|
286
|
+
descriptor = openSync(holding.claimPath, 'r+');
|
|
287
|
+
}
|
|
288
|
+
catch (error) {
|
|
289
|
+
if (isNotFound(error)) {
|
|
290
|
+
this.reacquire(holding.sessionKey);
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
this.warnRenewal(error);
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
let reaped = false;
|
|
297
|
+
try {
|
|
298
|
+
const bytes = Buffer.from(JSON.stringify(this.claimBody(holding.token, holding.acquiredAt, at)));
|
|
299
|
+
writeSync(descriptor, bytes, 0, bytes.length, 0);
|
|
300
|
+
ftruncateSync(descriptor, bytes.length);
|
|
301
|
+
// A peer may have unlinked the claim between our open and our write; the write then landed
|
|
302
|
+
// on an inode nobody can see, and extending our lease on it would be a lie.
|
|
303
|
+
reaped = fstatSync(descriptor).nlink === 0;
|
|
304
|
+
if (!reaped)
|
|
305
|
+
holding.renewedAt = at;
|
|
306
|
+
}
|
|
307
|
+
catch (error) {
|
|
308
|
+
// The on-disk lease was not extended, so neither is ours: we fence ourselves at the same
|
|
309
|
+
// moment a peer may reap us, instead of writing on a lease nobody else can see.
|
|
310
|
+
this.warnRenewal(error);
|
|
311
|
+
}
|
|
312
|
+
finally {
|
|
313
|
+
closeSync(descriptor);
|
|
314
|
+
}
|
|
315
|
+
if (reaped)
|
|
316
|
+
this.reacquire(holding.sessionKey);
|
|
317
|
+
}
|
|
318
|
+
/** Service shutdown: every session ends (D-02 § 5), and the claim goes with it. */
|
|
319
|
+
dispose() {
|
|
320
|
+
this.disposed = true;
|
|
321
|
+
for (const ticket of this.pending)
|
|
322
|
+
ticket.closed = true;
|
|
323
|
+
this.dropHolding();
|
|
324
|
+
}
|
|
325
|
+
async acquireSerial(ticket) {
|
|
326
|
+
for (let attempt = 0; attempt < OWNER_ACQUIRE_ATTEMPTS; attempt += 1) {
|
|
327
|
+
if (ticket.closed)
|
|
328
|
+
return { outcome: 'closed' };
|
|
329
|
+
const live = this.liveHolding();
|
|
330
|
+
if (live) {
|
|
331
|
+
if (live.sessionKey === ticket.sessionKey)
|
|
332
|
+
return { outcome: 'owner', token: live.token };
|
|
333
|
+
return { outcome: 'occupied', error: projectOccupiedError(this.projectId) };
|
|
334
|
+
}
|
|
335
|
+
// Whoever notices first ends an expired holding; its claim is ours to remove.
|
|
336
|
+
if (this.holding)
|
|
337
|
+
this.dropHolding();
|
|
338
|
+
const won = this.attemptOnce();
|
|
339
|
+
if (won) {
|
|
340
|
+
this.holding = { sessionKey: ticket.sessionKey, ...won };
|
|
341
|
+
this.startTimer();
|
|
342
|
+
return { outcome: 'owner', token: won.token };
|
|
343
|
+
}
|
|
344
|
+
if (attempt < OWNER_ACQUIRE_ATTEMPTS - 1) {
|
|
345
|
+
const window = Math.min(OWNER_BACKOFF_CAP_MS, OWNER_BACKOFF_BASE_MS * 2 ** attempt);
|
|
346
|
+
await this.sleep(this.random() * window);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return { outcome: 'occupied', error: projectOccupiedError(this.projectId) };
|
|
350
|
+
}
|
|
351
|
+
/** Publish, then scan. Synchronous from the create to the verdict, so nothing in this process
|
|
352
|
+
* can interleave with one attempt. */
|
|
353
|
+
attemptOnce() {
|
|
354
|
+
mkdirSync(this.dir, { recursive: true, mode: 0o700 });
|
|
355
|
+
const at = this.now();
|
|
356
|
+
const token = `${at}-${randomUUID()}`;
|
|
357
|
+
const claimPath = join(this.dir, `${this.pid}-${randomUUID()}.json`);
|
|
358
|
+
let published = false;
|
|
359
|
+
try {
|
|
360
|
+
const descriptor = openSync(claimPath, 'wx', 0o600);
|
|
361
|
+
published = true; // The exclusive create is the publication, even if the write below fails.
|
|
362
|
+
try {
|
|
363
|
+
writeSync(descriptor, JSON.stringify(this.claimBody(token, at, at)));
|
|
364
|
+
}
|
|
365
|
+
finally {
|
|
366
|
+
closeSync(descriptor);
|
|
367
|
+
}
|
|
368
|
+
for (const name of readdirSync(this.dir)) {
|
|
369
|
+
const path = join(this.dir, name);
|
|
370
|
+
if (path === claimPath)
|
|
371
|
+
continue;
|
|
372
|
+
const match = CLAIM_NAME.exec(name);
|
|
373
|
+
if (!match)
|
|
374
|
+
continue; // Every claim carries this name; anything else is not a claim.
|
|
375
|
+
const verdict = this.classify(path, Number(match[1]));
|
|
376
|
+
if (verdict === 'live') {
|
|
377
|
+
unlinkIfPresent(claimPath);
|
|
378
|
+
published = false;
|
|
379
|
+
return undefined;
|
|
380
|
+
}
|
|
381
|
+
// Safe to reap only because our own claim is already published: a contender arriving now
|
|
382
|
+
// sees us and stands down. Names are unique, so this can never remove a replacement's claim.
|
|
383
|
+
// The verdict is what admits us, not the unlink: a dead or expired claim we cannot remove
|
|
384
|
+
// (a read-only entry) blocks nobody, and every other contender reads the same verdict.
|
|
385
|
+
if (verdict === 'dead' || verdict === 'expired') {
|
|
386
|
+
try {
|
|
387
|
+
unlinkIfPresent(path);
|
|
388
|
+
}
|
|
389
|
+
catch {
|
|
390
|
+
/* Left for the next acquirer; it is not an owner either way. */
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return { token, claimPath, acquiredAt: at, renewedAt: at };
|
|
395
|
+
}
|
|
396
|
+
catch (error) {
|
|
397
|
+
if (published) {
|
|
398
|
+
try {
|
|
399
|
+
unlinkSync(claimPath);
|
|
400
|
+
}
|
|
401
|
+
catch {
|
|
402
|
+
/* Never remove anything but our own claim. */
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
throw error;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* The one classifier acquisition and `state` share. Fails closed: an unreadable or half-written
|
|
410
|
+
* claim is live until its pid is confirmed dead or its file outlives the lease.
|
|
411
|
+
*/
|
|
412
|
+
classify(path, pid) {
|
|
413
|
+
let raw;
|
|
414
|
+
try {
|
|
415
|
+
raw = readFileSync(path, 'utf8');
|
|
416
|
+
}
|
|
417
|
+
catch (error) {
|
|
418
|
+
if (isNotFound(error))
|
|
419
|
+
return 'gone'; // A refused contender removed its own claim.
|
|
420
|
+
// Unreadable (EACCES, EISDIR, …): judged like a half-written claim, by pid and age, so one
|
|
421
|
+
// odd entry can neither block the project forever nor be mistaken for a free slot.
|
|
422
|
+
}
|
|
423
|
+
let claim;
|
|
424
|
+
try {
|
|
425
|
+
const parsed = raw === undefined ? undefined : claimSchema.safeParse(JSON.parse(raw));
|
|
426
|
+
if (parsed?.success)
|
|
427
|
+
claim = parsed.data;
|
|
428
|
+
}
|
|
429
|
+
catch {
|
|
430
|
+
/* A contender mid-write, or a torn renewal. Judged by pid and mtime below. */
|
|
431
|
+
}
|
|
432
|
+
// A pid is only meaningful on the host that issued it.
|
|
433
|
+
if ((!claim || claim.host === this.host) && !this.isAlive(pid))
|
|
434
|
+
return 'dead';
|
|
435
|
+
let renewedAt = claim?.renewedAt;
|
|
436
|
+
if (renewedAt === undefined) {
|
|
437
|
+
try {
|
|
438
|
+
renewedAt = statSync(path).mtimeMs;
|
|
439
|
+
}
|
|
440
|
+
catch (error) {
|
|
441
|
+
if (isNotFound(error))
|
|
442
|
+
return 'gone';
|
|
443
|
+
throw error;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
return this.now() - renewedAt > OWNER_LEASE_MS ? 'expired' : 'live';
|
|
447
|
+
}
|
|
448
|
+
/** The holding, if its lease has not lapsed. Expiry is arithmetic, not an event: a frozen
|
|
449
|
+
* process that wakes up reads itself expired before any timer has had a chance to run. */
|
|
450
|
+
liveHolding() {
|
|
451
|
+
const holding = this.holding;
|
|
452
|
+
if (!holding || this.now() - holding.renewedAt > OWNER_LEASE_MS)
|
|
453
|
+
return undefined;
|
|
454
|
+
return holding;
|
|
455
|
+
}
|
|
456
|
+
/** Lost time or a lost claim: drop what we held and run acquisition from scratch. The old token
|
|
457
|
+
* is fenced whatever happens next, because a win mints a new one. */
|
|
458
|
+
reacquire(sessionKey) {
|
|
459
|
+
this.dropHolding();
|
|
460
|
+
void this.acquire(sessionKey).catch((error) => {
|
|
461
|
+
console.warn(`[xezar] MCP owner re-acquisition failed for project ${this.projectId}: ${String(error)}`);
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
dropHolding() {
|
|
465
|
+
const holding = this.holding;
|
|
466
|
+
this.holding = undefined;
|
|
467
|
+
this.stopTimer();
|
|
468
|
+
if (!holding)
|
|
469
|
+
return;
|
|
470
|
+
try {
|
|
471
|
+
unlinkIfPresent(holding.claimPath);
|
|
472
|
+
}
|
|
473
|
+
catch (error) {
|
|
474
|
+
// The claim outlives us on disk; its lease ages out and the next acquirer reaps it.
|
|
475
|
+
console.warn(`[xezar] could not remove MCP owner claim for project ${this.projectId}: ${String(error)}`);
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
// A project nobody owns keeps no owner directory: an MCP session leaves no trace in the
|
|
479
|
+
// project's data once it ends. Only an EMPTY directory goes — `rmdir` refuses anything else, so
|
|
480
|
+
// a peer's claim is never touched — and the next acquisition recreates it (D-02.8).
|
|
481
|
+
try {
|
|
482
|
+
rmdirSync(this.dir);
|
|
483
|
+
}
|
|
484
|
+
catch {
|
|
485
|
+
/* Not empty, already gone, or not ours to remove: all fine. */
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
claimBody(token, acquiredAt, renewedAt) {
|
|
489
|
+
return { v: 1, token, pid: this.pid, host: this.host, acquiredAt, renewedAt };
|
|
490
|
+
}
|
|
491
|
+
startTimer() {
|
|
492
|
+
if (!this.autoRenew || this.timer)
|
|
493
|
+
return;
|
|
494
|
+
// A throw here would be an uncaught exception in the service. A failed tick leaves the lease
|
|
495
|
+
// un-renewed, which expires on its own: the fail-closed outcome.
|
|
496
|
+
this.timer = setInterval(() => {
|
|
497
|
+
try {
|
|
498
|
+
this.renewalTick();
|
|
499
|
+
}
|
|
500
|
+
catch (error) {
|
|
501
|
+
this.warnRenewal(error);
|
|
502
|
+
}
|
|
503
|
+
}, OWNER_RENEW_INTERVAL_MS);
|
|
504
|
+
this.timer.unref();
|
|
505
|
+
}
|
|
506
|
+
stopTimer() {
|
|
507
|
+
if (this.timer)
|
|
508
|
+
clearInterval(this.timer);
|
|
509
|
+
this.timer = undefined;
|
|
510
|
+
}
|
|
511
|
+
warnRenewal(error) {
|
|
512
|
+
if (this.warnedRenewal)
|
|
513
|
+
return;
|
|
514
|
+
this.warnedRenewal = true;
|
|
515
|
+
console.warn(`[xezar] MCP owner lease renewal failed for project ${this.projectId}: ${String(error)}`);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
//# sourceMappingURL=project-owner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-owner.js","sourceRoot":"","sources":["../../src/workspace/project-owner.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qodeca/xezar",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Local cockpit for running and tracking AI agent tasks in your repo. Uses your logged-in `claude` CLI and `gh` — zero config, zero database.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -50,8 +50,10 @@
|
|
|
50
50
|
"zod": "^4.4.3"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@qodeca/xezar-api-client": "^0.
|
|
54
|
-
"@qodeca/xezar-contract": "^0.
|
|
53
|
+
"@qodeca/xezar-api-client": "^0.14.0",
|
|
54
|
+
"@qodeca/xezar-contract": "^0.14.0",
|
|
55
|
+
"@stryker-mutator/core": "^9.6.1",
|
|
56
|
+
"@stryker-mutator/vitest-runner": "^9.6.1",
|
|
55
57
|
"@types/node": "^20.14.0",
|
|
56
58
|
"@types/ws": "^8.18.1",
|
|
57
59
|
"esbuild": "^0.28.1",
|