@cleocode/cleo 2026.5.132 → 2026.5.133

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": "@cleocode/cleo",
3
- "version": "2026.5.132",
3
+ "version": "2026.5.133",
4
4
  "description": "CLEO CLI — the assembled product consuming @cleocode/core",
5
5
  "type": "module",
6
6
  "main": "./dist/cli/index.js",
@@ -30,18 +30,18 @@
30
30
  "tree-sitter-rust": "0.23.1",
31
31
  "tree-sitter-typescript": "^0.23.2",
32
32
  "yaml": "^2.8.3",
33
- "@cleocode/animations": "2026.5.132",
34
- "@cleocode/cant": "2026.5.132",
35
- "@cleocode/caamp": "2026.5.132",
36
- "@cleocode/contracts": "2026.5.132",
37
- "@cleocode/core": "2026.5.132",
38
- "@cleocode/nexus": "2026.5.132",
39
- "@cleocode/paths": "2026.5.132",
40
- "@cleocode/lafs": "2026.5.132",
41
- "@cleocode/playbooks": "2026.5.132",
42
- "@cleocode/runtime": "2026.5.132",
33
+ "@cleocode/animations": "2026.5.133",
34
+ "@cleocode/caamp": "2026.5.133",
35
+ "@cleocode/cant": "2026.5.133",
36
+ "@cleocode/contracts": "2026.5.133",
37
+ "@cleocode/core": "2026.5.133",
38
+ "@cleocode/lafs": "2026.5.133",
39
+ "@cleocode/paths": "2026.5.133",
40
+ "@cleocode/runtime": "2026.5.133",
41
+ "@cleocode/playbooks": "2026.5.133",
43
42
  "@cleocode/utils": "2026.5.122",
44
- "@cleocode/worktree": "2026.5.132"
43
+ "@cleocode/nexus": "2026.5.133",
44
+ "@cleocode/worktree": "2026.5.133"
45
45
  },
