@songsid/agend 2.3.0-beta.22 → 2.3.0-beta.24
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 +2 -2
- package/README.zh-TW.md +2 -2
- package/dist/agent-cli.js +4 -2
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-endpoint.d.ts +1 -0
- package/dist/agent-endpoint.js +4 -0
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/agent-whats-new.d.ts +5 -0
- package/dist/agent-whats-new.js +16 -1
- package/dist/agent-whats-new.js.map +1 -1
- package/dist/auth-api.d.ts +7 -0
- package/dist/auth-api.js +54 -21
- package/dist/auth-api.js.map +1 -1
- package/dist/backend/codex-package.d.ts +30 -0
- package/dist/backend/codex-package.js +133 -0
- package/dist/backend/codex-package.js.map +1 -0
- package/dist/backend/codex.d.ts +2 -0
- package/dist/backend/codex.js +9 -2
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/grok.js +3 -1
- package/dist/backend/grok.js.map +1 -1
- package/dist/backend/kiro.d.ts +9 -1
- package/dist/backend/kiro.js +102 -1
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/opencode-permission.js +1 -1
- package/dist/backend/opencode-permission.js.map +1 -1
- package/dist/backend/opencode.js +2 -1
- package/dist/backend/opencode.js.map +1 -1
- package/dist/binary-probe.js +1 -1
- package/dist/bug-report-cli.js +11 -10
- package/dist/bug-report-cli.js.map +1 -1
- package/dist/bug-report.js +11 -10
- package/dist/bug-report.js.map +1 -1
- package/dist/bundled-skills.d.ts +7 -3
- package/dist/bundled-skills.js +16 -7
- package/dist/bundled-skills.js.map +1 -1
- package/dist/channel/adapters/discord.js +3 -3
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/mcp-server.js +12 -4
- package/dist/channel/mcp-server.js.map +1 -1
- package/dist/channel/mcp-tools.d.ts +3 -1
- package/dist/channel/mcp-tools.js +36 -0
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/child-process.d.ts +21 -0
- package/dist/child-process.js +54 -0
- package/dist/child-process.js.map +1 -0
- package/dist/cli.js +188 -204
- package/dist/cli.js.map +1 -1
- package/dist/command-table.d.ts +1 -1
- package/dist/command-table.js +1 -1
- package/dist/command-table.js.map +1 -1
- package/dist/config-validator.js +20 -1
- package/dist/config-validator.js.map +1 -1
- package/dist/config.js +3 -1
- package/dist/config.js.map +1 -1
- package/dist/daemon.d.ts +8 -0
- package/dist/daemon.js +31 -8
- package/dist/daemon.js.map +1 -1
- package/dist/darwin-memory.js +1 -1
- package/dist/doctor.d.ts +5 -0
- package/dist/doctor.js +42 -0
- package/dist/doctor.js.map +1 -1
- package/dist/export-import.js +4 -3
- package/dist/export-import.js.map +1 -1
- package/dist/fleet-level-config.d.ts +1 -1
- package/dist/fleet-level-config.js +2 -0
- package/dist/fleet-level-config.js.map +1 -1
- package/dist/fleet-manager.d.ts +45 -0
- package/dist/fleet-manager.js +324 -36
- package/dist/fleet-manager.js.map +1 -1
- package/dist/full-restart.d.ts +5 -5
- package/dist/full-restart.js +5 -5
- package/dist/full-restart.js.map +1 -1
- package/dist/general-knowledge/skills/credential-profiles/SKILL.md +48 -10
- package/dist/general-knowledge/skills/fleet-config/SKILL.md +1 -1
- package/dist/general-knowledge/skills/fleet-restart/SKILL.md +7 -8
- package/dist/general-knowledge/skills/multi-channel/SKILL.md +1 -1
- package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +319 -0
- package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +529 -0
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +17 -4
- package/dist/general-knowledge/steering/core-rules.md +1 -1
- package/dist/instance-config-impact.js +10 -3
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.js +4 -4
- package/dist/locale.js +296 -4
- package/dist/locale.js.map +1 -1
- package/dist/login-flows.js +1 -1
- package/dist/login-shell.js +3 -1
- package/dist/login-shell.js.map +1 -1
- package/dist/ls-rows.js +1 -1
- package/dist/needs-you-hub.d.ts +98 -1
- package/dist/needs-you-hub.js +313 -44
- package/dist/needs-you-hub.js.map +1 -1
- package/dist/needs-you-live.d.ts +5 -2
- package/dist/needs-you-live.js +6 -3
- package/dist/needs-you-live.js.map +1 -1
- package/dist/needs-you.d.ts +58 -3
- package/dist/needs-you.js +36 -3
- package/dist/needs-you.js.map +1 -1
- package/dist/outbound-schemas.d.ts +3 -3
- package/dist/public-link-progress.d.ts +12 -1
- package/dist/public-link-progress.js +5 -10
- package/dist/public-link-progress.js.map +1 -1
- package/dist/public-tunnel-config.d.ts +5 -0
- package/dist/public-tunnel-config.js +45 -1
- package/dist/public-tunnel-config.js.map +1 -1
- package/dist/public-web-link.js +6 -5
- package/dist/public-web-link.js.map +1 -1
- package/dist/quickstart.js +15 -9
- package/dist/quickstart.js.map +1 -1
- package/dist/resource-report.js +1 -1
- package/dist/scheduler/task-board.d.ts +41 -1
- package/dist/scheduler/task-board.js +152 -5
- package/dist/scheduler/task-board.js.map +1 -1
- package/dist/sd-notify.js +2 -1
- package/dist/sd-notify.js.map +1 -1
- package/dist/service-installer.d.ts +69 -0
- package/dist/service-installer.js +182 -0
- package/dist/service-installer.js.map +1 -1
- package/dist/service-owner.d.ts +44 -0
- package/dist/service-owner.js +48 -0
- package/dist/service-owner.js.map +1 -0
- package/dist/service-plan.d.ts +8 -0
- package/dist/service-plan.js +13 -0
- package/dist/service-plan.js.map +1 -1
- package/dist/settings-api.d.ts +4 -0
- package/dist/settings-api.js +21 -3
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-change.js +88 -4
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-confirmation.d.ts +2 -0
- package/dist/settings-confirmation.js +14 -8
- package/dist/settings-confirmation.js.map +1 -1
- package/dist/settings-control.js +2 -1
- package/dist/settings-control.js.map +1 -1
- package/dist/settings-effect.js +2 -0
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-http-confirmation.d.ts +2 -0
- package/dist/settings-http-confirmation.js +3 -2
- package/dist/settings-http-confirmation.js.map +1 -1
- package/dist/settings-request-capability.d.ts +4 -1
- package/dist/settings-request-capability.js +11 -3
- package/dist/settings-request-capability.js.map +1 -1
- package/dist/setup-auth.d.ts +1 -0
- package/dist/setup-auth.js +2 -1
- package/dist/setup-auth.js.map +1 -1
- package/dist/setup-host.d.ts +1 -0
- package/dist/setup-host.js +7 -3
- package/dist/setup-host.js.map +1 -1
- package/dist/setup-wizard.js +1 -1
- package/dist/setup-wizard.js.map +1 -1
- package/dist/task-board-summary.d.ts +101 -0
- package/dist/task-board-summary.js +177 -0
- package/dist/task-board-summary.js.map +1 -0
- package/dist/task-board-waker.d.ts +8 -1
- package/dist/task-board-waker.js +15 -6
- package/dist/task-board-waker.js.map +1 -1
- package/dist/tmux-control.js +1 -1
- package/dist/tmux-control.js.map +1 -1
- package/dist/tmux-exec-helper.d.ts +13 -3
- package/dist/tmux-exec-helper.js +34 -29
- package/dist/tmux-exec-helper.js.map +1 -1
- package/dist/tmux-manager.js +1 -1
- package/dist/tmux-read.js +1 -1
- package/dist/tmux-read.js.map +1 -1
- package/dist/topic-commands.d.ts +3 -0
- package/dist/topic-commands.js +29 -18
- package/dist/topic-commands.js.map +1 -1
- package/dist/transcript-monitor.js +5 -0
- package/dist/transcript-monitor.js.map +1 -1
- package/dist/transcript-sources.d.ts +2 -0
- package/dist/transcript-sources.js +4 -0
- package/dist/transcript-sources.js.map +1 -1
- package/dist/tunnel/cloudflared-install.js +3 -1
- package/dist/tunnel/cloudflared-install.js.map +1 -1
- package/dist/tunnel/cloudflared.d.ts +1 -1
- package/dist/tunnel/cloudflared.js +51 -10
- package/dist/tunnel/cloudflared.js.map +1 -1
- package/dist/tunnel/named-diagnostics.d.ts +13 -0
- package/dist/tunnel/named-diagnostics.js +52 -0
- package/dist/tunnel/named-diagnostics.js.map +1 -0
- package/dist/tunnel/types.d.ts +2 -1
- package/dist/tunnel/types.js.map +1 -1
- package/dist/types.d.ts +9 -0
- package/dist/ui/app-effects.js +10 -4
- package/dist/ui/chat-strings.js +3 -0
- package/dist/ui/chat-thread.js +14 -7
- package/dist/ui/effect-trial-offer.js +2 -31
- package/dist/ui/effects-waker.js +2 -70
- package/dist/ui/fleet-task-card.js +5 -5
- package/dist/ui/fleet-task-common.js +43 -9
- package/dist/ui/fleet-task-work.js +107 -0
- package/dist/ui/fleet-tasks.js +46 -12
- package/dist/ui/image-lightbox.js +39 -1
- package/dist/ui/image-zoom.js +242 -0
- package/dist/ui/panel-chat.js +24 -13
- package/dist/ui/panel-details.js +2 -0
- package/dist/ui/panel-fleet.js +6 -2
- package/dist/ui/panel-needs.js +21 -6
- package/dist/ui/panel-settings.js +35 -13
- package/dist/ui/preview-panel.js +2 -1
- package/dist/ui/search-dialog.js +2 -1
- package/dist/ui/settings-appearance.js +44 -10
- package/dist/ui/settings-dialogs.js +33 -17
- package/dist/ui/settings-discord.js +6 -2
- package/dist/ui/settings-guests.js +2 -1
- package/dist/ui/settings-model.js +2 -11
- package/dist/ui/settings-mods.js +8 -3
- package/dist/ui/settings-strings.js +32 -0
- package/dist/ui/settings-token.js +3 -1
- package/dist/ui/settings-web-authority.js +6 -3
- package/dist/ui/settings-wizard.js +13 -7
- package/dist/ui/shared/app-i18n.js +2 -2
- package/dist/ui/shared/app-needs.js +2 -2
- package/dist/ui/shared/app-store.js +2 -2
- package/dist/ui/shared/app.css +93 -32
- package/dist/ui/shared/app.js +5 -1
- package/dist/ui/shared/effect-app-runtime.js +7 -5
- package/dist/ui/shared/effect-chat-runtime.js +2 -7
- package/dist/ui/shared/effect-cursor.js +3 -2
- package/dist/ui/shared/effect-display-metadata.js +39 -0
- package/dist/ui/shared/effect-registry.js +4 -2
- package/dist/ui/shared/effect-runtime-loader.js +3 -1
- package/dist/ui/shared/effect-stock-trust.js +5 -5
- package/dist/ui/shared/feature-flags.js +127 -0
- package/dist/ui/shared/identity-color.js +6 -3
- package/dist/ui/shared/instance-nav.js +3 -2
- package/dist/ui/shared/panel-view.js +14 -29
- package/dist/ui/shared/text-undo.js +210 -0
- package/dist/ui/shared/ui-dialog.js +4 -3
- package/dist/ui/shared/ui-icons.js +2 -0
- package/dist/ui/shared/usage-dialog.js +29 -8
- package/dist/ui/shared/view-strings.js +2 -4
- package/dist/ui/web-terminal/terminal.html +10 -10
- package/dist/ui/web-terminal/terminal.js +58 -12
- package/dist/update-dispatch.js +1 -1
- package/dist/update-launch.d.ts +1 -1
- package/dist/update-launch.js +1 -2
- package/dist/update-launch.js.map +1 -1
- package/dist/update-preflight.js +1 -1
- package/dist/usage/providers.js +1 -1
- package/dist/usage/providers.js.map +1 -1
- package/dist/view-api.js +1 -1
- package/dist/web-api.d.ts +6 -0
- package/dist/web-api.js +163 -21
- package/dist/web-api.js.map +1 -1
- package/dist/web-app-icon-worker.js +2 -1
- package/dist/web-app-icon-worker.js.map +1 -1
- package/dist/web-app-icon.d.ts +10 -8
- package/dist/web-app-icon.js +14 -13
- package/dist/web-app-icon.js.map +1 -1
- package/dist/web-appearance-tools.d.ts +1 -0
- package/dist/web-appearance-tools.js +7 -3
- package/dist/web-appearance-tools.js.map +1 -1
- package/dist/web-appearance.d.ts +4 -10
- package/dist/web-appearance.js +4 -3
- package/dist/web-appearance.js.map +1 -1
- package/dist/web-auth.d.ts +8 -4
- package/dist/web-auth.js +28 -17
- package/dist/web-auth.js.map +1 -1
- package/dist/web-chat-history.d.ts +14 -0
- package/dist/web-chat-history.js +26 -1
- package/dist/web-chat-history.js.map +1 -1
- package/dist/web-cookie-names.d.ts +5 -0
- package/dist/web-cookie-names.js +12 -0
- package/dist/web-cookie-names.js.map +1 -0
- package/dist/web-experimental-http.d.ts +2 -0
- package/dist/web-experimental-http.js +12 -0
- package/dist/web-experimental-http.js.map +1 -0
- package/dist/web-experimental.d.ts +11 -0
- package/dist/web-experimental.js +49 -0
- package/dist/web-experimental.js.map +1 -0
- package/dist/web-guest-access.d.ts +1 -0
- package/dist/web-guest-access.js +4 -2
- package/dist/web-guest-access.js.map +1 -1
- package/dist/web-mod-store.d.ts +2 -0
- package/dist/web-mod-store.js +10 -0
- package/dist/web-mod-store.js.map +1 -1
- package/dist/web-png.d.ts +4 -0
- package/dist/web-png.js +10 -2
- package/dist/web-png.js.map +1 -1
- package/dist/web-preview.d.ts +2 -0
- package/dist/web-preview.js +2 -0
- package/dist/web-preview.js.map +1 -1
- package/dist/web-returning-device.d.ts +4 -2
- package/dist/web-returning-device.js +12 -5
- package/dist/web-returning-device.js.map +1 -1
- package/dist/web-settings-patch.d.ts +2 -1
- package/dist/web-settings-patch.js +5 -1
- package/dist/web-settings-patch.js.map +1 -1
- package/dist/web-settings-tools.d.ts +1 -0
- package/dist/web-settings-tools.js +14 -10
- package/dist/web-settings-tools.js.map +1 -1
- package/dist/web-terminal.js +1 -1
- package/dist/web-theme-store.d.ts +2 -2
- package/dist/web-theme-store.js +6 -3
- package/dist/web-theme-store.js.map +1 -1
- package/package.json +11 -11
package/dist/cli.js
CHANGED
|
@@ -13,7 +13,7 @@ applyNetworkReliabilityDefaults();
|
|
|
13
13
|
// never restarts into a binary that would crash at the first native DB open.
|
|
14
14
|
import { checkNodeVersion } from "./node-version-guard.js";
|
|
15
15
|
checkNodeVersion();
|
|
16
|
-
import { Command } from "commander";
|
|
16
|
+
import { Command, Option } from "commander";
|
|
17
17
|
import { registerBugReportCommand } from "./bug-report-cli.js";
|
|
18
18
|
import { join, dirname } from "node:path";
|
|
19
19
|
import { SchedulerDb } from "./scheduler/db.js";
|
|
@@ -21,7 +21,8 @@ import { Cron } from "croner";
|
|
|
21
21
|
import { existsSync, readFileSync, writeFileSync, appendFileSync, unlinkSync, mkdirSync, chmodSync, readdirSync, rmSync, statSync, realpathSync, openSync, writeSync, closeSync, } from "node:fs";
|
|
22
22
|
import { homedir, totalmem, freemem, userInfo } from "node:os";
|
|
23
23
|
import { fileURLToPath } from "node:url";
|
|
24
|
-
import {
|
|
24
|
+
import { spawnSync, execSync, execFileSync } from "node:child_process";
|
|
25
|
+
import { spawn } from "./child-process.js";
|
|
25
26
|
import { getAgendHome, getTmuxSocketName, isDefaultAgendHome } from "./paths.js";
|
|
26
27
|
import { hasPausedMarker } from "./pause-marker.js";
|
|
27
28
|
import { COMPLETION_SHELLS, completionScript } from "./completion.js";
|
|
@@ -31,15 +32,17 @@ import { describeSignalSource, forceAllowed, gateFleetControl, recordInstanceCon
|
|
|
31
32
|
import { FLEET_STOP_TIMEOUT_MS, stopDetachedOwner, systemdStopTimeoutMs, detachedProcessStart, detachedProcessExited } from "./fleet-stop-budget.js";
|
|
32
33
|
import { acquireFleetLock, isFleetStartCommandLine, readProcessCommandLine, releaseProcessFleetLock, setProcessFleetLock } from "./fleet-lock.js";
|
|
33
34
|
import { limitFleetCoreDumps } from "./coredump-filter.js";
|
|
34
|
-
import { SYSTEMD_RESTART_TIMEOUT_MS } from "./service-installer.js";
|
|
35
|
+
import { SYSTEMD_RESTART_TIMEOUT_MS, getServicePath, getSystemServicePath } from "./service-installer.js";
|
|
35
36
|
import { selectSystemdRestartTarget, SYSTEMD_RESTART_INDETERMINATE_EXIT_CODE, } from "./service-restart-selection.js";
|
|
36
37
|
import { loadRawFleetConfig } from "./config.js";
|
|
37
|
-
import { setLocale, t } from "./locale.js";
|
|
38
|
+
import { detectLocale, setLocale, t } from "./locale.js";
|
|
39
|
+
import { settingsSourceLabel } from "./settings-confirmation.js";
|
|
38
40
|
import { DeliveryOutbox, deliveryStatusSelector } from "./delivery-outbox.js";
|
|
39
41
|
import { DeliveryStatusArgs } from "./outbound-schemas.js";
|
|
40
42
|
import { requestCpuProfile } from "./profile-control.js";
|
|
41
43
|
import { requestSettingsConfirmation } from "./settings-control.js";
|
|
42
44
|
import { canonicalCliEntry, selfCommand } from "./cli-entry.js";
|
|
45
|
+
import { DIRECT_FLEET_START_ENV, redirectsToService, startedByServiceManager } from "./service-owner.js";
|
|
43
46
|
import { handOff, shouldHandOff } from "./launchd-handoff.js";
|
|
44
47
|
/** Prefix tmux args with -L when socket isolation is active. */
|
|
45
48
|
function tmuxArgs(args) {
|
|
@@ -105,14 +108,15 @@ async function handOffLaunchdActivation(action) {
|
|
|
105
108
|
return false;
|
|
106
109
|
}
|
|
107
110
|
const FLEET_CONFIG_PATH = join(DATA_DIR, "fleet.yaml");
|
|
108
|
-
// CLI commands run outside FleetManager
|
|
109
|
-
//
|
|
111
|
+
// CLI commands run outside FleetManager, in the fleet's language as the fleet decides it (#2390 follow-up): an explicit
|
|
112
|
+
// defaults.locale, else the host's zone (UTC+8 → zh-TW), else English. A line another program reads (the updater, the
|
|
113
|
+
// Windows installer and shortcuts, the rehearsal scripts) is never a locale string: tests/cli-machine-lines-2390 pins them.
|
|
114
|
+
let configForLocale;
|
|
110
115
|
try {
|
|
111
|
-
|
|
112
|
-
if (configuredLocale === "en" || configuredLocale === "zh-TW")
|
|
113
|
-
setLocale(configuredLocale);
|
|
116
|
+
configForLocale = loadRawFleetConfig(FLEET_CONFIG_PATH);
|
|
114
117
|
}
|
|
115
|
-
catch { /* malformed or missing config:
|
|
118
|
+
catch { /* malformed or missing config: the zone decides */ }
|
|
119
|
+
setLocale(detectLocale(configForLocale));
|
|
116
120
|
const program = new Command();
|
|
117
121
|
function claimFleetSingleton() {
|
|
118
122
|
try {
|
|
@@ -165,15 +169,15 @@ settingsCommand.command("confirm <id>").option("--yes", "Explicit noninteractive
|
|
|
165
169
|
.action(async (id, options) => {
|
|
166
170
|
try {
|
|
167
171
|
const inspected = await requestSettingsConfirmation(DATA_DIR, { action: "inspect", id });
|
|
168
|
-
console.log(
|
|
172
|
+
console.log([t("settings_confirm.source", settingsSourceLabel(inspected.pending_change.source)), t("settings_confirm.requester", inspected.pending_change.requested_by), ...inspected.pending_change.summary].join("\n"));
|
|
169
173
|
let confirmed = options.yes === true;
|
|
170
174
|
if (!confirmed) {
|
|
171
175
|
if (!process.stdin.isTTY)
|
|
172
|
-
throw new Error("
|
|
176
|
+
throw new Error(t("settings_confirm.cli_interactive"));
|
|
173
177
|
const { createInterface } = await import("node:readline/promises");
|
|
174
178
|
const input = createInterface({ input: process.stdin, output: process.stdout });
|
|
175
179
|
try {
|
|
176
|
-
confirmed = (await input.question("
|
|
180
|
+
confirmed = (await input.question(t("settings_confirm.cli_question"))).trim().toLowerCase() === "y";
|
|
177
181
|
}
|
|
178
182
|
finally {
|
|
179
183
|
input.close();
|
|
@@ -189,10 +193,10 @@ settingsCommand.command("confirm <id>").option("--yes", "Explicit noninteractive
|
|
|
189
193
|
process.exitCode = 1;
|
|
190
194
|
}
|
|
191
195
|
});
|
|
192
|
-
settingsCommand.command("reject <id>").action(async (id) => {
|
|
196
|
+
settingsCommand.command("reject <id>").description("Reject a pending Settings change on this host").action(async (id) => {
|
|
193
197
|
try {
|
|
194
198
|
const inspected = await requestSettingsConfirmation(DATA_DIR, { action: "inspect", id });
|
|
195
|
-
console.log(
|
|
199
|
+
console.log([t("settings_confirm.source", settingsSourceLabel(inspected.pending_change.source)), t("settings_confirm.requester", inspected.pending_change.requested_by), ...inspected.pending_change.summary].join("\n"));
|
|
196
200
|
const result = await requestSettingsConfirmation(DATA_DIR, { action: "reject", ticket: inspected.ticket });
|
|
197
201
|
console.log(result.pending_change.outcome?.message ?? result.pending_change.state);
|
|
198
202
|
}
|
|
@@ -218,12 +222,24 @@ fleet
|
|
|
218
222
|
.command("start")
|
|
219
223
|
.description("Start fleet or specific instance")
|
|
220
224
|
.argument("[instance]", "Specific instance to start")
|
|
221
|
-
.
|
|
225
|
+
.option("--direct", "Start here even though an AgEnD service is installed (operators only: the service cannot run on this host)")
|
|
226
|
+
.action(async (instance, opts) => {
|
|
222
227
|
// Root running fleet = sandbox environment (e.g. Docker, WSL root service)
|
|
223
228
|
// Set IS_SANDBOX so child processes (claude-code) don't refuse to run
|
|
224
229
|
if (process.getuid?.() === 0 && !process.env.IS_SANDBOX) {
|
|
225
230
|
process.env.IS_SANDBOX = "1";
|
|
226
231
|
}
|
|
232
|
+
const marked = process.env[DIRECT_FLEET_START_ENV] === "1";
|
|
233
|
+
delete process.env[DIRECT_FLEET_START_ENV];
|
|
234
|
+
// #2356: the way out when the installed service cannot run here (never activated, no GUI session for launchd) — an
|
|
235
|
+
// operator's own decision, as `restart --force` is; the fleet's singleton lock still refuses a second fleet.
|
|
236
|
+
if (opts?.direct && !forceAllowed()) {
|
|
237
|
+
console.error(t("cli.direct_refused"));
|
|
238
|
+
process.exit(1);
|
|
239
|
+
}
|
|
240
|
+
const direct = marked || !!opts?.direct;
|
|
241
|
+
if (!instance && redirectToService("start", [], direct))
|
|
242
|
+
return;
|
|
227
243
|
if (instance) {
|
|
228
244
|
// If fleet daemon is already running, delegate via HTTP API
|
|
229
245
|
const { loadFleetConfig } = await import("./config.js");
|
|
@@ -318,6 +334,8 @@ fleet
|
|
|
318
334
|
.argument("[instance]", "Specific instance to stop")
|
|
319
335
|
.option("-y, --yes", "Confirm when run from a fleet agent session (this affects every instance)")
|
|
320
336
|
.action(async (instance, opts) => {
|
|
337
|
+
if (!instance && redirectToService("stop", opts?.yes ? ["--yes"] : [], false))
|
|
338
|
+
return;
|
|
321
339
|
if (instance)
|
|
322
340
|
recordInstanceControl(DATA_DIR, "instance-stop", instance);
|
|
323
341
|
else if (!gateFleetControl(DATA_DIR, "fleet-stop", { yes: opts?.yes }))
|
|
@@ -351,7 +369,7 @@ fleet
|
|
|
351
369
|
}
|
|
352
370
|
}
|
|
353
371
|
catch {
|
|
354
|
-
console.error(
|
|
372
|
+
console.error(t("cli.fleet_unreachable", port));
|
|
355
373
|
process.exit(1);
|
|
356
374
|
}
|
|
357
375
|
return;
|
|
@@ -392,159 +410,37 @@ fleet
|
|
|
392
410
|
});
|
|
393
411
|
fleet
|
|
394
412
|
.command("restart")
|
|
395
|
-
.description("
|
|
396
|
-
.argument("[instance]", "
|
|
397
|
-
.option("--reload", "
|
|
413
|
+
.description("Deprecated: runs `agend restart` (removed in 2.4)")
|
|
414
|
+
.argument("[instance]", "Restart only this instance (now `agend restart <instance>`)")
|
|
415
|
+
.option("--reload", "Ignored: every full restart is `agend restart`")
|
|
398
416
|
.option("-y, --yes", "Confirm when run from a fleet agent session (this affects every instance)")
|
|
399
|
-
.action(
|
|
417
|
+
.action((instance, opts) => {
|
|
400
418
|
if (instance && opts?.reload) {
|
|
401
419
|
console.error("--reload restarts the entire fleet process. Cannot combine with instance name.");
|
|
402
420
|
process.exit(1);
|
|
403
421
|
}
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
const port = fleet.health_port ?? 19280;
|
|
413
|
-
let token = "";
|
|
414
|
-
try {
|
|
415
|
-
token = readFileSync(join(DATA_DIR, "web.token"), "utf-8").trim();
|
|
416
|
-
}
|
|
417
|
-
catch { /* fleet may not be running */ }
|
|
418
|
-
try {
|
|
419
|
-
const resp = await fetch(`http://127.0.0.1:${port}/restart/${encodeURIComponent(instance)}`, {
|
|
420
|
-
method: "POST",
|
|
421
|
-
headers: token ? { "X-Agend-Token": token } : {},
|
|
422
|
-
});
|
|
423
|
-
const body = await resp.json();
|
|
424
|
-
if (resp.ok) {
|
|
425
|
-
console.log(`Instance "${instance}" restarted (immediate)`);
|
|
426
|
-
}
|
|
427
|
-
else {
|
|
428
|
-
console.error(`Restart failed: ${body.error ?? resp.statusText}`);
|
|
429
|
-
process.exit(1);
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
catch (err) {
|
|
433
|
-
console.error(`Cannot connect to fleet (port ${port}). Is the fleet running?`);
|
|
434
|
-
process.exit(1);
|
|
435
|
-
}
|
|
436
|
-
return;
|
|
437
|
-
}
|
|
438
|
-
const pidPath = join(DATA_DIR, "fleet.pid");
|
|
439
|
-
if (!existsSync(pidPath)) {
|
|
440
|
-
console.error("Fleet is not running (no PID file found)");
|
|
441
|
-
process.exit(1);
|
|
442
|
-
}
|
|
443
|
-
const pid = parseInt(readFileSync(pidPath, "utf-8").trim(), 10);
|
|
444
|
-
if (!Number.isInteger(pid) || pid <= 0) {
|
|
445
|
-
console.error(`Fleet PID file at ${pidPath} is corrupted`);
|
|
446
|
-
process.exit(1);
|
|
447
|
-
}
|
|
448
|
-
if (opts?.reload) {
|
|
449
|
-
// Check if managed by launchd — if so, just signal and let launchd restart
|
|
450
|
-
let managedByLaunchd = false;
|
|
451
|
-
try {
|
|
452
|
-
const ppid = parseInt(execFileSync("ps", ["-o", "ppid=", "-p", String(pid)]).toString().trim(), 10);
|
|
453
|
-
managedByLaunchd = ppid === 1;
|
|
454
|
-
}
|
|
455
|
-
catch { /* ignore */ }
|
|
456
|
-
try {
|
|
457
|
-
process.kill(pid, "SIGUSR1");
|
|
458
|
-
}
|
|
459
|
-
catch {
|
|
460
|
-
console.error("Failed to send reload signal (process may have exited)");
|
|
461
|
-
process.exit(1);
|
|
462
|
-
}
|
|
463
|
-
if (managedByLaunchd) {
|
|
464
|
-
console.log("Fleet is managed by launchd — sent reload signal.");
|
|
465
|
-
console.log("launchd will automatically restart with new code.");
|
|
466
|
-
// Wait briefly for old process to exit, then confirm new one started
|
|
467
|
-
const deadline = Date.now() + 6 * 60 * 1000;
|
|
468
|
-
while (Date.now() < deadline) {
|
|
469
|
-
try {
|
|
470
|
-
process.kill(pid, 0);
|
|
471
|
-
await new Promise(r => setTimeout(r, 500));
|
|
472
|
-
}
|
|
473
|
-
catch {
|
|
474
|
-
break;
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
// Wait for launchd to start new process
|
|
478
|
-
await new Promise(r => setTimeout(r, 2000));
|
|
479
|
-
if (existsSync(pidPath)) {
|
|
480
|
-
const newPid = parseInt(readFileSync(pidPath, "utf-8").trim(), 10);
|
|
481
|
-
if (newPid !== pid) {
|
|
482
|
-
console.log(`New fleet process started (PID ${newPid})`);
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
return;
|
|
486
|
-
}
|
|
487
|
-
console.log("Full restart signal sent — waiting for fleet to stop...");
|
|
488
|
-
// Wait for old process to exit (up to 6 minutes: 5 min idle wait + buffer)
|
|
489
|
-
const deadline = Date.now() + 6 * 60 * 1000;
|
|
490
|
-
while (Date.now() < deadline) {
|
|
491
|
-
try {
|
|
492
|
-
process.kill(pid, 0); // check if alive
|
|
493
|
-
await new Promise(r => setTimeout(r, 500));
|
|
494
|
-
}
|
|
495
|
-
catch {
|
|
496
|
-
break; // process exited
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
// Verify it actually exited
|
|
500
|
-
try {
|
|
501
|
-
process.kill(pid, 0);
|
|
502
|
-
console.error("Old fleet process still running after timeout — aborting");
|
|
503
|
-
process.exit(1);
|
|
504
|
-
}
|
|
505
|
-
catch {
|
|
506
|
-
// Good, it exited
|
|
507
|
-
}
|
|
508
|
-
console.log("Old fleet stopped. Starting with new code...");
|
|
509
|
-
// Start new fleet in this process (new Node.js process = new code loaded)
|
|
510
|
-
if (!claimFleetSingleton())
|
|
511
|
-
return;
|
|
512
|
-
const { FleetManager } = await import("./fleet-manager.js");
|
|
513
|
-
const fm = new FleetManager(DATA_DIR);
|
|
514
|
-
const handlers = installFleetProcessHandlers({
|
|
515
|
-
dataDir: DATA_DIR, manager: fm, runtime: process, console,
|
|
516
|
-
describeSignal: () => describeSignalSource(DATA_DIR, "SIGTERM"),
|
|
517
|
-
});
|
|
518
|
-
if (handlers.stopping)
|
|
519
|
-
return;
|
|
520
|
-
await fm.startAll(FLEET_CONFIG_PATH);
|
|
521
|
-
console.log("Fleet restarted with new code");
|
|
522
|
-
}
|
|
523
|
-
else {
|
|
524
|
-
// Instance-only restart (existing behavior)
|
|
525
|
-
try {
|
|
526
|
-
process.kill(pid, "SIGUSR2");
|
|
527
|
-
console.log("Graceful restart signal sent — fleet will restart when all instances are idle");
|
|
528
|
-
}
|
|
529
|
-
catch {
|
|
530
|
-
console.error("Failed to send restart signal (process may have exited)");
|
|
531
|
-
process.exit(1);
|
|
532
|
-
}
|
|
533
|
-
}
|
|
422
|
+
// #2356: no restart of its own any more. Its SIGUSR1 reload made the fleet exit 0 and took over in this process, so
|
|
423
|
+
// under a Restart=on-failure unit the fleet stayed down (and this process, in an agent pane, died with the unit's
|
|
424
|
+
// cgroup). It runs `agend restart` itself — this Node, this CLI — with the same gate, guard and exit code.
|
|
425
|
+
const args = instance ? ["restart", instance] : ["restart", ...(opts?.yes ? ["--yes"] : [])];
|
|
426
|
+
console.error(t("cli.fleet_restart_deprecated", args.join(" ")));
|
|
427
|
+
const self = selfCommand(args);
|
|
428
|
+
const result = spawnSync(self.command, self.args, { stdio: "inherit" });
|
|
429
|
+
process.exit(result.status ?? 1);
|
|
534
430
|
});
|
|
535
431
|
fleet
|
|
536
|
-
.command("status")
|
|
537
|
-
.description("
|
|
432
|
+
.command("status", { hidden: true })
|
|
433
|
+
.description("Alias of `agend ls --resources`")
|
|
538
434
|
.option("--json", "Output as JSON")
|
|
539
435
|
.action(async (opts) => {
|
|
540
|
-
// Delegate to the `ls` command implementation
|
|
541
436
|
await lsAction({ ...opts, resources: true });
|
|
542
437
|
});
|
|
543
438
|
fleet
|
|
544
|
-
.command("logs")
|
|
545
|
-
.description("
|
|
439
|
+
.command("logs", { hidden: true })
|
|
440
|
+
.description("Removed; use `agend logs`")
|
|
546
441
|
.action(() => {
|
|
547
|
-
console.
|
|
442
|
+
console.error(t("cli.fleet_logs_removed"));
|
|
443
|
+
process.exitCode = 1;
|
|
548
444
|
});
|
|
549
445
|
fleet
|
|
550
446
|
.command("history")
|
|
@@ -876,9 +772,6 @@ backend
|
|
|
876
772
|
console.error(`Unknown backend: ${backendName}. Available: ${BACKENDS.map(b => b.id).join(", ")}`);
|
|
877
773
|
process.exit(1);
|
|
878
774
|
}
|
|
879
|
-
if (info.deprecated) {
|
|
880
|
-
console.warn(`⚠️ ${info.label} is deprecated (stops 2026-06-18). Consider switching to backend: antigravity`);
|
|
881
|
-
}
|
|
882
775
|
let issues = 0;
|
|
883
776
|
const ok = (msg) => console.log(` \x1b[32m✓\x1b[0m ${msg}`);
|
|
884
777
|
const fail = (msg) => { issues++; console.log(` \x1b[31m✗\x1b[0m ${msg}`); };
|
|
@@ -1142,7 +1035,7 @@ async function doctorMcp() {
|
|
|
1142
1035
|
}
|
|
1143
1036
|
if (!ipcOk) {
|
|
1144
1037
|
issues.push("IPC ✗ (socket not responding)");
|
|
1145
|
-
suggestions.push("agend
|
|
1038
|
+
suggestions.push("agend restart");
|
|
1146
1039
|
}
|
|
1147
1040
|
// 2. MCP config check
|
|
1148
1041
|
let mcpOk = false;
|
|
@@ -1490,7 +1383,7 @@ program
|
|
|
1490
1383
|
// #2264 review: the old system copy is retired only for a confirmed 2.1-era layout — the copy this updater runs
|
|
1491
1384
|
// from is a 2.1.x release (2.1's updater left it there). Never from "nvm" or "root" alone: a 2.2+ copy stays.
|
|
1492
1385
|
if (verified.retireSystemCopy && !/^2\.1\./.test(pkgVersion)) {
|
|
1493
|
-
console.log(
|
|
1386
|
+
console.log(t("cli.system_install_kept", pkgVersion));
|
|
1494
1387
|
delete verified.retireSystemCopy;
|
|
1495
1388
|
}
|
|
1496
1389
|
if (verified.retireSystemCopy) {
|
|
@@ -1763,7 +1656,7 @@ program
|
|
|
1763
1656
|
};
|
|
1764
1657
|
const viaInstaller = !needsSudo && targetVersion !== null && shipsInstaller();
|
|
1765
1658
|
if (!needsSudo && !viaInstaller)
|
|
1766
|
-
console.log(
|
|
1659
|
+
console.log(t("cli.no_own_installer", pkg));
|
|
1767
1660
|
if (viaInstaller) {
|
|
1768
1661
|
console.log(`\n Updating AgEnD v${pkgVersion} → v${targetVersion} (its own installer)...\n`);
|
|
1769
1662
|
markUpdateInProgress(DATA_DIR);
|
|
@@ -1894,9 +1787,12 @@ program
|
|
|
1894
1787
|
program
|
|
1895
1788
|
.command("install")
|
|
1896
1789
|
.description("Install the AgEnD system service and start it by default")
|
|
1897
|
-
.
|
|
1790
|
+
.addOption(new Option("--activate").hideHelp())
|
|
1898
1791
|
.option("--no-activate", "Write the service file without activating it")
|
|
1899
1792
|
.action(async (opts) => {
|
|
1793
|
+
if (process.argv.includes("--activate")) {
|
|
1794
|
+
console.error(t("cli.install_activate_removed"));
|
|
1795
|
+
}
|
|
1900
1796
|
const { installService, activateService, detectPlatform, renderLaunchdPlist, launchdPlistPath, getServicePath, getSystemServicePath, serviceHomeFor } = await import("./service-installer.js");
|
|
1901
1797
|
// #1631 B: an older updater (2.2.0-beta.1 and before) refreshes a hand-started fleet's service too, through this
|
|
1902
1798
|
// command — which would CREATE a unit or plist, and every later update would then take a manager it may not reach
|
|
@@ -1977,6 +1873,13 @@ program
|
|
|
1977
1873
|
process.exitCode = 1;
|
|
1978
1874
|
}
|
|
1979
1875
|
}
|
|
1876
|
+
// #2331: a host whose fleet runs under the system unit gets no second, user unit from the refresh — it would only
|
|
1877
|
+
// sit beside it unused, and be named as a leftover on every update after.
|
|
1878
|
+
if (systemUnit) {
|
|
1879
|
+
console.log(t("install.path", systemUnit));
|
|
1880
|
+
console.log(t("install.updated"));
|
|
1881
|
+
return;
|
|
1882
|
+
}
|
|
1980
1883
|
const svcPath = installService(serviceVars);
|
|
1981
1884
|
console.log(t("install.path", svcPath));
|
|
1982
1885
|
if (opts.activate !== false) {
|
|
@@ -2075,7 +1978,17 @@ program
|
|
|
2075
1978
|
.action(async (opts) => {
|
|
2076
1979
|
if (!gateFleetControl(DATA_DIR, "stop", { yes: opts.yes }))
|
|
2077
1980
|
process.exit(1);
|
|
2078
|
-
const { getServicePath, stopService } = await import("./service-installer.js");
|
|
1981
|
+
const { getServicePath, getSystemServicePath, stopService, stopSystemService } = await import("./service-installer.js");
|
|
1982
|
+
// #2356: the system unit first, as `agend start` and `agend restart` choose it; a SIGTERM would only stop the process.
|
|
1983
|
+
if (getSystemServicePath()) {
|
|
1984
|
+
if (stopSystemService()) {
|
|
1985
|
+
console.log(t("cli.system_service_stopped"));
|
|
1986
|
+
return;
|
|
1987
|
+
}
|
|
1988
|
+
console.error(t("cli.system_service_stop_failed"));
|
|
1989
|
+
process.exitCode = 1;
|
|
1990
|
+
return;
|
|
1991
|
+
}
|
|
2079
1992
|
if (!getServicePath()) {
|
|
2080
1993
|
// No service — try killing by PID
|
|
2081
1994
|
const pidPath = join(DATA_DIR, "fleet.pid");
|
|
@@ -2124,10 +2037,10 @@ program
|
|
|
2124
2037
|
const systemServicePath = getSystemServicePath();
|
|
2125
2038
|
if (!userServicePath && !systemServicePath) {
|
|
2126
2039
|
console.log("No service installed. Starting fleet directly...");
|
|
2127
|
-
const { spawn } = await import("
|
|
2040
|
+
const { spawn } = await import("./child-process.js");
|
|
2128
2041
|
// This Node on this CLI, not `sh -c "agend fleet start"` through PATH (#1450 C5).
|
|
2129
2042
|
const start = selfCommand(["fleet", "start"]);
|
|
2130
|
-
const child = spawn(start.command, start.args, { detached: true, stdio: "ignore" });
|
|
2043
|
+
const child = spawn(start.command, start.args, { detached: true, stdio: "ignore", env: { ...process.env, [DIRECT_FLEET_START_ENV]: "1" } });
|
|
2131
2044
|
child.unref();
|
|
2132
2045
|
console.log("Fleet starting in background.");
|
|
2133
2046
|
return;
|
|
@@ -2140,16 +2053,79 @@ program
|
|
|
2140
2053
|
// A service file means the service manager owns this fleet. Falling back
|
|
2141
2054
|
// to a detached process here creates a second fleet when the bus recovers.
|
|
2142
2055
|
console.error("Failed to start the installed AgEnD service; refusing to start a detached duplicate.");
|
|
2143
|
-
console.error("
|
|
2056
|
+
console.error(t("cli.service_retry", process.platform === "darwin" ? "launchctl print gui/$(id -u)/com.agend.fleet" : systemServicePath ? "systemctl status agend" : "systemctl --user status com.agend.fleet"));
|
|
2057
|
+
// #2356: a service file that cannot run here (never activated, no session for it) would otherwise leave no start.
|
|
2058
|
+
console.error(t("cli.service_direct_hint"));
|
|
2144
2059
|
process.exitCode = 1;
|
|
2145
2060
|
}
|
|
2146
2061
|
});
|
|
2062
|
+
/**
|
|
2063
|
+
* #2356 (user decision): on a host with an AgEnD service installed, a hand-run `fleet start` / `fleet stop` would run or
|
|
2064
|
+
* kill a fleet the service manager does not own — a duplicate beside the unit, or a stop systemd undoes. Run `agend
|
|
2065
|
+
* start` / `agend stop` instead (this Node, this CLI; their own gate and exit code). The manager's own `fleet start`
|
|
2066
|
+
* (the unit's ExecStart, the launchd job) and AgEnD's marked detached start go ahead directly; so does every host
|
|
2067
|
+
* without a service (Docker, manual setups). Exits when it redirected; false to go on.
|
|
2068
|
+
*/
|
|
2069
|
+
function redirectToService(command, extra, directMarker) {
|
|
2070
|
+
let ownCgroup = null;
|
|
2071
|
+
try {
|
|
2072
|
+
ownCgroup = readFileSync("/proc/self/cgroup", "utf-8");
|
|
2073
|
+
}
|
|
2074
|
+
catch { /* not Linux */ }
|
|
2075
|
+
const byServiceManager = startedByServiceManager({ platform: process.platform, env: process.env, ownCgroup, ppid: process.ppid, launchdLabel: "com.agend.fleet" });
|
|
2076
|
+
const installed = getSystemServicePath() ?? getServicePath();
|
|
2077
|
+
if (!redirectsToService({ command, directMarker, byServiceManager, installedServicePath: installed }))
|
|
2078
|
+
return false;
|
|
2079
|
+
console.error(t("cli.service_redirect", String(installed), [command, ...extra].join(" ")));
|
|
2080
|
+
const self = selfCommand([command, ...extra]);
|
|
2081
|
+
const result = spawnSync(self.command, self.args, { stdio: "inherit" });
|
|
2082
|
+
process.exit(result.status ?? 1);
|
|
2083
|
+
}
|
|
2084
|
+
/** One instance, at once, through the running fleet's HTTP API; the fleet process keeps running. */
|
|
2085
|
+
async function restartOneInstance(instance) {
|
|
2086
|
+
recordInstanceControl(DATA_DIR, "instance-restart", instance);
|
|
2087
|
+
const { loadFleetConfig } = await import("./config.js");
|
|
2088
|
+
const fleet = loadFleetConfig(FLEET_CONFIG_PATH);
|
|
2089
|
+
const port = fleet.health_port ?? 19280;
|
|
2090
|
+
let token = "";
|
|
2091
|
+
try {
|
|
2092
|
+
token = readFileSync(join(DATA_DIR, "web.token"), "utf-8").trim();
|
|
2093
|
+
}
|
|
2094
|
+
catch { /* fleet may not be running */ }
|
|
2095
|
+
try {
|
|
2096
|
+
const resp = await fetch(`http://127.0.0.1:${port}/restart/${encodeURIComponent(instance)}`, {
|
|
2097
|
+
method: "POST",
|
|
2098
|
+
headers: token ? { "X-Agend-Token": token } : {},
|
|
2099
|
+
});
|
|
2100
|
+
const body = await resp.json();
|
|
2101
|
+
if (resp.ok) {
|
|
2102
|
+
console.log(t("cli.instance_restarted", instance));
|
|
2103
|
+
}
|
|
2104
|
+
else {
|
|
2105
|
+
console.error(t("cli.restart_failed", String(body.error ?? resp.statusText)));
|
|
2106
|
+
process.exit(1);
|
|
2107
|
+
}
|
|
2108
|
+
}
|
|
2109
|
+
catch {
|
|
2110
|
+
console.error(t("cli.fleet_unreachable", port));
|
|
2111
|
+
process.exit(1);
|
|
2112
|
+
}
|
|
2113
|
+
}
|
|
2147
2114
|
program
|
|
2148
2115
|
.command("restart")
|
|
2149
|
-
.description("Restart the AgEnD service (auto-detects systemd/launchd/detached)")
|
|
2116
|
+
.description("Restart the AgEnD service (auto-detects systemd/launchd/detached) — the one full restart; or one instance")
|
|
2117
|
+
.argument("[instance]", "Restart only this instance, immediately; the fleet keeps running")
|
|
2150
2118
|
.option("-y, --yes", "Confirm when run from a fleet agent session (this affects every instance)")
|
|
2151
2119
|
.option("--force", "Restart even when the loaded service does not start this install on its selected Node (operators only)")
|
|
2152
|
-
.action(async (opts) => {
|
|
2120
|
+
.action(async (instance, opts) => {
|
|
2121
|
+
if (instance) {
|
|
2122
|
+
if (opts.force) {
|
|
2123
|
+
console.error(t("cli.force_whole_service"));
|
|
2124
|
+
process.exit(1);
|
|
2125
|
+
}
|
|
2126
|
+
await restartOneInstance(instance);
|
|
2127
|
+
return;
|
|
2128
|
+
}
|
|
2153
2129
|
// --force overrides the C6 guard: an operator's own decision, never a fleet agent's or a fleet-internal spawn's.
|
|
2154
2130
|
if (opts.force && !forceAllowed()) {
|
|
2155
2131
|
console.error(" ✗ Not restarting: --force is for an operator's own shell, not a fleet agent session or the fleet's own commands. Nothing was stopped.");
|
|
@@ -2199,8 +2175,9 @@ program
|
|
|
2199
2175
|
// service's own HOME, which may differ from what this command resolves (sudo,
|
|
2200
2176
|
// AGEND_HOME) — an absent pid file does NOT mean it's stopped. Ask the service
|
|
2201
2177
|
// manager first. This is the canonical restart the `update` flow spawns.
|
|
2202
|
-
const { detectPlatform, getServicePath, getSystemServicePath, getSystemdServiceState, systemdRestartOutcome, ensureSystemdUnitHardening, effectiveUnitDropIns, unitCoredumpFilterState, } = await import("./service-installer.js");
|
|
2203
|
-
const {
|
|
2178
|
+
const { detectPlatform, getServicePath, getSystemServicePath, getSystemdServiceState, systemdRestartOutcome, ensureSystemdUnitHardening, effectiveUnitDropIns, unitCoredumpFilterState, loadedUnitCheck, } = await import("./service-installer.js");
|
|
2179
|
+
const { spawnSync } = await import("node:child_process");
|
|
2180
|
+
const { spawn } = await import("./child-process.js");
|
|
2204
2181
|
const plat = detectPlatform();
|
|
2205
2182
|
const pidPath = join(DATA_DIR, "fleet.pid");
|
|
2206
2183
|
const run = (cmd) => {
|
|
@@ -2329,7 +2306,11 @@ program
|
|
|
2329
2306
|
.filter(([key, state]) => key !== "KillMode" && (state === "added" || state === "upgraded"))
|
|
2330
2307
|
.map(([key]) => key);
|
|
2331
2308
|
if (updated.length > 0)
|
|
2332
|
-
console.log(
|
|
2309
|
+
console.log(t("cli.unit_updated", String(unitPath), updated.join(", ")));
|
|
2310
|
+
// #2331: what systemd LOADED — a drop-in that refuses the fleet's READY is overridden by AgEnD's own, leftovers
|
|
2311
|
+
// are named. Not a gate: the fleet still restarts, and the line says what will happen and what to remove.
|
|
2312
|
+
for (const line of loadedUnitCheck({ user: systemdTarget.user, unit: systemdTarget.unit, unitPath }))
|
|
2313
|
+
console.log(line);
|
|
2333
2314
|
// Re-judged after the reload, against what systemd now applies: an
|
|
2334
2315
|
// operator's own mask (anywhere — main file, unit or type drop-in, or a
|
|
2335
2316
|
// trailing empty assignment that restores the inherited one) is warned
|
|
@@ -2400,13 +2381,10 @@ program
|
|
|
2400
2381
|
if (printed.status === 0) {
|
|
2401
2382
|
const plistPath = getServicePath() ?? join(homedir(), "Library", "LaunchAgents", `${label}.plist`);
|
|
2402
2383
|
// Path 2 (#1450 C6): a proven new plist waits on disk with its plan — exactly one bootout + bootstrap.
|
|
2403
|
-
const {
|
|
2404
|
-
|
|
2405
|
-
//
|
|
2406
|
-
|
|
2407
|
-
const plan = recorded && planCarriedOut(recorded, target, deps) ? null : recorded;
|
|
2408
|
-
if (recorded && !plan)
|
|
2409
|
-
console.log(" ℹ launchd already runs the job an interrupted update planned; restarting it as it is.");
|
|
2384
|
+
const { pendingPlan, admitPlan, planPath } = await import("./service-plan.js");
|
|
2385
|
+
// #1871: a plan whose job launchd already runs (an interrupted update, then `agend start`) is done: restart that
|
|
2386
|
+
// job as an unchanged one (path 1) instead of refusing it for its new pid. #2375: quietly (no note on every restart).
|
|
2387
|
+
const plan = opts.force ? null : pendingPlan(DATA_DIR, target, deps);
|
|
2410
2388
|
if (plan && expectation.ok) {
|
|
2411
2389
|
const pkgDir = dirname(dirname(expectation.expected.entry));
|
|
2412
2390
|
const admitted = admitPlan(plan, { target, expected: expectation.expected, pkgDir }, deps);
|
|
@@ -2566,7 +2544,7 @@ program
|
|
|
2566
2544
|
unlinkSync(pidPath);
|
|
2567
2545
|
}
|
|
2568
2546
|
catch { /* old owner already removed it */ }
|
|
2569
|
-
const child = spawn(start.command, start.args, { detached: true, stdio: "ignore" });
|
|
2547
|
+
const child = spawn(start.command, start.args, { detached: true, stdio: "ignore", env: { ...process.env, [DIRECT_FLEET_START_ENV]: "1" } });
|
|
2570
2548
|
child.unref();
|
|
2571
2549
|
console.log("Fleet restarting in background.");
|
|
2572
2550
|
return;
|
|
@@ -2583,7 +2561,7 @@ program
|
|
|
2583
2561
|
});
|
|
2584
2562
|
program
|
|
2585
2563
|
.command("setup")
|
|
2586
|
-
.description("
|
|
2564
|
+
.description("Browser first-run page, before a fleet exists (not the CLI wizard; see `agend quickstart`)")
|
|
2587
2565
|
.option("--reset", "Allow setup again after it has already been completed")
|
|
2588
2566
|
.option("--port <port>", "Port for the setup page (default: the health port)")
|
|
2589
2567
|
.option("--tunnel", "Expose the setup page through a Cloudflare quick tunnel so a phone can open it")
|
|
@@ -2678,14 +2656,14 @@ program
|
|
|
2678
2656
|
});
|
|
2679
2657
|
program
|
|
2680
2658
|
.command("quickstart")
|
|
2681
|
-
.description("
|
|
2659
|
+
.description("CLI guided setup: backend, chat channel, projects, and fleet service (recommended)")
|
|
2682
2660
|
.action(async () => {
|
|
2683
2661
|
const { runQuickstart } = await import("./quickstart.js");
|
|
2684
2662
|
await runQuickstart();
|
|
2685
2663
|
});
|
|
2686
2664
|
program
|
|
2687
2665
|
.command("init")
|
|
2688
|
-
.description("Interactive
|
|
2666
|
+
.description("Interactive advanced wizard (setup-wizard); for first-run use `agend quickstart` or `agend setup`")
|
|
2689
2667
|
.action(async () => {
|
|
2690
2668
|
const { runSetupWizard } = await import("./setup-wizard.js");
|
|
2691
2669
|
await runSetupWizard();
|
|
@@ -2734,7 +2712,7 @@ program
|
|
|
2734
2712
|
minutes = Math.max(1, Math.round(((body.expiresAt ?? Date.now()) - Date.now()) / 60_000));
|
|
2735
2713
|
}
|
|
2736
2714
|
catch {
|
|
2737
|
-
console.error(
|
|
2715
|
+
console.error(t("cli.fleet_unreachable", port));
|
|
2738
2716
|
process.exit(1);
|
|
2739
2717
|
}
|
|
2740
2718
|
const signin = `http://localhost:${port}/signin`;
|
|
@@ -3006,11 +2984,11 @@ schedule
|
|
|
3006
2984
|
}
|
|
3007
2985
|
});
|
|
3008
2986
|
schedule
|
|
3009
|
-
.command("trigger")
|
|
3010
|
-
.
|
|
3011
|
-
.
|
|
3012
|
-
.
|
|
3013
|
-
|
|
2987
|
+
.command("trigger", { hidden: true })
|
|
2988
|
+
.argument("[id]", "Schedule ID")
|
|
2989
|
+
.action(() => {
|
|
2990
|
+
console.error(t("cli.schedule_trigger_removed"));
|
|
2991
|
+
process.exitCode = 1;
|
|
3014
2992
|
});
|
|
3015
2993
|
// === Chat Export ===
|
|
3016
2994
|
program
|
|
@@ -3511,16 +3489,21 @@ async function lsAction(opts) {
|
|
|
3511
3489
|
console.log("Tip: agend completion install — then agend attach <TAB> completes instance names.");
|
|
3512
3490
|
}
|
|
3513
3491
|
}
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3492
|
+
function addLsOptions(cmd) {
|
|
3493
|
+
return cmd
|
|
3494
|
+
.option("--json", "Output as JSON")
|
|
3495
|
+
.option("--names-only", "Print instance names one per line (for shell completion)")
|
|
3496
|
+
.option("--resources", "Also report workspace disk usage, unregistered instance directories, and host memory/swap (text only); `agend fleet status` is a hidden alias of this")
|
|
3497
|
+
.option("--running", "Show only running instances")
|
|
3498
|
+
.option("--team <name>", "Filter by team name")
|
|
3499
|
+
.option("--backend <name>", "Filter by backend (exact match)")
|
|
3500
|
+
.option("--display", "Show display names as last column");
|
|
3501
|
+
}
|
|
3502
|
+
addLsOptions(program.command("ls").description("List all instances with status, backend, team, and last activity"))
|
|
3503
|
+
.action(async (opts) => {
|
|
3504
|
+
await lsAction(opts);
|
|
3505
|
+
});
|
|
3506
|
+
addLsOptions(program.command("status", { hidden: true }).description("Alias of `agend ls`"))
|
|
3524
3507
|
.action(async (opts) => {
|
|
3525
3508
|
await lsAction(opts);
|
|
3526
3509
|
});
|
|
@@ -3547,9 +3530,10 @@ Then reload the shell. Tab-completes instance names for \`agend attach\` and
|
|
|
3547
3530
|
// Subcommand names come from commander itself, so the script can't drift
|
|
3548
3531
|
// out of sync with the CLI the way a hardcoded list would.
|
|
3549
3532
|
const fleetCmd = program.commands.find(c => c.name() === "fleet");
|
|
3533
|
+
const visible = (cmds) => cmds.filter(c => !c._hidden).map(c => c.name());
|
|
3550
3534
|
const spec = {
|
|
3551
|
-
topLevel: program.commands
|
|
3552
|
-
fleetSub: fleetCmd?.commands
|
|
3535
|
+
topLevel: visible(program.commands),
|
|
3536
|
+
fleetSub: visible(fleetCmd?.commands ?? []),
|
|
3553
3537
|
instanceCommands: ["attach"],
|
|
3554
3538
|
fleetInstanceCommands: ["start", "stop", "restart"],
|
|
3555
3539
|
};
|
|
@@ -3606,7 +3590,7 @@ Then reload the shell. Tab-completes instance names for \`agend attach\` and
|
|
|
3606
3590
|
console.log(completionScript(target, spec));
|
|
3607
3591
|
});
|
|
3608
3592
|
program
|
|
3609
|
-
.command("health").description("
|
|
3593
|
+
.command("health").description("Live fleet health of running instances (HTTP, tmux, IPC); for host/setup diagnostics use `agend doctor`")
|
|
3610
3594
|
.option("--json", "Output as JSON")
|
|
3611
3595
|
.option("-q, --quiet", "One-line summary only")
|
|
3612
3596
|
.action(async (opts) => {
|
|
@@ -3844,7 +3828,7 @@ program
|
|
|
3844
3828
|
});
|
|
3845
3829
|
program
|
|
3846
3830
|
.command("logs")
|
|
3847
|
-
.description("Show fleet log (
|
|
3831
|
+
.description("Show fleet log (daemon.log, or fleet.log if the daemon log is not there yet)")
|
|
3848
3832
|
.option("-n, --lines <count>", "Number of lines to show", "50")
|
|
3849
3833
|
.option("-f, --follow", "Follow log output (like tail -f)")
|
|
3850
3834
|
.option("--instance <name>", "Filter by instance name")
|