@cleocode/core 2026.4.11 → 2026.4.12

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 (169) hide show
  1. package/dist/codebase-map/analyzers/architecture.d.ts.map +1 -1
  2. package/dist/codebase-map/analyzers/architecture.js +0 -1
  3. package/dist/codebase-map/analyzers/architecture.js.map +1 -1
  4. package/dist/conduit/local-transport.d.ts +18 -8
  5. package/dist/conduit/local-transport.d.ts.map +1 -1
  6. package/dist/conduit/local-transport.js +23 -13
  7. package/dist/conduit/local-transport.js.map +1 -1
  8. package/dist/config.d.ts.map +1 -1
  9. package/dist/config.js +0 -1
  10. package/dist/config.js.map +1 -1
  11. package/dist/errors.d.ts +19 -0
  12. package/dist/errors.d.ts.map +1 -1
  13. package/dist/errors.js +6 -0
  14. package/dist/errors.js.map +1 -1
  15. package/dist/index.js +175 -68950
  16. package/dist/index.js.map +1 -7
  17. package/dist/init.d.ts +1 -2
  18. package/dist/init.d.ts.map +1 -1
  19. package/dist/init.js +1 -2
  20. package/dist/init.js.map +1 -1
  21. package/dist/internal.d.ts +8 -3
  22. package/dist/internal.d.ts.map +1 -1
  23. package/dist/internal.js +13 -6
  24. package/dist/internal.js.map +1 -1
  25. package/dist/memory/learnings.d.ts +2 -2
  26. package/dist/memory/patterns.d.ts +6 -6
  27. package/dist/output.d.ts +32 -11
  28. package/dist/output.d.ts.map +1 -1
  29. package/dist/output.js +67 -67
  30. package/dist/output.js.map +1 -1
  31. package/dist/paths.js +80 -14
  32. package/dist/paths.js.map +1 -1
  33. package/dist/skills/dynamic-skill-generator.d.ts +0 -2
  34. package/dist/skills/dynamic-skill-generator.d.ts.map +1 -1
  35. package/dist/skills/dynamic-skill-generator.js.map +1 -1
  36. package/dist/store/agent-registry-accessor.d.ts +203 -12
  37. package/dist/store/agent-registry-accessor.d.ts.map +1 -1
  38. package/dist/store/agent-registry-accessor.js +618 -100
  39. package/dist/store/agent-registry-accessor.js.map +1 -1
  40. package/dist/store/api-key-kdf.d.ts +73 -0
  41. package/dist/store/api-key-kdf.d.ts.map +1 -0
  42. package/dist/store/api-key-kdf.js +84 -0
  43. package/dist/store/api-key-kdf.js.map +1 -0
  44. package/dist/store/cleanup-legacy.js +171 -0
  45. package/dist/store/cleanup-legacy.js.map +1 -0
  46. package/dist/store/conduit-sqlite.d.ts +184 -0
  47. package/dist/store/conduit-sqlite.d.ts.map +1 -0
  48. package/dist/store/conduit-sqlite.js +570 -0
  49. package/dist/store/conduit-sqlite.js.map +1 -0
  50. package/dist/store/global-salt.d.ts +78 -0
  51. package/dist/store/global-salt.d.ts.map +1 -0
  52. package/dist/store/global-salt.js +147 -0
  53. package/dist/store/global-salt.js.map +1 -0
  54. package/dist/store/migrate-signaldock-to-conduit.d.ts +81 -0
  55. package/dist/store/migrate-signaldock-to-conduit.d.ts.map +1 -0
  56. package/dist/store/migrate-signaldock-to-conduit.js +555 -0
  57. package/dist/store/migrate-signaldock-to-conduit.js.map +1 -0
  58. package/dist/store/nexus-sqlite.js +28 -3
  59. package/dist/store/nexus-sqlite.js.map +1 -1
  60. package/dist/store/signaldock-sqlite.d.ts +122 -19
  61. package/dist/store/signaldock-sqlite.d.ts.map +1 -1
  62. package/dist/store/signaldock-sqlite.js +401 -251
  63. package/dist/store/signaldock-sqlite.js.map +1 -1
  64. package/dist/store/sqlite-backup.js +122 -4
  65. package/dist/store/sqlite-backup.js.map +1 -1
  66. package/dist/system/backup.d.ts +0 -26
  67. package/dist/system/backup.d.ts.map +1 -1
  68. package/dist/system/runtime.d.ts +0 -2
  69. package/dist/system/runtime.d.ts.map +1 -1
  70. package/dist/system/runtime.js +3 -3
  71. package/dist/system/runtime.js.map +1 -1
  72. package/dist/tasks/add.d.ts +1 -1
  73. package/dist/tasks/add.d.ts.map +1 -1
  74. package/dist/tasks/add.js +98 -23
  75. package/dist/tasks/add.js.map +1 -1
  76. package/dist/tasks/complete.d.ts.map +1 -1
  77. package/dist/tasks/complete.js +4 -1
  78. package/dist/tasks/complete.js.map +1 -1
  79. package/dist/tasks/find.d.ts.map +1 -1
  80. package/dist/tasks/find.js +4 -1
  81. package/dist/tasks/find.js.map +1 -1
  82. package/dist/tasks/labels.d.ts.map +1 -1
  83. package/dist/tasks/labels.js +4 -1
  84. package/dist/tasks/labels.js.map +1 -1
  85. package/dist/tasks/relates.d.ts.map +1 -1
  86. package/dist/tasks/relates.js +16 -4
  87. package/dist/tasks/relates.js.map +1 -1
  88. package/dist/tasks/show.d.ts.map +1 -1
  89. package/dist/tasks/show.js +4 -1
  90. package/dist/tasks/show.js.map +1 -1
  91. package/dist/tasks/update.d.ts.map +1 -1
  92. package/dist/tasks/update.js +32 -6
  93. package/dist/tasks/update.js.map +1 -1
  94. package/dist/validation/engine.d.ts.map +1 -1
  95. package/dist/validation/engine.js +16 -4
  96. package/dist/validation/engine.js.map +1 -1
  97. package/dist/validation/param-utils.d.ts +5 -3
  98. package/dist/validation/param-utils.d.ts.map +1 -1
  99. package/dist/validation/param-utils.js +8 -6
  100. package/dist/validation/param-utils.js.map +1 -1
  101. package/dist/validation/protocols/_shared.d.ts.map +1 -1
  102. package/dist/validation/protocols/_shared.js +13 -6
  103. package/dist/validation/protocols/_shared.js.map +1 -1
  104. package/package.json +7 -7
  105. package/src/adapters/__tests__/manager.test.ts +0 -1
  106. package/src/codebase-map/analyzers/architecture.ts +0 -1
  107. package/src/conduit/__tests__/local-credential-flow.test.ts +20 -18
  108. package/src/conduit/__tests__/local-transport.test.ts +14 -12
  109. package/src/conduit/local-transport.ts +23 -13
  110. package/src/config.ts +0 -1
  111. package/src/errors.ts +24 -0
  112. package/src/hooks/handlers/__tests__/hook-automation-e2e.test.ts +2 -5
  113. package/src/init.ts +1 -2
  114. package/src/internal.ts +49 -2
  115. package/src/lifecycle/cant/lifecycle-rcasd.cant +133 -0
  116. package/src/memory/__tests__/engine-compat.test.ts +2 -2
  117. package/src/memory/__tests__/pipeline-manifest-sqlite.test.ts +4 -4
  118. package/src/observability/__tests__/index.test.ts +4 -4
  119. package/src/observability/__tests__/log-filter.test.ts +4 -4
  120. package/src/output.ts +73 -75
  121. package/src/sessions/__tests__/session-grade.integration.test.ts +1 -1
  122. package/src/sessions/__tests__/session-grade.test.ts +2 -2
  123. package/src/skills/__tests__/dynamic-skill-generator.test.ts +0 -2
  124. package/src/skills/dynamic-skill-generator.ts +0 -2
  125. package/src/store/__tests__/agent-registry-accessor.test.ts +807 -0
  126. package/src/store/__tests__/api-key-kdf.test.ts +113 -0
  127. package/src/store/__tests__/conduit-sqlite.test.ts +413 -0
  128. package/src/store/__tests__/global-salt.test.ts +195 -0
  129. package/src/store/__tests__/migrate-signaldock-to-conduit.test.ts +715 -0
  130. package/src/store/__tests__/signaldock-sqlite.test.ts +652 -0
  131. package/src/store/__tests__/sqlite-backup-global.test.ts +307 -3
  132. package/src/store/__tests__/sqlite-backup.test.ts +5 -1
  133. package/src/store/__tests__/t310-integration.test.ts +1150 -0
  134. package/src/store/agent-registry-accessor.ts +847 -140
  135. package/src/store/api-key-kdf.ts +104 -0
  136. package/src/store/conduit-sqlite.ts +655 -0
  137. package/src/store/global-salt.ts +175 -0
  138. package/src/store/migrate-signaldock-to-conduit.ts +669 -0
  139. package/src/store/signaldock-sqlite.ts +431 -254
  140. package/src/store/sqlite-backup.ts +185 -10
  141. package/src/system/backup.ts +2 -62
  142. package/src/system/runtime.ts +4 -6
  143. package/src/tasks/__tests__/error-hints.test.ts +256 -0
  144. package/src/tasks/add.ts +99 -9
  145. package/src/tasks/complete.ts +4 -1
  146. package/src/tasks/find.ts +4 -1
  147. package/src/tasks/labels.ts +4 -1
  148. package/src/tasks/relates.ts +16 -4
  149. package/src/tasks/show.ts +4 -1
  150. package/src/tasks/update.ts +32 -3
  151. package/src/validation/__tests__/error-hints.test.ts +97 -0
  152. package/src/validation/engine.ts +16 -1
  153. package/src/validation/param-utils.ts +10 -7
  154. package/src/validation/protocols/_shared.ts +14 -6
  155. package/src/validation/protocols/cant/architecture-decision.cant +80 -0
  156. package/src/validation/protocols/cant/artifact-publish.cant +95 -0
  157. package/src/validation/protocols/cant/consensus.cant +74 -0
  158. package/src/validation/protocols/cant/contribution.cant +82 -0
  159. package/src/validation/protocols/cant/decomposition.cant +92 -0
  160. package/src/validation/protocols/cant/implementation.cant +67 -0
  161. package/src/validation/protocols/cant/provenance.cant +88 -0
  162. package/src/validation/protocols/cant/release.cant +96 -0
  163. package/src/validation/protocols/cant/research.cant +66 -0
  164. package/src/validation/protocols/cant/specification.cant +67 -0
  165. package/src/validation/protocols/cant/testing.cant +88 -0
  166. package/src/validation/protocols/cant/validation.cant +65 -0
  167. package/src/validation/protocols/protocols-markdown/decomposition.md +0 -4
  168. package/templates/config.template.json +0 -1
  169. package/templates/global-config.template.json +0 -1
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Global-salt subsystem for the CLEO API key KDF.
3
+ *
4
+ * @task T348
5
+ * @epic T310
6
+ * @why ADR-037 §5 — API key KDF uses machine-key + global-salt + agentId.
7
+ * global-salt must persist across process restarts but is machine-local.
8
+ * @what Atomic first-run generation, memoized read, permission/size validation.
9
+ */
10
+
11
+ import crypto from 'node:crypto';
12
+ import fs from 'node:fs';
13
+ import path from 'node:path';
14
+ import { getCleoHome } from '../paths.js';
15
+
16
+ /** Filename for the global salt file under CLEO home. */
17
+ export const GLOBAL_SALT_FILENAME = 'global-salt';
18
+
19
+ /** Required size of the global salt in bytes. */
20
+ export const GLOBAL_SALT_SIZE = 32;
21
+
22
+ /** Required file permission mode for the global salt file (POSIX). */
23
+ const SALT_FILE_MODE = 0o600;
24
+
25
+ /**
26
+ * In-process memoization. Invalidated only by process restart.
27
+ * Cleared in tests via `__clearGlobalSaltCache()` (test-only export).
28
+ */
29
+ let cached: Buffer | null = null;
30
+
31
+ /**
32
+ * Returns the absolute path to the global-salt file.
33
+ *
34
+ * @returns Absolute path: `{cleoHome}/global-salt`
35
+ *
36
+ * @task T348
37
+ * @epic T310
38
+ *
39
+ * @example
40
+ * ```typescript
41
+ * const saltPath = getGlobalSaltPath();
42
+ * // Linux: "/home/user/.local/share/cleo/global-salt"
43
+ * ```
44
+ */
45
+ export function getGlobalSaltPath(): string {
46
+ return path.join(getCleoHome(), GLOBAL_SALT_FILENAME);
47
+ }
48
+
49
+ /**
50
+ * Returns the 32-byte global salt. Generates and persists atomically on first
51
+ * call when the file does not exist. Subsequent calls return the memoized value.
52
+ *
53
+ * Never overwrites an existing salt — doing so would invalidate every stored
54
+ * API key derived from it.
55
+ *
56
+ * @returns A 32-byte Buffer containing the global salt
57
+ * @throws {Error} If the salt file exists with wrong size or wrong permissions
58
+ *
59
+ * @task T348
60
+ * @epic T310
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * const salt = getGlobalSalt(); // Buffer(32) [...]
65
+ * ```
66
+ */
67
+ export function getGlobalSalt(): Buffer {
68
+ if (cached !== null) return cached;
69
+
70
+ const saltPath = getGlobalSaltPath();
71
+ const cleoHome = getCleoHome();
72
+
73
+ if (!fs.existsSync(saltPath)) {
74
+ // First-run generation: ensure the directory exists
75
+ if (!fs.existsSync(cleoHome)) {
76
+ fs.mkdirSync(cleoHome, { recursive: true });
77
+ }
78
+
79
+ const salt = crypto.randomBytes(GLOBAL_SALT_SIZE);
80
+
81
+ // Atomic write: write to tmp file, chmod, then rename into place
82
+ const tmpPath = `${saltPath}.tmp-${process.pid}-${Date.now()}`;
83
+ fs.writeFileSync(tmpPath, salt, { mode: SALT_FILE_MODE });
84
+ // Explicit chmod in case writeFileSync's mode arg is ignored on some FS
85
+ fs.chmodSync(tmpPath, SALT_FILE_MODE);
86
+ fs.renameSync(tmpPath, saltPath);
87
+
88
+ cached = salt;
89
+ return cached;
90
+ }
91
+
92
+ // Existing file — validate before trusting
93
+ const stat = fs.statSync(saltPath);
94
+
95
+ if (stat.size !== GLOBAL_SALT_SIZE) {
96
+ throw new Error(
97
+ `global-salt at ${saltPath} has wrong size: expected ${GLOBAL_SALT_SIZE} bytes, got ${stat.size}. ` +
98
+ `Refusing to use a corrupted salt file. Delete the file manually if you intend to regenerate it ` +
99
+ `(this will invalidate all stored API keys).`,
100
+ );
101
+ }
102
+
103
+ // Permission check: only meaningful on POSIX; Windows does not support mode bits
104
+ if (process.platform !== 'win32') {
105
+ const mode = stat.mode & 0o777;
106
+ if (mode !== SALT_FILE_MODE) {
107
+ throw new Error(
108
+ `global-salt at ${saltPath} has wrong permissions: expected 0o600, got 0o${mode.toString(8)}. ` +
109
+ `Fix with: chmod 600 ${saltPath}`,
110
+ );
111
+ }
112
+ }
113
+
114
+ const salt = fs.readFileSync(saltPath);
115
+ cached = salt;
116
+ return cached;
117
+ }
118
+
119
+ /**
120
+ * Runtime validation helper for startup integrity checks.
121
+ *
122
+ * Throws if the salt file exists but is malformed (wrong size or permissions).
123
+ * Safe to call when the file does not yet exist — returns silently in that case
124
+ * because first-run generation is handled lazily by `getGlobalSalt()`.
125
+ *
126
+ * @throws {Error} If the salt file exists with wrong size or wrong permissions
127
+ *
128
+ * @task T348
129
+ * @epic T310
130
+ *
131
+ * @example
132
+ * ```typescript
133
+ * // Called at process startup to catch accidental salt corruption early
134
+ * validateGlobalSalt();
135
+ * ```
136
+ */
137
+ export function validateGlobalSalt(): void {
138
+ const saltPath = getGlobalSaltPath();
139
+
140
+ if (!fs.existsSync(saltPath)) {
141
+ // Not yet generated — first-run case; no error
142
+ return;
143
+ }
144
+
145
+ const stat = fs.statSync(saltPath);
146
+
147
+ if (stat.size !== GLOBAL_SALT_SIZE) {
148
+ throw new Error(
149
+ `global-salt validation failed: size ${stat.size}, expected ${GLOBAL_SALT_SIZE}`,
150
+ );
151
+ }
152
+
153
+ if (process.platform !== 'win32') {
154
+ const mode = stat.mode & 0o777;
155
+ if (mode !== SALT_FILE_MODE) {
156
+ throw new Error(
157
+ `global-salt validation failed: permissions 0o${mode.toString(8)}, expected 0o600`,
158
+ );
159
+ }
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Clears the in-process memoization cache so tests can exercise the
165
+ * first-call generation path independently.
166
+ *
167
+ * @internal TEST ONLY — do NOT export through internal.ts or re-export
168
+ * from any public barrel. This symbol must never appear in production call paths.
169
+ *
170
+ * @task T348
171
+ * @epic T310
172
+ */
173
+ export function __clearGlobalSaltCache(): void {
174
+ cached = null;
175
+ }