chainlesschain 0.47.5 → 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.5",
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": {
@@ -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 = "") {
@@ -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")
@@ -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
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * CLI session module — thin re-export of @chainlesschain/session-core
3
+ *
4
+ * Managed Agents parity Phase A+B.
5
+ * Consume via: require("../session") inside packages/cli/src/.
6
+ */
7
+ module.exports = require("@chainlesschain/session-core");