@mnemom/mnemom 0.17.33 → 0.17.34-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/base-url-proxy.mjs +18 -4
- package/dist/commands/agent-config.js +5 -1
- package/dist/commands/agent-doctor.d.ts +9 -0
- package/dist/commands/agent-doctor.js +4 -0
- package/dist/commands/agent-session.d.ts +1 -2
- package/dist/commands/agent-session.js +1 -2
- package/dist/commands/agent-setup.d.ts +6 -0
- package/dist/commands/agent-setup.js +12 -1
- package/dist/commands/agent-share-render.d.ts +1 -1
- package/dist/commands/agent-share-render.js +1 -1
- package/dist/commands/agent.d.ts +26 -0
- package/dist/commands/agent.js +228 -53
- package/dist/commands/durable-doctor.d.ts +50 -0
- package/dist/commands/durable-doctor.js +186 -0
- package/dist/commands/durable-lock.d.ts +254 -0
- package/dist/commands/durable-lock.js +595 -0
- package/dist/commands/durable-sessions.d.ts +87 -0
- package/dist/commands/durable-sessions.js +303 -0
- package/dist/commands/durable-verbs.d.ts +116 -0
- package/dist/commands/durable-verbs.js +393 -0
- package/dist/commands/protection.js +1 -1
- package/dist/commands/scan.d.ts +97 -0
- package/dist/commands/scan.js +238 -0
- package/dist/durable/flock.d.ts +26 -0
- package/dist/durable/flock.js +80 -0
- package/dist/durable/launch-spec.d.ts +7 -1
- package/dist/durable/launch-spec.js +10 -3
- package/dist/durable/seat-proxy-entry.d.ts +11 -0
- package/dist/durable/seat-proxy-entry.js +25 -0
- package/dist/durable/seat-proxy.d.ts +107 -0
- package/dist/durable/seat-proxy.js +599 -0
- package/dist/durable/seat-socket.d.ts +46 -0
- package/dist/durable/seat-socket.js +179 -0
- package/dist/durable/seat-spec-validator.d.ts +28 -0
- package/dist/durable/seat-spec-validator.js +59 -0
- package/dist/durable/test-mode.mjs +81 -0
- package/dist/durable/turn-chain.d.ts +55 -0
- package/dist/durable/turn-chain.js +178 -0
- package/dist/host/auto-continue.d.ts +67 -0
- package/dist/host/auto-continue.js +118 -0
- package/dist/host/bootid.d.ts +13 -0
- package/dist/host/bootid.js +41 -0
- package/dist/host/client.d.ts +123 -0
- package/dist/host/client.js +171 -0
- package/dist/host/commands.d.ts +2 -0
- package/dist/host/commands.js +122 -0
- package/dist/host/control.d.ts +33 -0
- package/dist/host/control.js +144 -0
- package/dist/host/daemon.d.ts +217 -0
- package/dist/host/daemon.js +606 -0
- package/dist/host/gate.d.ts +46 -0
- package/dist/host/gate.js +82 -0
- package/dist/host/grant.d.ts +24 -0
- package/dist/host/grant.js +24 -0
- package/dist/host/instance.d.ts +35 -0
- package/dist/host/instance.js +62 -0
- package/dist/host/integrity.d.ts +35 -0
- package/dist/host/integrity.js +115 -0
- package/dist/host/launchd.d.ts +16 -0
- package/dist/host/launchd.js +45 -0
- package/dist/host/lock.d.ts +20 -0
- package/dist/host/lock.js +63 -0
- package/dist/host/owner.d.ts +55 -0
- package/dist/host/owner.js +121 -0
- package/dist/host/plist.d.ts +16 -0
- package/dist/host/plist.js +85 -0
- package/dist/host/procs.d.ts +27 -0
- package/dist/host/procs.js +105 -0
- package/dist/host/run.d.ts +66 -0
- package/dist/host/run.js +314 -0
- package/dist/host/runtime.d.ts +8 -0
- package/dist/host/runtime.js +22 -0
- package/dist/host/s1-names.d.ts +22 -0
- package/dist/host/s1-names.js +21 -0
- package/dist/host/seat-credential.d.ts +27 -0
- package/dist/host/seat-credential.js +41 -0
- package/dist/host/seat-launch-main.d.ts +1 -0
- package/dist/host/seat-launch-main.js +59 -0
- package/dist/host/seat-launch.d.ts +116 -0
- package/dist/host/seat-launch.js +302 -0
- package/dist/host/seat.d.ts +48 -0
- package/dist/host/seat.js +149 -0
- package/dist/host/state.d.ts +33 -0
- package/dist/host/state.js +117 -0
- package/dist/host/status.d.ts +101 -0
- package/dist/host/status.js +307 -0
- package/dist/host/tmux.d.ts +56 -0
- package/dist/host/tmux.js +182 -0
- package/dist/host/transcript.d.ts +30 -0
- package/dist/host/transcript.js +130 -0
- package/dist/host/verbs.d.ts +50 -0
- package/dist/host/verbs.js +271 -0
- package/dist/index.d.ts +8 -6
- package/dist/index.js +232 -35
- package/dist/lib/agent.d.ts +8 -26
- package/dist/lib/agent.js +11 -26
- package/dist/lib/api.d.ts +13 -0
- package/dist/lib/api.js +8 -0
- package/dist/lib/claude-plugin.d.ts +11 -2
- package/dist/lib/claude-plugin.js +10 -1
- package/dist/lib/durable/api.d.ts +136 -0
- package/dist/lib/durable/api.js +220 -0
- package/dist/lib/durable/codes.d.ts +8 -0
- package/dist/lib/durable/codes.js +2 -0
- package/dist/lib/durable/first-turn.d.ts +50 -0
- package/dist/lib/durable/first-turn.js +102 -0
- package/dist/lib/durable/gate.d.ts +48 -0
- package/dist/lib/durable/gate.js +122 -0
- package/dist/lib/durable/handover.d.ts +101 -0
- package/dist/lib/durable/handover.js +175 -0
- package/dist/lib/durable/launch.d.ts +182 -0
- package/dist/lib/durable/launch.js +443 -0
- package/dist/lib/durable/launching.d.ts +15 -0
- package/dist/lib/durable/launching.js +70 -0
- package/dist/lib/durable/live.d.ts +194 -0
- package/dist/lib/durable/live.js +635 -0
- package/dist/lib/durable/refusal.d.ts +57 -0
- package/dist/lib/durable/refusal.js +78 -0
- package/dist/lib/durable/view.d.ts +83 -0
- package/dist/lib/durable/view.js +244 -0
- package/dist/lib/experimental.d.ts +0 -9
- package/dist/lib/experimental.js +18 -17
- package/dist/lib/launcher-config.d.ts +7 -0
- package/dist/lib/launcher-config.js +21 -0
- package/dist/lib/scan/caps.d.ts +35 -0
- package/dist/lib/scan/caps.js +67 -0
- package/dist/lib/scan/credential.d.ts +37 -0
- package/dist/lib/scan/credential.js +104 -0
- package/dist/lib/scan/failure.d.ts +10 -0
- package/dist/lib/scan/failure.js +43 -0
- package/dist/lib/scan/pr-source.d.ts +57 -0
- package/dist/lib/scan/pr-source.js +130 -0
- package/dist/lib/scan/record.d.ts +49 -0
- package/dist/lib/scan/record.js +85 -0
- package/dist/lib/scan/report-email.d.ts +92 -0
- package/dist/lib/scan/report-email.js +144 -0
- package/dist/lib/scan/report.d.ts +13 -0
- package/dist/lib/scan/report.js +30 -0
- package/dist/lib/scan/scan.d.ts +64 -0
- package/dist/lib/scan/scan.js +182 -0
- package/dist/lib/scan/share.d.ts +38 -0
- package/dist/lib/scan/share.js +47 -0
- package/dist/lib/scan/spend/ai-tool-detect.d.ts +6 -0
- package/dist/lib/scan/spend/ai-tool-detect.js +18 -0
- package/dist/lib/scan/spend/anthropic-usage.d.ts +57 -0
- package/dist/lib/scan/spend/anthropic-usage.js +244 -0
- package/dist/lib/scan/spend/cost-corpus.v1.d.ts +56 -0
- package/dist/lib/scan/spend/cost-corpus.v1.js +64 -0
- package/dist/lib/scan/spend/prices.d.ts +33 -0
- package/dist/lib/scan/spend/prices.js +57 -0
- package/dist/lib/scan/spend/spend-estimate.d.ts +30 -0
- package/dist/lib/scan/spend/spend-estimate.js +70 -0
- package/dist/lib/scan/spend/spend-tiers.d.ts +25 -0
- package/dist/lib/scan/spend/spend-tiers.js +42 -0
- package/dist/lib/scan/spend/token-rate.d.ts +30 -0
- package/dist/lib/scan/spend/token-rate.js +54 -0
- package/dist/lib/session-key.d.ts +41 -0
- package/dist/lib/session-key.js +124 -0
- package/dist/lib/subscription-login.d.ts +15 -0
- package/dist/lib/subscription-login.js +28 -1
- package/dist/rc-key-401.mjs +75 -0
- package/dist/rc-proxy.mjs +221 -25
- package/dist/vendor/durable-contract/index.js +240 -18
- package/dist/vendor/shared/durable-contract/admission.d.ts +240 -0
- package/dist/vendor/shared/durable-contract/admission.js +533 -0
- package/dist/vendor/shared/durable-contract/arm.d.ts +51 -0
- package/dist/vendor/shared/durable-contract/arm.js +133 -0
- package/dist/vendor/shared/durable-contract/canonical.d.ts +29 -0
- package/dist/vendor/shared/durable-contract/canonical.js +98 -0
- package/dist/vendor/shared/durable-contract/cell-id.d.ts +22 -0
- package/dist/vendor/shared/durable-contract/cell-id.js +38 -0
- package/dist/vendor/shared/durable-contract/cli-output.d.ts +342 -0
- package/dist/vendor/shared/durable-contract/cli-output.js +201 -0
- package/dist/vendor/shared/durable-contract/cli-surface.d.ts +119 -0
- package/dist/vendor/shared/durable-contract/cli-surface.js +270 -0
- package/dist/vendor/shared/durable-contract/codes.d.ts +537 -0
- package/dist/vendor/shared/durable-contract/codes.js +475 -0
- package/dist/vendor/shared/durable-contract/constants.d.ts +153 -0
- package/dist/vendor/shared/durable-contract/constants.js +179 -0
- package/dist/vendor/shared/durable-contract/doors.d.ts +119 -0
- package/dist/vendor/shared/durable-contract/doors.js +249 -0
- package/dist/vendor/shared/durable-contract/envelope.d.ts +103 -0
- package/dist/vendor/shared/durable-contract/envelope.js +317 -0
- package/dist/vendor/shared/durable-contract/events.d.ts +147 -0
- package/dist/vendor/shared/durable-contract/events.js +630 -0
- package/dist/vendor/shared/durable-contract/executor-state.d.ts +41 -0
- package/dist/vendor/shared/durable-contract/executor-state.js +32 -0
- package/dist/vendor/shared/durable-contract/fixlines.d.ts +318 -0
- package/dist/vendor/shared/durable-contract/fixlines.js +483 -0
- package/dist/vendor/shared/durable-contract/freeze-record.d.ts +787 -0
- package/dist/vendor/shared/durable-contract/freeze-record.js +361 -0
- package/dist/vendor/shared/durable-contract/index.d.ts +36 -0
- package/dist/vendor/shared/durable-contract/index.js +37 -0
- package/dist/vendor/shared/durable-contract/journal-approvals.d.ts +29 -0
- package/dist/vendor/shared/durable-contract/journal-approvals.js +60 -0
- package/dist/vendor/shared/durable-contract/keys.d.ts +24 -0
- package/dist/vendor/shared/durable-contract/keys.js +66 -0
- package/dist/vendor/shared/durable-contract/lock.d.ts +128 -0
- package/dist/vendor/shared/durable-contract/lock.js +151 -0
- package/dist/vendor/shared/durable-contract/names.d.ts +25 -0
- package/dist/vendor/shared/durable-contract/names.js +78 -0
- package/dist/vendor/shared/durable-contract/owner-verbs.d.ts +175 -0
- package/dist/vendor/shared/durable-contract/owner-verbs.js +403 -0
- package/dist/vendor/shared/durable-contract/paths.d.ts +23 -0
- package/dist/vendor/shared/durable-contract/paths.js +35 -0
- package/dist/vendor/shared/durable-contract/pure-fn.d.ts +48 -0
- package/dist/vendor/shared/durable-contract/pure-fn.js +89 -0
- package/dist/vendor/shared/durable-contract/routes.d.ts +205 -0
- package/dist/vendor/shared/durable-contract/routes.js +315 -0
- package/dist/vendor/shared/durable-contract/schema.d.ts +126 -0
- package/dist/vendor/shared/durable-contract/schema.js +441 -0
- package/dist/vendor/shared/durable-contract/seal.d.ts +54 -0
- package/dist/vendor/shared/durable-contract/seal.js +99 -0
- package/dist/vendor/shared/durable-contract/secret-scope.d.ts +28 -0
- package/dist/vendor/shared/durable-contract/secret-scope.js +76 -0
- package/dist/vendor/shared/durable-contract/session-id.d.ts +21 -0
- package/dist/vendor/shared/durable-contract/session-id.js +58 -0
- package/dist/vendor/shared/durable-contract/spec.d.ts +162 -0
- package/dist/vendor/shared/durable-contract/spec.js +286 -0
- package/dist/vendor/shared/durable-contract/states.d.ts +96 -0
- package/dist/vendor/shared/durable-contract/states.js +218 -0
- package/dist/vendor/shared/durable-contract/telemetry.d.ts +94 -0
- package/dist/vendor/shared/durable-contract/telemetry.js +180 -0
- package/dist/vendor/shared/durable-contract/test-mode.d.ts +62 -0
- package/dist/vendor/shared/durable-contract/test-mode.js +140 -0
- package/dist/vendor/shared/durable-contract/turn.d.ts +57 -0
- package/dist/vendor/shared/durable-contract/turn.js +81 -0
- package/dist/vendor/shared/durable-contract/vectors.d.ts +191 -0
- package/dist/vendor/shared/durable-contract/vectors.js +208 -0
- package/package.json +4 -3
- package/plugins/integrity-manifest.json +35 -0
- package/plugins/mnemom/hooks/hooks.json +15 -1
- package/plugins/mnemom/hooks/register.tsx +60 -2
- package/plugins/mnemom/hooks/seat-hello.mjs +116 -0
- package/dist/commands/agent-implicit-notice.d.ts +0 -31
- package/dist/commands/agent-implicit-notice.js +0 -73
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
// GENERATED from shared/durable-contract/src/vectors.ts by cli/scripts/sync-durable-contract.mjs; do not edit.
|
|
2
|
+
/**
|
|
3
|
+
* Golden vectors for the recipes S1 freezes, computed independently with node:crypto (a separate
|
|
4
|
+
* canonical-JSON and AES-256-GCM implementation, scratchpad s1gen/gen.cjs) and pinned here. The
|
|
5
|
+
* tests recompute each with this package's code; a mismatch is a contract break.
|
|
6
|
+
*/
|
|
7
|
+
export const CONTRACT_VECTOR = {
|
|
8
|
+
dek_b64url: "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8",
|
|
9
|
+
iv_b64url: "oKGio6Slpqeoqaqr",
|
|
10
|
+
session_id: "11111111-2222-4333-8444-555555555555",
|
|
11
|
+
contract: {
|
|
12
|
+
statement: "Ship the M1 durable contract and keep every flag inert when off.",
|
|
13
|
+
requirements: ["tests pass", "no prod change"],
|
|
14
|
+
allowed_paths: ["shared/durable-contract/**"],
|
|
15
|
+
forbidden_paths: [".github/**"],
|
|
16
|
+
},
|
|
17
|
+
plaintext: '{"allowed_paths":["shared/durable-contract/**"],"forbidden_paths":[".github/**"],"requirements":["tests pass","no prod change"],"statement":"Ship the M1 durable contract and keep every flag inert when off."}',
|
|
18
|
+
statement_hash: "51d9393d4b1b22b84e4fe45acb3e4f3c561e75d03701771aa40c805a5146f939",
|
|
19
|
+
requirements_hash: "566af8b913e8827626360e11b53b0356f9784508e3e51e36c9d6d4ce5b64bb31",
|
|
20
|
+
envelopes: [
|
|
21
|
+
{
|
|
22
|
+
charter_version: 1,
|
|
23
|
+
envelope: "v1.oKGio6Slpqeoqaqr.nTodQSmkddoGOveycxKz_Er3e2P61jAJ-CFC8w3KF223WySQwVYhXDzoK-IjWN7VZX0pOgC5fhokMFQuxQTtw5aG3k0ewo2UnJedN6Xk7ufhKdnBtLTwCIsYW_TF6W-u1KZfznDa_LvuunUjp6TPRktwEdyxUbtfR66ww9F3r2HnYsQepyftclkt3LEwGfm_-PnZA9vwt73dqciHzqVYTuZ7cN_CGCF19ipKTAvy3YQSVt39dAPcR6LkGlg7onY5UUQ46Re53oPTMiapZwZPU3bq5U_b2kWGfRebX73T3g",
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
charter_version: 2,
|
|
27
|
+
envelope: "v1.oKGio6Slpqeoqaqr.nTodQSmkddoGOveycxKz_Er3e2P61jAJ-CFC8w3KF223WySQwVYhXDzoK-IjWN7VZX0pOgC5fhokMFQuxQTtw5aG3k0ewo2UnJedN6Xk7ufhKdnBtLTwCIsYW_TF6W-u1KZfznDa_LvuunUjp6TPRktwEdyxUbtfR66ww9F3r2HnYsQepyftclkt3LEwGfm_-PnZA9vwt73dqciHzqVYTuZ7cN_CGCF19ipKTAvy3YQSVt39dAPcR6LkGlg7onY5UUQ46Re53oPTMiapZwZPLBiJm0K86YthUHE-qc35MQ",
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
};
|
|
31
|
+
/** One journal row per writer class, each hashed as a genesis row (prev_hash = 64 zeros). */
|
|
32
|
+
export const EVENT_PREIMAGE_VECTORS = [
|
|
33
|
+
{
|
|
34
|
+
writer: "executor",
|
|
35
|
+
refs: {
|
|
36
|
+
spawn_id: "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee",
|
|
37
|
+
},
|
|
38
|
+
detail: "executor.spawned spawn_id=aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee",
|
|
39
|
+
preimage: '{"detail_sha256":"9869cd123386f64b766dbff0fcf4a6f7d35f4bf9f6eec5594055e77c5fe0d4b0","epoch":2,"idempotency_key":"spawn:11111111-2222-4333-8444-555555555555:2:aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee","kind":"executor.spawned","prev_hash":"0000000000000000000000000000000000000000000000000000000000000000","principal_ref":null,"refs_sha256":"80280db047606c26674cc10fa3e08ac9dabbde08c3958116f31f0211f15b31c9","seq":3,"session_id":"11111111-2222-4333-8444-555555555555","ts":"2026-10-16T12:00:00.123000Z","v":1}',
|
|
40
|
+
hash: "a54e7c93b2bc865905a57755b02b0af397b6b281caab922c411de689a2e2273d",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
writer: "gateway",
|
|
44
|
+
refs: {
|
|
45
|
+
admitted_epoch: 2,
|
|
46
|
+
current_epoch: 3,
|
|
47
|
+
},
|
|
48
|
+
detail: "lease.zombie_call admitted_epoch=2 current_epoch=3",
|
|
49
|
+
preimage: '{"detail_sha256":"9ee4f5d787302fe3464b96cc8d38cfffe049c503fea6292db98e68135ceafd9b","epoch":3,"idempotency_key":"zombie:req-0001","kind":"lease.zombie_call","prev_hash":"0000000000000000000000000000000000000000000000000000000000000000","principal_ref":null,"refs_sha256":"351c59d5e2d263f0e3edc09e0ad8bf205b4fb0ba12898c5b5e666e7edf821eb4","seq":4,"session_id":"11111111-2222-4333-8444-555555555555","ts":"2026-10-16T12:00:01.000000Z","v":1}',
|
|
50
|
+
hash: "db229bf5c9d46295dd6e3b282750ddfd291ea164c2b8fced450790fc141d9c39",
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
writer: "api",
|
|
54
|
+
refs: {
|
|
55
|
+
durable_mode: "locked",
|
|
56
|
+
},
|
|
57
|
+
detail: "session.registered durable_mode=locked",
|
|
58
|
+
preimage: '{"detail_sha256":"eab692f69df0b5aa9984cd233af2135fa08329f21236f6a095d9a289002a28b0","epoch":0,"idempotency_key":"tr:11111111-2222-4333-8444-555555555555:session.registered:0","kind":"session.registered","prev_hash":"0000000000000000000000000000000000000000000000000000000000000000","principal_ref":"9999999999999999999999999999999999999999999999999999999999999999","refs_sha256":"b62d326eeec5672858e7bd2cfa73a0520968329af7e405a0d8cf86cd6cecd891","seq":1,"session_id":"11111111-2222-4333-8444-555555555555","ts":"2026-10-16T11:59:00.000000Z","v":1}',
|
|
59
|
+
hash: "13acfe4d0979d989464c0a71fbae440afb4d6056eaf770db2b27d39e1793d6d3",
|
|
60
|
+
},
|
|
61
|
+
];
|
|
62
|
+
export const PRINCIPAL_REF_VECTOR = {
|
|
63
|
+
salt_utf8: "salt-0123456789abcdef",
|
|
64
|
+
principal_uid: "user-uid-1",
|
|
65
|
+
principal_ref: "beb9218556929a56f74799caabfb6679f829cbc1521d139fdb710a66ab2e29b6",
|
|
66
|
+
};
|
|
67
|
+
export const SPEC_HASH_VECTOR = {
|
|
68
|
+
spec: {
|
|
69
|
+
v: 1,
|
|
70
|
+
cwd: "/Users/dev/repo",
|
|
71
|
+
plugin: "bundled-mnemom",
|
|
72
|
+
trim_mcp: false,
|
|
73
|
+
model: "opus",
|
|
74
|
+
effort: "high",
|
|
75
|
+
},
|
|
76
|
+
hash: "ccd6829afca0f806e52f010b15a0ae407f58df6465a6edd11c58a6a543e369d8",
|
|
77
|
+
};
|
|
78
|
+
export const PLUGIN_DIR_HASH_VECTOR = {
|
|
79
|
+
files: [
|
|
80
|
+
{
|
|
81
|
+
path: "hooks/x.sh",
|
|
82
|
+
sha256: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
|
83
|
+
},
|
|
84
|
+
{ path: "a.json", sha256: "0000000000000000000000000000000000000000000000000000000000000000" },
|
|
85
|
+
],
|
|
86
|
+
hash: "c9df73b3ae9cd900bb324ee0c5bb3f142a58cf5fac29673a038e95098edab5cd",
|
|
87
|
+
};
|
|
88
|
+
export const CHAIN_ID_VECTOR = {
|
|
89
|
+
root_prompt_id: "root-prompt-0001",
|
|
90
|
+
chain_id: "66e05a0707771bf96685f5963062f0c6413ec65c3cc159038aba55b081545100",
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Charter hash chain (C07-R04): a v1 genesis row and a v2 row chained to it, computed with an
|
|
94
|
+
* independent Python canonical-JSON + hashlib generator (scratchpad s1gen/charter_gen.py). created_at
|
|
95
|
+
* is given in the row's text form; the preimage carries its canonical form.
|
|
96
|
+
*/
|
|
97
|
+
export const CHARTER_HASH_VECTORS = {
|
|
98
|
+
"session_id": "11111111-2222-4333-8444-555555555555",
|
|
99
|
+
"rows": [
|
|
100
|
+
{
|
|
101
|
+
"version": 1,
|
|
102
|
+
"prev_hash": "0000000000000000000000000000000000000000000000000000000000000000",
|
|
103
|
+
"charter": {
|
|
104
|
+
"statement_hash": "51d9393d4b1b22b84e4fe45acb3e4f3c561e75d03701771aa40c805a5146f939",
|
|
105
|
+
"requirements_hash": "566af8b913e8827626360e11b53b0356f9784508e3e51e36c9d6d4ce5b64bb31",
|
|
106
|
+
"budget_usd": 5,
|
|
107
|
+
"max_turns": 40,
|
|
108
|
+
"pins": {
|
|
109
|
+
"card_content_hash": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
|
|
110
|
+
"policy_engine_major": 3
|
|
111
|
+
},
|
|
112
|
+
"tool_classes": {
|
|
113
|
+
"Bash": "input_dependent"
|
|
114
|
+
},
|
|
115
|
+
"launch_spec": {
|
|
116
|
+
"v": 1,
|
|
117
|
+
"cwd": "/Users/dev/repo",
|
|
118
|
+
"plugin": "bundled-mnemom",
|
|
119
|
+
"trim_mcp": false,
|
|
120
|
+
"model": "opus",
|
|
121
|
+
"effort": "high"
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
"created_at": "2026-10-16 12:00:00.123+00",
|
|
125
|
+
"preimage": "{\"charter\":{\"budget_usd\":5,\"launch_spec\":{\"cwd\":\"/Users/dev/repo\",\"effort\":\"high\",\"model\":\"opus\",\"plugin\":\"bundled-mnemom\",\"trim_mcp\":false,\"v\":1},\"max_turns\":40,\"pins\":{\"card_content_hash\":\"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\",\"policy_engine_major\":3},\"requirements_hash\":\"566af8b913e8827626360e11b53b0356f9784508e3e51e36c9d6d4ce5b64bb31\",\"statement_hash\":\"51d9393d4b1b22b84e4fe45acb3e4f3c561e75d03701771aa40c805a5146f939\",\"tool_classes\":{\"Bash\":\"input_dependent\"}},\"created_at\":\"2026-10-16T12:00:00.123000Z\",\"prev_hash\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"session_id\":\"11111111-2222-4333-8444-555555555555\",\"v\":1,\"version\":1}",
|
|
126
|
+
"hash": "1db9e38158199cec38e592881b9568aa79005c230c28f4fee3cc139ddf676eaf"
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"version": 2,
|
|
130
|
+
"prev_hash": "1db9e38158199cec38e592881b9568aa79005c230c28f4fee3cc139ddf676eaf",
|
|
131
|
+
"charter": {
|
|
132
|
+
"statement_hash": "51d9393d4b1b22b84e4fe45acb3e4f3c561e75d03701771aa40c805a5146f939",
|
|
133
|
+
"requirements_hash": "566af8b913e8827626360e11b53b0356f9784508e3e51e36c9d6d4ce5b64bb31",
|
|
134
|
+
"budget_usd": 4,
|
|
135
|
+
"max_turns": 40,
|
|
136
|
+
"pins": {
|
|
137
|
+
"card_content_hash": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
|
|
138
|
+
"policy_engine_major": 3
|
|
139
|
+
},
|
|
140
|
+
"tool_classes": {
|
|
141
|
+
"Bash": "input_dependent"
|
|
142
|
+
},
|
|
143
|
+
"launch_spec": {
|
|
144
|
+
"v": 1,
|
|
145
|
+
"cwd": "/Users/dev/repo",
|
|
146
|
+
"plugin": "bundled-mnemom",
|
|
147
|
+
"trim_mcp": false,
|
|
148
|
+
"model": "opus",
|
|
149
|
+
"effort": "high"
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
"created_at": "2026-10-16T12:05:00Z",
|
|
153
|
+
"preimage": "{\"charter\":{\"budget_usd\":4,\"launch_spec\":{\"cwd\":\"/Users/dev/repo\",\"effort\":\"high\",\"model\":\"opus\",\"plugin\":\"bundled-mnemom\",\"trim_mcp\":false,\"v\":1},\"max_turns\":40,\"pins\":{\"card_content_hash\":\"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\",\"policy_engine_major\":3},\"requirements_hash\":\"566af8b913e8827626360e11b53b0356f9784508e3e51e36c9d6d4ce5b64bb31\",\"statement_hash\":\"51d9393d4b1b22b84e4fe45acb3e4f3c561e75d03701771aa40c805a5146f939\",\"tool_classes\":{\"Bash\":\"input_dependent\"}},\"created_at\":\"2026-10-16T12:05:00.000000Z\",\"prev_hash\":\"1db9e38158199cec38e592881b9568aa79005c230c28f4fee3cc139ddf676eaf\",\"session_id\":\"11111111-2222-4333-8444-555555555555\",\"v\":1,\"version\":2}",
|
|
154
|
+
"hash": "70306a09f19c8df756547dae953756c3151536d30e0d7d46cbc8c4db0252b4c1"
|
|
155
|
+
}
|
|
156
|
+
]
|
|
157
|
+
};
|
|
158
|
+
/**
|
|
159
|
+
* Amendment 55 seal round trip (C07-R02, R13, R14). `seal` is the contract C07-HDR-01 sealed through a
|
|
160
|
+
* live gateway, which answered x-mnemom-contract-hash `gateway_enforce_h16` (mode enforce) and, for the
|
|
161
|
+
* same contract rehydrated as nudge, `gateway_nudge_h16`. The full hashes, the commitments and the v1
|
|
162
|
+
* charter row are from an independent Python canonical-JSON + hashlib generator (scratchpad
|
|
163
|
+
* s1gen/seal_gen.py). `sealed_at` is the seal instant in an offset form; charter_v1.created_at is it in UTC.
|
|
164
|
+
*/
|
|
165
|
+
export const SEAL_VECTORS = {
|
|
166
|
+
"seal": {
|
|
167
|
+
"statement": "Ship the release. canary zq-k1-102d461d964a345ca757",
|
|
168
|
+
"requirements": [
|
|
169
|
+
"Tests stay green. canary zq-k2-54e87989d0dd1c2f7a00"
|
|
170
|
+
],
|
|
171
|
+
"budget_usd": 5,
|
|
172
|
+
"max_turns": 40,
|
|
173
|
+
"time_limit_s": 3600,
|
|
174
|
+
"mode": "enforce",
|
|
175
|
+
"allowed_paths": [
|
|
176
|
+
"src/**"
|
|
177
|
+
],
|
|
178
|
+
"forbidden_paths": [
|
|
179
|
+
"secrets/**"
|
|
180
|
+
]
|
|
181
|
+
},
|
|
182
|
+
"enforce_hash": "85fc982c26cf4a28ac1e7e3ba0f746a83bd96bc3ce7a3ed84401f79aa684d13a",
|
|
183
|
+
"gateway_enforce_h16": "85fc982c26cf4a28",
|
|
184
|
+
"nudge_hash": "d0344555137faf1ce06f81bb905ec9dfb15dd385de57b6a959e381bf1f3fe654",
|
|
185
|
+
"gateway_nudge_h16": "d0344555137faf1c",
|
|
186
|
+
"sealed_at": "2026-10-29T12:45:33.355-07:00",
|
|
187
|
+
"charter_v1": {
|
|
188
|
+
"commitments": {
|
|
189
|
+
"statement_hash": "04ed1e6039e500e2a1d09fd4238a77863cdfc699e504cea01a4c63263ffdf538",
|
|
190
|
+
"requirements_hash": "d594733b87aa9594eb4d084a49e8450aa8ac9e32ffb9c985d7a2f24fa6513fcd",
|
|
191
|
+
"contract_hash": "85fc982c26cf4a28ac1e7e3ba0f746a83bd96bc3ce7a3ed84401f79aa684d13a",
|
|
192
|
+
"mode": "enforce",
|
|
193
|
+
"budget_usd": 5,
|
|
194
|
+
"max_turns": 40,
|
|
195
|
+
"active_time_limit_s": 3600,
|
|
196
|
+
"pins": {
|
|
197
|
+
"card_content_hash": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
|
|
198
|
+
"policy_engine_major": 3
|
|
199
|
+
},
|
|
200
|
+
"tool_classes": {
|
|
201
|
+
"Bash": "input_dependent"
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
"created_at": "2026-10-29T19:45:33.355000Z",
|
|
205
|
+
"preimage": "{\"charter\":{\"active_time_limit_s\":3600,\"budget_usd\":5,\"contract_hash\":\"85fc982c26cf4a28ac1e7e3ba0f746a83bd96bc3ce7a3ed84401f79aa684d13a\",\"max_turns\":40,\"mode\":\"enforce\",\"pins\":{\"card_content_hash\":\"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\",\"policy_engine_major\":3},\"requirements_hash\":\"d594733b87aa9594eb4d084a49e8450aa8ac9e32ffb9c985d7a2f24fa6513fcd\",\"statement_hash\":\"04ed1e6039e500e2a1d09fd4238a77863cdfc699e504cea01a4c63263ffdf538\",\"tool_classes\":{\"Bash\":\"input_dependent\"}},\"created_at\":\"2026-10-29T19:45:33.355000Z\",\"prev_hash\":\"0000000000000000000000000000000000000000000000000000000000000000\",\"session_id\":\"11111111-2222-4333-8444-555555555555\",\"v\":1,\"version\":1}",
|
|
206
|
+
"hash": "5a3bb041c155d67e50d18ee9afb0e6903f7a64988c881ab6373d3447fd5906f5"
|
|
207
|
+
}
|
|
208
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mnemom/mnemom",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.34-next.2",
|
|
4
4
|
"description": "Transparent AI agent tracing",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
"smoltbot": "./dist/smoltbot-shim.js"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
-
"build": "node scripts/vendor-durable-contract.mjs && tsc && node scripts/copy-assets.mjs",
|
|
11
|
+
"build": "node scripts/vendor-durable-contract.mjs && tsc && node scripts/copy-assets.mjs && node scripts/gen-integrity-manifest.mjs",
|
|
12
|
+
"prepack": "node scripts/gen-integrity-manifest.mjs --shipped",
|
|
12
13
|
"prepublishOnly": "npm run build",
|
|
13
14
|
"dev": "tsx src/index.ts",
|
|
14
15
|
"gen:command-tree": "node scripts/vendor-durable-contract.mjs && tsx scripts/gen-command-tree.mjs",
|
|
@@ -17,6 +18,7 @@
|
|
|
17
18
|
"test": "vitest"
|
|
18
19
|
},
|
|
19
20
|
"dependencies": {
|
|
21
|
+
"@mnemom/aip-verifier": "https://github.com/mnemom/aip/releases/download/aip-verifier-v0.6.0/mnemom-aip-verifier-0.6.0.tgz",
|
|
20
22
|
"@mnemom/policy-engine": "^0.3.0",
|
|
21
23
|
"chalk": "^5.3.0",
|
|
22
24
|
"commander": "^12.0.0",
|
|
@@ -24,7 +26,6 @@
|
|
|
24
26
|
"smol-toml": "^1.9.0"
|
|
25
27
|
},
|
|
26
28
|
"devDependencies": {
|
|
27
|
-
"@mnemom/aip-verifier": "https://github.com/mnemom/aip/releases/download/aip-verifier-v0.6.0/mnemom-aip-verifier-0.6.0.tgz",
|
|
28
29
|
"@types/js-yaml": "^4.0.9",
|
|
29
30
|
"@types/node": "^20.10.0",
|
|
30
31
|
"@vitest/coverage-v8": "^4.1.12",
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"recipe_version": 1,
|
|
3
|
+
"plugin_dir": "plugins/mnemom",
|
|
4
|
+
"files": [
|
|
5
|
+
{
|
|
6
|
+
"path": ".claude-plugin/plugin.json",
|
|
7
|
+
"sha256": "3f2e41856c19f2d5ef74a18b47d2dd742211a79ee4dbbdb408129fc38d6cd6df"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"path": ".mcp.json",
|
|
11
|
+
"sha256": "5ad367ef1aa4ade2de2ff7d3fac90131d9a160c2a16b2a6133e40b7d7be17ac7"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"path": "hooks/hooks.json",
|
|
15
|
+
"sha256": "c9fe91672a14aa8fc74d8fe523e412b7fdbe16a281cdc1d3e51b162fef3a7ed3"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"path": "hooks/register.tsx",
|
|
19
|
+
"sha256": "98da58c198d4015a5d454110249b1bc5c9fe0a1e2271c310f46c1185935d4436"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"path": "hooks/seat-hello.mjs",
|
|
23
|
+
"sha256": "4d6cd4e2fed2dc701bc6990ed5c43b37fb4aaf202b25012c3a052845d624daee"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"path": "skills/about-mnemom/SKILL.md",
|
|
27
|
+
"sha256": "30712f4630e769986c17260f6187323b5d0df11623b03dbdeaf7d3a5fb709081"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"path": "types/index.d.ts",
|
|
31
|
+
"sha256": "b877ea4d4d6fe11ae2eb10e035b5f017b225905f7f9ec015b3c3010609cad27b"
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
"dir_hash": "ad16249ecbdd1e2fc6913529f9aefb357d516da7230f26a4e1c2c0ccf09735c5"
|
|
35
|
+
}
|
|
@@ -1,3 +1,17 @@
|
|
|
1
1
|
{
|
|
2
|
-
"modules": ["./register.tsx"]
|
|
2
|
+
"modules": ["./register.tsx"],
|
|
3
|
+
"hooks": {
|
|
4
|
+
"SessionStart": [
|
|
5
|
+
{
|
|
6
|
+
"matcher": "startup|resume",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{
|
|
9
|
+
"type": "command",
|
|
10
|
+
"command": "[ -z \"$MNEMOM_SEAT_SOCKET\" ] || node \"${CLAUDE_PLUGIN_ROOT}/hooks/seat-hello.mjs\"",
|
|
11
|
+
"timeout": 30
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
3
17
|
}
|
|
@@ -197,6 +197,24 @@ const GOAL_REFRESH_DELAY_MS = 1500;
|
|
|
197
197
|
/** How long one `mnemom agent … --json` may take before it reads as unavailable. */
|
|
198
198
|
const GOAL_READ_TIMEOUT_MS = 8000;
|
|
199
199
|
|
|
200
|
+
/**
|
|
201
|
+
* `/mnemom lock` (durable sessions, BACKBONE C1; S1 PLUGIN_LOCK_ARGV, ruling 33.27.1): typed by the
|
|
202
|
+
* person, never run by the mod on its own. Offered only when the launcher said the launch is
|
|
203
|
+
* durable (MNEMOM_CC_DURABLE=1, set only with the `durable` experimental gate on); otherwise
|
|
204
|
+
* `/mnemom lock` is the plain status, exactly as before.
|
|
205
|
+
*/
|
|
206
|
+
// The env reads below name MNEMOM_CC_DURABLE (the CLI's PLUGIN_DURABLE_ENV) and
|
|
207
|
+
// MNEMOM_AGENT_SESSION_NAME (the env slot of S1 PLUGIN_LOCK_ARGV: the session's name, set by the
|
|
208
|
+
// launcher in the claude it starts) as literals only because `claude plugin validate` requires a
|
|
209
|
+
// literal first argument to $.env.get. claude-plugin.test.ts fails CI if either drifts from its
|
|
210
|
+
// source constant.
|
|
211
|
+
/** The CLI call: `mnemom agent lock <session name>`, no option, cwd inherited (S1 PLUGIN_LOCK_ARGV). */
|
|
212
|
+
function pluginLockArgv(sessionName: string | undefined): string[] | null {
|
|
213
|
+
return sessionName ? ["agent", "lock", sessionName] : null;
|
|
214
|
+
}
|
|
215
|
+
/** The lock waits for the host daemon's seat (up to ATTACH_WAIT_S) before it answers. */
|
|
216
|
+
const LOCK_TIMEOUT_MS = 300_000;
|
|
217
|
+
|
|
200
218
|
/**
|
|
201
219
|
* The Trust Rating lookup in flight, if any. Started beside the session start (never in its way),
|
|
202
220
|
* awaited by `/mnemom status` and `/mnemom doctor` so they report a settled rating, and swallowed
|
|
@@ -896,6 +914,17 @@ function statusText(
|
|
|
896
914
|
return lines.join("\n");
|
|
897
915
|
}
|
|
898
916
|
|
|
917
|
+
const HELP_LOCK =
|
|
918
|
+
" /mnemom lock make this session durable (the host daemon keeps it running)";
|
|
919
|
+
|
|
920
|
+
function helpText(durable: boolean): string {
|
|
921
|
+
if (!durable) return HELP;
|
|
922
|
+
const lines = HELP.split("\n");
|
|
923
|
+
const at = lines.findIndex((x) => x.startsWith(" /mnemom show"));
|
|
924
|
+
lines.splice(at + 1, 0, HELP_LOCK);
|
|
925
|
+
return lines.join("\n");
|
|
926
|
+
}
|
|
927
|
+
|
|
899
928
|
const HELP = [
|
|
900
929
|
`${SIGN} /mnemom — Mnemom for Claude Code`,
|
|
901
930
|
"",
|
|
@@ -935,6 +964,29 @@ async function refreshGoal(
|
|
|
935
964
|
return g;
|
|
936
965
|
}
|
|
937
966
|
|
|
967
|
+
/** `/mnemom lock`: run `mnemom agent lock <name>` through the launcher's own argv, show its answer. */
|
|
968
|
+
async function runLock(
|
|
969
|
+
$: RunDollar & { env: { get: (k: string) => Promise<string | undefined> } },
|
|
970
|
+
l: MnemomLaunch | null,
|
|
971
|
+
): Promise<string> {
|
|
972
|
+
// As S1 pluginLockArgv: the value as is; unset or empty runs no CLI call.
|
|
973
|
+
const argv = pluginLockArgv((await $.env.get("MNEMOM_AGENT_SESSION_NAME")) || undefined);
|
|
974
|
+
if (l === null || l.launcherExec.length === 0 || argv === null) {
|
|
975
|
+
return `${SIGN} /mnemom lock — this session was not started by \`mnemom agent <name>\`, so there is nothing to lock from here.`;
|
|
976
|
+
}
|
|
977
|
+
try {
|
|
978
|
+
const res = await $.process.run([...l.launcherExec, ...argv], { timeoutMs: LOCK_TIMEOUT_MS });
|
|
979
|
+
const said = [res.stdout, res.stderr]
|
|
980
|
+
.map((x) => x.trim())
|
|
981
|
+
.filter(Boolean)
|
|
982
|
+
.join("\n");
|
|
983
|
+
const head = res.exitCode === 0 ? `${SIGN} /mnemom lock` : `${SIGN} /mnemom lock — not locked`;
|
|
984
|
+
return said ? `${head}\n${said}` : head;
|
|
985
|
+
} catch (err) {
|
|
986
|
+
return `${SIGN} /mnemom lock — could not run mnemom (${err instanceof Error ? err.message : String(err)})`;
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
|
|
938
990
|
export const register: Register = (on, rawOptions) => {
|
|
939
991
|
const options = readOptions(rawOptions);
|
|
940
992
|
let composeCache: { key: string; text: string } | null = null;
|
|
@@ -946,11 +998,14 @@ export const register: Register = (on, rawOptions) => {
|
|
|
946
998
|
await update($, reputation, () => (l ? { state: "loading" } : null));
|
|
947
999
|
await update($, goal, () => (l && l.goalMode !== "off" ? { state: "loading" } : null));
|
|
948
1000
|
|
|
1001
|
+
const durable = (await $.env.get("MNEMOM_CC_DURABLE")) === "1";
|
|
949
1002
|
await $.command.register({
|
|
950
1003
|
name: "mnemom",
|
|
951
1004
|
description:
|
|
952
1005
|
"Mnemom governance: status, the goal, status pane, doctor, verify, hide/show the band",
|
|
953
|
-
argumentHint:
|
|
1006
|
+
argumentHint: durable
|
|
1007
|
+
? "[status|goal|panel|close|doctor|verify|hide|show|lock|help]"
|
|
1008
|
+
: "[status|goal|panel|close|doctor|verify|hide|show|help]",
|
|
954
1009
|
immediate: true,
|
|
955
1010
|
});
|
|
956
1011
|
|
|
@@ -997,7 +1052,10 @@ export const register: Register = (on, rawOptions) => {
|
|
|
997
1052
|
const l = await read($, launch);
|
|
998
1053
|
const verb = (e.args ?? "").trim().split(/\s+/)[0]?.toLowerCase() ?? "";
|
|
999
1054
|
|
|
1000
|
-
|
|
1055
|
+
const durable = (await $.env.get("MNEMOM_CC_DURABLE")) === "1";
|
|
1056
|
+
if (verb === "help" || verb === "-h" || verb === "--help") return { text: helpText(durable) };
|
|
1057
|
+
|
|
1058
|
+
if (verb === "lock" && durable) return { text: await runLock($, l) };
|
|
1001
1059
|
|
|
1002
1060
|
if (verb === "goal" || verb === "contract") {
|
|
1003
1061
|
if (l === null) return { text: statusText(null, null, null, await read($, turns), 0) };
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// The seat hello (BACKBONE C2 item 15; ruling B-hellohook; dogfood B2): a COMMAND hook on
|
|
2
|
+
// SessionStart, so it runs whether or not the engine loads hooks modules (register.tsx needs
|
|
3
|
+
// CLAUDE_CODE_ENABLE_FUNCTION_HOOKS; this does not).
|
|
4
|
+
//
|
|
5
|
+
// In a durable seat the seat launcher puts MNEMOM_SEAT_SOCKET (the seat proxy's per-seat 0600
|
|
6
|
+
// socket) and the seat's session, spawn and epoch ids in claude's env. This sends the one hello
|
|
7
|
+
// that socket serves, `{op:"hello", session_id, spawn_id, epoch}` as one JSON line, and reads its
|
|
8
|
+
// one-line answer (cli/src/durable/seat-socket.ts). Without MNEMOM_SEAT_SOCKET (every launch that
|
|
9
|
+
// is not a durable seat) it does nothing. It never sees a key: the ids are non-secret, and the
|
|
10
|
+
// seat proxy relays the hello to the daemon, which holds the executor key.
|
|
11
|
+
//
|
|
12
|
+
// It never fails the session: it always exits 0 and writes nothing to stdout (a SessionStart
|
|
13
|
+
// hook's stdout becomes model context). A refused or failed hello is one stderr line.
|
|
14
|
+
import net from "node:net";
|
|
15
|
+
import { pathToFileURL } from "node:url";
|
|
16
|
+
|
|
17
|
+
export const SEAT_SOCKET_ENV = "MNEMOM_SEAT_SOCKET";
|
|
18
|
+
export const SEAT_SESSION_ENV = "MNEMOM_SEAT_SESSION_ID";
|
|
19
|
+
export const SEAT_SPAWN_ENV = "MNEMOM_SEAT_SPAWN_ID";
|
|
20
|
+
export const SEAT_EPOCH_ENV = "MNEMOM_SEAT_EPOCH";
|
|
21
|
+
|
|
22
|
+
/** The seat socket answers within the daemon's API round trip; the hook's own timeout is 30 s. */
|
|
23
|
+
export const HELLO_TIMEOUT_MS = 20_000;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* What to send, from the env: `{ skip: true }` outside a seat, `{ error }` when the seat env is
|
|
27
|
+
* incomplete, else the socket path and the hello frame. The epoch goes as a number (the seat
|
|
28
|
+
* socket compares it strictly).
|
|
29
|
+
*/
|
|
30
|
+
export function helloFromEnv(env) {
|
|
31
|
+
const socketPath = env[SEAT_SOCKET_ENV];
|
|
32
|
+
if (!socketPath) return { skip: true };
|
|
33
|
+
const sessionId = env[SEAT_SESSION_ENV];
|
|
34
|
+
const spawnId = env[SEAT_SPAWN_ENV];
|
|
35
|
+
const epoch = env[SEAT_EPOCH_ENV];
|
|
36
|
+
if (!sessionId || !spawnId) return { error: "the seat env has no session or spawn id" };
|
|
37
|
+
if (!/^\d{1,9}$/.test(epoch ?? "")) return { error: "the seat env has no valid epoch" };
|
|
38
|
+
return {
|
|
39
|
+
socketPath,
|
|
40
|
+
frame: { op: "hello", session_id: sessionId, spawn_id: spawnId, epoch: Number(epoch) },
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** The seat socket's answer is one short JSON line; a longer one without a newline is not it. */
|
|
45
|
+
export const MAX_ANSWER_BYTES = 4096;
|
|
46
|
+
|
|
47
|
+
/** One JSON line out, the first line back. Rejects on a socket error, a reply-less close or the timeout. */
|
|
48
|
+
export function sendHello(socketPath, frame, timeoutMs = HELLO_TIMEOUT_MS) {
|
|
49
|
+
return new Promise((resolve, reject) => {
|
|
50
|
+
const sock = net.createConnection({ path: socketPath });
|
|
51
|
+
let buf = "";
|
|
52
|
+
const timer = setTimeout(() => {
|
|
53
|
+
sock.destroy();
|
|
54
|
+
reject(new Error("no answer in time"));
|
|
55
|
+
}, timeoutMs);
|
|
56
|
+
sock.on("connect", () => sock.write(`${JSON.stringify(frame)}\n`));
|
|
57
|
+
sock.on("data", (d) => {
|
|
58
|
+
buf += d.toString("utf8");
|
|
59
|
+
const i = buf.indexOf("\n");
|
|
60
|
+
if (i < 0 && buf.length > MAX_ANSWER_BYTES) {
|
|
61
|
+
clearTimeout(timer);
|
|
62
|
+
sock.destroy();
|
|
63
|
+
reject(new Error("answer too long"));
|
|
64
|
+
} else if (i >= 0) {
|
|
65
|
+
clearTimeout(timer);
|
|
66
|
+
sock.end();
|
|
67
|
+
resolve(buf.slice(0, i));
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
sock.on("error", (e) => {
|
|
71
|
+
clearTimeout(timer);
|
|
72
|
+
reject(e);
|
|
73
|
+
});
|
|
74
|
+
sock.on("close", () => {
|
|
75
|
+
clearTimeout(timer);
|
|
76
|
+
if (buf.indexOf("\n") < 0) reject(new Error("closed without an answer"));
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Whether the answer line is an accepted hello (`{"ok":true,...}`). */
|
|
82
|
+
export function accepted(line) {
|
|
83
|
+
try {
|
|
84
|
+
const v = JSON.parse(line);
|
|
85
|
+
return Boolean(v) && typeof v === "object" && v.ok === true;
|
|
86
|
+
} catch {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** The hook: resolves to what it did ("skipped" | "accepted" | "refused" | "failed"). Never throws. */
|
|
92
|
+
export async function runSeatHello(env, deps = {}) {
|
|
93
|
+
const send = deps.send ?? sendHello;
|
|
94
|
+
const warn = deps.warn ?? ((l) => process.stderr.write(`${l}\n`));
|
|
95
|
+
const h = helloFromEnv(env);
|
|
96
|
+
if (h.skip) return "skipped";
|
|
97
|
+
if (h.error) {
|
|
98
|
+
warn(`mnemom: seat hello not sent: ${h.error}`);
|
|
99
|
+
return "failed";
|
|
100
|
+
}
|
|
101
|
+
let line;
|
|
102
|
+
try {
|
|
103
|
+
line = await send(h.socketPath, h.frame);
|
|
104
|
+
} catch (e) {
|
|
105
|
+
warn(`mnemom: seat hello failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
106
|
+
return "failed";
|
|
107
|
+
}
|
|
108
|
+
if (accepted(line)) return "accepted";
|
|
109
|
+
warn(`mnemom: seat hello refused: ${line}`);
|
|
110
|
+
return "refused";
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
114
|
+
await runSeatHello(process.env);
|
|
115
|
+
process.exitCode = 0;
|
|
116
|
+
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The one-time notice for door one's T16 default (decisions 12 and 22, OD-13): on a
|
|
3
|
-
* prerelease (`next`) build an interactive or Remote Control launch with nothing
|
|
4
|
-
* configured runs with an implicit goal. The first launch that gets that default says
|
|
5
|
-
* so once, with both opt-outs; every later launch is silent.
|
|
6
|
-
*
|
|
7
|
-
* State file (~/.mnemom/implicit-notice.json): { shown_at }. A launch with an explicit
|
|
8
|
-
* mode (a flag, `--goal`, `goal_mode`, the experimental feature) never reaches this, and
|
|
9
|
-
* --dry-run neither prints nor records it. A state file that cannot be read counts as
|
|
10
|
-
* not shown; one that cannot be written never fails the launch.
|
|
11
|
-
*/
|
|
12
|
-
export declare const IMPLICIT_NOTICE_FILE = "implicit-notice.json";
|
|
13
|
-
export declare const IMPLICIT_DEFAULT_NOTICE: string;
|
|
14
|
-
export interface ImplicitNoticeDeps {
|
|
15
|
-
/** The state file's text, or null when it is missing or unreadable. */
|
|
16
|
-
read(): string | null;
|
|
17
|
-
write(text: string): void;
|
|
18
|
-
note(line: string): void;
|
|
19
|
-
now(): Date;
|
|
20
|
-
}
|
|
21
|
-
/** Has the notice been shown on this machine? Any parseable `shown_at` string counts. */
|
|
22
|
-
export declare function noticeShown(text: string | null): boolean;
|
|
23
|
-
/** Print the notice unless it was shown before, then record it. Returns whether it printed. */
|
|
24
|
-
export declare function maybeShowImplicitNotice(opts: {
|
|
25
|
-
dryRun?: boolean;
|
|
26
|
-
}, deps: ImplicitNoticeDeps): boolean;
|
|
27
|
-
export declare function defaultImplicitNoticeDeps(mnemomDir?: string): ImplicitNoticeDeps;
|
|
28
|
-
/** Called by the launch when its implicit goal came from the prerelease default. */
|
|
29
|
-
export declare function showImplicitDefaultNoticeOnce(opts: {
|
|
30
|
-
dryRun?: boolean;
|
|
31
|
-
}, deps?: ImplicitNoticeDeps): boolean;
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The one-time notice for door one's T16 default (decisions 12 and 22, OD-13): on a
|
|
3
|
-
* prerelease (`next`) build an interactive or Remote Control launch with nothing
|
|
4
|
-
* configured runs with an implicit goal. The first launch that gets that default says
|
|
5
|
-
* so once, with both opt-outs; every later launch is silent.
|
|
6
|
-
*
|
|
7
|
-
* State file (~/.mnemom/implicit-notice.json): { shown_at }. A launch with an explicit
|
|
8
|
-
* mode (a flag, `--goal`, `goal_mode`, the experimental feature) never reaches this, and
|
|
9
|
-
* --dry-run neither prints nor records it. A state file that cannot be read counts as
|
|
10
|
-
* not shown; one that cannot be written never fails the launch.
|
|
11
|
-
*/
|
|
12
|
-
import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
13
|
-
import { dirname, join } from "node:path";
|
|
14
|
-
import { MNEMOM_DIR } from "../lib/config.js";
|
|
15
|
-
export const IMPLICIT_NOTICE_FILE = "implicit-notice.json";
|
|
16
|
-
export const IMPLICIT_DEFAULT_NOTICE = "mnemom: implicit goals are on by default in this prerelease. The gateway infers the " +
|
|
17
|
-
"session's goal from your messages, and the record says the goal was implicit, never sealed. " +
|
|
18
|
-
"Turn it off for one launch with --no-implicit, or for every launch with " +
|
|
19
|
-
"`mnemom agent config set goal_mode off`.";
|
|
20
|
-
/** Has the notice been shown on this machine? Any parseable `shown_at` string counts. */
|
|
21
|
-
export function noticeShown(text) {
|
|
22
|
-
if (text === null)
|
|
23
|
-
return false;
|
|
24
|
-
try {
|
|
25
|
-
const v = JSON.parse(text);
|
|
26
|
-
return (typeof v === "object" &&
|
|
27
|
-
v !== null &&
|
|
28
|
-
typeof v.shown_at === "string");
|
|
29
|
-
}
|
|
30
|
-
catch {
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
/** Print the notice unless it was shown before, then record it. Returns whether it printed. */
|
|
35
|
-
export function maybeShowImplicitNotice(opts, deps) {
|
|
36
|
-
if (opts.dryRun)
|
|
37
|
-
return false;
|
|
38
|
-
if (noticeShown(deps.read()))
|
|
39
|
-
return false;
|
|
40
|
-
deps.note(IMPLICIT_DEFAULT_NOTICE);
|
|
41
|
-
try {
|
|
42
|
-
deps.write(`${JSON.stringify({ shown_at: deps.now().toISOString() })}\n`);
|
|
43
|
-
}
|
|
44
|
-
catch {
|
|
45
|
-
// Never fail a launch over a notice.
|
|
46
|
-
}
|
|
47
|
-
return true;
|
|
48
|
-
}
|
|
49
|
-
export function defaultImplicitNoticeDeps(mnemomDir = MNEMOM_DIR) {
|
|
50
|
-
const path = join(mnemomDir, IMPLICIT_NOTICE_FILE);
|
|
51
|
-
return {
|
|
52
|
-
read: () => {
|
|
53
|
-
try {
|
|
54
|
-
return readFileSync(path, "utf8");
|
|
55
|
-
}
|
|
56
|
-
catch {
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
write: (text) => {
|
|
61
|
-
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
62
|
-
const tmp = `${path}.${process.pid}.tmp`;
|
|
63
|
-
writeFileSync(tmp, text, { mode: 0o600 });
|
|
64
|
-
renameSync(tmp, path);
|
|
65
|
-
},
|
|
66
|
-
note: (line) => console.error(line),
|
|
67
|
-
now: () => new Date(),
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
/** Called by the launch when its implicit goal came from the prerelease default. */
|
|
71
|
-
export function showImplicitDefaultNoticeOnce(opts, deps = defaultImplicitNoticeDeps()) {
|
|
72
|
-
return maybeShowImplicitNotice(opts, deps);
|
|
73
|
-
}
|