@smartmemory/compose 0.4.0 → 0.5.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.
Files changed (114) hide show
  1. package/.claude/agents/compose-architect.md +40 -0
  2. package/.claude/agents/compose-explorer.md +35 -0
  3. package/.claude/hooks/canon-guard.mjs +52 -0
  4. package/README.md +1 -1
  5. package/bin/compose.js +33 -14
  6. package/bin/git-hooks/pre-push.template +26 -1
  7. package/bin/receipts-gate.js +39 -0
  8. package/contracts/fluid-record.schema.json +5 -0
  9. package/dist/assets/{App-Z4MU-H_F.js → App-DC7paCZv.js} +190 -190
  10. package/dist/assets/{_baseUniq-ClWoCPFl.js → _baseUniq-Czad7yiy.js} +1 -1
  11. package/dist/assets/{arc-DY26UIVo.js → arc-EquvLk8y.js} +1 -1
  12. package/dist/assets/{architectureDiagram-Q4EWVU46-6Ggq4DqJ.js → architectureDiagram-Q4EWVU46-Dr_qinWi.js} +1 -1
  13. package/dist/assets/{blockDiagram-DXYQGD6D-CH3Ked0l.js → blockDiagram-DXYQGD6D-D2z46ED_.js} +1 -1
  14. package/dist/assets/{c4Diagram-AHTNJAMY-Bk8dYilu.js → c4Diagram-AHTNJAMY-BHob1Yt0.js} +1 -1
  15. package/dist/assets/channel-B-7ZRCKC.js +1 -0
  16. package/dist/assets/{chunk-4BX2VUAB-BMR0XaAQ.js → chunk-4BX2VUAB-DomWBRa_.js} +1 -1
  17. package/dist/assets/{chunk-4TB4RGXK-JytR14a9.js → chunk-4TB4RGXK-WyC_x_DH.js} +1 -1
  18. package/dist/assets/{chunk-55IACEB6-B4Q97BCP.js → chunk-55IACEB6-BajRv3zx.js} +1 -1
  19. package/dist/assets/{chunk-EDXVE4YY-R_qarkSf.js → chunk-EDXVE4YY-rMnedK_r.js} +1 -1
  20. package/dist/assets/{chunk-FMBD7UC4-C9s7KR9m.js → chunk-FMBD7UC4-BPi03Hcb.js} +1 -1
  21. package/dist/assets/{chunk-OYMX7WX6-BySQzVxc.js → chunk-OYMX7WX6-B7J_mKX0.js} +1 -1
  22. package/dist/assets/{chunk-QZHKN3VN-DdpSYZsW.js → chunk-QZHKN3VN-BLXTVr8N.js} +1 -1
  23. package/dist/assets/{chunk-YZCP3GAM-iE_tzriw.js → chunk-YZCP3GAM-BYWjo2OJ.js} +1 -1
  24. package/dist/assets/classDiagram-6PBFFD2Q-Balz1OEB.js +1 -0
  25. package/dist/assets/classDiagram-v2-HSJHXN6E-Balz1OEB.js +1 -0
  26. package/dist/assets/clone-CfNV0lUO.js +1 -0
  27. package/dist/assets/{cose-bilkent-S5V4N54A-BdlU6ZX_.js → cose-bilkent-S5V4N54A-Coaq0xaU.js} +1 -1
  28. package/dist/assets/{dagre-KV5264BT-Cp3F5KTn.js → dagre-KV5264BT-DvUvAxlj.js} +1 -1
  29. package/dist/assets/{diagram-5BDNPKRD-DiR6_2q_.js → diagram-5BDNPKRD-70bXRUXV.js} +1 -1
  30. package/dist/assets/{diagram-G4DWMVQ6-w0i-p5HX.js → diagram-G4DWMVQ6-hMA8wgzx.js} +1 -1
  31. package/dist/assets/{diagram-MMDJMWI5-tIHhwUv3.js → diagram-MMDJMWI5-BNir7C6i.js} +1 -1
  32. package/dist/assets/{diagram-TYMM5635-BAeY3B19.js → diagram-TYMM5635-BCYl1xrE.js} +1 -1
  33. package/dist/assets/{erDiagram-SMLLAGMA-Ckx_Knko.js → erDiagram-SMLLAGMA-bjxP0_bt.js} +1 -1
  34. package/dist/assets/{flowDiagram-DWJPFMVM-DeoNka6J.js → flowDiagram-DWJPFMVM-CBn9fhEp.js} +1 -1
  35. package/dist/assets/{ganttDiagram-T4ZO3ILL-BmGnFbEg.js → ganttDiagram-T4ZO3ILL-y1O7mWzn.js} +1 -1
  36. package/dist/assets/{gitGraphDiagram-UUTBAWPF-Dk48IHsx.js → gitGraphDiagram-UUTBAWPF-DIxwDXHB.js} +1 -1
  37. package/dist/assets/{graph-BNzKGvoy.js → graph-9D1ZumWp.js} +1 -1
  38. package/dist/assets/{index-BEfrNBp8.js → index-Ds_IXQo3.js} +2 -2
  39. package/dist/assets/{infoDiagram-42DDH7IO-BRf827i0.js → infoDiagram-42DDH7IO-DsWLGhaY.js} +1 -1
  40. package/dist/assets/{ishikawaDiagram-UXIWVN3A-0kCZaeCM.js → ishikawaDiagram-UXIWVN3A-CipZIE90.js} +1 -1
  41. package/dist/assets/{journeyDiagram-VCZTEJTY-rvU7ayRt.js → journeyDiagram-VCZTEJTY-Vr5xqcQm.js} +1 -1
  42. package/dist/assets/{kanban-definition-6JOO6SKY-DpQwX1C5.js → kanban-definition-6JOO6SKY-EqUYneyh.js} +1 -1
  43. package/dist/assets/{layout-BI8cXFPI.js → layout-hfWIIs0-.js} +1 -1
  44. package/dist/assets/{linear-a0glcDiw.js → linear-BdDWoN0t.js} +1 -1
  45. package/dist/assets/{min-vPHfnXcC.js → min-Bn_xAS7n.js} +1 -1
  46. package/dist/assets/{mindmap-definition-QFDTVHPH-D14eF-7C.js → mindmap-definition-QFDTVHPH-qsgubzCF.js} +1 -1
  47. package/dist/assets/{pieDiagram-DEJITSTG-Cno-gETh.js → pieDiagram-DEJITSTG-Bv1xq_58.js} +1 -1
  48. package/dist/assets/{quadrantDiagram-34T5L4WZ-BUQM1Hfm.js → quadrantDiagram-34T5L4WZ-DwMbAegF.js} +1 -1
  49. package/dist/assets/{requirementDiagram-MS252O5E-pOXlN2-q.js → requirementDiagram-MS252O5E-BJVmLNcp.js} +1 -1
  50. package/dist/assets/{sankeyDiagram-XADWPNL6-Crynd3_b.js → sankeyDiagram-XADWPNL6-o5GZb8Y1.js} +1 -1
  51. package/dist/assets/{sequenceDiagram-FGHM5R23-D9fZdCM8.js → sequenceDiagram-FGHM5R23-ocqJp2qk.js} +1 -1
  52. package/dist/assets/{stateDiagram-FHFEXIEX-CW9qVec8.js → stateDiagram-FHFEXIEX-DGaDUFxP.js} +1 -1
  53. package/dist/assets/stateDiagram-v2-QKLJ7IA2-Dz-15i-r.js +1 -0
  54. package/dist/assets/{timeline-definition-GMOUNBTQ-BcHzhm_8.js → timeline-definition-GMOUNBTQ-C4YwFvAn.js} +1 -1
  55. package/dist/assets/{vennDiagram-DHZGUBPP-BfytJcWk.js → vennDiagram-DHZGUBPP-uOKn9j-y.js} +1 -1
  56. package/dist/assets/{wardley-RL74JXVD-DLj-IjyB.js → wardley-RL74JXVD-DIQSmQde.js} +1 -1
  57. package/dist/assets/{wardleyDiagram-NUSXRM2D-Ds0Ue68c.js → wardleyDiagram-NUSXRM2D-CdamsEDC.js} +1 -1
  58. package/dist/assets/{xychartDiagram-5P7HB3ND-vjWDXFL6.js → xychartDiagram-5P7HB3ND-DhLs41yk.js} +1 -1
  59. package/dist/index.html +1 -1
  60. package/lib/build-cancel.js +205 -0
  61. package/lib/build.js +552 -87
  62. package/lib/canon-guard.js +3 -24
  63. package/lib/canon-registry.js +2 -71
  64. package/lib/codex-preflight.js +8 -0
  65. package/lib/colleague/context.js +123 -0
  66. package/lib/consumer-fanout.js +24 -1
  67. package/lib/decision-blocks.js +38 -0
  68. package/lib/dispatch-ledger.js +7 -0
  69. package/lib/fluid/factory.js +112 -1
  70. package/lib/fluid/ideabox-manifest.js +203 -0
  71. package/lib/fluid/ideabox-migrate.js +177 -29
  72. package/lib/fluid/ideabox-preamble.js +155 -0
  73. package/lib/fluid/ideabox-readable.js +83 -0
  74. package/lib/fluid/ideabox-recover.js +393 -0
  75. package/lib/fluid/import-ideabox.js +188 -45
  76. package/lib/fluid/local-provider.js +6 -0
  77. package/lib/fluid/portfolio.js +255 -0
  78. package/lib/fluid/record-shape.js +7 -0
  79. package/lib/fluid/render-ideabox.js +153 -7
  80. package/lib/fluid/smartmemory-provider.js +6 -0
  81. package/lib/gate-prompt.js +14 -7
  82. package/lib/ideabox-cli.js +68 -0
  83. package/lib/ideabox.js +209 -9
  84. package/lib/maya-identity.js +16 -2
  85. package/lib/process-termination.js +121 -3
  86. package/lib/receipts-gate.js +268 -0
  87. package/lib/result-normalizer.js +28 -1
  88. package/lib/smartmemory-client.js +68 -1
  89. package/lib/stratum-mcp-client.js +104 -5
  90. package/lib/tool-inventory.js +0 -1
  91. package/lib/version-check.js +9 -3
  92. package/package.json +7 -5
  93. package/server/build-stream-bridge.js +43 -1
  94. package/server/cc-session-watcher.js +54 -5
  95. package/server/compose-mcp-tools.js +48 -50
  96. package/server/compose-mcp.js +0 -2
  97. package/server/design-routes.js +1 -1
  98. package/server/file-watcher.js +14 -0
  99. package/server/ideabox-routes.js +10 -0
  100. package/server/index.js +5 -1
  101. package/server/lifecycle-guard.js +13 -0
  102. package/server/maya-routes.js +111 -7
  103. package/server/mcp-tool-defs.js +0 -25
  104. package/server/mcp-tool-policy.js +6 -13
  105. package/server/stratum-client.js +61 -15
  106. package/server/supervisor.js +18 -4
  107. package/server/vision-routes.js +9 -3
  108. package/dist/assets/channel-SnZzzh7k.js +0 -1
  109. package/dist/assets/classDiagram-6PBFFD2Q-CBu92dSH.js +0 -1
  110. package/dist/assets/classDiagram-v2-HSJHXN6E-CBu92dSH.js +0 -1
  111. package/dist/assets/clone-DgklGjHm.js +0 -1
  112. package/dist/assets/stateDiagram-v2-QKLJ7IA2-DkVLzHbY.js +0 -1
  113. package/lib/append-integrity.js +0 -81
  114. package/lib/canon-override.js +0 -196
