@cleocode/core 2026.4.11 → 2026.4.13
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/codebase-map/analyzers/architecture.d.ts.map +1 -1
- package/dist/codebase-map/analyzers/architecture.js +0 -1
- package/dist/codebase-map/analyzers/architecture.js.map +1 -1
- package/dist/conduit/local-transport.d.ts +18 -8
- package/dist/conduit/local-transport.d.ts.map +1 -1
- package/dist/conduit/local-transport.js +23 -13
- package/dist/conduit/local-transport.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +0 -1
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts +19 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +6 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.js +175 -68950
- package/dist/index.js.map +1 -7
- package/dist/init.d.ts +1 -2
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +1 -2
- package/dist/init.js.map +1 -1
- package/dist/internal.d.ts +8 -3
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +13 -6
- package/dist/internal.js.map +1 -1
- package/dist/memory/learnings.d.ts +2 -2
- package/dist/memory/patterns.d.ts +6 -6
- package/dist/output.d.ts +32 -11
- package/dist/output.d.ts.map +1 -1
- package/dist/output.js +67 -67
- package/dist/output.js.map +1 -1
- package/dist/paths.js +80 -14
- package/dist/paths.js.map +1 -1
- package/dist/skills/dynamic-skill-generator.d.ts +0 -2
- package/dist/skills/dynamic-skill-generator.d.ts.map +1 -1
- package/dist/skills/dynamic-skill-generator.js.map +1 -1
- package/dist/store/agent-registry-accessor.d.ts +203 -12
- package/dist/store/agent-registry-accessor.d.ts.map +1 -1
- package/dist/store/agent-registry-accessor.js +618 -100
- package/dist/store/agent-registry-accessor.js.map +1 -1
- package/dist/store/api-key-kdf.d.ts +73 -0
- package/dist/store/api-key-kdf.d.ts.map +1 -0
- package/dist/store/api-key-kdf.js +84 -0
- package/dist/store/api-key-kdf.js.map +1 -0
- package/dist/store/cleanup-legacy.js +171 -0
- package/dist/store/cleanup-legacy.js.map +1 -0
- package/dist/store/conduit-sqlite.d.ts +184 -0
- package/dist/store/conduit-sqlite.d.ts.map +1 -0
- package/dist/store/conduit-sqlite.js +570 -0
- package/dist/store/conduit-sqlite.js.map +1 -0
- package/dist/store/global-salt.d.ts +78 -0
- package/dist/store/global-salt.d.ts.map +1 -0
- package/dist/store/global-salt.js +147 -0
- package/dist/store/global-salt.js.map +1 -0
- package/dist/store/migrate-signaldock-to-conduit.d.ts +81 -0
- package/dist/store/migrate-signaldock-to-conduit.d.ts.map +1 -0
- package/dist/store/migrate-signaldock-to-conduit.js +555 -0
- package/dist/store/migrate-signaldock-to-conduit.js.map +1 -0
- package/dist/store/nexus-sqlite.js +28 -3
- package/dist/store/nexus-sqlite.js.map +1 -1
- package/dist/store/signaldock-sqlite.d.ts +122 -19
- package/dist/store/signaldock-sqlite.d.ts.map +1 -1
- package/dist/store/signaldock-sqlite.js +401 -251
- package/dist/store/signaldock-sqlite.js.map +1 -1
- package/dist/store/sqlite-backup.js +122 -4
- package/dist/store/sqlite-backup.js.map +1 -1
- package/dist/system/backup.d.ts +0 -26
- package/dist/system/backup.d.ts.map +1 -1
- package/dist/system/runtime.d.ts +0 -2
- package/dist/system/runtime.d.ts.map +1 -1
- package/dist/system/runtime.js +3 -3
- package/dist/system/runtime.js.map +1 -1
- package/dist/tasks/add.d.ts +1 -1
- package/dist/tasks/add.d.ts.map +1 -1
- package/dist/tasks/add.js +98 -23
- package/dist/tasks/add.js.map +1 -1
- package/dist/tasks/complete.d.ts.map +1 -1
- package/dist/tasks/complete.js +4 -1
- package/dist/tasks/complete.js.map +1 -1
- package/dist/tasks/find.d.ts.map +1 -1
- package/dist/tasks/find.js +4 -1
- package/dist/tasks/find.js.map +1 -1
- package/dist/tasks/labels.d.ts.map +1 -1
- package/dist/tasks/labels.js +4 -1
- package/dist/tasks/labels.js.map +1 -1
- package/dist/tasks/relates.d.ts.map +1 -1
- package/dist/tasks/relates.js +16 -4
- package/dist/tasks/relates.js.map +1 -1
- package/dist/tasks/show.d.ts.map +1 -1
- package/dist/tasks/show.js +4 -1
- package/dist/tasks/show.js.map +1 -1
- package/dist/tasks/update.d.ts.map +1 -1
- package/dist/tasks/update.js +32 -6
- package/dist/tasks/update.js.map +1 -1
- package/dist/validation/engine.d.ts.map +1 -1
- package/dist/validation/engine.js +16 -4
- package/dist/validation/engine.js.map +1 -1
- package/dist/validation/param-utils.d.ts +5 -3
- package/dist/validation/param-utils.d.ts.map +1 -1
- package/dist/validation/param-utils.js +8 -6
- package/dist/validation/param-utils.js.map +1 -1
- package/dist/validation/protocols/_shared.d.ts.map +1 -1
- package/dist/validation/protocols/_shared.js +13 -6
- package/dist/validation/protocols/_shared.js.map +1 -1
- package/package.json +9 -7
- package/src/adapters/__tests__/manager.test.ts +0 -1
- package/src/codebase-map/analyzers/architecture.ts +0 -1
- package/src/conduit/__tests__/local-credential-flow.test.ts +20 -18
- package/src/conduit/__tests__/local-transport.test.ts +14 -12
- package/src/conduit/local-transport.ts +23 -13
- package/src/config.ts +0 -1
- package/src/errors.ts +24 -0
- package/src/hooks/handlers/__tests__/hook-automation-e2e.test.ts +2 -5
- package/src/init.ts +1 -2
- package/src/internal.ts +96 -2
- package/src/lifecycle/cant/lifecycle-rcasd.cant +133 -0
- package/src/memory/__tests__/engine-compat.test.ts +2 -2
- package/src/memory/__tests__/pipeline-manifest-sqlite.test.ts +4 -4
- package/src/observability/__tests__/index.test.ts +4 -4
- package/src/observability/__tests__/log-filter.test.ts +4 -4
- package/src/output.ts +73 -75
- package/src/sessions/__tests__/session-grade.integration.test.ts +1 -1
- package/src/sessions/__tests__/session-grade.test.ts +2 -2
- package/src/skills/__tests__/dynamic-skill-generator.test.ts +0 -2
- package/src/skills/dynamic-skill-generator.ts +0 -2
- package/src/store/__tests__/agent-registry-accessor.test.ts +807 -0
- package/src/store/__tests__/api-key-kdf.test.ts +113 -0
- package/src/store/__tests__/backup-crypto.test.ts +101 -0
- package/src/store/__tests__/backup-pack.test.ts +491 -0
- package/src/store/__tests__/backup-unpack.test.ts +298 -0
- package/src/store/__tests__/conduit-sqlite.test.ts +413 -0
- package/src/store/__tests__/global-salt.test.ts +195 -0
- package/src/store/__tests__/migrate-signaldock-to-conduit.test.ts +715 -0
- package/src/store/__tests__/regenerators.test.ts +234 -0
- package/src/store/__tests__/restore-conflict-report.test.ts +274 -0
- package/src/store/__tests__/restore-json-merge.test.ts +521 -0
- package/src/store/__tests__/signaldock-sqlite.test.ts +652 -0
- package/src/store/__tests__/sqlite-backup-global.test.ts +307 -3
- package/src/store/__tests__/sqlite-backup.test.ts +5 -1
- package/src/store/__tests__/t310-integration.test.ts +1150 -0
- package/src/store/__tests__/t310-readiness.test.ts +111 -0
- package/src/store/__tests__/t311-integration.test.ts +661 -0
- package/src/store/agent-registry-accessor.ts +847 -140
- package/src/store/api-key-kdf.ts +104 -0
- package/src/store/backup-crypto.ts +209 -0
- package/src/store/backup-pack.ts +739 -0
- package/src/store/backup-unpack.ts +583 -0
- package/src/store/conduit-sqlite.ts +655 -0
- package/src/store/global-salt.ts +175 -0
- package/src/store/migrate-signaldock-to-conduit.ts +669 -0
- package/src/store/regenerators.ts +243 -0
- package/src/store/restore-conflict-report.ts +317 -0
- package/src/store/restore-json-merge.ts +653 -0
- package/src/store/signaldock-sqlite.ts +431 -254
- package/src/store/sqlite-backup.ts +185 -10
- package/src/store/t310-readiness.ts +119 -0
- package/src/system/backup.ts +2 -62
- package/src/system/runtime.ts +4 -6
- package/src/tasks/__tests__/error-hints.test.ts +256 -0
- package/src/tasks/add.ts +99 -9
- package/src/tasks/complete.ts +4 -1
- package/src/tasks/find.ts +4 -1
- package/src/tasks/labels.ts +4 -1
- package/src/tasks/relates.ts +16 -4
- package/src/tasks/show.ts +4 -1
- package/src/tasks/update.ts +32 -3
- package/src/validation/__tests__/error-hints.test.ts +97 -0
- package/src/validation/engine.ts +16 -1
- package/src/validation/param-utils.ts +10 -7
- package/src/validation/protocols/_shared.ts +14 -6
- package/src/validation/protocols/cant/architecture-decision.cant +80 -0
- package/src/validation/protocols/cant/artifact-publish.cant +95 -0
- package/src/validation/protocols/cant/consensus.cant +74 -0
- package/src/validation/protocols/cant/contribution.cant +82 -0
- package/src/validation/protocols/cant/decomposition.cant +92 -0
- package/src/validation/protocols/cant/implementation.cant +67 -0
- package/src/validation/protocols/cant/provenance.cant +88 -0
- package/src/validation/protocols/cant/release.cant +96 -0
- package/src/validation/protocols/cant/research.cant +66 -0
- package/src/validation/protocols/cant/specification.cant +67 -0
- package/src/validation/protocols/cant/testing.cant +88 -0
- package/src/validation/protocols/cant/validation.cant +65 -0
- package/src/validation/protocols/protocols-markdown/decomposition.md +0 -4
- package/templates/config.template.json +0 -1
- 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
|
+
}
|