@mono-agent/agent-app 0.8.0 → 0.9.0
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/README.md +71 -22
- package/dist/account-home.d.ts +6 -0
- package/dist/account-home.d.ts.map +1 -0
- package/dist/account-home.js +9 -0
- package/dist/account-home.js.map +1 -0
- package/dist/app-config.d.ts +3 -1
- package/dist/app-config.d.ts.map +1 -1
- package/dist/app-config.js +8 -5
- package/dist/app-config.js.map +1 -1
- package/dist/app.d.ts +25 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +237 -16
- package/dist/app.js.map +1 -1
- package/dist/background-environment.d.ts +16 -0
- package/dist/background-environment.d.ts.map +1 -0
- package/dist/background-environment.js +68 -0
- package/dist/background-environment.js.map +1 -0
- package/dist/background-runtime.d.ts +62 -0
- package/dist/background-runtime.d.ts.map +1 -0
- package/dist/background-runtime.js +1115 -0
- package/dist/background-runtime.js.map +1 -0
- package/dist/background-snapshot-key.d.ts +13 -0
- package/dist/background-snapshot-key.d.ts.map +1 -0
- package/dist/background-snapshot-key.js +194 -0
- package/dist/background-snapshot-key.js.map +1 -0
- package/dist/background-snapshot.d.ts +96 -0
- package/dist/background-snapshot.d.ts.map +1 -0
- package/dist/background-snapshot.js +450 -0
- package/dist/background-snapshot.js.map +1 -0
- package/dist/background-worker-lease.d.ts +39 -0
- package/dist/background-worker-lease.d.ts.map +1 -0
- package/dist/background-worker-lease.js +356 -0
- package/dist/background-worker-lease.js.map +1 -0
- package/dist/background.d.ts +74 -2
- package/dist/background.d.ts.map +1 -1
- package/dist/background.js +815 -73
- package/dist/background.js.map +1 -1
- package/dist/channel-plugins.d.ts +2 -0
- package/dist/channel-plugins.d.ts.map +1 -1
- package/dist/channel-plugins.js +8 -0
- package/dist/channel-plugins.js.map +1 -1
- package/dist/channels.d.ts +10 -0
- package/dist/channels.d.ts.map +1 -1
- package/dist/channels.js +71 -3
- package/dist/channels.js.map +1 -1
- package/dist/cli.d.ts +12 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +341 -63
- package/dist/cli.js.map +1 -1
- package/dist/config-reference.d.ts.map +1 -1
- package/dist/config-reference.js +253 -0
- package/dist/config-reference.js.map +1 -1
- package/dist/configuration-proposal-tool.d.ts +7 -0
- package/dist/configuration-proposal-tool.d.ts.map +1 -1
- package/dist/configuration-proposal-tool.js +55 -6
- package/dist/configuration-proposal-tool.js.map +1 -1
- package/dist/configured-agent.d.ts +4 -0
- package/dist/configured-agent.d.ts.map +1 -1
- package/dist/configured-agent.js +15 -0
- package/dist/configured-agent.js.map +1 -1
- package/dist/continuation-command.d.ts +15 -0
- package/dist/continuation-command.d.ts.map +1 -0
- package/dist/continuation-command.js +170 -0
- package/dist/continuation-command.js.map +1 -0
- package/dist/continuation-config.d.ts +25 -0
- package/dist/continuation-config.d.ts.map +1 -0
- package/dist/continuation-config.js +236 -0
- package/dist/continuation-config.js.map +1 -0
- package/dist/continuation-service.d.ts +99 -0
- package/dist/continuation-service.d.ts.map +1 -0
- package/dist/continuation-service.js +1313 -0
- package/dist/continuation-service.js.map +1 -0
- package/dist/continuation-store.d.ts +104 -0
- package/dist/continuation-store.d.ts.map +1 -0
- package/dist/continuation-store.js +688 -0
- package/dist/continuation-store.js.map +1 -0
- package/dist/continuations.d.ts +167 -0
- package/dist/continuations.d.ts.map +1 -0
- package/dist/continuations.js +71 -0
- package/dist/continuations.js.map +1 -0
- package/dist/doctor.d.ts +2 -0
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +426 -27
- package/dist/doctor.js.map +1 -1
- package/dist/first-run-managed-memory.d.ts.map +1 -1
- package/dist/first-run-managed-memory.js +66 -3
- package/dist/first-run-managed-memory.js.map +1 -1
- package/dist/first-run-readiness.d.ts.map +1 -1
- package/dist/first-run-readiness.js +2 -31
- package/dist/first-run-readiness.js.map +1 -1
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +7 -0
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +7 -2
- package/dist/init.js.map +1 -1
- package/dist/launchd.d.ts +16 -6
- package/dist/launchd.d.ts.map +1 -1
- package/dist/launchd.js +30 -15
- package/dist/launchd.js.map +1 -1
- package/dist/local-configuration.d.ts +61 -18
- package/dist/local-configuration.d.ts.map +1 -1
- package/dist/local-configuration.js +530 -145
- package/dist/local-configuration.js.map +1 -1
- package/dist/managed-runtime-packages.d.ts +9 -0
- package/dist/managed-runtime-packages.d.ts.map +1 -0
- package/dist/managed-runtime-packages.js +56 -0
- package/dist/managed-runtime-packages.js.map +1 -0
- package/dist/memory-embedding-service.d.ts +33 -0
- package/dist/memory-embedding-service.d.ts.map +1 -0
- package/dist/memory-embedding-service.js +207 -0
- package/dist/memory-embedding-service.js.map +1 -0
- package/dist/memory-recall.d.ts +5 -4
- package/dist/memory-recall.d.ts.map +1 -1
- package/dist/memory-recall.js +21 -8
- package/dist/memory-recall.js.map +1 -1
- package/dist/modules/catalog.d.ts.map +1 -1
- package/dist/modules/catalog.js +91 -9
- package/dist/modules/catalog.js.map +1 -1
- package/dist/notify-runtime.d.ts +26 -0
- package/dist/notify-runtime.d.ts.map +1 -0
- package/dist/notify-runtime.js +27 -0
- package/dist/notify-runtime.js.map +1 -0
- package/dist/notify-tool.d.ts +51 -0
- package/dist/notify-tool.d.ts.map +1 -0
- package/dist/notify-tool.js +182 -0
- package/dist/notify-tool.js.map +1 -0
- package/dist/proactive-notify.d.ts +2 -0
- package/dist/proactive-notify.d.ts.map +1 -1
- package/dist/proactive-notify.js +1 -0
- package/dist/proactive-notify.js.map +1 -1
- package/dist/process-incarnation.d.ts +23 -0
- package/dist/process-incarnation.d.ts.map +1 -0
- package/dist/process-incarnation.js +208 -0
- package/dist/process-incarnation.js.map +1 -0
- package/dist/project-skills.d.ts +1 -1
- package/dist/project-skills.js +6 -6
- package/dist/recipes/base.d.ts +15 -0
- package/dist/recipes/base.d.ts.map +1 -0
- package/dist/recipes/base.js +51 -0
- package/dist/recipes/base.js.map +1 -0
- package/dist/recipes/catalog.d.ts +4 -0
- package/dist/recipes/catalog.d.ts.map +1 -0
- package/dist/recipes/catalog.js +525 -0
- package/dist/recipes/catalog.js.map +1 -0
- package/dist/recipes/index.d.ts +11 -0
- package/dist/recipes/index.d.ts.map +1 -0
- package/dist/recipes/index.js +14 -0
- package/dist/recipes/index.js.map +1 -0
- package/dist/recipes/types.d.ts +70 -0
- package/dist/recipes/types.d.ts.map +1 -0
- package/dist/recipes/types.js +15 -0
- package/dist/recipes/types.js.map +1 -0
- package/dist/sandbox-manager.d.ts +17 -0
- package/dist/sandbox-manager.d.ts.map +1 -1
- package/dist/sandbox-manager.js +673 -127
- package/dist/sandbox-manager.js.map +1 -1
- package/dist/setup.d.ts +29 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +97 -0
- package/dist/setup.js.map +1 -0
- package/dist/supermemory-plugin.d.ts +5 -3
- package/dist/supermemory-plugin.d.ts.map +1 -1
- package/dist/supermemory-plugin.js +11 -5
- package/dist/supermemory-plugin.js.map +1 -1
- package/dist/tui-command.d.ts +43 -2
- package/dist/tui-command.d.ts.map +1 -1
- package/dist/tui-command.js +261 -27
- package/dist/tui-command.js.map +1 -1
- package/dist/wizard/answers.d.ts +4 -4
- package/dist/wizard/answers.d.ts.map +1 -1
- package/dist/wizard/answers.js +4 -21
- package/dist/wizard/answers.js.map +1 -1
- package/dist/wizard/run.d.ts.map +1 -1
- package/dist/wizard/run.js +162 -5
- package/dist/wizard/run.js.map +1 -1
- package/package.json +15 -15
- package/schema/mono-agent.config.schema.json +206 -3
- package/skills/mono-agent-composer/SKILL.md +4 -4
- package/skills/mono-agent-composer/references/config-blueprint.md +6 -6
- package/skills/mono-agent-composer/references/discovery-questions.md +25 -10
- package/skills/mono-agent-composer/references/feature-coverage.md +7 -7
- package/skills/mono-agent-composer/references/package-map.md +1 -1
- package/skills/mono-agent-composer/references/validation.md +2 -2
package/dist/cli.js
CHANGED
|
@@ -13,7 +13,9 @@ import { startMonoAgentApp } from "./app.js";
|
|
|
13
13
|
import { describeSensitiveDataExportWarning, isAppCoreConfigError, loadAppCoreConfig, phoenixAppBaseUrl, } from "./app-config.js";
|
|
14
14
|
import { runAuditRuns } from "./audit-runs.js";
|
|
15
15
|
import { runBackfill } from "./backfill.js";
|
|
16
|
-
import { defaultBackgroundDeps, resolveInstanceTarget, restartBackground, startBackground, statusBackground, stopBackground, tailLogs, } from "./background.js";
|
|
16
|
+
import { acquireBackgroundWorkerLease, canonicalBackgroundConfigPath, defaultBackgroundDeps, ensureBackgroundReady, forceRestartBackground, managedBackgroundEnvironment, resolveInstanceTarget, restartBackground, startBackground, statusBackground, stopBackground, tailLogs, } from "./background.js";
|
|
17
|
+
import { MANAGED_BACKGROUND_WORKER_ENV, sanitizeManagedBackgroundWorkerEnvironment, } from "./background-runtime.js";
|
|
18
|
+
import { captureBackgroundSnapshot, decodeBackgroundSnapshot, captureDurableBackgroundInputs, loadDurableBackgroundEnvironment, materializeBackgroundRuntimeInputs, } from "./background-snapshot.js";
|
|
17
19
|
import { collectChannelConfigViews } from "./channel-config-view.js";
|
|
18
20
|
import { formatChannelFactValue } from "./channel-fact-format.js";
|
|
19
21
|
import { resolveChannelDrivers } from "./channels.js";
|
|
@@ -22,6 +24,7 @@ import { validateMonoAgentFolder } from "./doctor.js";
|
|
|
22
24
|
import { effectiveFirstRunEnvironment, evaluateFirstRunConfigurationReadiness, evaluateFirstRunReadiness, hasSensitivePersistedEnvironmentValue, piAuthPathBackgroundConflict, readCliConfigSnapshot, readCliDotenvFile, readCliDotenvSnapshot, resolveEffectivePiAuthPath, selectedSecretEnvironmentConflicts, selectedSecretValues, unexpectedPersistedMonoAgentOverrides, validateWizardPlanInStaging, withExactProcessEnvironment, } from "./first-run-readiness.js";
|
|
23
25
|
import { initMonoAgentFolder, SecretEnvConcurrentModificationError, verifySecretEnvPersistenceGuard, } from "./init.js";
|
|
24
26
|
import { installComposerSkill } from "./install-skill.js";
|
|
27
|
+
import { deriveLaunchdLabel, launchdPathsFor } from "./launchd.js";
|
|
25
28
|
import { checkManagedProjectSkills, updateManagedProjectSkills } from "./project-skills.js";
|
|
26
29
|
import { runMetrics } from "./metrics.js";
|
|
27
30
|
import { buildRunsHealthDisplay, RUNS_HEALTH_MAX_RUNS } from "./runs-health.js";
|
|
@@ -41,7 +44,7 @@ const DEFAULT_LOG_LINES = 200;
|
|
|
41
44
|
// busy-waiting; larger values silently overflow to a 1ms delay.
|
|
42
45
|
const KEEP_ALIVE_INTERVAL_MS = 2_147_483_647;
|
|
43
46
|
const BACKGROUND_COMMANDS = ["start", "restart", "stop", "status", "logs"];
|
|
44
|
-
const KNOWN_COMMANDS = ["init", "setup", "validate", "doctor", "auth", "sandbox", "config", "recipes", "presets", "start", "restart", "stop", "status", "logs", "tui", "web", "install-skill", "backfill", "audit-runs", "metrics", "memory"];
|
|
47
|
+
const KNOWN_COMMANDS = ["init", "setup", "validate", "doctor", "auth", "sandbox", "config", "recipes", "presets", "start", "restart", "stop", "status", "logs", "tui", "web", "install-skill", "backfill", "audit-runs", "metrics", "memory", "continuations"];
|
|
45
48
|
export function parseCliArgs(argv) {
|
|
46
49
|
const [command, ...rest] = argv;
|
|
47
50
|
if (command === undefined || command === "help" || command === "--help" || command === "-h") {
|
|
@@ -83,6 +86,7 @@ export function parseCliArgs(argv) {
|
|
|
83
86
|
let codexAuthMode;
|
|
84
87
|
const positionals = [];
|
|
85
88
|
let envFile;
|
|
89
|
+
let expectedBackgroundSnapshot;
|
|
86
90
|
let target;
|
|
87
91
|
let force = false;
|
|
88
92
|
let foreground = false;
|
|
@@ -108,6 +112,7 @@ export function parseCliArgs(argv) {
|
|
|
108
112
|
let json = false;
|
|
109
113
|
let strict = false;
|
|
110
114
|
let limit;
|
|
115
|
+
let cursor;
|
|
111
116
|
let host;
|
|
112
117
|
let port;
|
|
113
118
|
let open;
|
|
@@ -196,12 +201,18 @@ export function parseCliArgs(argv) {
|
|
|
196
201
|
case "--limit": {
|
|
197
202
|
const raw = requireValue(rest, ++i, flag);
|
|
198
203
|
const parsed = Number(raw);
|
|
199
|
-
|
|
200
|
-
|
|
204
|
+
const maximum = cmd === "continuations" ? 500 : 100;
|
|
205
|
+
if (!Number.isInteger(parsed) || parsed < 1 || parsed > maximum) {
|
|
206
|
+
throw new Error(`--limit must be an integer between 1 and ${String(maximum)}.`);
|
|
201
207
|
}
|
|
202
208
|
limit = parsed;
|
|
203
209
|
break;
|
|
204
210
|
}
|
|
211
|
+
case "--cursor":
|
|
212
|
+
cursor = requireValue(rest, ++i, flag).trim();
|
|
213
|
+
if (cursor.length === 0 || cursor.length > 512)
|
|
214
|
+
throw new Error("--cursor must be 1-512 characters.");
|
|
215
|
+
break;
|
|
205
216
|
case "--host":
|
|
206
217
|
host = requireValue(rest, ++i, flag);
|
|
207
218
|
break;
|
|
@@ -335,6 +346,9 @@ export function parseCliArgs(argv) {
|
|
|
335
346
|
case "--env-file":
|
|
336
347
|
envFile = requireValue(rest, ++i, flag);
|
|
337
348
|
break;
|
|
349
|
+
case "--expected-background-snapshot":
|
|
350
|
+
expectedBackgroundSnapshot = requireValue(rest, ++i, flag);
|
|
351
|
+
break;
|
|
338
352
|
case "--target": {
|
|
339
353
|
const raw = requireValue(rest, ++i, flag);
|
|
340
354
|
if (raw !== "claude" && raw !== "codex" && raw !== "both") {
|
|
@@ -388,8 +402,8 @@ export function parseCliArgs(argv) {
|
|
|
388
402
|
if ((local || configure) && cmd !== "tui") {
|
|
389
403
|
throw new Error("--local and --configure are only supported for `mono-agent tui`.");
|
|
390
404
|
}
|
|
391
|
-
if (configure &&
|
|
392
|
-
throw new Error("--configure
|
|
405
|
+
if (configure && local) {
|
|
406
|
+
throw new Error("--configure attaches to the authoritative background agent; omit --local.");
|
|
393
407
|
}
|
|
394
408
|
if ((project || check || update) && cmd !== "install-skill") {
|
|
395
409
|
throw new Error("--project, --check, and --update are only supported for `mono-agent install-skill`.");
|
|
@@ -412,8 +426,14 @@ export function parseCliArgs(argv) {
|
|
|
412
426
|
if (includeMemory && cmd !== "audit-runs" && cmd !== "metrics" && cmd !== "backfill" && cmd !== "web") {
|
|
413
427
|
throw new Error("--include-memory is only supported for `mono-agent audit-runs`, `mono-agent metrics`, `mono-agent backfill`, and `mono-agent web`.");
|
|
414
428
|
}
|
|
415
|
-
if (limit !== undefined && cmd !== "memory") {
|
|
416
|
-
throw new Error("--limit is only supported for `mono-agent memory`.");
|
|
429
|
+
if (limit !== undefined && cmd !== "memory" && cmd !== "continuations") {
|
|
430
|
+
throw new Error("--limit is only supported for `mono-agent memory` and `mono-agent continuations list`.");
|
|
431
|
+
}
|
|
432
|
+
if ((limit !== undefined || cursor !== undefined) && cmd === "continuations" && (positionals[0] ?? "list") !== "list") {
|
|
433
|
+
throw new Error("--limit and --cursor are only supported for `mono-agent continuations list`.");
|
|
434
|
+
}
|
|
435
|
+
if (cursor !== undefined && cmd !== "continuations") {
|
|
436
|
+
throw new Error("--cursor is only supported for `mono-agent continuations list`.");
|
|
417
437
|
}
|
|
418
438
|
if (strict && (cmd !== "memory" || (positionals[0] ?? "stats") !== "audit")) {
|
|
419
439
|
throw new Error("--strict is only supported for `mono-agent memory audit`.");
|
|
@@ -460,6 +480,7 @@ export function parseCliArgs(argv) {
|
|
|
460
480
|
...(codexAuthMode === undefined ? {} : { codexAuthMode }),
|
|
461
481
|
positionals,
|
|
462
482
|
...(envFile === undefined ? {} : { envFile }),
|
|
483
|
+
...(expectedBackgroundSnapshot === undefined ? {} : { expectedBackgroundSnapshot }),
|
|
463
484
|
...(target === undefined ? {} : { target }),
|
|
464
485
|
force,
|
|
465
486
|
foreground,
|
|
@@ -478,6 +499,7 @@ export function parseCliArgs(argv) {
|
|
|
478
499
|
...(json ? { json } : {}),
|
|
479
500
|
...(strict ? { strict } : {}),
|
|
480
501
|
...(limit === undefined ? {} : { limit }),
|
|
502
|
+
...(cursor === undefined ? {} : { cursor }),
|
|
481
503
|
...(agent === undefined ? {} : { agent }),
|
|
482
504
|
...(conversation === undefined ? {} : { conversation }),
|
|
483
505
|
...(local ? { local } : {}),
|
|
@@ -617,14 +639,14 @@ const HELP_COMMANDS = [
|
|
|
617
639
|
},
|
|
618
640
|
{
|
|
619
641
|
signature: "mono-agent tui [--agent <label|sourceId>] [--conversation <id>]\n" +
|
|
620
|
-
" [--
|
|
642
|
+
" [--configure | --local]",
|
|
621
643
|
lines: [
|
|
622
644
|
"Open the operator console from any directory: live chat with full",
|
|
623
645
|
"thinking/tool/telemetry insight, recorded-run replay, and config view.",
|
|
624
646
|
"Discovers running agents via the trace-source registry; one running",
|
|
625
647
|
"agent connects directly, several open a picker.",
|
|
626
|
-
"--
|
|
627
|
-
"
|
|
648
|
+
"--configure opens the guided configuration chat on the authoritative",
|
|
649
|
+
"background agent; --local is an ordinary in-process chat only.",
|
|
628
650
|
],
|
|
629
651
|
},
|
|
630
652
|
{
|
|
@@ -694,6 +716,14 @@ const HELP_COMMANDS = [
|
|
|
694
716
|
"operation. It returns metadata only and requires rebuild before restart.",
|
|
695
717
|
],
|
|
696
718
|
},
|
|
719
|
+
{
|
|
720
|
+
signature: "mono-agent continuations [list [--limit <n>] [--cursor <opaque>]|health|retry <id>|cancel <id>|resolve <id> delivered|not-delivered|dead-lettered [delivery-id]] [--json]",
|
|
721
|
+
lines: [
|
|
722
|
+
"Inspect and operate the authenticated durable-continuation service.",
|
|
723
|
+
"Ambiguous delivery cannot be retried until it is explicitly resolved;",
|
|
724
|
+
"no command accepts or changes a channel destination.",
|
|
725
|
+
],
|
|
726
|
+
},
|
|
697
727
|
];
|
|
698
728
|
const HELP_NOTES = `Background mode runs the agent under launchd, keeping it alive across logins
|
|
699
729
|
(auto-restarting only on crash) until you run stop. Secrets are read from the
|
|
@@ -776,6 +806,21 @@ export async function runCli(argv) {
|
|
|
776
806
|
process.stdout.write(`\n${renderHelp()}`);
|
|
777
807
|
return 2;
|
|
778
808
|
}
|
|
809
|
+
// Only the internal launchd foreground shape may honor the managed-worker
|
|
810
|
+
// marker. A hostile/global launchctl environment must not sanitize unrelated
|
|
811
|
+
// commands such as `mono-agent validate` or `mono-agent status`.
|
|
812
|
+
const managedBackgroundWorker = args.command === "start" && args.foreground && process.env[MANAGED_BACKGROUND_WORKER_ENV] === "1";
|
|
813
|
+
if (args.expectedBackgroundSnapshot !== undefined && !managedBackgroundWorker) {
|
|
814
|
+
process.stderr.write(ui.errorLine("--expected-background-snapshot is reserved for the managed LaunchAgent worker."));
|
|
815
|
+
return 2;
|
|
816
|
+
}
|
|
817
|
+
if (managedBackgroundWorker && args.expectedBackgroundSnapshot === undefined) {
|
|
818
|
+
process.stderr.write(ui.errorLine("Managed LaunchAgent worker is missing its approved background snapshot."));
|
|
819
|
+
return 0;
|
|
820
|
+
}
|
|
821
|
+
if (managedBackgroundWorker) {
|
|
822
|
+
sanitizeManagedBackgroundWorkerEnvironment(process.env);
|
|
823
|
+
}
|
|
779
824
|
if (args.command === "memory"
|
|
780
825
|
&& args.positionals[0] === "adopt-replay"
|
|
781
826
|
&& hasUnsupportedReplayAdoptionFlag(argv)) {
|
|
@@ -822,7 +867,7 @@ export async function runCli(argv) {
|
|
|
822
867
|
case "presets":
|
|
823
868
|
return runPresets(args);
|
|
824
869
|
case "start":
|
|
825
|
-
return await runStart(args);
|
|
870
|
+
return await runStart(args, undefined, managedBackgroundWorker);
|
|
826
871
|
case "restart":
|
|
827
872
|
case "stop":
|
|
828
873
|
case "status":
|
|
@@ -835,6 +880,7 @@ export async function runCli(argv) {
|
|
|
835
880
|
configPath: resolve(process.cwd(), args.configPath ?? "mono-agent.config.json"),
|
|
836
881
|
cwd: process.cwd(),
|
|
837
882
|
env: process.env,
|
|
883
|
+
...(args.envFile === undefined ? {} : { envFile: args.envFile }),
|
|
838
884
|
...(args.agent === undefined ? {} : { agent: args.agent }),
|
|
839
885
|
...(args.conversation === undefined ? {} : { conversationId: args.conversation }),
|
|
840
886
|
...(args.local === true ? { local: true } : {}),
|
|
@@ -859,6 +905,18 @@ export async function runCli(argv) {
|
|
|
859
905
|
}
|
|
860
906
|
case "install-skill":
|
|
861
907
|
return await runInstallSkill(args);
|
|
908
|
+
case "continuations": {
|
|
909
|
+
const { runContinuationCommand } = await import("./continuation-command.js");
|
|
910
|
+
return await runContinuationCommand({
|
|
911
|
+
cwd: process.cwd(),
|
|
912
|
+
configPath: resolve(process.cwd(), args.configPath ?? "mono-agent.config.json"),
|
|
913
|
+
env: process.env,
|
|
914
|
+
positionals: args.positionals,
|
|
915
|
+
...(args.json === true ? { json: true } : {}),
|
|
916
|
+
...(args.limit === undefined ? {} : { limit: args.limit }),
|
|
917
|
+
...(args.cursor === undefined ? {} : { cursor: args.cursor }),
|
|
918
|
+
});
|
|
919
|
+
}
|
|
862
920
|
case "backfill":
|
|
863
921
|
return await runBackfill({
|
|
864
922
|
...(args.configPath === undefined ? {} : { configPath: args.configPath }),
|
|
@@ -1346,6 +1404,14 @@ async function runInit(args, environment) {
|
|
|
1346
1404
|
printIncompleteSetup(["The committed .env could not be read back safely; no readiness claim is safe."], result.configPath);
|
|
1347
1405
|
return 1;
|
|
1348
1406
|
}
|
|
1407
|
+
// A missing default .env is a valid, durable empty environment. Keep
|
|
1408
|
+
// proving its absence in the approved snapshot, but do not turn that
|
|
1409
|
+
// default into an explicit --env-file argument: the managed worker
|
|
1410
|
+
// treats an explicitly named missing file as an operator error.
|
|
1411
|
+
const backgroundEnvFile = args.envFile === undefined
|
|
1412
|
+
&& committedDotenvSnapshot.fingerprint === "missing"
|
|
1413
|
+
? undefined
|
|
1414
|
+
: environment.dotenvPath;
|
|
1349
1415
|
const postWriteConflicts = selectedSecretEnvironmentConflicts(result.plan, environment.shellEnv, committedDotenvSnapshot.env, moduleSecrets);
|
|
1350
1416
|
const postWriteOverrides = unexpectedPersistedMonoAgentOverrides(result.plan, committedDotenvSnapshot.env);
|
|
1351
1417
|
const postWritePiAuthConflict = piAuthPathBackgroundConflict({
|
|
@@ -1369,6 +1435,28 @@ async function runInit(args, environment) {
|
|
|
1369
1435
|
printIncompleteSetup(["The durable environment changed after the primary-model check. Retry setup before claiming readiness."], result.configPath);
|
|
1370
1436
|
return 1;
|
|
1371
1437
|
}
|
|
1438
|
+
let committedBackgroundSnapshot;
|
|
1439
|
+
let committedBackgroundEnvironment;
|
|
1440
|
+
let committedBackgroundConfigSourceFingerprint;
|
|
1441
|
+
try {
|
|
1442
|
+
const durableInputs = await captureDurableBackgroundInputs({
|
|
1443
|
+
cwd,
|
|
1444
|
+
configPath: result.configPath,
|
|
1445
|
+
envFile: environment.dotenvPath,
|
|
1446
|
+
operationalEnvironment: managedBackgroundEnvironment(postWriteEnv),
|
|
1447
|
+
});
|
|
1448
|
+
committedBackgroundSnapshot = durableInputs.snapshot;
|
|
1449
|
+
committedBackgroundEnvironment = durableInputs.environment;
|
|
1450
|
+
committedBackgroundConfigSourceFingerprint = durableInputs.configSourceFingerprint;
|
|
1451
|
+
}
|
|
1452
|
+
catch {
|
|
1453
|
+
printIncompleteSetup(["The complete committed config, dotenv, Identity, Soul, and MCP snapshot could not be proven safely."], result.configPath);
|
|
1454
|
+
return 1;
|
|
1455
|
+
}
|
|
1456
|
+
if (committedBackgroundConfigSourceFingerprint !== committedConfigSnapshot.fingerprint) {
|
|
1457
|
+
printIncompleteSetup(["The committed config or durable environment changed before the background snapshot was captured."], result.configPath);
|
|
1458
|
+
return 1;
|
|
1459
|
+
}
|
|
1372
1460
|
printInitResult(result);
|
|
1373
1461
|
let report;
|
|
1374
1462
|
try {
|
|
@@ -1416,7 +1504,7 @@ async function runInit(args, environment) {
|
|
|
1416
1504
|
return 1;
|
|
1417
1505
|
}
|
|
1418
1506
|
process.stdout.write(ui.badge("ok") + ui.style.green("All runtime route checks passed — every selected model produced a real no-tool response.\n") +
|
|
1419
|
-
ui.badge("ok") + ui.style.green("Agent
|
|
1507
|
+
ui.badge("ok") + ui.style.green("Agent configuration validated — every selected capability passed full validation.\n"));
|
|
1420
1508
|
const preTuiConfigDrift = await firstRunConfigDrift(result.configPath, committedConfigSnapshot);
|
|
1421
1509
|
if (preTuiConfigDrift !== undefined) {
|
|
1422
1510
|
printIncompleteSetup([preTuiConfigDrift.message], result.configPath);
|
|
@@ -1432,13 +1520,46 @@ async function runInit(args, environment) {
|
|
|
1432
1520
|
printIncompleteSetup([preTuiSecretGuard.message], result.configPath);
|
|
1433
1521
|
return 1;
|
|
1434
1522
|
}
|
|
1435
|
-
process.
|
|
1523
|
+
if (process.platform !== "darwin") {
|
|
1524
|
+
printUnsupportedGuidedInitHandoff(result.configPath, backgroundEnvFile);
|
|
1525
|
+
return 0;
|
|
1526
|
+
}
|
|
1527
|
+
process.stdout.write(ui.hint("Starting the authoritative background agent before configuration chat…"));
|
|
1528
|
+
let background;
|
|
1529
|
+
try {
|
|
1530
|
+
const resolvedBackgroundTarget = await resolveInstanceTarget({
|
|
1531
|
+
args: {
|
|
1532
|
+
configPath: result.configPath,
|
|
1533
|
+
...(backgroundEnvFile === undefined ? {} : { envFile: backgroundEnvFile }),
|
|
1534
|
+
},
|
|
1535
|
+
env: { ...committedBackgroundEnvironment },
|
|
1536
|
+
cwd,
|
|
1537
|
+
cliPath: fileURLToPath(import.meta.url),
|
|
1538
|
+
requireTui: true,
|
|
1539
|
+
});
|
|
1540
|
+
const backgroundTarget = {
|
|
1541
|
+
...resolvedBackgroundTarget,
|
|
1542
|
+
expectedSnapshot: committedBackgroundSnapshot,
|
|
1543
|
+
};
|
|
1544
|
+
background = await ensureBackgroundReady(backgroundTarget, defaultBackgroundDeps());
|
|
1545
|
+
}
|
|
1546
|
+
catch (error) {
|
|
1547
|
+
printUnexpectedGuidedBackgroundFailure(result.configPath, backgroundEnvFile, error);
|
|
1548
|
+
return 1;
|
|
1549
|
+
}
|
|
1550
|
+
if (!background.ok) {
|
|
1551
|
+
process.stderr.write(ui.hint("The validated agent files were preserved, but configuration chat was not opened because the background agent is not ready."));
|
|
1552
|
+
return 1;
|
|
1553
|
+
}
|
|
1554
|
+
process.stdout.write(ui.badge("ok") + ui.style.green("Agent ready — the background process reported startup complete.\n") +
|
|
1555
|
+
ui.badge("ok") + ui.style.green("Opening configuration chat on the authoritative background agent.\n"));
|
|
1436
1556
|
const { runTui } = await import("./tui-command.js");
|
|
1437
|
-
return await withExactProcessEnvironment(
|
|
1557
|
+
return await withExactProcessEnvironment(committedBackgroundEnvironment, () => runTui({
|
|
1438
1558
|
configPath: result.configPath,
|
|
1439
1559
|
cwd,
|
|
1440
|
-
env:
|
|
1441
|
-
|
|
1560
|
+
env: committedBackgroundEnvironment,
|
|
1561
|
+
...(backgroundEnvFile === undefined ? {} : { envFile: backgroundEnvFile }),
|
|
1562
|
+
agent: background.source.sourceId,
|
|
1442
1563
|
configure: true,
|
|
1443
1564
|
}));
|
|
1444
1565
|
}
|
|
@@ -2521,7 +2642,7 @@ async function runAuth(args) {
|
|
|
2521
2642
|
return 2;
|
|
2522
2643
|
}
|
|
2523
2644
|
const cwd = process.cwd();
|
|
2524
|
-
const configPath =
|
|
2645
|
+
const configPath = await canonicalBackgroundConfigPath(cwd, args.configPath);
|
|
2525
2646
|
const directCodex = provider === "codex";
|
|
2526
2647
|
if (directCodex && args.piAuthPath !== undefined) {
|
|
2527
2648
|
process.stderr.write(ui.errorLine("--pi-auth-path does not apply to direct Codex login."));
|
|
@@ -2728,6 +2849,19 @@ export function initChangeDisplayRows(result) {
|
|
|
2728
2849
|
unchanged: change.kind === "unchanged",
|
|
2729
2850
|
}));
|
|
2730
2851
|
}
|
|
2852
|
+
/** Human-readable, value-free proof of where the wizard Role did (or did not) land. */
|
|
2853
|
+
export function identityRoleDisplayLine(identityRole) {
|
|
2854
|
+
switch (identityRole.status) {
|
|
2855
|
+
case "created":
|
|
2856
|
+
return `Role saved to ${identityRole.path} → ${identityRole.section}. ` +
|
|
2857
|
+
`Edit ${identityRole.path} → ${identityRole.section} later to change it.`;
|
|
2858
|
+
case "preserved":
|
|
2859
|
+
return `${identityRole.path} already existed and was preserved; the entered Role was not written. ` +
|
|
2860
|
+
`Add or edit ${identityRole.path} → ${identityRole.section} to set it.`;
|
|
2861
|
+
case "planned-create":
|
|
2862
|
+
return `Dry run: Role would be saved to ${identityRole.path} → ${identityRole.section}.`;
|
|
2863
|
+
}
|
|
2864
|
+
}
|
|
2731
2865
|
export function secretChecklistDisplayRows(secrets, configured) {
|
|
2732
2866
|
return secrets.map((secret) => ({
|
|
2733
2867
|
envVar: secret.envVar,
|
|
@@ -2749,6 +2883,7 @@ function printInitResult(result) {
|
|
|
2749
2883
|
// included in this result or printed here.
|
|
2750
2884
|
process.stdout.write(`${prefix}${rendered} ${row.path}\n`);
|
|
2751
2885
|
}
|
|
2886
|
+
process.stdout.write(`\n${identityRoleDisplayLine(result.identityRole)}\n`);
|
|
2752
2887
|
if (result.knowledgeFiles.length > 0) {
|
|
2753
2888
|
process.stdout.write(`\nIdentity references existing knowledge: ${ui.style.cyan(result.knowledgeFiles.join(", "))}\n`);
|
|
2754
2889
|
}
|
|
@@ -2792,12 +2927,45 @@ function printSecretsChecklist(secrets, configured = new Set()) {
|
|
|
2792
2927
|
}
|
|
2793
2928
|
}
|
|
2794
2929
|
function printNextSteps(configPath) {
|
|
2930
|
+
const startCommand = process.platform === "darwin" ? "mono-agent start" : "mono-agent start --foreground";
|
|
2931
|
+
const tuiCommand = process.platform === "darwin"
|
|
2932
|
+
? `mono-agent tui --configure ${ui.style.dim("(after the agent reports ready)")}`
|
|
2933
|
+
: `mono-agent tui ${ui.style.dim("(ordinary chat after foreground startup; edit config files manually)")}`;
|
|
2795
2934
|
process.stdout.write("\n" +
|
|
2796
2935
|
ui.heading("Next steps") +
|
|
2797
2936
|
` ${ui.style.bold("1.")} Edit ${configPath} ${ui.style.dim("(model, channels, skills, memory, sandbox)")}\n` +
|
|
2798
2937
|
` ${ui.style.bold("2.")} mono-agent validate\n` +
|
|
2799
|
-
` ${ui.style.bold("3.")}
|
|
2800
|
-
` ${ui.style.bold("4.")} ${
|
|
2938
|
+
` ${ui.style.bold("3.")} ${startCommand}\n` +
|
|
2939
|
+
` ${ui.style.bold("4.")} ${tuiCommand}\n`);
|
|
2940
|
+
}
|
|
2941
|
+
function printUnsupportedGuidedInitHandoff(configPath, envFile) {
|
|
2942
|
+
const flags = guidedHandoffFlags(configPath, envFile);
|
|
2943
|
+
process.stdout.write("\n" +
|
|
2944
|
+
ui.heading("Manual start required") +
|
|
2945
|
+
ui.style.yellow("Automatic background start and configuration chat require macOS launchd.\n") +
|
|
2946
|
+
ui.style.dim("The validated agent files were preserved, but no agent process was started and readiness is not claimed.\n") +
|
|
2947
|
+
` ${ui.style.bold("Configure manually:")} edit ${configPath} and IDENTITY.md, then run mono-agent validate${flags}\n` +
|
|
2948
|
+
` ${ui.style.bold("Terminal 1:")} mono-agent start --foreground${flags}\n` +
|
|
2949
|
+
` ${ui.style.bold("Terminal 2:")} mono-agent tui${flags} ${ui.style.dim("(ordinary chat after startup completes)")}\n` +
|
|
2950
|
+
ui.style.dim("Conversational configuration requires the managed macOS background lifecycle.\n"));
|
|
2951
|
+
}
|
|
2952
|
+
function printUnexpectedGuidedBackgroundFailure(configPath, envFile, error) {
|
|
2953
|
+
const flags = guidedHandoffFlags(configPath, envFile);
|
|
2954
|
+
const paths = launchdPathsFor(deriveLaunchdLabel(configPath));
|
|
2955
|
+
process.stderr.write(ui.errorLine(`The background lifecycle failed unexpectedly: ${error instanceof Error ? error.message : String(error)}`));
|
|
2956
|
+
process.stderr.write(ui.style.dim("The validated agent files were preserved, but configuration chat was not opened. Retry or inspect with:\n"));
|
|
2957
|
+
process.stderr.write(` ${ui.style.gray("logs: ")} ${paths.stderrPath}\n` +
|
|
2958
|
+
` ${paths.stdoutPath}\n` +
|
|
2959
|
+
` ${ui.style.gray("retry: ")} mono-agent start${flags}\n` +
|
|
2960
|
+
` ${ui.style.gray("status:")} mono-agent status${flags}\n` +
|
|
2961
|
+
` ${ui.style.gray("follow:")} mono-agent logs${flags} --follow\n`);
|
|
2962
|
+
}
|
|
2963
|
+
function guidedHandoffFlags(configPath, envFile) {
|
|
2964
|
+
return ` --config ${shellCommandArgument(configPath)}`
|
|
2965
|
+
+ (envFile === undefined ? "" : ` --env-file ${shellCommandArgument(envFile)}`);
|
|
2966
|
+
}
|
|
2967
|
+
function shellCommandArgument(value) {
|
|
2968
|
+
return /^[a-zA-Z0-9_./:@%+=,-]+$/u.test(value) ? value : `'${value.replaceAll("'", `'"'"'`)}'`;
|
|
2801
2969
|
}
|
|
2802
2970
|
async function runInstallSkill(args) {
|
|
2803
2971
|
if (args.project === true) {
|
|
@@ -3150,13 +3318,19 @@ function colorDetail(status, detail) {
|
|
|
3150
3318
|
* refuse on any `error` section. `waiting` (e.g. Ollama/Phoenix not up yet) is
|
|
3151
3319
|
* runtime-soft and never blocks.
|
|
3152
3320
|
*/
|
|
3153
|
-
export async function ensureStartable(args, env = process.env) {
|
|
3154
|
-
const cwd = process.cwd();
|
|
3155
|
-
const configPath = resolve(cwd, args.configPath ?? "mono-agent.config.json");
|
|
3321
|
+
export async function ensureStartable(args, env = process.env, options = {}) {
|
|
3322
|
+
const cwd = options.cwd ?? process.cwd();
|
|
3323
|
+
const configPath = options.configPath ?? resolve(cwd, args.configPath ?? "mono-agent.config.json");
|
|
3156
3324
|
if (!(await pathExists(configPath))) {
|
|
3157
3325
|
return { ok: false, code: 2, kind: "missing-config", configPath };
|
|
3158
3326
|
}
|
|
3159
|
-
const report = await validateMonoAgentFolder({
|
|
3327
|
+
const report = await validateMonoAgentFolder({
|
|
3328
|
+
env,
|
|
3329
|
+
cwd,
|
|
3330
|
+
configPath,
|
|
3331
|
+
liveness: false,
|
|
3332
|
+
...(options.preferAppPluginInstall === true ? { preferAppPluginInstall: true } : {}),
|
|
3333
|
+
});
|
|
3160
3334
|
if (!report.ok) {
|
|
3161
3335
|
return { ok: false, code: 1, kind: "validation", report };
|
|
3162
3336
|
}
|
|
@@ -3185,9 +3359,9 @@ async function pathExists(path) {
|
|
|
3185
3359
|
return false;
|
|
3186
3360
|
}
|
|
3187
3361
|
}
|
|
3188
|
-
async function runStart(args, env) {
|
|
3362
|
+
async function runStart(args, env, managedBackgroundWorker = false) {
|
|
3189
3363
|
if (args.foreground) {
|
|
3190
|
-
return await runForeground(args, env);
|
|
3364
|
+
return await runForeground(args, env, managedBackgroundWorker);
|
|
3191
3365
|
}
|
|
3192
3366
|
return await runBackgroundCommand(args, "start", env);
|
|
3193
3367
|
}
|
|
@@ -3196,56 +3370,155 @@ async function runStart(args, env) {
|
|
|
3196
3370
|
* plus traceability, and stays alive until a signal. This is what launchd
|
|
3197
3371
|
* invokes (via `start --foreground`) and what users get with `--foreground`/`-f`.
|
|
3198
3372
|
*/
|
|
3199
|
-
async function runForeground(args, env = process.env) {
|
|
3200
|
-
const
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3373
|
+
async function runForeground(args, env = process.env, managedBackgroundWorker = false) {
|
|
3374
|
+
const cwd = process.cwd();
|
|
3375
|
+
const configPath = await canonicalBackgroundConfigPath(cwd, args.configPath);
|
|
3376
|
+
const startupEnvironment = { ...env };
|
|
3377
|
+
let lease;
|
|
3378
|
+
try {
|
|
3379
|
+
lease = await acquireBackgroundWorkerLease(configPath);
|
|
3380
|
+
}
|
|
3381
|
+
catch (error) {
|
|
3382
|
+
process.stderr.write(ui.errorLine(`Could not acquire the worker singleton lease: ${error instanceof Error ? error.message : String(error)}`));
|
|
3383
|
+
return 1;
|
|
3384
|
+
}
|
|
3385
|
+
if (lease === undefined) {
|
|
3386
|
+
process.stderr.write(ui.errorLine(`Another foreground or managed background worker already owns ${configPath}; refusing to start a duplicate.`));
|
|
3387
|
+
return 1;
|
|
3388
|
+
}
|
|
3389
|
+
let runtimeInputs;
|
|
3390
|
+
let app;
|
|
3391
|
+
try {
|
|
3392
|
+
let backgroundSnapshot;
|
|
3393
|
+
if (managedBackgroundWorker) {
|
|
3394
|
+
try {
|
|
3395
|
+
backgroundSnapshot = decodeBackgroundSnapshot(args.expectedBackgroundSnapshot ?? "");
|
|
3396
|
+
const dotenvPath = resolve(cwd, args.envFile ?? ".env");
|
|
3397
|
+
if (backgroundSnapshot.configPath !== configPath || backgroundSnapshot.dotenvPath !== dotenvPath) {
|
|
3398
|
+
throw new Error("The approved snapshot paths do not match the managed worker arguments.");
|
|
3399
|
+
}
|
|
3400
|
+
runtimeInputs = await materializeBackgroundRuntimeInputs({
|
|
3401
|
+
snapshot: backgroundSnapshot,
|
|
3402
|
+
cwd,
|
|
3403
|
+
env: startupEnvironment,
|
|
3404
|
+
});
|
|
3405
|
+
}
|
|
3406
|
+
catch (error) {
|
|
3407
|
+
process.stderr.write(ui.errorLine(`Managed worker could not freeze its startup snapshot: ${error instanceof Error ? error.message : String(error)}`));
|
|
3408
|
+
// KeepAlive restarts only unsuccessful exits. This refusal cannot heal
|
|
3409
|
+
// without a new approved snapshot, so exit successfully and let the
|
|
3410
|
+
// controller unload/recreate the job instead of retrying forever.
|
|
3411
|
+
return 0;
|
|
3412
|
+
}
|
|
3413
|
+
}
|
|
3414
|
+
const preflightEnvironment = runtimeInputs?.environment ?? startupEnvironment;
|
|
3415
|
+
const pre = await ensureStartable(args, preflightEnvironment, runtimeInputs === undefined
|
|
3416
|
+
? {}
|
|
3417
|
+
: {
|
|
3418
|
+
cwd,
|
|
3419
|
+
configPath: runtimeInputs.configPath,
|
|
3420
|
+
preferAppPluginInstall: true,
|
|
3421
|
+
});
|
|
3422
|
+
if (!pre.ok) {
|
|
3423
|
+
printPreflightFailure(pre);
|
|
3424
|
+
return managedBackgroundWorker ? 0 : pre.code;
|
|
3425
|
+
}
|
|
3426
|
+
try {
|
|
3427
|
+
await readCliConfigSnapshot(runtimeInputs?.configPath ?? configPath);
|
|
3428
|
+
}
|
|
3429
|
+
catch (error) {
|
|
3430
|
+
process.stderr.write(ui.errorLine(`Cannot establish the foreground config identity: ${error instanceof Error ? error.message : String(error)}`));
|
|
3431
|
+
return managedBackgroundWorker ? 0 : 1;
|
|
3432
|
+
}
|
|
3433
|
+
app = await startMonoAgentApp({
|
|
3434
|
+
cwd,
|
|
3435
|
+
configPath,
|
|
3436
|
+
...(runtimeInputs === undefined ? {} : { configReadPath: runtimeInputs.configPath }),
|
|
3437
|
+
env: runtimeInputs?.environment ?? startupEnvironment,
|
|
3438
|
+
logger: consoleLogger(),
|
|
3439
|
+
...(backgroundSnapshot === undefined ? {} : { backgroundSnapshot }),
|
|
3440
|
+
});
|
|
3441
|
+
await printAppStatus(app);
|
|
3442
|
+
// Block until a shutdown signal. Returning here (the old behavior) let the
|
|
3443
|
+
// process exit immediately whenever no channel owned a live handle — e.g. a
|
|
3444
|
+
// traceability-only config, now that the operator console is retired and the
|
|
3445
|
+
// trace heartbeat timer is unref'd.
|
|
3446
|
+
return await waitForShutdownSignal(app);
|
|
3447
|
+
}
|
|
3448
|
+
finally {
|
|
3449
|
+
await app?.stop().catch(() => undefined);
|
|
3450
|
+
await runtimeInputs?.dispose().catch(() => undefined);
|
|
3451
|
+
await lease.release().catch((error) => {
|
|
3452
|
+
process.stderr.write(ui.style.yellow(`⚠ Could not cleanly release worker singleton lease ${lease.path}: ${error instanceof Error ? error.message : String(error)}`) + "\n");
|
|
3453
|
+
});
|
|
3204
3454
|
}
|
|
3205
|
-
const app = await startMonoAgentApp({
|
|
3206
|
-
cwd: process.cwd(),
|
|
3207
|
-
env,
|
|
3208
|
-
...(args.configPath === undefined ? {} : { configPath: args.configPath }),
|
|
3209
|
-
logger: consoleLogger(),
|
|
3210
|
-
});
|
|
3211
|
-
await printAppStatus(app);
|
|
3212
|
-
// Block until a shutdown signal. Returning here (the old behavior) let the
|
|
3213
|
-
// process exit immediately whenever no channel owned a live handle — e.g. a
|
|
3214
|
-
// traceability-only config, now that the operator console is retired and the
|
|
3215
|
-
// trace heartbeat timer is unref'd.
|
|
3216
|
-
return await waitForShutdownSignal(app);
|
|
3217
3455
|
}
|
|
3218
3456
|
async function runBackgroundCommand(args, command, env = process.env) {
|
|
3219
3457
|
const guard = requireDarwin(command);
|
|
3220
3458
|
if (guard !== undefined) {
|
|
3221
3459
|
return guard;
|
|
3222
3460
|
}
|
|
3461
|
+
let controllerEnvironment;
|
|
3462
|
+
try {
|
|
3463
|
+
controllerEnvironment = await loadDurableBackgroundEnvironment({
|
|
3464
|
+
cwd: process.cwd(),
|
|
3465
|
+
...(args.envFile === undefined ? {} : { envFile: args.envFile }),
|
|
3466
|
+
operationalEnvironment: managedBackgroundEnvironment(env),
|
|
3467
|
+
});
|
|
3468
|
+
}
|
|
3469
|
+
catch (error) {
|
|
3470
|
+
if (command === "start" || command === "restart") {
|
|
3471
|
+
process.stderr.write(ui.errorLine(`Cannot reconstruct the managed worker environment: ${error instanceof Error ? error.message : String(error)}`));
|
|
3472
|
+
process.stderr.write(ui.hint("No LaunchAgent changes were made. Fix the dotenv path and retry."));
|
|
3473
|
+
return 1;
|
|
3474
|
+
}
|
|
3475
|
+
controllerEnvironment = { ...env };
|
|
3476
|
+
process.stderr.write(ui.style.yellow(`⚠ Could not reconstruct the managed worker environment; ${command} will use the current shell only: ${error instanceof Error ? error.message : String(error)}`) + "\n");
|
|
3477
|
+
}
|
|
3223
3478
|
// Refuse to launch (or relaunch) an unconfigured/broken folder BEFORE writing
|
|
3224
3479
|
// the plist and bootstrapping launchctl — otherwise the worker would crash and
|
|
3225
3480
|
// launchd's KeepAlive would retry it forever. stop/status/logs stay ungated so
|
|
3226
3481
|
// a broken instance can still be inspected and torn down.
|
|
3227
3482
|
if (command === "start" || command === "restart") {
|
|
3228
|
-
const pre = await ensureStartable(args,
|
|
3483
|
+
const pre = await ensureStartable(args, controllerEnvironment);
|
|
3229
3484
|
if (!pre.ok) {
|
|
3230
3485
|
printPreflightFailure(pre);
|
|
3231
3486
|
return pre.code;
|
|
3232
3487
|
}
|
|
3233
3488
|
}
|
|
3234
|
-
|
|
3489
|
+
let target = await resolveInstanceTarget({
|
|
3235
3490
|
args: {
|
|
3236
3491
|
...(args.configPath === undefined ? {} : { configPath: args.configPath }),
|
|
3237
3492
|
...(args.envFile === undefined ? {} : { envFile: args.envFile }),
|
|
3238
3493
|
},
|
|
3239
|
-
env,
|
|
3494
|
+
env: controllerEnvironment,
|
|
3240
3495
|
cwd: process.cwd(),
|
|
3241
3496
|
cliPath: fileURLToPath(import.meta.url),
|
|
3242
3497
|
});
|
|
3498
|
+
if (command === "start" || command === "restart") {
|
|
3499
|
+
try {
|
|
3500
|
+
const expectedSnapshot = await captureBackgroundSnapshot({
|
|
3501
|
+
cwd: target.cwd,
|
|
3502
|
+
configPath: target.configPath,
|
|
3503
|
+
...(target.envFile === undefined ? {} : { envFile: target.envFile }),
|
|
3504
|
+
env: controllerEnvironment,
|
|
3505
|
+
});
|
|
3506
|
+
target = { ...target, expectedSnapshot };
|
|
3507
|
+
}
|
|
3508
|
+
catch (error) {
|
|
3509
|
+
process.stderr.write(ui.errorLine(`Cannot prove the durable background snapshot: ${error instanceof Error ? error.message : String(error)}`));
|
|
3510
|
+
process.stderr.write(ui.hint("No LaunchAgent changes were made. Fix the config/dotenv/Identity/Soul/MCP mismatch and retry."));
|
|
3511
|
+
return 1;
|
|
3512
|
+
}
|
|
3513
|
+
}
|
|
3243
3514
|
const deps = defaultBackgroundDeps();
|
|
3244
3515
|
switch (command) {
|
|
3245
3516
|
case "start":
|
|
3246
3517
|
return await startBackground(target, deps);
|
|
3247
3518
|
case "restart":
|
|
3248
|
-
return args.force
|
|
3519
|
+
return args.force
|
|
3520
|
+
? await runForceRestart(target, deps, controllerEnvironment)
|
|
3521
|
+
: await restartBackground(target, deps);
|
|
3249
3522
|
case "stop":
|
|
3250
3523
|
return await stopBackground(target, deps);
|
|
3251
3524
|
case "status":
|
|
@@ -3260,20 +3533,17 @@ async function runBackgroundCommand(args, command, env = process.env) {
|
|
|
3260
3533
|
* they are deleted; the runtime recreates the store on the next session, and the
|
|
3261
3534
|
* agent's durable memory lives elsewhere, so only resumable transcripts are dropped.
|
|
3262
3535
|
*/
|
|
3263
|
-
async function runForceRestart(target, deps) {
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
process.stdout.write(ui.style.dim("No persisted sessions to clear (in-memory or none on disk).") + "\n");
|
|
3275
|
-
}
|
|
3276
|
-
return await startBackground(target, deps);
|
|
3536
|
+
async function runForceRestart(target, deps, environment) {
|
|
3537
|
+
return await forceRestartBackground(target, deps, async () => {
|
|
3538
|
+
const result = await purgeSessions({ env: environment, cwd: target.cwd, configPath: target.configPath });
|
|
3539
|
+
if (result.removed) {
|
|
3540
|
+
const count = result.files === 0 ? "" : ` (${result.files} session file${result.files === 1 ? "" : "s"})`;
|
|
3541
|
+
process.stdout.write(`${ui.badge("ok")}${ui.style.bold("Cleared persisted sessions")}${count}.\n`);
|
|
3542
|
+
}
|
|
3543
|
+
else {
|
|
3544
|
+
process.stdout.write(ui.style.dim("No persisted sessions to clear (in-memory or none on disk).") + "\n");
|
|
3545
|
+
}
|
|
3546
|
+
});
|
|
3277
3547
|
}
|
|
3278
3548
|
/**
|
|
3279
3549
|
* Background service mode is launchd-specific. On other platforms point the
|
|
@@ -3419,8 +3689,16 @@ export function waitForShutdownSignal(app) {
|
|
|
3419
3689
|
clearInterval(keepAlive);
|
|
3420
3690
|
void (async () => {
|
|
3421
3691
|
process.stdout.write("\n" + ui.hint(`Received ${signal}; stopping mono agent app…`));
|
|
3422
|
-
|
|
3423
|
-
|
|
3692
|
+
try {
|
|
3693
|
+
await app.stop();
|
|
3694
|
+
resolve(0);
|
|
3695
|
+
}
|
|
3696
|
+
catch (error) {
|
|
3697
|
+
process.stderr.write(ui.errorLine(`Foreground shutdown failed: ${error instanceof Error ? error.message : String(error)}`));
|
|
3698
|
+
// Resolve so runForeground's finally block can retry idempotent app
|
|
3699
|
+
// cleanup and release the process-lifetime singleton lease.
|
|
3700
|
+
resolve(1);
|
|
3701
|
+
}
|
|
3424
3702
|
})();
|
|
3425
3703
|
};
|
|
3426
3704
|
process.on("SIGINT", onSignal);
|