@camerontaylor/paseo-cli 0.8.0-fork.1
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/bin/paseo +3 -0
- package/dist/classify.d.ts +19 -0
- package/dist/classify.js +49 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +135 -0
- package/dist/commands/agent/archive.d.ts +18 -0
- package/dist/commands/agent/archive.js +102 -0
- package/dist/commands/agent/attach.d.ts +11 -0
- package/dist/commands/agent/attach.js +161 -0
- package/dist/commands/agent/delete.d.ts +15 -0
- package/dist/commands/agent/delete.js +107 -0
- package/dist/commands/agent/detach.d.ts +9 -0
- package/dist/commands/agent/detach.js +38 -0
- package/dist/commands/agent/import.d.ts +14 -0
- package/dist/commands/agent/import.js +122 -0
- package/dist/commands/agent/index.d.ts +3 -0
- package/dist/commands/agent/index.js +56 -0
- package/dist/commands/agent/inspect.d.ts +15 -0
- package/dist/commands/agent/inspect.js +209 -0
- package/dist/commands/agent/logs.d.ts +19 -0
- package/dist/commands/agent/logs.js +180 -0
- package/dist/commands/agent/ls.d.ts +44 -0
- package/dist/commands/agent/ls.js +212 -0
- package/dist/commands/agent/mode.d.ts +18 -0
- package/dist/commands/agent/mode.js +100 -0
- package/dist/commands/agent/open.d.ts +11 -0
- package/dist/commands/agent/open.js +61 -0
- package/dist/commands/agent/reload.d.ts +15 -0
- package/dist/commands/agent/reload.js +75 -0
- package/dist/commands/agent/run.d.ts +78 -0
- package/dist/commands/agent/run.js +554 -0
- package/dist/commands/agent/send.d.ts +19 -0
- package/dist/commands/agent/send.js +187 -0
- package/dist/commands/agent/stop.d.ts +17 -0
- package/dist/commands/agent/stop.js +115 -0
- package/dist/commands/agent/update.d.ts +51 -0
- package/dist/commands/agent/update.js +186 -0
- package/dist/commands/agent/wait.d.ts +17 -0
- package/dist/commands/agent/wait.js +158 -0
- package/dist/commands/clone.d.ts +17 -0
- package/dist/commands/clone.js +65 -0
- package/dist/commands/daemon/index.d.ts +3 -0
- package/dist/commands/daemon/index.js +60 -0
- package/dist/commands/daemon/local-daemon.d.ts +78 -0
- package/dist/commands/daemon/local-daemon.js +547 -0
- package/dist/commands/daemon/pair.d.ts +35 -0
- package/dist/commands/daemon/pair.js +167 -0
- package/dist/commands/daemon/reload.d.ts +10 -0
- package/dist/commands/daemon/reload.js +36 -0
- package/dist/commands/daemon/restart.d.ts +12 -0
- package/dist/commands/daemon/restart.js +99 -0
- package/dist/commands/daemon/runtime-toolchain.d.ts +6 -0
- package/dist/commands/daemon/runtime-toolchain.js +87 -0
- package/dist/commands/daemon/set-password.d.ts +17 -0
- package/dist/commands/daemon/set-password.js +82 -0
- package/dist/commands/daemon/start.d.ts +6 -0
- package/dist/commands/daemon/start.js +57 -0
- package/dist/commands/daemon/status.d.ts +21 -0
- package/dist/commands/daemon/status.js +363 -0
- package/dist/commands/daemon/stop.d.ts +15 -0
- package/dist/commands/daemon/stop.js +60 -0
- package/dist/commands/heartbeat/index.d.ts +3 -0
- package/dist/commands/heartbeat/index.js +139 -0
- package/dist/commands/hooks.d.ts +19 -0
- package/dist/commands/hooks.js +89 -0
- package/dist/commands/hub/authority.d.ts +17 -0
- package/dist/commands/hub/authority.js +18 -0
- package/dist/commands/hub/connect.d.ts +23 -0
- package/dist/commands/hub/connect.js +44 -0
- package/dist/commands/hub/credentials.d.ts +21 -0
- package/dist/commands/hub/credentials.js +143 -0
- package/dist/commands/hub/daemon-client.d.ts +40 -0
- package/dist/commands/hub/daemon-client.js +14 -0
- package/dist/commands/hub/deploy-bundle.d.ts +16 -0
- package/dist/commands/hub/deploy-bundle.js +248 -0
- package/dist/commands/hub/deploy-triggers.d.ts +6 -0
- package/dist/commands/hub/deploy-triggers.js +116 -0
- package/dist/commands/hub/deploy.d.ts +50 -0
- package/dist/commands/hub/deploy.js +159 -0
- package/dist/commands/hub/disconnect.d.ts +16 -0
- package/dist/commands/hub/disconnect.js +24 -0
- package/dist/commands/hub/error.d.ts +6 -0
- package/dist/commands/hub/error.js +9 -0
- package/dist/commands/hub/export.d.ts +28 -0
- package/dist/commands/hub/export.js +80 -0
- package/dist/commands/hub/help.d.ts +3 -0
- package/dist/commands/hub/help.js +5 -0
- package/dist/commands/hub/hub-client/index.d.ts +22 -0
- package/dist/commands/hub/hub-client/index.js +135 -0
- package/dist/commands/hub/hub-client/internal/contracts.d.ts +126 -0
- package/dist/commands/hub/hub-client/internal/contracts.js +85 -0
- package/dist/commands/hub/hub-client/internal/problem.d.ts +3 -0
- package/dist/commands/hub/hub-client/internal/problem.js +85 -0
- package/dist/commands/hub/hub-client/internal/transport.d.ts +15 -0
- package/dist/commands/hub/hub-client/internal/transport.js +30 -0
- package/dist/commands/hub/index.d.ts +20 -0
- package/dist/commands/hub/index.js +94 -0
- package/dist/commands/hub/init-plan.d.ts +33 -0
- package/dist/commands/hub/init-plan.js +94 -0
- package/dist/commands/hub/init.d.ts +35 -0
- package/dist/commands/hub/init.js +524 -0
- package/dist/commands/hub/login-flow.d.ts +34 -0
- package/dist/commands/hub/login-flow.js +78 -0
- package/dist/commands/hub/login.d.ts +23 -0
- package/dist/commands/hub/login.js +40 -0
- package/dist/commands/hub/logout.d.ts +32 -0
- package/dist/commands/hub/logout.js +71 -0
- package/dist/commands/hub/origin.d.ts +2 -0
- package/dist/commands/hub/origin.js +27 -0
- package/dist/commands/hub/permissions.d.ts +21 -0
- package/dist/commands/hub/permissions.js +61 -0
- package/dist/commands/hub/projects.d.ts +24 -0
- package/dist/commands/hub/projects.js +49 -0
- package/dist/commands/hub/reporter.d.ts +10 -0
- package/dist/commands/hub/reporter.js +11 -0
- package/dist/commands/hub/starter-agent-runtime.d.ts +37 -0
- package/dist/commands/hub/starter-agent-runtime.js +49 -0
- package/dist/commands/hub/starter-trigger.d.ts +10 -0
- package/dist/commands/hub/starter-trigger.js +30 -0
- package/dist/commands/hub/status-output.d.ts +13 -0
- package/dist/commands/hub/status-output.js +30 -0
- package/dist/commands/onboard.d.ts +10 -0
- package/dist/commands/onboard.js +400 -0
- package/dist/commands/open.d.ts +4 -0
- package/dist/commands/open.js +89 -0
- package/dist/commands/permit/allow.d.ts +20 -0
- package/dist/commands/permit/allow.js +133 -0
- package/dist/commands/permit/deny.d.ts +12 -0
- package/dist/commands/permit/deny.js +105 -0
- package/dist/commands/permit/index.d.ts +3 -0
- package/dist/commands/permit/index.js +27 -0
- package/dist/commands/permit/ls.d.ts +18 -0
- package/dist/commands/permit/ls.js +66 -0
- package/dist/commands/plugin/index.d.ts +17 -0
- package/dist/commands/plugin/index.js +138 -0
- package/dist/commands/plugin/scaffold.d.ts +6 -0
- package/dist/commands/plugin/scaffold.js +162 -0
- package/dist/commands/plugin/shared.d.ts +5 -0
- package/dist/commands/plugin/shared.js +30 -0
- package/dist/commands/project/create.d.ts +10 -0
- package/dist/commands/project/create.js +41 -0
- package/dist/commands/project/delete.d.ts +9 -0
- package/dist/commands/project/delete.js +33 -0
- package/dist/commands/project/index.d.ts +3 -0
- package/dist/commands/project/index.js +28 -0
- package/dist/commands/project/ls.d.ts +5 -0
- package/dist/commands/project/ls.js +19 -0
- package/dist/commands/project/rename.d.ts +15 -0
- package/dist/commands/project/rename.js +50 -0
- package/dist/commands/project/shared.d.ts +11 -0
- package/dist/commands/project/shared.js +18 -0
- package/dist/commands/provider/add.d.ts +30 -0
- package/dist/commands/provider/add.js +123 -0
- package/dist/commands/provider/diagnostic.d.ts +12 -0
- package/dist/commands/provider/diagnostic.js +31 -0
- package/dist/commands/provider/index.d.ts +3 -0
- package/dist/commands/provider/index.js +38 -0
- package/dist/commands/provider/ls.d.ts +20 -0
- package/dist/commands/provider/ls.js +76 -0
- package/dist/commands/provider/models.d.ts +20 -0
- package/dist/commands/provider/models.js +53 -0
- package/dist/commands/provider/rm.d.ts +10 -0
- package/dist/commands/provider/rm.js +45 -0
- package/dist/commands/provider/shared.d.ts +7 -0
- package/dist/commands/provider/shared.js +10 -0
- package/dist/commands/schedule/create.d.ts +19 -0
- package/dist/commands/schedule/create.js +41 -0
- package/dist/commands/schedule/delete.d.ts +10 -0
- package/dist/commands/schedule/delete.js +32 -0
- package/dist/commands/schedule/index.d.ts +3 -0
- package/dist/commands/schedule/index.js +66 -0
- package/dist/commands/schedule/inspect.d.ts +6 -0
- package/dist/commands/schedule/inspect.js +27 -0
- package/dist/commands/schedule/logs.d.ts +6 -0
- package/dist/commands/schedule/logs.js +24 -0
- package/dist/commands/schedule/ls.d.ts +5 -0
- package/dist/commands/schedule/ls.js +25 -0
- package/dist/commands/schedule/pause.d.ts +5 -0
- package/dist/commands/schedule/pause.js +24 -0
- package/dist/commands/schedule/resume.d.ts +5 -0
- package/dist/commands/schedule/resume.js +24 -0
- package/dist/commands/schedule/run-once.d.ts +5 -0
- package/dist/commands/schedule/run-once.js +24 -0
- package/dist/commands/schedule/schema.d.ts +21 -0
- package/dist/commands/schedule/schema.js +67 -0
- package/dist/commands/schedule/shared.d.ts +59 -0
- package/dist/commands/schedule/shared.js +358 -0
- package/dist/commands/schedule/types.d.ts +165 -0
- package/dist/commands/schedule/types.js +2 -0
- package/dist/commands/schedule/update.d.ts +21 -0
- package/dist/commands/schedule/update.js +40 -0
- package/dist/commands/script/index.d.ts +3 -0
- package/dist/commands/script/index.js +19 -0
- package/dist/commands/script/ls.d.ts +6 -0
- package/dist/commands/script/ls.js +20 -0
- package/dist/commands/script/schema.d.ts +5 -0
- package/dist/commands/script/schema.js +13 -0
- package/dist/commands/script/shared.d.ts +11 -0
- package/dist/commands/script/shared.js +59 -0
- package/dist/commands/script/start.d.ts +6 -0
- package/dist/commands/script/start.js +23 -0
- package/dist/commands/script/stop.d.ts +6 -0
- package/dist/commands/script/stop.js +23 -0
- package/dist/commands/speech/index.d.ts +3 -0
- package/dist/commands/speech/index.js +5 -0
- package/dist/commands/terminal/capture.d.ts +10 -0
- package/dist/commands/terminal/capture.js +68 -0
- package/dist/commands/terminal/create.d.ts +11 -0
- package/dist/commands/terminal/create.js +29 -0
- package/dist/commands/terminal/index.d.ts +3 -0
- package/dist/commands/terminal/index.js +45 -0
- package/dist/commands/terminal/kill.d.ts +6 -0
- package/dist/commands/terminal/kill.js +36 -0
- package/dist/commands/terminal/ls.d.ts +11 -0
- package/dist/commands/terminal/ls.js +21 -0
- package/dist/commands/terminal/schema.d.ts +10 -0
- package/dist/commands/terminal/schema.js +17 -0
- package/dist/commands/terminal/send-keys.d.ts +7 -0
- package/dist/commands/terminal/send-keys.js +45 -0
- package/dist/commands/terminal/shared.d.ts +12 -0
- package/dist/commands/terminal/shared.js +62 -0
- package/dist/commands/workspace/archive.d.ts +12 -0
- package/dist/commands/workspace/archive.js +41 -0
- package/dist/commands/workspace/create.d.ts +49 -0
- package/dist/commands/workspace/create.js +114 -0
- package/dist/commands/workspace/index.d.ts +3 -0
- package/dist/commands/workspace/index.js +45 -0
- package/dist/commands/workspace/ls.d.ts +7 -0
- package/dist/commands/workspace/ls.js +28 -0
- package/dist/commands/workspace/rename.d.ts +22 -0
- package/dist/commands/workspace/rename.js +61 -0
- package/dist/commands/workspace/setup.d.ts +11 -0
- package/dist/commands/workspace/setup.js +41 -0
- package/dist/commands/workspace/shared.d.ts +12 -0
- package/dist/commands/workspace/shared.js +20 -0
- package/dist/commands/worktree/archive.d.ts +20 -0
- package/dist/commands/worktree/archive.js +104 -0
- package/dist/commands/worktree/create-input.d.ts +15 -0
- package/dist/commands/worktree/create-input.js +56 -0
- package/dist/commands/worktree/create.d.ts +11 -0
- package/dist/commands/worktree/create.js +58 -0
- package/dist/commands/worktree/index.d.ts +3 -0
- package/dist/commands/worktree/index.js +25 -0
- package/dist/commands/worktree/ls.d.ts +19 -0
- package/dist/commands/worktree/ls.js +97 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +6 -0
- package/dist/output/index.d.ts +45 -0
- package/dist/output/index.js +47 -0
- package/dist/output/json.d.ts +11 -0
- package/dist/output/json.js +37 -0
- package/dist/output/pairing.d.ts +8 -0
- package/dist/output/pairing.js +24 -0
- package/dist/output/quiet.d.ts +9 -0
- package/dist/output/quiet.js +22 -0
- package/dist/output/render.d.ts +15 -0
- package/dist/output/render.js +84 -0
- package/dist/output/table.d.ts +13 -0
- package/dist/output/table.js +135 -0
- package/dist/output/types.d.ts +73 -0
- package/dist/output/types.js +8 -0
- package/dist/output/with-output.d.ts +41 -0
- package/dist/output/with-output.js +85 -0
- package/dist/output/yaml.d.ts +11 -0
- package/dist/output/yaml.js +38 -0
- package/dist/run.d.ts +14 -0
- package/dist/run.js +40 -0
- package/dist/ssh/ssh-tunnel.d.ts +9 -0
- package/dist/ssh/ssh-tunnel.js +79 -0
- package/dist/utils/client-id.d.ts +2 -0
- package/dist/utils/client-id.js +37 -0
- package/dist/utils/client.d.ts +54 -0
- package/dist/utils/client.js +363 -0
- package/dist/utils/command-options.d.ts +7 -0
- package/dist/utils/command-options.js +25 -0
- package/dist/utils/duration.d.ts +7 -0
- package/dist/utils/duration.js +39 -0
- package/dist/utils/errors.d.ts +5 -0
- package/dist/utils/errors.js +10 -0
- package/dist/utils/paths.d.ts +12 -0
- package/dist/utils/paths.js +22 -0
- package/dist/utils/provider-model.d.ts +11 -0
- package/dist/utils/provider-model.js +49 -0
- package/dist/utils/timeline.d.ts +11 -0
- package/dist/utils/timeline.js +11 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +10 -0
- package/package.json +50 -0
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { getOrCreateServerId, findExecutable, execCommand } from "@camerontaylor/paseo-server";
|
|
3
|
+
import { connectToDaemon } from "../../utils/client.js";
|
|
4
|
+
import { resolveLocalDaemonState } from "./local-daemon.js";
|
|
5
|
+
import { resolveNodePathFromPid } from "./runtime-toolchain.js";
|
|
6
|
+
const DAEMON_STATUS_PROBE_TIMEOUT_MS = 1500;
|
|
7
|
+
const require = createRequire(import.meta.url);
|
|
8
|
+
function normalizeError(error) {
|
|
9
|
+
if (error instanceof Error) {
|
|
10
|
+
return error.message;
|
|
11
|
+
}
|
|
12
|
+
return String(error);
|
|
13
|
+
}
|
|
14
|
+
function shortenMessage(message, max = 120) {
|
|
15
|
+
const normalized = message.replace(/\s+/g, " ").trim();
|
|
16
|
+
if (normalized.length <= max) {
|
|
17
|
+
return normalized;
|
|
18
|
+
}
|
|
19
|
+
return `${normalized.slice(0, max - 3)}...`;
|
|
20
|
+
}
|
|
21
|
+
function appendNote(current, next) {
|
|
22
|
+
if (!next)
|
|
23
|
+
return current;
|
|
24
|
+
if (!current)
|
|
25
|
+
return next;
|
|
26
|
+
return `${current}; ${next}`;
|
|
27
|
+
}
|
|
28
|
+
function resolveCliVersion() {
|
|
29
|
+
try {
|
|
30
|
+
const packageJson = require("../../../package.json");
|
|
31
|
+
if (typeof packageJson.version === "string" && packageJson.version.trim().length > 0) {
|
|
32
|
+
return packageJson.version.trim();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// Fall through.
|
|
37
|
+
}
|
|
38
|
+
return "unknown";
|
|
39
|
+
}
|
|
40
|
+
function createStatusSchema(status) {
|
|
41
|
+
return {
|
|
42
|
+
idField: "key",
|
|
43
|
+
columns: [
|
|
44
|
+
{ header: "KEY", field: "key" },
|
|
45
|
+
{
|
|
46
|
+
header: "VALUE",
|
|
47
|
+
field: "value",
|
|
48
|
+
color: (_, item) => {
|
|
49
|
+
if (item.key === "Local Daemon") {
|
|
50
|
+
if (item.value === "running")
|
|
51
|
+
return "green";
|
|
52
|
+
if (item.value === "unresponsive")
|
|
53
|
+
return "yellow";
|
|
54
|
+
return "red";
|
|
55
|
+
}
|
|
56
|
+
if (item.key === "Connected Daemon") {
|
|
57
|
+
if (item.value === "reachable")
|
|
58
|
+
return "green";
|
|
59
|
+
if (item.value === "not_probed" || item.value === "auth_required")
|
|
60
|
+
return "yellow";
|
|
61
|
+
return "red";
|
|
62
|
+
}
|
|
63
|
+
if (item.key.startsWith(" ")) {
|
|
64
|
+
if (item.value === "not found" || item.value === "not found (daemon)")
|
|
65
|
+
return "red";
|
|
66
|
+
if (item.value.endsWith("(--version failed)"))
|
|
67
|
+
return "yellow";
|
|
68
|
+
return "green";
|
|
69
|
+
}
|
|
70
|
+
return undefined;
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
serialize: () => status,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function toStatusRows(status) {
|
|
78
|
+
const rows = [
|
|
79
|
+
{ key: "Server ID", value: status.serverId ?? "-" },
|
|
80
|
+
{ key: "Local Daemon", value: status.localDaemon },
|
|
81
|
+
{ key: "Connected Daemon", value: status.connectedDaemon },
|
|
82
|
+
{ key: "Home", value: status.home },
|
|
83
|
+
{ key: "Listen", value: status.listen },
|
|
84
|
+
{ key: "Relay", value: status.relay },
|
|
85
|
+
{ key: "Hostname", value: status.hostname ?? "-" },
|
|
86
|
+
{ key: "PID", value: status.pid === null ? "-" : String(status.pid) },
|
|
87
|
+
{ key: "Started", value: status.startedAt ?? "-" },
|
|
88
|
+
{ key: "Owner", value: status.owner ?? "-" },
|
|
89
|
+
{ key: "Logs", value: status.logPath },
|
|
90
|
+
{ key: "Daemon Node", value: status.daemonNode },
|
|
91
|
+
{ key: "CLI Node", value: status.cliNode },
|
|
92
|
+
{ key: "CLI", value: status.cliVersion },
|
|
93
|
+
{ key: "Daemon Version", value: status.daemonVersion ?? "-" },
|
|
94
|
+
];
|
|
95
|
+
if (status.note) {
|
|
96
|
+
rows.push({ key: "Note", value: status.note });
|
|
97
|
+
}
|
|
98
|
+
rows.push({ key: "", value: "" });
|
|
99
|
+
rows.push({ key: "Providers", value: "" });
|
|
100
|
+
for (const provider of status.providers) {
|
|
101
|
+
if (provider.source === "daemon") {
|
|
102
|
+
if (!provider.path) {
|
|
103
|
+
rows.push({ key: ` ${provider.label}`, value: "not found (daemon)" });
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
rows.push({ key: ` ${provider.label}`, value: `${provider.path} (daemon)` });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else if (!provider.path) {
|
|
110
|
+
rows.push({ key: ` ${provider.label}`, value: "not found" });
|
|
111
|
+
}
|
|
112
|
+
else if (!provider.version) {
|
|
113
|
+
rows.push({ key: ` ${provider.label}`, value: `${provider.path} (--version failed)` });
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
rows.push({ key: ` ${provider.label}`, value: `${provider.path} (${provider.version})` });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return rows;
|
|
120
|
+
}
|
|
121
|
+
const PROVIDER_BINARIES = [
|
|
122
|
+
{ label: "Claude", binary: "claude" },
|
|
123
|
+
{ label: "Codex", binary: "codex" },
|
|
124
|
+
{ label: "OpenCode", binary: "opencode" },
|
|
125
|
+
];
|
|
126
|
+
async function checkProviderBinary(binary) {
|
|
127
|
+
const binaryPath = await findExecutable(binary);
|
|
128
|
+
if (!binaryPath) {
|
|
129
|
+
return { path: null, version: null };
|
|
130
|
+
}
|
|
131
|
+
try {
|
|
132
|
+
const { stdout } = await execCommand(binaryPath, ["--version"], {
|
|
133
|
+
timeout: 5000,
|
|
134
|
+
});
|
|
135
|
+
return { path: binaryPath, version: stdout.trim() || null };
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
return { path: binaryPath, version: null };
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
async function checkProviderBinaries() {
|
|
142
|
+
const results = await Promise.all(PROVIDER_BINARIES.map(async ({ label, binary }) => {
|
|
143
|
+
const result = await checkProviderBinary(binary);
|
|
144
|
+
return Object.assign({ label }, result);
|
|
145
|
+
}));
|
|
146
|
+
return results;
|
|
147
|
+
}
|
|
148
|
+
function resolveOwnerLabel(uid, hostname) {
|
|
149
|
+
if (uid === undefined && !hostname) {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
const uidPart = uid === undefined ? "?" : String(uid);
|
|
153
|
+
const hostPart = hostname ?? "unknown-host";
|
|
154
|
+
return `${uidPart}@${hostPart}`;
|
|
155
|
+
}
|
|
156
|
+
function classifyDaemonAuthProbeFailure(error) {
|
|
157
|
+
if (!(error instanceof Error))
|
|
158
|
+
return null;
|
|
159
|
+
if (error.message === "Password required")
|
|
160
|
+
return "auth_required";
|
|
161
|
+
if (error.message === "Incorrect password")
|
|
162
|
+
return "auth_failed";
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
function describeDaemonAuthProbeFailure(host, failure) {
|
|
166
|
+
if (failure === "auth_required") {
|
|
167
|
+
return `Daemon is reachable at ${host} but requires a password. Set PASEO_PASSWORD and retry.`;
|
|
168
|
+
}
|
|
169
|
+
return `Daemon is reachable at ${host} but the supplied password was rejected. Check PASEO_PASSWORD and retry.`;
|
|
170
|
+
}
|
|
171
|
+
async function probeDaemonOverWebsocket(args) {
|
|
172
|
+
const { host, state } = args;
|
|
173
|
+
let client;
|
|
174
|
+
try {
|
|
175
|
+
client = await connectToDaemon({ host, timeout: 1500 });
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
const authFailure = classifyDaemonAuthProbeFailure(error);
|
|
179
|
+
if (authFailure) {
|
|
180
|
+
return {
|
|
181
|
+
connectedDaemon: authFailure,
|
|
182
|
+
note: describeDaemonAuthProbeFailure(host, authFailure),
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
if (state.running) {
|
|
186
|
+
return {
|
|
187
|
+
connectedDaemon: "unreachable",
|
|
188
|
+
localDaemonOverride: "unresponsive",
|
|
189
|
+
note: `Local daemon PID is running but websocket at ${host} is not reachable`,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
return { connectedDaemon: "unreachable" };
|
|
193
|
+
}
|
|
194
|
+
const daemonVersion = client.getLastServerInfoMessage()?.version ?? null;
|
|
195
|
+
try {
|
|
196
|
+
const statusPayload = await client.getDaemonStatus({
|
|
197
|
+
timeout: DAEMON_STATUS_PROBE_TIMEOUT_MS,
|
|
198
|
+
});
|
|
199
|
+
const labelMap = new Map(PROVIDER_BINARIES.map((p) => [p.binary, p.label]));
|
|
200
|
+
const daemonProviders = statusPayload.providers.map((p) => ({
|
|
201
|
+
label: labelMap.get(p.provider) ?? p.provider,
|
|
202
|
+
path: p.available ? "available" : null,
|
|
203
|
+
version: p.available ? null : (p.error ?? null),
|
|
204
|
+
source: "daemon",
|
|
205
|
+
}));
|
|
206
|
+
const relayStatus = statusPayload.relay == null
|
|
207
|
+
? undefined
|
|
208
|
+
: selectRelayStatus({
|
|
209
|
+
persisted: relayConfigFromLocalState(state),
|
|
210
|
+
live: statusPayload.relay,
|
|
211
|
+
});
|
|
212
|
+
if (!state.running) {
|
|
213
|
+
return {
|
|
214
|
+
connectedDaemon: "reachable",
|
|
215
|
+
daemonVersion: statusPayload.version ?? daemonVersion,
|
|
216
|
+
daemonNodeOverride: statusPayload.nodePath,
|
|
217
|
+
daemonProviders,
|
|
218
|
+
relayStatus,
|
|
219
|
+
note: state.pidInfo
|
|
220
|
+
? `Connected daemon is reachable at ${host} even though local daemon PID ${state.pidInfo.pid} is stale`
|
|
221
|
+
: `Connected daemon is reachable at ${host} but no local daemon PID file was found`,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
return {
|
|
225
|
+
connectedDaemon: "reachable",
|
|
226
|
+
daemonVersion: statusPayload.version ?? daemonVersion,
|
|
227
|
+
daemonNodeOverride: statusPayload.nodePath,
|
|
228
|
+
daemonProviders,
|
|
229
|
+
relayStatus,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
return {
|
|
234
|
+
connectedDaemon: "reachable",
|
|
235
|
+
daemonVersion,
|
|
236
|
+
note: state.running
|
|
237
|
+
? `Local daemon PID is running but daemon detail request to ${host} failed`
|
|
238
|
+
: `Connected daemon websocket is reachable at ${host} but daemon status request failed`,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
finally {
|
|
242
|
+
await client.close().catch(() => { });
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
function applyProbeToStatus(input) {
|
|
246
|
+
const { probe } = input;
|
|
247
|
+
return {
|
|
248
|
+
connectedDaemon: probe.connectedDaemon,
|
|
249
|
+
localDaemon: probe.localDaemonOverride ?? input.localDaemon,
|
|
250
|
+
daemonNode: probe.daemonNodeOverride ?? input.daemonNode,
|
|
251
|
+
daemonVersion: probe.daemonVersion !== undefined ? probe.daemonVersion : input.daemonVersion,
|
|
252
|
+
daemonProviders: probe.daemonProviders ?? input.daemonProviders,
|
|
253
|
+
relayStatus: probe.relayStatus ?? input.relayStatus,
|
|
254
|
+
note: probe.note ? appendNote(input.note, probe.note) : input.note,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
function resolveServerIdSafely(home) {
|
|
258
|
+
try {
|
|
259
|
+
return { serverId: getOrCreateServerId(home), error: null };
|
|
260
|
+
}
|
|
261
|
+
catch (error) {
|
|
262
|
+
return {
|
|
263
|
+
serverId: null,
|
|
264
|
+
error: `serverId unavailable: ${shortenMessage(normalizeError(error))}`,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
async function resolveDaemonNodeLabel(state) {
|
|
269
|
+
if (!state.running)
|
|
270
|
+
return "-";
|
|
271
|
+
if (!state.pidInfo?.pid)
|
|
272
|
+
return "unknown (no PID available)";
|
|
273
|
+
const fromPid = await resolveNodePathFromPid(state.pidInfo.pid);
|
|
274
|
+
return fromPid.nodePath ?? `unknown (${fromPid.error ?? "could not resolve from PID"})`;
|
|
275
|
+
}
|
|
276
|
+
function relayConfigFromLocalState(state) {
|
|
277
|
+
return {
|
|
278
|
+
enabled: state.relayEnabled,
|
|
279
|
+
endpoint: state.relayEndpoint,
|
|
280
|
+
publicEndpoint: state.relayEndpoint,
|
|
281
|
+
useTls: state.relayUseTls,
|
|
282
|
+
publicUseTls: state.relayPublicUseTls,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
export function selectRelayStatus(input) {
|
|
286
|
+
const relay = input.live ?? input.persisted;
|
|
287
|
+
if (!relay.enabled)
|
|
288
|
+
return "disabled";
|
|
289
|
+
const scheme = relay.publicUseTls ? "wss" : "ws";
|
|
290
|
+
return `${scheme}://${relay.publicEndpoint}`;
|
|
291
|
+
}
|
|
292
|
+
export async function runStatusCommand(options, _command) {
|
|
293
|
+
const home = typeof options.home === "string" ? options.home : undefined;
|
|
294
|
+
const state = resolveLocalDaemonState({ home });
|
|
295
|
+
const daemonTarget = state.listen.trim();
|
|
296
|
+
const owner = resolveOwnerLabel(state.pidInfo?.uid, state.pidInfo?.hostname);
|
|
297
|
+
let daemonNode = await resolveDaemonNodeLabel(state);
|
|
298
|
+
const cliNode = process.execPath;
|
|
299
|
+
let localDaemon = state.running ? "running" : "stopped";
|
|
300
|
+
let connectedDaemon = "not_probed";
|
|
301
|
+
let daemonVersion = null;
|
|
302
|
+
let daemonProviders;
|
|
303
|
+
let relayStatus = selectRelayStatus({ persisted: relayConfigFromLocalState(state) });
|
|
304
|
+
let note;
|
|
305
|
+
if (!state.running && state.stalePidFile && state.pidInfo) {
|
|
306
|
+
localDaemon = "stale_pid";
|
|
307
|
+
note = `Stale PID file found for PID ${state.pidInfo.pid}`;
|
|
308
|
+
}
|
|
309
|
+
if (daemonTarget) {
|
|
310
|
+
const probe = await probeDaemonOverWebsocket({ host: daemonTarget, state });
|
|
311
|
+
({
|
|
312
|
+
connectedDaemon,
|
|
313
|
+
localDaemon,
|
|
314
|
+
daemonNode,
|
|
315
|
+
daemonVersion,
|
|
316
|
+
daemonProviders,
|
|
317
|
+
relayStatus,
|
|
318
|
+
note,
|
|
319
|
+
} = applyProbeToStatus({
|
|
320
|
+
probe,
|
|
321
|
+
connectedDaemon,
|
|
322
|
+
localDaemon,
|
|
323
|
+
daemonNode,
|
|
324
|
+
daemonVersion,
|
|
325
|
+
daemonProviders,
|
|
326
|
+
relayStatus,
|
|
327
|
+
note,
|
|
328
|
+
}));
|
|
329
|
+
}
|
|
330
|
+
const cliVersion = resolveCliVersion();
|
|
331
|
+
const serverIdResult = resolveServerIdSafely(state.home);
|
|
332
|
+
const serverId = serverIdResult.serverId;
|
|
333
|
+
if (serverIdResult.error) {
|
|
334
|
+
note = appendNote(note, serverIdResult.error);
|
|
335
|
+
}
|
|
336
|
+
const providers = daemonProviders ?? (await checkProviderBinaries());
|
|
337
|
+
const daemonStatus = {
|
|
338
|
+
serverId,
|
|
339
|
+
localDaemon,
|
|
340
|
+
connectedDaemon,
|
|
341
|
+
home: state.home,
|
|
342
|
+
listen: state.listen,
|
|
343
|
+
relay: relayStatus,
|
|
344
|
+
hostname: state.pidInfo?.hostname ?? null,
|
|
345
|
+
pid: state.pidInfo?.pid ?? null,
|
|
346
|
+
startedAt: state.pidInfo?.startedAt ?? null,
|
|
347
|
+
owner,
|
|
348
|
+
logPath: state.logPath,
|
|
349
|
+
daemonNode,
|
|
350
|
+
cliNode,
|
|
351
|
+
cliVersion,
|
|
352
|
+
daemonVersion,
|
|
353
|
+
desktopManaged: state.pidInfo?.desktopManaged === true,
|
|
354
|
+
providers,
|
|
355
|
+
note,
|
|
356
|
+
};
|
|
357
|
+
return {
|
|
358
|
+
type: "list",
|
|
359
|
+
data: toStatusRows(daemonStatus),
|
|
360
|
+
schema: createStatusSchema(daemonStatus),
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Command } from "commander";
|
|
2
|
+
import type { CommandOptions, SingleResult } from "../../output/index.js";
|
|
3
|
+
interface StopResult {
|
|
4
|
+
action: "stopped" | "not_running";
|
|
5
|
+
home: string;
|
|
6
|
+
pid: string;
|
|
7
|
+
forced: boolean;
|
|
8
|
+
usedLifecycleRpc: boolean;
|
|
9
|
+
reason: "not_running" | "lifecycle_shutdown_rpc" | "owner_pid_signal" | "owner_pid_sigkill";
|
|
10
|
+
message: string;
|
|
11
|
+
}
|
|
12
|
+
export type StopCommandResult = SingleResult<StopResult>;
|
|
13
|
+
export declare function runStopCommand(options: CommandOptions, _command: Command): Promise<StopCommandResult>;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=stop.d.ts.map
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { stopLocalDaemon, DEFAULT_STOP_TIMEOUT_MS, DEFAULT_KILL_TIMEOUT_MS, } from "./local-daemon.js";
|
|
2
|
+
const stopResultSchema = {
|
|
3
|
+
idField: "action",
|
|
4
|
+
columns: [
|
|
5
|
+
{
|
|
6
|
+
header: "STATUS",
|
|
7
|
+
field: "action",
|
|
8
|
+
color: (value) => (value === "stopped" ? "green" : "yellow"),
|
|
9
|
+
},
|
|
10
|
+
{ header: "HOME", field: "home" },
|
|
11
|
+
{ header: "PID", field: "pid" },
|
|
12
|
+
{ header: "MESSAGE", field: "message" },
|
|
13
|
+
],
|
|
14
|
+
};
|
|
15
|
+
function parseSecondsOption(raw, fallbackMs, label) {
|
|
16
|
+
if (typeof raw !== "string" || raw.trim().length === 0) {
|
|
17
|
+
return fallbackMs;
|
|
18
|
+
}
|
|
19
|
+
const seconds = Number(raw);
|
|
20
|
+
if (!Number.isFinite(seconds) || seconds <= 0) {
|
|
21
|
+
const error = {
|
|
22
|
+
code: "INVALID_TIMEOUT",
|
|
23
|
+
message: `Invalid ${label} value: ${raw}`,
|
|
24
|
+
details: `${label} must be a positive number of seconds`,
|
|
25
|
+
};
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
return Math.ceil(seconds * 1000);
|
|
29
|
+
}
|
|
30
|
+
export async function runStopCommand(options, _command) {
|
|
31
|
+
const home = typeof options.home === "string" ? options.home : undefined;
|
|
32
|
+
const force = options.force === true;
|
|
33
|
+
const timeoutMs = parseSecondsOption(options.timeout, DEFAULT_STOP_TIMEOUT_MS, "timeout");
|
|
34
|
+
const killTimeoutMs = parseSecondsOption(options.killTimeout, DEFAULT_KILL_TIMEOUT_MS, "kill-timeout");
|
|
35
|
+
try {
|
|
36
|
+
const result = await stopLocalDaemon({ home, force, timeoutMs, killTimeoutMs });
|
|
37
|
+
return {
|
|
38
|
+
type: "single",
|
|
39
|
+
data: {
|
|
40
|
+
action: result.action,
|
|
41
|
+
home: result.home,
|
|
42
|
+
pid: result.pid === null ? "-" : String(result.pid),
|
|
43
|
+
forced: result.forced,
|
|
44
|
+
usedLifecycleRpc: result.usedLifecycleRpc,
|
|
45
|
+
reason: result.reason,
|
|
46
|
+
message: result.message,
|
|
47
|
+
},
|
|
48
|
+
schema: stopResultSchema,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
53
|
+
const error = {
|
|
54
|
+
code: "STOP_FAILED",
|
|
55
|
+
message: `Failed to stop local daemon: ${message}`,
|
|
56
|
+
};
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=stop.js.map
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { withOutput } from "../../output/index.js";
|
|
3
|
+
import { addJsonAndDaemonHostOptions } from "../../utils/command-options.js";
|
|
4
|
+
import { parseDuration } from "../../utils/duration.js";
|
|
5
|
+
import { connectScheduleClient, toScheduleCommandError, toScheduleRow, } from "../schedule/shared.js";
|
|
6
|
+
import { scheduleSchema } from "../schedule/schema.js";
|
|
7
|
+
const heartbeatDeleteSchema = {
|
|
8
|
+
idField: "id",
|
|
9
|
+
columns: [
|
|
10
|
+
{ header: "ID", field: "id" },
|
|
11
|
+
{ header: "STATUS", field: "status" },
|
|
12
|
+
],
|
|
13
|
+
};
|
|
14
|
+
function requireCallerAgentId() {
|
|
15
|
+
const agentId = process.env.PASEO_AGENT_ID?.trim();
|
|
16
|
+
if (!agentId) {
|
|
17
|
+
throw new Error("Heartbeat commands must run inside a Paseo agent");
|
|
18
|
+
}
|
|
19
|
+
return agentId;
|
|
20
|
+
}
|
|
21
|
+
async function requireOwnedHeartbeat(client, id, agentId) {
|
|
22
|
+
const payload = await client.scheduleInspect({ id });
|
|
23
|
+
if (payload.error || !payload.schedule) {
|
|
24
|
+
throw new Error(payload.error ?? `Heartbeat not found: ${id}`);
|
|
25
|
+
}
|
|
26
|
+
if (payload.schedule.target.type !== "agent" || payload.schedule.target.agentId !== agentId) {
|
|
27
|
+
throw new Error(`Heartbeat ${id} does not belong to agent ${agentId}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async function runCreateHeartbeat(prompt, options, _command) {
|
|
31
|
+
const agentId = requireCallerAgentId();
|
|
32
|
+
const cron = options.cron?.trim();
|
|
33
|
+
if (!cron) {
|
|
34
|
+
throw new Error("--cron is required");
|
|
35
|
+
}
|
|
36
|
+
const { client } = await connectScheduleClient(options.host);
|
|
37
|
+
try {
|
|
38
|
+
const maxRuns = options.maxRuns ? Number.parseInt(options.maxRuns, 10) : undefined;
|
|
39
|
+
if (maxRuns !== undefined && (!Number.isSafeInteger(maxRuns) || maxRuns <= 0)) {
|
|
40
|
+
throw new Error("--max-runs must be a positive integer");
|
|
41
|
+
}
|
|
42
|
+
const payload = await client.scheduleCreate({
|
|
43
|
+
prompt: prompt.trim(),
|
|
44
|
+
cadence: {
|
|
45
|
+
type: "cron",
|
|
46
|
+
expression: cron,
|
|
47
|
+
...(options.timezone?.trim() ? { timezone: options.timezone.trim() } : {}),
|
|
48
|
+
},
|
|
49
|
+
target: { type: "agent", agentId },
|
|
50
|
+
...(options.name?.trim() ? { name: options.name.trim() } : {}),
|
|
51
|
+
...(maxRuns ? { maxRuns } : {}),
|
|
52
|
+
...(options.expiresIn
|
|
53
|
+
? { expiresAt: new Date(Date.now() + parseDuration(options.expiresIn)).toISOString() }
|
|
54
|
+
: {}),
|
|
55
|
+
});
|
|
56
|
+
if (payload.error || !payload.schedule) {
|
|
57
|
+
throw new Error(payload.error ?? "Heartbeat creation failed");
|
|
58
|
+
}
|
|
59
|
+
return { type: "single", data: toScheduleRow(payload.schedule), schema: scheduleSchema };
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
throw toScheduleCommandError("HEARTBEAT_CREATE_FAILED", "create heartbeat", error);
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
await client.close().catch(() => undefined);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async function runUpdateHeartbeat(id, options, _command) {
|
|
69
|
+
const agentId = requireCallerAgentId();
|
|
70
|
+
const cron = options.cron?.trim();
|
|
71
|
+
if (!cron) {
|
|
72
|
+
throw new Error("--cron is required");
|
|
73
|
+
}
|
|
74
|
+
const { client } = await connectScheduleClient(options.host);
|
|
75
|
+
try {
|
|
76
|
+
await requireOwnedHeartbeat(client, id, agentId);
|
|
77
|
+
const payload = await client.scheduleUpdate({
|
|
78
|
+
id,
|
|
79
|
+
cadence: {
|
|
80
|
+
type: "cron",
|
|
81
|
+
expression: cron,
|
|
82
|
+
...(options.timezone?.trim() ? { timezone: options.timezone.trim() } : {}),
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
if (payload.error || !payload.schedule) {
|
|
86
|
+
throw new Error(payload.error ?? `Heartbeat update failed: ${id}`);
|
|
87
|
+
}
|
|
88
|
+
return { type: "single", data: toScheduleRow(payload.schedule), schema: scheduleSchema };
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
throw toScheduleCommandError("HEARTBEAT_UPDATE_FAILED", "update heartbeat", error);
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
await client.close().catch(() => undefined);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
async function runDeleteHeartbeat(id, options, _command) {
|
|
98
|
+
const agentId = requireCallerAgentId();
|
|
99
|
+
const { client } = await connectScheduleClient(options.host);
|
|
100
|
+
try {
|
|
101
|
+
await requireOwnedHeartbeat(client, id, agentId);
|
|
102
|
+
const payload = await client.scheduleDelete({ id });
|
|
103
|
+
if (payload.error) {
|
|
104
|
+
throw new Error(payload.error);
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
type: "single",
|
|
108
|
+
data: { id: payload.scheduleId, status: "deleted" },
|
|
109
|
+
schema: heartbeatDeleteSchema,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
throw toScheduleCommandError("HEARTBEAT_DELETE_FAILED", "delete heartbeat", error);
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
await client.close().catch(() => undefined);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
export function createHeartbeatCommand() {
|
|
120
|
+
const heartbeat = new Command("heartbeat").description("Manage this agent's heartbeats");
|
|
121
|
+
addJsonAndDaemonHostOptions(heartbeat
|
|
122
|
+
.command("create")
|
|
123
|
+
.description("Create a recurring prompt for this agent")
|
|
124
|
+
.argument("<prompt>", "Prompt to send")
|
|
125
|
+
.requiredOption("--cron <expr>", "Five-field cron cadence")
|
|
126
|
+
.option("--timezone <iana>", "IANA time zone")
|
|
127
|
+
.option("--name <name>", "Heartbeat name")
|
|
128
|
+
.option("--max-runs <n>", "Maximum number of runs")
|
|
129
|
+
.option("--expires-in <duration>", "Time to live")).action(withOutput(runCreateHeartbeat));
|
|
130
|
+
addJsonAndDaemonHostOptions(heartbeat
|
|
131
|
+
.command("update")
|
|
132
|
+
.description("Change a heartbeat cron cadence")
|
|
133
|
+
.argument("<id>", "Heartbeat ID")
|
|
134
|
+
.requiredOption("--cron <expr>", "Five-field cron cadence")
|
|
135
|
+
.option("--timezone <iana>", "IANA time zone")).action(withOutput(runUpdateHeartbeat));
|
|
136
|
+
addJsonAndDaemonHostOptions(heartbeat.command("delete").description("Delete a heartbeat").argument("<id>", "Heartbeat ID")).action(withOutput(runDeleteHeartbeat));
|
|
137
|
+
return heartbeat;
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
interface HookEnvironment {
|
|
3
|
+
PASEO_TERMINAL_ID?: string;
|
|
4
|
+
PASEO_ACTIVITY_TOKEN?: string;
|
|
5
|
+
PASEO_TERMINAL_ACTIVITY_URL?: string;
|
|
6
|
+
}
|
|
7
|
+
interface HookInput {
|
|
8
|
+
[Symbol.asyncIterator](): AsyncIterator<string | Buffer>;
|
|
9
|
+
isTTY?: boolean;
|
|
10
|
+
}
|
|
11
|
+
interface HooksRuntime {
|
|
12
|
+
env: HookEnvironment;
|
|
13
|
+
input: HookInput;
|
|
14
|
+
fetch: typeof fetch;
|
|
15
|
+
}
|
|
16
|
+
export declare function createHooksCommand(): Command;
|
|
17
|
+
export declare function runHooksCommand(agent: string, event: string, runtime?: HooksRuntime): Promise<void>;
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=hooks.d.ts.map
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { resolveHookActivity } from "@camerontaylor/paseo-server/agent-hooks";
|
|
3
|
+
export function createHooksCommand() {
|
|
4
|
+
return new Command("hooks")
|
|
5
|
+
.description("Record agent hook activity")
|
|
6
|
+
.argument("<agent>", "Agent hook source")
|
|
7
|
+
.argument("<event>", "Agent hook event")
|
|
8
|
+
.action((agent, event) => runHooksCommand(agent, event));
|
|
9
|
+
}
|
|
10
|
+
export async function runHooksCommand(agent, event, runtime = {
|
|
11
|
+
env: process.env,
|
|
12
|
+
input: process.stdin,
|
|
13
|
+
fetch,
|
|
14
|
+
}) {
|
|
15
|
+
const target = resolveTarget(runtime.env);
|
|
16
|
+
if (!target)
|
|
17
|
+
return;
|
|
18
|
+
const state = await resolveHookActivity({
|
|
19
|
+
provider: agent,
|
|
20
|
+
event,
|
|
21
|
+
input: {
|
|
22
|
+
isTTY: runtime.input.isTTY,
|
|
23
|
+
read: () => readInput(runtime.input),
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
if (!state)
|
|
27
|
+
return;
|
|
28
|
+
await postActivity(target, state, runtime.fetch);
|
|
29
|
+
}
|
|
30
|
+
function resolveTarget(env) {
|
|
31
|
+
const terminalId = env.PASEO_TERMINAL_ID;
|
|
32
|
+
const token = env.PASEO_ACTIVITY_TOKEN;
|
|
33
|
+
const url = env.PASEO_TERMINAL_ACTIVITY_URL;
|
|
34
|
+
if (!terminalId || !token || !url)
|
|
35
|
+
return null;
|
|
36
|
+
return { terminalId, token, url };
|
|
37
|
+
}
|
|
38
|
+
async function readInput(input) {
|
|
39
|
+
const iterator = input[Symbol.asyncIterator]();
|
|
40
|
+
const chunks = [];
|
|
41
|
+
while (true) {
|
|
42
|
+
const next = await withTimeout(iterator.next(), 100);
|
|
43
|
+
if (!next) {
|
|
44
|
+
await iterator.return?.();
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
if (next.done)
|
|
48
|
+
return chunks.join("");
|
|
49
|
+
chunks.push(String(next.value));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async function withTimeout(promise, ms) {
|
|
53
|
+
let timeout;
|
|
54
|
+
try {
|
|
55
|
+
return await Promise.race([
|
|
56
|
+
promise,
|
|
57
|
+
new Promise((resolve) => {
|
|
58
|
+
timeout = setTimeout(() => resolve(null), ms);
|
|
59
|
+
}),
|
|
60
|
+
]);
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
if (timeout)
|
|
64
|
+
clearTimeout(timeout);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async function postActivity(target, state, send) {
|
|
68
|
+
const controller = new AbortController();
|
|
69
|
+
const timeout = setTimeout(() => controller.abort(), 500);
|
|
70
|
+
try {
|
|
71
|
+
await send(target.url, {
|
|
72
|
+
method: "POST",
|
|
73
|
+
headers: { "content-type": "application/json" },
|
|
74
|
+
body: JSON.stringify({
|
|
75
|
+
terminalId: target.terminalId,
|
|
76
|
+
token: target.token,
|
|
77
|
+
state,
|
|
78
|
+
}),
|
|
79
|
+
signal: controller.signal,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
finally {
|
|
86
|
+
clearTimeout(timeout);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=hooks.js.map
|