@@ -1,196 +0,0 @@
1
- /**
2
- * canon-override.js — the canon override: grant-then-write, ledger-first.
3
- *
4
- * COMP-CANON-OVERRIDE S2, implementing COMP-CANON-GUARD Decision 4.
5
- *
6
- * WHAT THIS IS: audit and careless-drift tooling. It makes the cooperative
7
- * path logged and the accidental path hard. It is NOT enforcement and must
8
- * never be described as such — `Bash` and Codex writes never reach the hook,
9
- * and every piece of state here lives in the workspace the agent can write.
10
- * A determined actor who forges a token AND its ledger row AND the baseline
11
- * passes. See design.md, "The in-workspace ceiling".
12
- *
13
- * ORDERING IS THE ATOMICITY ANSWER. The bypass row and the attest baseline are
14
- * written BEFORE the token is minted, so the failure mode is over-recording,
15
- * never under-recording: a token cannot exist without its row. If the write
16
- * that follows never happens, a bypass entry exists for a write that did not
17
- * occur — deliberately the safe direction.
18
- *
19
- * SINGLE-USE IS A RENAME, NOT A LOCK. Each grant is its own file, claimed by
20
- * renaming it into `consumed/`. Exactly one caller can rename a given path;
21
- * every loser gets ENOENT. An earlier draft used one shared JSON file with
22
- * temp-write-plus-rename, which gives atomic *publication* but not mutual
23
- * exclusion — two readers could each drop the token from their own snapshot
24
- * and both succeed.
25
- */
26
- import {
27
- mkdirSync, writeFileSync, readFileSync, renameSync, readdirSync, existsSync, appendFileSync,
28
- } from 'node:fs';
29
- import { join, dirname } from 'node:path';
30
- import { randomUUID } from 'node:crypto';
31
- import { isOverrideEligible } from './canon-registry.js';
32
- import { baselineFor } from './append-integrity.js';
33
-
34
- export const LEDGER_REL = '.compose/canon-overrides.jsonl';
35
- export const ATTEST_REL = '.compose/canon-overrides-attest.json';
36
- export const GRANTS_REL = '.compose/data/canon-grants';
37
- const CONSUMED_SUBDIR = 'consumed';
38
-
39
- /** 5 minutes: long enough for a grant-then-write round trip through an agent
40
- * turn, short enough that a forgotten grant is not a standing hole. */
41
- export const GRANT_TTL_MS = 5 * 60 * 1000;
42
-
43
- function typedError(code, message) {
44
- const err = new Error(message);
45
- err.code = code;
46
- return err;
47
- }
48
-
49
- function ensureDir(path) {
50
- mkdirSync(path, { recursive: true });
51
- }
52
-
53
- /** Read the bypass ledger as parsed rows. Malformed lines are skipped rather
54
- * than thrown on — a corrupt row must not make every claim fail open. */
55
- export function readOverrideLedger(cwd) {
56
- const path = join(cwd, LEDGER_REL);
57
- let raw;
58
- try {
59
- raw = readFileSync(path, 'utf8');
60
- } catch (err) {
61
- if (err?.code === 'ENOENT') return [];
62
- throw err;
63
- }
64
- const rows = [];
65
- for (const line of raw.split('\n')) {
66
- if (!line.trim()) continue;
67
- try { rows.push(JSON.parse(line)); } catch { /* skip a corrupt row */ }
68
- }
69
- return rows;
70
- }
71
-
72
- /**
73
- * Mint a single-use, path-scoped grant.
74
- *
75
- * @param {string} cwd workspace root
76
- * @param {{path:string, reason:string, operation?:string, featuresDir?:string}} args
77
- * `actor` is deliberately NOT accepted — it is stamped here per Decision 3.
78
- * @returns {{token_id:string, path:string, expires_at:string}}
79
- */
80
- export function mintGrant(cwd, { path, reason, operation, featuresDir = 'docs/features' } = {}) {
81
- if (typeof reason !== 'string' || reason.trim() === '') {
82
- throw typedError(
83
- 'CANON_OVERRIDE_REASON',
84
- 'canon_override_grant: a non-empty reason is required — the bypass row is the whole point',
85
- );
86
- }
87
- if (typeof path !== 'string' || path.trim() === '') {
88
- throw typedError('CANON_OVERRIDE_PATH', 'canon_override_grant: path is required');
89
- }
90
- if (!isOverrideEligible(path, { featuresDir, point: 'hook' })) {
91
- throw typedError(
92
- 'CANON_OVERRIDE_INELIGIBLE',
93
- `canon_override_grant: ${path} is not override-eligible. Either it is not guarded at the `
94
- + 'write-time hook (nothing is blocking it), or it is the override\'s own governance state, '
95
- + 'which is deliberately ungrantable so a bypass cannot authorise rewriting its own record.',
96
- );
97
- }
98
-
99
- const now = new Date();
100
- const tokenId = randomUUID();
101
- const row = {
102
- ts: now.toISOString(),
103
- actor: 'agent', // stamped here; never caller-supplied
104
- path,
105
- reason: reason.trim(),
106
- operation: typeof operation === 'string' ? operation : null,
107
- token_id: tokenId,
108
- };
109
-
110
- // ── Ledger and baseline FIRST ──────────────────────────────────────────────
111
- const ledgerPath = join(cwd, LEDGER_REL);
112
- ensureDir(dirname(ledgerPath));
113
- appendFileSync(ledgerPath, `${JSON.stringify(row)}\n`);
114
- writeAttestBaseline(cwd);
115
-
116
- // ── Then the token ─────────────────────────────────────────────────────────
117
- const grantsDir = join(cwd, GRANTS_REL);
118
- ensureDir(grantsDir);
119
- const expiresAt = new Date(now.getTime() + GRANT_TTL_MS).toISOString();
120
- writeFileSync(
121
- join(grantsDir, `${tokenId}.json`),
122
- `${JSON.stringify({
123
- token_id: tokenId,
124
- path,
125
- actor: 'agent',
126
- operation: row.operation,
127
- issued_at: now.toISOString(),
128
- expires_at: expiresAt,
129
- }, null, 2)}\n`,
130
- { flag: 'wx' }, // exclusive create: mint is serialized too
131
- );
132
-
133
- return { token_id: tokenId, path, expires_at: expiresAt };
134
- }
135
-
136
- /** Re-attest the bypass ledger. Called only from the append path — never as a
137
- * standalone "fix", which would be the laundering step (S5 R1). */
138
- function writeAttestBaseline(cwd) {
139
- const ledgerPath = join(cwd, LEDGER_REL);
140
- const bytes = existsSync(ledgerPath) ? readFileSync(ledgerPath) : Buffer.alloc(0);
141
- const attestPath = join(cwd, ATTEST_REL);
142
- ensureDir(dirname(attestPath));
143
- writeFileSync(attestPath, `${JSON.stringify(baselineFor(bytes), null, 2)}\n`);
144
- }
145
-
146
- /**
147
- * Claim a live grant for exactly `path`. Returns true if the write may proceed.
148
- *
149
- * Never throws: the hook's policy is fail-open, and a claim that explodes must
150
- * not wedge the session. A false return means "no grant" and the caller denies
151
- * on its own terms.
152
- */
153
- export function claimGrant(cwd, path) {
154
- try {
155
- const grantsDir = join(cwd, GRANTS_REL);
156
- if (!existsSync(grantsDir)) return false;
157
-
158
- // A token is only honoured if its row is in the ledger. This is what stops
159
- // a raw-written token file from being consumable — the Bash-forgery case.
160
- // It binds the two artifacts without pretending to be crypto: an actor who
161
- // writes BOTH still passes, which is the documented ceiling.
162
- const ledgerTokenIds = new Set(
163
- readOverrideLedger(cwd).filter((r) => r?.path === path).map((r) => r?.token_id),
164
- );
165
- if (ledgerTokenIds.size === 0) return false;
166
-
167
- const now = Date.now();
168
- for (const entry of readdirSync(grantsDir, { withFileTypes: true })) {
169
- if (!entry.isFile() || !entry.name.endsWith('.json')) continue;
170
- const tokenPath = join(grantsDir, entry.name);
171
-
172
- let token;
173
- try { token = JSON.parse(readFileSync(tokenPath, 'utf8')); } catch { continue; }
174
- if (token?.path !== path) continue;
175
- if (!ledgerTokenIds.has(token?.token_id)) continue;
176
-
177
- // Expiry from the immutable stamp, NOT mtime: a checkout gives a file a
178
- // fresh mtime, which would revive a mistakenly committed token.
179
- const expiresAt = Date.parse(token?.expires_at ?? '');
180
- if (!Number.isFinite(expiresAt) || expiresAt <= now) continue;
181
-
182
- // The claim. Exactly one caller can rename a given path; losers get ENOENT.
183
- const consumedDir = join(grantsDir, CONSUMED_SUBDIR);
184
- ensureDir(consumedDir);
185
- try {
186
- renameSync(tokenPath, join(consumedDir, entry.name));
187
- return true;
188
- } catch {
189
- continue; // another process won; try the next token
190
- }
191
- }
192
- return false;
193
- } catch {
194
- return false;
195
- }
196
- }