46
46
  "engines": {
47
47
  "node": ">=24.16.0"
@@ -342,13 +342,34 @@ function getSystemdUnitFile() {
342
342
  * lifecycle (restart policy, log collection). stdout/stderr are appended
343
343
  * to the shared daemon log via StandardOutput/StandardError directives.
344
344
  *
345
+ * When `scopeSagaId` or `scopeEpicId` is supplied the unit injects
346
+ * `CLEO_SENTIENT_SAGA` / `CLEO_SENTIENT_EPIC` into the service environment
347
+ * so the daemon only picks tasks within that scope (T11497 AC3).
348
+ *
345
349
  * @param {string} cleoExec - Absolute path to the `cleo` binary.
350
+ * @param {{ scopeSagaId?: string; scopeEpicId?: string }} [scope] - Optional scope filter.
346
351
  * @returns {string} Systemd unit file content.
347
352
  */
348
- function buildSystemdUnit(cleoExec) {
353
+ function buildSystemdUnit(cleoExec, scope) {
349
354
  const logFile = getDaemonLogFile();
355
+ // Build extra Environment= lines for scope env vars (one per line, systemd convention).
356
+ const scopeLines = [];
357
+ if (scope?.scopeSagaId) {
358
+ scopeLines.push(`Environment=CLEO_SENTIENT_SAGA=${scope.scopeSagaId}`);
359
+ }
360
+ if (scope?.scopeEpicId) {
361
+ scopeLines.push(`Environment=CLEO_SENTIENT_EPIC=${scope.scopeEpicId}`);
362
+ }
363
+ const scopeEnv = scopeLines.length > 0 ? `\n${scopeLines.join('\n')}` : '';
364
+
365
+ const description = scope?.scopeSagaId
366
+ ? `CLEO Sentient Daemon (saga ${scope.scopeSagaId} scoped)`
367
+ : scope?.scopeEpicId
368
+ ? `CLEO Sentient Daemon (epic ${scope.scopeEpicId} scoped)`
369
+ : 'CLEO Sentient Daemon (autonomous task hygiene + dream cycles)';
370
+
350
371
  return `[Unit]
351
- Description=CLEO Sentient Daemon (autonomous task hygiene + dream cycles)
372
+ Description=${description}
352
373
  Documentation=https://github.com/kryptobaseddev/cleocode
353
374
  After=network.target
354
375
 
@@ -359,7 +380,7 @@ Restart=on-failure
359
380
  RestartSec=5
360
381
  StandardOutput=append:${logFile}
361
382
  StandardError=append:${logFile}
362
- Environment=CLEO_SENTIENT_DAEMON=1
383
+ Environment=CLEO_SENTIENT_DAEMON=1${scopeEnv}
363
384
 
364
385
  [Install]
365
386
  WantedBy=default.target
@@ -370,10 +391,11 @@ WantedBy=default.target
370
391
  * Install and optionally activate the systemd user unit.
371
392
  *
372
393
  * @param {string} cleoExec - Absolute path to the `cleo` binary.
394
+ * @param {{ scopeSagaId?: string; scopeEpicId?: string }} [scope] - Optional scope filter (T11497 AC3).
373
395
  */
374
- function installSystemd(cleoExec) {
396
+ function installSystemd(cleoExec, scope) {
375
397
  const unitFile = getSystemdUnitFile();
376
- const unit = buildSystemdUnit(cleoExec);
398
+ const unit = buildSystemdUnit(cleoExec, scope);
377
399
  const written = writeIfChanged(unitFile, unit);
378
400
 
379
401
  if (written) {
@@ -443,11 +465,30 @@ function getLaunchdPlistFile() {
443
465
  * The plist uses KeepAlive=true so launchd restarts the daemon on exit,
444
466
  * and RunAtLoad=true to start it immediately on launchctl load.
445
467
  *
468
+ * When `scopeSagaId` or `scopeEpicId` is supplied the EnvironmentVariables
469
+ * dict includes `CLEO_SENTIENT_SAGA` / `CLEO_SENTIENT_EPIC` so the daemon
470
+ * only picks tasks within that scope (T11497 AC3).
471
+ *
446
472
  * @param {string} cleoExec - Absolute path to the `cleo` binary.
473
+ * @param {{ scopeSagaId?: string; scopeEpicId?: string }} [scope] - Optional scope filter.
447
474
  * @returns {string} Plist XML content.
448
475
  */
449
- function buildLaunchdPlist(cleoExec) {
476
+ function buildLaunchdPlist(cleoExec, scope) {
450
477
  const logFile = getDaemonLogFile();
478
+ // Build extra <key>/<string> pairs for scope env vars.
479
+ const scopePlistEntries = [];
480
+ if (scope?.scopeSagaId) {
481
+ scopePlistEntries.push(
482
+ ` <key>CLEO_SENTIENT_SAGA</key>\n <string>${scope.scopeSagaId}</string>`,
483
+ );
484
+ }
485
+ if (scope?.scopeEpicId) {
486
+ scopePlistEntries.push(
487
+ ` <key>CLEO_SENTIENT_EPIC</key>\n <string>${scope.scopeEpicId}</string>`,
488
+ );
489
+ }
490
+ const scopePlist = scopePlistEntries.length > 0 ? `\n${scopePlistEntries.join('\n')}` : '';
491
+
451
492
  return `<?xml version="1.0" encoding="UTF-8"?>
452
493
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
453
494
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -476,7 +517,7 @@ function buildLaunchdPlist(cleoExec) {
476
517
  <key>EnvironmentVariables</key>
477
518
  <dict>
478
519
  <key>CLEO_SENTIENT_DAEMON</key>
479
- <string>1</string>
520
+ <string>1</string>${scopePlist}
480
521
  </dict>
481
522
 
482
523
  <key>RunAtLoad</key>
@@ -490,10 +531,11 @@ function buildLaunchdPlist(cleoExec) {
490
531
  * Install and optionally load the launchd plist.
491
532
  *
492
533
  * @param {string} cleoExec - Absolute path to the `cleo` binary.
534
+ * @param {{ scopeSagaId?: string; scopeEpicId?: string }} [scope] - Optional scope filter (T11497 AC3).
493
535
  */
494
- function installLaunchd(cleoExec) {
536
+ function installLaunchd(cleoExec, scope) {
495
537
  const plistFile = getLaunchdPlistFile();
496
- const plist = buildLaunchdPlist(cleoExec);
538
+ const plist = buildLaunchdPlist(cleoExec, scope);
497
539
  const written = writeIfChanged(plistFile, plist);
498
540
 
499
541
  if (written) {
@@ -620,18 +662,23 @@ function resolveCleoExec() {
620
662
  *
621
663
  * WSL is detected and treated as Linux (systemd path resolution).
622
664
  *
665
+ * @param {{ scopeSagaId?: string; scopeEpicId?: string }} [opts] - Optional scope
666
+ * filter. When supplied, `CLEO_SENTIENT_SAGA` / `CLEO_SENTIENT_EPIC` are
667
+ * injected into the service environment so the daemon only picks tasks
668
+ * within the given Saga or Epic. (T11497 E5-HEADLESS AC3)
623
669
  * @returns {Promise<void>}
624
670
  */
625
- export async function installDaemonService() {
671
+ export async function installDaemonService(opts) {
626
672
  try {
627
673
  ensureLogDir();
628
674
  const cleoExec = resolveCleoExec();
629
675
  const platform = process.platform;
676
+ const scope = opts ?? {};
630
677
 
631
678
  if (platform === 'linux' || isWSL()) {
632
- installSystemd(cleoExec);
679
+ installSystemd(cleoExec, scope);
633
680
  } else if (platform === 'darwin') {
634
- installLaunchd(cleoExec);
681
+ installLaunchd(cleoExec, scope);
635
682
  } else if (platform === 'win32') {
636
683
  installWindows();
637
684
  } else {