chainlesschain 0.47.4 → 0.47.6
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chainlesschain",
|
|
3
|
-
"version": "0.47.
|
|
3
|
+
"version": "0.47.6",
|
|
4
4
|
"description": "CLI for ChainlessChain - install, configure, and manage your personal AI management system",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
"@chainlesschain/core-db": "0.1.0",
|
|
60
60
|
"@chainlesschain/core-config": "0.1.0",
|
|
61
61
|
"@chainlesschain/core-infra": "0.1.0",
|
|
62
|
+
"@chainlesschain/session-core": "0.1.0",
|
|
62
63
|
"ws": "^8.14.2"
|
|
63
64
|
},
|
|
64
65
|
"devDependencies": {
|
package/src/commands/config.js
CHANGED
|
@@ -129,6 +129,73 @@ export function registerConfigCommand(program) {
|
|
|
129
129
|
logger.info("Reset cancelled");
|
|
130
130
|
}
|
|
131
131
|
});
|
|
132
|
+
|
|
133
|
+
// config beta — Managed Agents parity Phase E2 beta flags
|
|
134
|
+
const beta = cmd
|
|
135
|
+
.command("beta")
|
|
136
|
+
.description("Manage beta / experimental feature flags");
|
|
137
|
+
|
|
138
|
+
beta
|
|
139
|
+
.command("list", { isDefault: true })
|
|
140
|
+
.description("List enabled and known beta flags")
|
|
141
|
+
.option("--json", "Output as JSON")
|
|
142
|
+
.action(async (options) => {
|
|
143
|
+
try {
|
|
144
|
+
const { getBetaFlags } =
|
|
145
|
+
await import("../lib/session-core-singletons.js");
|
|
146
|
+
const flags = await getBetaFlags();
|
|
147
|
+
const out = flags.list();
|
|
148
|
+
if (options.json) {
|
|
149
|
+
console.log(JSON.stringify(out, null, 2));
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
logger.log(chalk.bold("Enabled beta flags:"));
|
|
153
|
+
if (out.enabled.length === 0) logger.log(chalk.gray(" (none)"));
|
|
154
|
+
for (const f of out.enabled) logger.log(` ${chalk.green("✓")} ${f}`);
|
|
155
|
+
if (out.known.length > out.enabled.length) {
|
|
156
|
+
const disabled = out.known.filter((f) => !out.enabled.includes(f));
|
|
157
|
+
logger.log(chalk.bold("\nKnown (disabled):"));
|
|
158
|
+
for (const f of disabled) logger.log(` ${chalk.gray("·")} ${f}`);
|
|
159
|
+
}
|
|
160
|
+
} catch (err) {
|
|
161
|
+
logger.error(`Failed: ${err.message}`);
|
|
162
|
+
process.exit(1);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
beta
|
|
167
|
+
.command("enable")
|
|
168
|
+
.description("Enable a beta flag (format: <feature>-<YYYY-MM-DD>)")
|
|
169
|
+
.argument("<flag>")
|
|
170
|
+
.action(async (flag) => {
|
|
171
|
+
try {
|
|
172
|
+
const { getBetaFlags } =
|
|
173
|
+
await import("../lib/session-core-singletons.js");
|
|
174
|
+
const flags = await getBetaFlags();
|
|
175
|
+
flags.enable(flag);
|
|
176
|
+
logger.success(`Enabled: ${chalk.cyan(flag)}`);
|
|
177
|
+
} catch (err) {
|
|
178
|
+
logger.error(`Failed: ${err.message}`);
|
|
179
|
+
process.exit(1);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
beta
|
|
184
|
+
.command("disable")
|
|
185
|
+
.description("Disable a beta flag")
|
|
186
|
+
.argument("<flag>")
|
|
187
|
+
.action(async (flag) => {
|
|
188
|
+
try {
|
|
189
|
+
const { getBetaFlags } =
|
|
190
|
+
await import("../lib/session-core-singletons.js");
|
|
191
|
+
const flags = await getBetaFlags();
|
|
192
|
+
flags.disable(flag);
|
|
193
|
+
logger.success(`Disabled: ${chalk.cyan(flag)}`);
|
|
194
|
+
} catch (err) {
|
|
195
|
+
logger.error(`Failed: ${err.message}`);
|
|
196
|
+
process.exit(1);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
132
199
|
}
|
|
133
200
|
|
|
134
201
|
function printConfig(obj, indent = "") {
|
package/src/commands/memory.js
CHANGED
|
@@ -239,6 +239,100 @@ export function registerMemoryCommand(program) {
|
|
|
239
239
|
}
|
|
240
240
|
});
|
|
241
241
|
|
|
242
|
+
// memory recall — Managed Agents parity Phase D2 (session-core MemoryStore)
|
|
243
|
+
memory
|
|
244
|
+
.command("recall")
|
|
245
|
+
.description("Recall scoped memory (session-core MemoryStore)")
|
|
246
|
+
.argument("[query]", "Query string")
|
|
247
|
+
.option("--scope <scope>", "session | agent | global")
|
|
248
|
+
.option(
|
|
249
|
+
"--scope-id <id>",
|
|
250
|
+
"Session or agent id (required for session/agent)",
|
|
251
|
+
)
|
|
252
|
+
.option("--category <cat>", "Filter by category")
|
|
253
|
+
.option("--tags <tags>", "Comma-separated tags")
|
|
254
|
+
.option("-n, --limit <n>", "Max results", "10")
|
|
255
|
+
.option("--json", "Output as JSON")
|
|
256
|
+
.action(async (query, options) => {
|
|
257
|
+
try {
|
|
258
|
+
const { getMemoryStore } =
|
|
259
|
+
await import("../lib/session-core-singletons.js");
|
|
260
|
+
const store = getMemoryStore();
|
|
261
|
+
const tags = options.tags
|
|
262
|
+
? options.tags
|
|
263
|
+
.split(",")
|
|
264
|
+
.map((t) => t.trim())
|
|
265
|
+
.filter(Boolean)
|
|
266
|
+
: null;
|
|
267
|
+
const results = store.recall({
|
|
268
|
+
query: query || "",
|
|
269
|
+
scope: options.scope,
|
|
270
|
+
scopeId: options.scopeId,
|
|
271
|
+
category: options.category,
|
|
272
|
+
tags,
|
|
273
|
+
limit: Math.max(1, parseInt(options.limit) || 10),
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
if (options.json) {
|
|
277
|
+
console.log(JSON.stringify(results, null, 2));
|
|
278
|
+
} else if (results.length === 0) {
|
|
279
|
+
logger.info("No scoped memory entries matched.");
|
|
280
|
+
} else {
|
|
281
|
+
logger.log(
|
|
282
|
+
chalk.bold(`Scoped memory (${results.length} results):\n`),
|
|
283
|
+
);
|
|
284
|
+
for (const m of results) {
|
|
285
|
+
logger.log(
|
|
286
|
+
` ${chalk.gray(m.id.slice(0, 12))} ${chalk.cyan(m.scope)}${m.scopeId ? ":" + m.scopeId.slice(0, 12) : ""} ${chalk.yellow(m.category)} rel=${m.relevance?.toFixed(2) ?? "?"}`,
|
|
287
|
+
);
|
|
288
|
+
logger.log(` ${chalk.white(m.content.substring(0, 160))}`);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
} catch (err) {
|
|
292
|
+
logger.error(`Failed: ${err.message}`);
|
|
293
|
+
process.exit(1);
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
// memory store — add to session-core MemoryStore (separate from DB-backed memory add)
|
|
298
|
+
memory
|
|
299
|
+
.command("store")
|
|
300
|
+
.description("Write a scoped memory (session-core MemoryStore)")
|
|
301
|
+
.argument("<content>")
|
|
302
|
+
.requiredOption("--scope <scope>", "session | agent | global")
|
|
303
|
+
.option("--scope-id <id>", "Required for session/agent scope")
|
|
304
|
+
.option("--category <cat>", "Category", "general")
|
|
305
|
+
.option("--tags <tags>", "Comma-separated tags")
|
|
306
|
+
.option("--json", "Output as JSON")
|
|
307
|
+
.action(async (content, options) => {
|
|
308
|
+
try {
|
|
309
|
+
const { getMemoryStore } =
|
|
310
|
+
await import("../lib/session-core-singletons.js");
|
|
311
|
+
const store = getMemoryStore();
|
|
312
|
+
const tags = options.tags
|
|
313
|
+
? options.tags
|
|
314
|
+
.split(",")
|
|
315
|
+
.map((t) => t.trim())
|
|
316
|
+
.filter(Boolean)
|
|
317
|
+
: [];
|
|
318
|
+
const m = store.add({
|
|
319
|
+
scope: options.scope,
|
|
320
|
+
scopeId: options.scopeId || null,
|
|
321
|
+
category: options.category,
|
|
322
|
+
content,
|
|
323
|
+
tags,
|
|
324
|
+
});
|
|
325
|
+
if (options.json) console.log(JSON.stringify(m, null, 2));
|
|
326
|
+
else
|
|
327
|
+
logger.success(
|
|
328
|
+
`Stored ${chalk.gray(m.id.slice(0, 12))} [${chalk.cyan(m.scope)}/${m.category}]`,
|
|
329
|
+
);
|
|
330
|
+
} catch (err) {
|
|
331
|
+
logger.error(`Failed: ${err.message}`);
|
|
332
|
+
process.exit(1);
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
|
|
242
336
|
// memory file
|
|
243
337
|
memory
|
|
244
338
|
.command("file")
|
package/src/commands/session.js
CHANGED
|
@@ -416,6 +416,40 @@ export function registerSessionCommand(program) {
|
|
|
416
416
|
}
|
|
417
417
|
});
|
|
418
418
|
|
|
419
|
+
// session policy — Managed Agents parity Phase E1 approval policy
|
|
420
|
+
session
|
|
421
|
+
.command("policy")
|
|
422
|
+
.description("Show or set per-session approval policy")
|
|
423
|
+
.argument("<id>", "Session ID")
|
|
424
|
+
.option("--set <policy>", "strict | trusted | autopilot")
|
|
425
|
+
.option("--json", "Output as JSON")
|
|
426
|
+
.action(async (id, options) => {
|
|
427
|
+
try {
|
|
428
|
+
const { getApprovalGate } =
|
|
429
|
+
await import("../lib/session-core-singletons.js");
|
|
430
|
+
const gate = await getApprovalGate();
|
|
431
|
+
if (options.set) {
|
|
432
|
+
gate.setSessionPolicy(id, options.set);
|
|
433
|
+
// give persistence a tick before the CLI process exits
|
|
434
|
+
await new Promise((r) => setImmediate(r));
|
|
435
|
+
logger.success(
|
|
436
|
+
`Session ${chalk.gray(id.slice(0, 12))} policy → ${chalk.cyan(options.set)}`,
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
const current = gate.getSessionPolicy(id);
|
|
440
|
+
if (options.json) {
|
|
441
|
+
console.log(JSON.stringify({ sessionId: id, policy: current }));
|
|
442
|
+
} else if (!options.set) {
|
|
443
|
+
logger.log(
|
|
444
|
+
`Session ${chalk.gray(id.slice(0, 12))} policy: ${chalk.cyan(current)}`,
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
} catch (err) {
|
|
448
|
+
logger.error(`Failed: ${err.message}`);
|
|
449
|
+
process.exit(1);
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
|
|
419
453
|
// session workflow — inspect canonical coding workflow state
|
|
420
454
|
// Reads .chainlesschain/sessions/<id>/{intent.md,plan.md,progress.log,mode.json}
|
|
421
455
|
// written by the 4 workflow skills ($deep-interview/$ralplan/$ralph/$team).
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session-core singletons for the CLI
|
|
3
|
+
*
|
|
4
|
+
* Wires MemoryStore / BetaFlags / ApprovalGate with file-based persistence under
|
|
5
|
+
* the CLI home dir (`~/.chainlesschain/`).
|
|
6
|
+
*
|
|
7
|
+
* Lazy: instances are created on first access so bootstrap stays fast.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
import { getHomeDir } from "./paths.js";
|
|
12
|
+
import {
|
|
13
|
+
MemoryStore,
|
|
14
|
+
BetaFlags,
|
|
15
|
+
ApprovalGate,
|
|
16
|
+
APPROVAL_POLICY,
|
|
17
|
+
createMemoryFileAdapter,
|
|
18
|
+
createBetaFlagsFileAdapter,
|
|
19
|
+
createApprovalGateFileAdapter,
|
|
20
|
+
hydrateMemoryStore,
|
|
21
|
+
} from "@chainlesschain/session-core";
|
|
22
|
+
|
|
23
|
+
let _memoryStore = null;
|
|
24
|
+
let _betaFlags = null;
|
|
25
|
+
let _approvalGate = null;
|
|
26
|
+
|
|
27
|
+
export function getMemoryStorePath() {
|
|
28
|
+
return join(getHomeDir(), "memory-store.json");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function getBetaFlagsPath() {
|
|
32
|
+
return join(getHomeDir(), "beta-flags.json");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function getApprovalPoliciesPath() {
|
|
36
|
+
return join(getHomeDir(), "approval-policies.json");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function getMemoryStore() {
|
|
40
|
+
if (_memoryStore) return _memoryStore;
|
|
41
|
+
const adapter = createMemoryFileAdapter(getMemoryStorePath());
|
|
42
|
+
_memoryStore = new MemoryStore({ adapter });
|
|
43
|
+
hydrateMemoryStore(_memoryStore, adapter);
|
|
44
|
+
return _memoryStore;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function getBetaFlags() {
|
|
48
|
+
if (_betaFlags) return _betaFlags;
|
|
49
|
+
const store = createBetaFlagsFileAdapter(getBetaFlagsPath());
|
|
50
|
+
_betaFlags = new BetaFlags({ store });
|
|
51
|
+
await _betaFlags.load();
|
|
52
|
+
return _betaFlags;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export async function getApprovalGate() {
|
|
56
|
+
if (_approvalGate) return _approvalGate;
|
|
57
|
+
const store = createApprovalGateFileAdapter(getApprovalPoliciesPath());
|
|
58
|
+
_approvalGate = new ApprovalGate({
|
|
59
|
+
defaultPolicy: APPROVAL_POLICY.STRICT,
|
|
60
|
+
store,
|
|
61
|
+
});
|
|
62
|
+
await _approvalGate.load();
|
|
63
|
+
return _approvalGate;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function resetSessionCoreSingletonsForTests() {
|
|
67
|
+
_memoryStore = null;
|
|
68
|
+
_betaFlags = null;
|
|
69
|
+
_approvalGate = null;
|
|
70
|
+
}
|