agent-conveyor 0.1.24 → 0.1.26
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 +32 -15
- package/dist/cli/typescript-runtime.js +120 -12
- package/dist/cli/typescript-runtime.js.map +1 -1
- package/dist/runtime/app-autonomy.d.ts +29 -2
- package/dist/runtime/app-autonomy.js +101 -0
- package/dist/runtime/app-autonomy.js.map +1 -1
- package/package.json +1 -1
- package/plugin/agent-conveyor/plugin.json +1 -1
- package/plugin/agent-conveyor/skills/conveyor-create-pair/SKILL.md +11 -7
- package/plugin/agent-conveyor/skills/conveyor-create-worker-set/SKILL.md +8 -5
- package/plugin/agent-conveyor/skills/conveyor-smoke-app-connections/SKILL.md +71 -46
package/README.md
CHANGED
|
@@ -122,7 +122,10 @@ PATH="$tmp_prefix/bin:$PATH" conveyor --help
|
|
|
122
122
|
PATH="$tmp_prefix/bin:$PATH" workerctl --help
|
|
123
123
|
```
|
|
124
124
|
|
|
125
|
-
`conveyor doctor` reports local dependency health (tmux, codex, etc.)
|
|
125
|
+
`conveyor doctor --json` reports local dependency health (tmux, codex, etc.),
|
|
126
|
+
package/bin resolution, Codex home, installed operator plugin version, installed
|
|
127
|
+
operator skills, and an `operator_ready` summary for Codex app manager/worker
|
|
128
|
+
setup.
|
|
126
129
|
`conveyor db-doctor` initializes and checks the SQLite control-plane
|
|
127
130
|
database.
|
|
128
131
|
On Node versions where `node:sqlite` is still marked experimental, SQLite
|
|
@@ -151,6 +154,13 @@ static landing page. From the repo, `npm run docs:landing` serves it at
|
|
|
151
154
|
`http://127.0.0.1:8765/`.
|
|
152
155
|
The GitHub Pages version lives at
|
|
153
156
|
[`neonwatty.github.io/agent-conveyor`](https://neonwatty.github.io/agent-conveyor/).
|
|
157
|
+
Pages deploys from the protected `landing-page` branch through the
|
|
158
|
+
`Pages` GitHub Actions workflow; propose public landing-page edits against
|
|
159
|
+
that branch rather than relying on ordinary `main` package PRs to publish the
|
|
160
|
+
site.
|
|
161
|
+
Pull requests into `landing-page` run the `Landing Page PR` workflow, which
|
|
162
|
+
checks linting, unused exports/files, tests, build output, the landing-page
|
|
163
|
+
screenshot gate, and a diff-scoped max-lines guard for changed text files.
|
|
154
164
|
Use `node scripts/check-landing-page.mjs` for a docs-only desktop/mobile
|
|
155
165
|
screenshot gate; this does not run the full package release smoke.
|
|
156
166
|
|
|
@@ -163,7 +173,7 @@ and inspect the plugin:
|
|
|
163
173
|
```bash
|
|
164
174
|
npm install -g agent-conveyor
|
|
165
175
|
conveyor install-plugin
|
|
166
|
-
conveyor
|
|
176
|
+
conveyor doctor --json
|
|
167
177
|
```
|
|
168
178
|
|
|
169
179
|
The per-project default ledger for operator sessions is
|
|
@@ -189,15 +199,19 @@ the no-tmux binding with `create-disposable-binding`, point the worker at
|
|
|
189
199
|
that the loop is ready. Pair and worker-set skills run
|
|
190
200
|
`conveyor-smoke-app-connections` before real task work by default. Required
|
|
191
201
|
smoke first checks package/plugin/ledger/thread metadata, then starts a
|
|
192
|
-
nonce-scoped `app-smoke` session and blocks real work until the
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
202
|
+
nonce-scoped `app-smoke` session and blocks real work until the worker has
|
|
203
|
+
accepted smoke and delivered the manager report, then the manager validates
|
|
204
|
+
that report. Both roles need visible app-thread send receipts, fresh app
|
|
205
|
+
heartbeats, durable received/accepted acknowledgements, and an
|
|
206
|
+
`app-smoke status` result with `real_work_allowed=true`. The plain CLI records
|
|
207
|
+
and evaluates receipts; the Codex app skill/operator layer must perform live
|
|
208
|
+
`send_message_to_thread` delivery and record `sent`, `blocked`, or
|
|
209
|
+
skipped/advisory evidence. If a smoke role blocks and later succeeds, the later
|
|
210
|
+
accepted receipt for the same smoke id/nonce becomes the current terminal role
|
|
211
|
+
state. After required smoke passes, pair and worker-set skills start
|
|
212
|
+
`app-autopilot` before real work so the just-proved sessions keep polling. A
|
|
213
|
+
setup is autonomous only when the emitted heartbeat automation specs have been
|
|
214
|
+
applied and recorded with `app-autopilot record-automation`, or explicitly
|
|
201
215
|
deferred as `manual-poll only`; smoke-passed by itself only proves connection
|
|
202
216
|
plumbing at that moment.
|
|
203
217
|
When the manager is itself running in the Codex app and
|
|
@@ -538,16 +552,19 @@ stay out of receipts.
|
|
|
538
552
|
a matching `ready_to_send` action with `send_ready=true` and the same thread
|
|
539
553
|
id; healthy roles must be recorded as `skipped`; missing-thread blockers and
|
|
540
554
|
failed app-thread sends must be recorded as `blocked` with a reason.
|
|
541
|
-
- `app-autopilot start|stop|status TASK [--dispatcher-id ID]
|
|
555
|
+
- `app-autopilot start|stop|status|record-automation TASK [--dispatcher-id ID]
|
|
542
556
|
[--interval SECONDS] [--watch-iterations N] [--stale-after N]
|
|
543
|
-
[--quiet-after N] [--json]` —
|
|
557
|
+
[--quiet-after N] [--role manager|worker --automation-id ID] [--json]` —
|
|
544
558
|
Manage the pair-level app-native heartbeat policy for the active
|
|
545
559
|
manager/worker binding. `start` and `stop` write telemetry receipts and emit
|
|
546
560
|
the exact manager/worker Codex app heartbeat automation specs plus the
|
|
547
561
|
bounded Dispatch watch command. A plain shell CLI cannot call Codex app
|
|
548
562
|
thread tools, so create/pause those heartbeat automations from a Codex app
|
|
549
|
-
operator session using the emitted specs
|
|
550
|
-
|
|
563
|
+
operator session using the emitted specs, then run `record-automation` once
|
|
564
|
+
per created role automation. Conveyor remains the durable source of truth
|
|
565
|
+
through Dispatch, inboxes, automation-applied receipts, wake receipts, and app
|
|
566
|
+
heartbeat status. `status` reports `plan.readiness`; do not call a loop
|
|
567
|
+
autonomous unless `plan.readiness.autonomous_ready=true`.
|
|
551
568
|
`status` also reports `plan.quiescence`: when the loop is healthy, has no
|
|
552
569
|
`next_actions`, and both roles have produced `--quiet-after` paired
|
|
553
570
|
heartbeats since the last command or inbox-consumption receipt, it recommends
|
|
@@ -444,13 +444,14 @@ function commandHelpText(program, command) {
|
|
|
444
444
|
` ${program} dispatch --once --type nudge_worker --path /tmp/work/workerctl.db`,
|
|
445
445
|
],
|
|
446
446
|
"app-autopilot": [
|
|
447
|
-
`usage: ${program} app-autopilot start|stop|status <task> [--dispatcher-id ID] [--interval SECONDS] [--watch-iterations N] [--stale-after N] [--quiet-after N] ${path} [--json]`,
|
|
447
|
+
`usage: ${program} app-autopilot start|stop|status|record-automation <task> [--dispatcher-id ID] [--interval SECONDS] [--watch-iterations N] [--stale-after N] [--quiet-after N] [--role manager|worker --automation-id ID] ${path} [--json]`,
|
|
448
448
|
"",
|
|
449
449
|
"Manage the app-native heartbeat policy for a bound manager/worker pair.",
|
|
450
450
|
"The CLI records policy receipts and emits Codex app heartbeat automation specs; app-thread automation creation still happens through Codex app tools.",
|
|
451
451
|
"",
|
|
452
452
|
"Examples:",
|
|
453
453
|
` ${program} app-autopilot start dogfood --dispatcher-id dispatch-local --path /tmp/work/workerctl.db --json`,
|
|
454
|
+
` ${program} app-autopilot record-automation dogfood --role worker --automation-id conveyor-dogfood-worker-heartbeat --path /tmp/work/workerctl.db --json`,
|
|
454
455
|
` ${program} app-autopilot status dogfood --path /tmp/work/workerctl.db`,
|
|
455
456
|
` ${program} app-autopilot stop dogfood --path /tmp/work/workerctl.db --json`,
|
|
456
457
|
],
|
|
@@ -544,6 +545,7 @@ function parseRuntimeArgs(args, env) {
|
|
|
544
545
|
all: false,
|
|
545
546
|
allowAdditionalReceipt: false,
|
|
546
547
|
action: null,
|
|
548
|
+
automationId: null,
|
|
547
549
|
artifactPath: null,
|
|
548
550
|
assetType: null,
|
|
549
551
|
assignment: null,
|
|
@@ -1128,7 +1130,7 @@ function parseRuntimeArgs(args, env) {
|
|
|
1128
1130
|
index += 1;
|
|
1129
1131
|
}
|
|
1130
1132
|
else if (arg === "--codex-home") {
|
|
1131
|
-
if (command !== "install-skills" && command !== "install-plugin" && command !== "plugin-status" && command !== "plugin-path") {
|
|
1133
|
+
if (command !== "install-skills" && command !== "install-plugin" && command !== "plugin-status" && command !== "plugin-path" && command !== "doctor") {
|
|
1132
1134
|
return { command, enabled, error: "Unsupported TypeScript runtime option: --codex-home", explicit, flags, task };
|
|
1133
1135
|
}
|
|
1134
1136
|
const value = valueAfter(queue, index, arg);
|
|
@@ -1450,6 +1452,17 @@ function parseRuntimeArgs(args, env) {
|
|
|
1450
1452
|
flags.codexProfile = value.value;
|
|
1451
1453
|
index += 1;
|
|
1452
1454
|
}
|
|
1455
|
+
else if (arg === "--automation-id") {
|
|
1456
|
+
if (command !== "app-autopilot") {
|
|
1457
|
+
return { command, enabled, error: "Unsupported TypeScript runtime option: --automation-id", explicit, flags, task };
|
|
1458
|
+
}
|
|
1459
|
+
const value = valueAfter(queue, index, arg);
|
|
1460
|
+
if (value.error) {
|
|
1461
|
+
return { command, enabled, error: value.error, explicit, flags, task };
|
|
1462
|
+
}
|
|
1463
|
+
flags.automationId = value.value;
|
|
1464
|
+
index += 1;
|
|
1465
|
+
}
|
|
1453
1466
|
else if (arg === "--session-dir") {
|
|
1454
1467
|
if (command !== "create-disposable-binding") {
|
|
1455
1468
|
return { command, enabled, error: "Unsupported TypeScript runtime option: --session-dir", explicit, flags, task };
|
|
@@ -3130,7 +3143,7 @@ function parseRuntimeArgs(args, env) {
|
|
|
3130
3143
|
flags.subtype = arg;
|
|
3131
3144
|
}
|
|
3132
3145
|
else if (command === "app-autopilot" && flags.action === null) {
|
|
3133
|
-
if (!["start", "stop", "status"].includes(arg)) {
|
|
3146
|
+
if (!["record-automation", "start", "stop", "status"].includes(arg)) {
|
|
3134
3147
|
return { command, enabled, error: `Unsupported app-autopilot action: ${arg}`, explicit, flags, task };
|
|
3135
3148
|
}
|
|
3136
3149
|
flags.action = arg;
|
|
@@ -4349,8 +4362,8 @@ function renderAppWorkerRotationPlanText(plan) {
|
|
|
4349
4362
|
}
|
|
4350
4363
|
function runAppAutopilotCommand(parsed, options) {
|
|
4351
4364
|
const action = parsed.flags.action;
|
|
4352
|
-
if (action !== "start" && action !== "stop" && action !== "status") {
|
|
4353
|
-
return errorResult("app-autopilot requires an action: start, stop, or
|
|
4365
|
+
if (action !== "record-automation" && action !== "start" && action !== "stop" && action !== "status") {
|
|
4366
|
+
return errorResult("app-autopilot requires an action: start, stop, status, or record-automation");
|
|
4354
4367
|
}
|
|
4355
4368
|
const taskName = requireTask(parsed);
|
|
4356
4369
|
const database = openRuntimeDatabase(parsed, options);
|
|
@@ -4358,7 +4371,39 @@ function runAppAutopilotCommand(parsed, options) {
|
|
|
4358
4371
|
const timestamp = nowIsoSeconds(options);
|
|
4359
4372
|
const dbPath = runtimeDbPath(parsed, options);
|
|
4360
4373
|
const dispatcherId = parsed.flags.dispatcherId ?? "dispatch-local";
|
|
4374
|
+
const task = taskRowForDiagnostics(database, taskName);
|
|
4361
4375
|
const desiredState = action === "start" ? "active" : action === "stop" ? "stopped" : null;
|
|
4376
|
+
let receipt = null;
|
|
4377
|
+
if (action === "record-automation") {
|
|
4378
|
+
const role = parseAppSmokeRole(parsed.flags.role);
|
|
4379
|
+
if (role instanceof Error) {
|
|
4380
|
+
return errorResult(role.message);
|
|
4381
|
+
}
|
|
4382
|
+
const automationId = requiredStringFlag(parsed.flags.automationId, "--automation-id");
|
|
4383
|
+
const eventId = emitTelemetrySync(database, {
|
|
4384
|
+
actor: "operator",
|
|
4385
|
+
attributes: {
|
|
4386
|
+
automation_id: automationId,
|
|
4387
|
+
role,
|
|
4388
|
+
},
|
|
4389
|
+
correlation: {
|
|
4390
|
+
action,
|
|
4391
|
+
command: "app-autopilot",
|
|
4392
|
+
dispatcher_id: dispatcherId,
|
|
4393
|
+
role,
|
|
4394
|
+
},
|
|
4395
|
+
eventType: "app_autopilot_automation_applied",
|
|
4396
|
+
severity: "info",
|
|
4397
|
+
summary: `App autopilot ${role} automation applied for ${task.name}.`,
|
|
4398
|
+
taskId: task.id,
|
|
4399
|
+
timestamp,
|
|
4400
|
+
});
|
|
4401
|
+
receipt = {
|
|
4402
|
+
event_id: eventId,
|
|
4403
|
+
event_type: "app_autopilot_automation_applied",
|
|
4404
|
+
recorded_at: timestamp,
|
|
4405
|
+
};
|
|
4406
|
+
}
|
|
4362
4407
|
let plan = appAutopilotPlanSync(database, {
|
|
4363
4408
|
dbPath,
|
|
4364
4409
|
dispatchIntervalSeconds: parsed.flags.intervalSeconds,
|
|
@@ -4371,12 +4416,12 @@ function runAppAutopilotCommand(parsed, options) {
|
|
|
4371
4416
|
taskName,
|
|
4372
4417
|
watchIterations: parsed.flags.watchIterations ?? 1000000,
|
|
4373
4418
|
});
|
|
4374
|
-
let receipt = null;
|
|
4375
4419
|
if (action === "start" || action === "stop") {
|
|
4376
4420
|
const eventType = action === "start" ? "app_autopilot_started" : "app_autopilot_stopped";
|
|
4377
4421
|
const eventId = emitTelemetrySync(database, {
|
|
4378
4422
|
actor: "operator",
|
|
4379
4423
|
attributes: {
|
|
4424
|
+
automation_state: plan.automation_state,
|
|
4380
4425
|
automation_specs: plan.automation_specs.map((spec) => ({
|
|
4381
4426
|
can_create: spec.can_create,
|
|
4382
4427
|
interval_minutes: spec.interval_minutes,
|
|
@@ -4390,6 +4435,7 @@ function runAppAutopilotCommand(parsed, options) {
|
|
|
4390
4435
|
dispatcher_id: dispatcherId,
|
|
4391
4436
|
interval_minutes: plan.interval_minutes,
|
|
4392
4437
|
quiescence: plan.quiescence,
|
|
4438
|
+
readiness: plan.readiness,
|
|
4393
4439
|
summary: plan.summary,
|
|
4394
4440
|
},
|
|
4395
4441
|
correlation: {
|
|
@@ -4662,8 +4708,10 @@ function appSmokeRoleStatus(role, session, receipts, smoke, options) {
|
|
|
4662
4708
|
const roleReceipts = receipts.filter((receipt) => receipt.role === role && receipt.nonce === smoke.nonce);
|
|
4663
4709
|
const sent = roleReceipts.some((receipt) => receipt.status === "sent");
|
|
4664
4710
|
const received = roleReceipts.some((receipt) => receipt.status === "received");
|
|
4665
|
-
const
|
|
4666
|
-
const
|
|
4711
|
+
const terminalReceipts = roleReceipts.filter((receipt) => receipt.status === "accepted" || receipt.status === "blocked");
|
|
4712
|
+
const terminalReceipt = terminalReceipts.at(-1);
|
|
4713
|
+
const accepted = terminalReceipt?.status === "accepted";
|
|
4714
|
+
const blockedReceipt = terminalReceipt?.status === "blocked" ? terminalReceipt : undefined;
|
|
4667
4715
|
const heartbeatFresh = session.last_heartbeat_at !== null
|
|
4668
4716
|
&& session.last_heartbeat_at >= smoke.recorded_at
|
|
4669
4717
|
&& secondsBetweenIso(session.last_heartbeat_at, options.now) <= options.staleAfterSeconds;
|
|
@@ -4739,14 +4787,18 @@ function latestAppSmokeSessionSync(database, options) {
|
|
|
4739
4787
|
}
|
|
4740
4788
|
function appSmokeReceiptsSync(database, options) {
|
|
4741
4789
|
const rows = database.prepare(`
|
|
4742
|
-
select attributes_json
|
|
4790
|
+
select id, timestamp, attributes_json
|
|
4743
4791
|
from telemetry_events
|
|
4744
4792
|
where task_id = ?
|
|
4745
4793
|
and event_type = 'app_smoke_receipt_recorded'
|
|
4746
4794
|
and json_extract(attributes_json, '$.smoke_id') = ?
|
|
4747
4795
|
order by timestamp, id
|
|
4748
4796
|
`).all(options.taskId, options.smokeId);
|
|
4749
|
-
return rows.map((row) =>
|
|
4797
|
+
return rows.map((row) => ({
|
|
4798
|
+
...JSON.parse(row.attributes_json),
|
|
4799
|
+
event_id: row.id,
|
|
4800
|
+
recorded_at: row.timestamp,
|
|
4801
|
+
}));
|
|
4750
4802
|
}
|
|
4751
4803
|
function appSmokeBoundSessionsSync(database, taskId) {
|
|
4752
4804
|
const row = database.prepare(`
|
|
@@ -4952,6 +5004,7 @@ function renderAppWakeupPlanText(plan) {
|
|
|
4952
5004
|
function renderAppAutopilotText(result) {
|
|
4953
5005
|
const lines = [
|
|
4954
5006
|
`App autopilot ${result.action} for ${result.plan.task.name}: ${result.plan.desired_state}`,
|
|
5007
|
+
`Readiness: ${result.plan.readiness.state}${result.plan.readiness.autonomous_ready ? " (autonomous)" : " (setup required)"}`,
|
|
4955
5008
|
`Loop status: ${result.plan.status.ok ? "ok" : "attention required"}`,
|
|
4956
5009
|
`Dispatch: ${result.plan.dispatcher.state}${result.plan.dispatcher.required ? " required" : ""}`,
|
|
4957
5010
|
`Dispatch command: ${result.plan.control.dispatcher_command}`,
|
|
@@ -4973,12 +5026,19 @@ function renderAppAutopilotText(result) {
|
|
|
4973
5026
|
else {
|
|
4974
5027
|
lines.push("Last policy: unconfigured");
|
|
4975
5028
|
}
|
|
5029
|
+
for (const blocker of result.plan.readiness.blockers) {
|
|
5030
|
+
lines.push(`Readiness blocker: ${blocker}`);
|
|
5031
|
+
}
|
|
4976
5032
|
for (const spec of result.plan.automation_specs) {
|
|
4977
5033
|
lines.push(`${spec.role} automation: ${spec.can_create ? "ready" : "blocked"} ${spec.name}`, ` thread: ${spec.target_thread_title ?? "(untitled)"} ${spec.target_thread_id ?? "(missing)"}`, ` schedule: ${spec.rrule}`);
|
|
4978
5034
|
if (spec.blocker) {
|
|
4979
5035
|
lines.push(` blocker: ${spec.blocker}`);
|
|
4980
5036
|
}
|
|
4981
5037
|
}
|
|
5038
|
+
for (const role of result.plan.automation_state.applied_roles) {
|
|
5039
|
+
const receipt = result.plan.automation_state.receipts.find((item) => item.role === role);
|
|
5040
|
+
lines.push(`${role} automation applied: ${receipt?.automation_id ?? "(unknown)"}`);
|
|
5041
|
+
}
|
|
4982
5042
|
lines.push(result.plan.control.note);
|
|
4983
5043
|
return `${lines.join("\n")}\n`;
|
|
4984
5044
|
}
|
|
@@ -11892,9 +11952,20 @@ function runDoctorCommand(parsed, options) {
|
|
|
11892
11952
|
const root = stateRoot({ cwd: targetCwd, env: options.env });
|
|
11893
11953
|
const tmuxPath = commandPath("tmux", options);
|
|
11894
11954
|
const codexPath = options.codexCommandResolver?.("codex") ?? commandPath("codex", options);
|
|
11955
|
+
const conveyorPath = commandPath("conveyor", options);
|
|
11956
|
+
const workerctlPath = commandPath("workerctl", options);
|
|
11957
|
+
const packageRoot = packageRootFromRuntimeModule();
|
|
11958
|
+
const packageVersion = packageVersionFromRoot(packageRoot);
|
|
11959
|
+
const plugin = agentConveyorPluginStatus(parsed, options);
|
|
11960
|
+
const pluginSkillsInstalled = plugin.skills.every((skill) => skill.installed);
|
|
11895
11961
|
const checks = [
|
|
11896
11962
|
{ name: "tmux", ok: Boolean(tmuxPath), path: tmuxPath },
|
|
11897
11963
|
{ name: "codex", ok: Boolean(codexPath), path: codexPath },
|
|
11964
|
+
{ name: "conveyor_on_path", ok: Boolean(conveyorPath), path: conveyorPath },
|
|
11965
|
+
{ name: "workerctl_on_path", ok: Boolean(workerctlPath), path: workerctlPath },
|
|
11966
|
+
{ name: "plugin_installed", ok: plugin.installed, installed_version: plugin.installed_version },
|
|
11967
|
+
{ name: "plugin_version_matches", ok: plugin.version_matches, package_version: packageVersion, plugin_version: plugin.plugin_version },
|
|
11968
|
+
{ name: "plugin_skills_installed", ok: pluginSkillsInstalled, missing: plugin.skills.filter((skill) => !skill.installed).map((skill) => skill.name) },
|
|
11898
11969
|
];
|
|
11899
11970
|
if (tmuxPath) {
|
|
11900
11971
|
const proc = runProcess(["tmux", "-V"], options);
|
|
@@ -11906,8 +11977,44 @@ function runDoctorCommand(parsed, options) {
|
|
|
11906
11977
|
}
|
|
11907
11978
|
checks.push({ name: "target_cwd_exists", ok: pathIsDirectory(targetCwd), path: targetCwd });
|
|
11908
11979
|
checks.push({ name: "state_root_exists", ok: existsSync(root), path: root });
|
|
11909
|
-
const
|
|
11910
|
-
|
|
11980
|
+
const commandReady = Boolean(conveyorPath) && Boolean(workerctlPath) && Boolean(codexPath) && Boolean(tmuxPath);
|
|
11981
|
+
const operatorReady = commandReady && plugin.installed && plugin.version_matches && pluginSkillsInstalled;
|
|
11982
|
+
const ok = checks.every((check) => check.name === "state_root_exists"
|
|
11983
|
+
|| check.name === "conveyor_on_path"
|
|
11984
|
+
|| check.name === "workerctl_on_path"
|
|
11985
|
+
|| check.name === "plugin_installed"
|
|
11986
|
+
|| check.name === "plugin_version_matches"
|
|
11987
|
+
|| check.name === "plugin_skills_installed"
|
|
11988
|
+
|| check.ok === true);
|
|
11989
|
+
return {
|
|
11990
|
+
...jsonResult({
|
|
11991
|
+
checks,
|
|
11992
|
+
codex_home: plugin.paths.codex_home,
|
|
11993
|
+
commands: {
|
|
11994
|
+
codex: { ok: Boolean(codexPath), path: codexPath },
|
|
11995
|
+
conveyor: { ok: Boolean(conveyorPath), path: conveyorPath },
|
|
11996
|
+
tmux: { ok: Boolean(tmuxPath), path: tmuxPath },
|
|
11997
|
+
workerctl: { ok: Boolean(workerctlPath), path: workerctlPath },
|
|
11998
|
+
},
|
|
11999
|
+
ok,
|
|
12000
|
+
operator_ready: operatorReady,
|
|
12001
|
+
package: {
|
|
12002
|
+
name: "agent-conveyor",
|
|
12003
|
+
root: packageRoot,
|
|
12004
|
+
version: packageVersion,
|
|
12005
|
+
},
|
|
12006
|
+
platform: process.platform,
|
|
12007
|
+
plugin,
|
|
12008
|
+
project_root: packageRoot,
|
|
12009
|
+
runtime: {
|
|
12010
|
+
node: process.version,
|
|
12011
|
+
state_root: root,
|
|
12012
|
+
target_cwd: targetCwd,
|
|
12013
|
+
},
|
|
12014
|
+
workers: doctorWorkerSummaries(root),
|
|
12015
|
+
}),
|
|
12016
|
+
exitCode: ok ? 0 : 1,
|
|
12017
|
+
};
|
|
11911
12018
|
}
|
|
11912
12019
|
function runDoctorSelfCommand(parsed, options) {
|
|
11913
12020
|
if (parsed.task !== null) {
|
|
@@ -18966,6 +19073,7 @@ function telemetryEventsForRunSync(database, options) {
|
|
|
18966
19073
|
}
|
|
18967
19074
|
function appTaskDispatchSummarySync(database, options) {
|
|
18968
19075
|
const taskDispatchEventTypes = [
|
|
19076
|
+
"app_autopilot_automation_applied",
|
|
18969
19077
|
"app_autopilot_started",
|
|
18970
19078
|
"app_autopilot_stopped",
|
|
18971
19079
|
"app_heartbeat",
|