gsd-pi 2.57.0-dev.f22a903 → 2.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/resources/extensions/gsd/auto.js +4 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/required-server-files.json +4 -4
- package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
- package/dist/web/standalone/.next/server/chunks/2229.js +1 -1
- package/dist/web/standalone/.next/server/chunks/7471.js +3 -3
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware.js +2 -2
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-f2a7482d42a5614b.js → page-2f24283c162b6ab3.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/{layout-a16c7a7ecdf0c2cf.js → layout-9ecfd95f343793f0.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/page-62be3b5fa91e4c8f.js +1 -0
- package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +1 -0
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
- package/dist/web/standalone/server.js +1 -1
- package/package.json +1 -1
- package/packages/daemon/src/cli.ts +49 -0
- package/packages/daemon/src/daemon.test.ts +104 -1
- package/packages/daemon/src/daemon.ts +23 -0
- package/packages/daemon/src/discord-bot.ts +62 -3
- package/packages/daemon/src/index.ts +9 -0
- package/packages/daemon/src/launchd.test.ts +356 -0
- package/packages/daemon/src/launchd.ts +242 -0
- package/packages/pi-coding-agent/package.json +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/gsd/auto.ts +5 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +18 -0
- package/dist/web/standalone/.next/static/chunks/app/page-0c485498795110d6.js +0 -1
- package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +0 -1
- /package/dist/web/standalone/.next/static/{OS7_z6QaL6uqp8q5pjHSJ → IoheXIe-5DH7ieX8AUo8U}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{OS7_z6QaL6uqp8q5pjHSJ → IoheXIe-5DH7ieX8AUo8U}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { writeFileSync, unlinkSync, existsSync, chmodSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { execSync } from 'node:child_process';
|
|
5
|
+
import { dirname } from 'node:path';
|
|
6
|
+
|
|
7
|
+
// --------------- types ---------------
|
|
8
|
+
|
|
9
|
+
export interface PlistOptions {
|
|
10
|
+
/** Absolute path to the Node.js binary */
|
|
11
|
+
nodePath: string;
|
|
12
|
+
/** Absolute path to the daemon script (cli.js) */
|
|
13
|
+
scriptPath: string;
|
|
14
|
+
/** Absolute path to the config file */
|
|
15
|
+
configPath: string;
|
|
16
|
+
/** Directory to use as WorkingDirectory in the plist (defaults to homedir) */
|
|
17
|
+
workingDirectory?: string;
|
|
18
|
+
/** Override stdout log path */
|
|
19
|
+
stdoutPath?: string;
|
|
20
|
+
/** Override stderr log path */
|
|
21
|
+
stderrPath?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface LaunchdStatus {
|
|
25
|
+
/** Whether the daemon is registered with launchd */
|
|
26
|
+
registered: boolean;
|
|
27
|
+
/** PID if currently running, null otherwise */
|
|
28
|
+
pid: number | null;
|
|
29
|
+
/** Last exit status code, null if never exited or not available */
|
|
30
|
+
lastExitStatus: number | null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type RunCommandFn = (cmd: string) => string;
|
|
34
|
+
|
|
35
|
+
// --------------- constants ---------------
|
|
36
|
+
|
|
37
|
+
const LABEL = 'com.gsd.daemon';
|
|
38
|
+
const PLIST_FILENAME = `${LABEL}.plist`;
|
|
39
|
+
|
|
40
|
+
// --------------- helpers ---------------
|
|
41
|
+
|
|
42
|
+
/** Escape special XML characters in a string. */
|
|
43
|
+
export function escapeXml(str: string): string {
|
|
44
|
+
return str
|
|
45
|
+
.replace(/&/g, '&')
|
|
46
|
+
.replace(/</g, '<')
|
|
47
|
+
.replace(/>/g, '>')
|
|
48
|
+
.replace(/"/g, '"')
|
|
49
|
+
.replace(/'/g, ''');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Return the canonical plist path under ~/Library/LaunchAgents/. */
|
|
53
|
+
export function getPlistPath(): string {
|
|
54
|
+
return resolve(homedir(), 'Library', 'LaunchAgents', PLIST_FILENAME);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Build the NVM-aware PATH string.
|
|
59
|
+
* Includes the directory containing the Node binary so that launchd can find node
|
|
60
|
+
* even when launched outside a shell session (where NVM isn't sourced).
|
|
61
|
+
*/
|
|
62
|
+
function buildEnvPath(nodePath: string): string {
|
|
63
|
+
const nodeBinDir = dirname(nodePath);
|
|
64
|
+
// Keep system essentials and prepend the node binary's directory
|
|
65
|
+
return `${nodeBinDir}:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// --------------- plist generation ---------------
|
|
69
|
+
|
|
70
|
+
/** Generate valid launchd plist XML for the GSD daemon. */
|
|
71
|
+
export function generatePlist(opts: PlistOptions): string {
|
|
72
|
+
const home = homedir();
|
|
73
|
+
const workDir = opts.workingDirectory ?? home;
|
|
74
|
+
const stdoutPath = opts.stdoutPath ?? resolve(home, '.gsd', 'daemon-stdout.log');
|
|
75
|
+
const stderrPath = opts.stderrPath ?? resolve(home, '.gsd', 'daemon-stderr.log');
|
|
76
|
+
const envPath = buildEnvPath(opts.nodePath);
|
|
77
|
+
|
|
78
|
+
// Forward ANTHROPIC_API_KEY so the orchestrator LLM can authenticate.
|
|
79
|
+
// Captured at install time from the current process environment.
|
|
80
|
+
const anthropicKey = process.env.ANTHROPIC_API_KEY;
|
|
81
|
+
const anthropicKeyXml = anthropicKey
|
|
82
|
+
? `\n\t\t<key>ANTHROPIC_API_KEY</key>\n\t\t<string>${escapeXml(anthropicKey)}</string>`
|
|
83
|
+
: '';
|
|
84
|
+
|
|
85
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
86
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
87
|
+
<plist version="1.0">
|
|
88
|
+
<dict>
|
|
89
|
+
\t<key>Label</key>
|
|
90
|
+
\t<string>${escapeXml(LABEL)}</string>
|
|
91
|
+
|
|
92
|
+
\t<key>ProgramArguments</key>
|
|
93
|
+
\t<array>
|
|
94
|
+
\t\t<string>${escapeXml(opts.nodePath)}</string>
|
|
95
|
+
\t\t<string>${escapeXml(opts.scriptPath)}</string>
|
|
96
|
+
\t\t<string>--config</string>
|
|
97
|
+
\t\t<string>${escapeXml(opts.configPath)}</string>
|
|
98
|
+
\t</array>
|
|
99
|
+
|
|
100
|
+
\t<key>KeepAlive</key>
|
|
101
|
+
\t<dict>
|
|
102
|
+
\t\t<key>SuccessfulExit</key>
|
|
103
|
+
\t\t<false/>
|
|
104
|
+
\t</dict>
|
|
105
|
+
|
|
106
|
+
\t<key>RunAtLoad</key>
|
|
107
|
+
\t<true/>
|
|
108
|
+
|
|
109
|
+
\t<key>EnvironmentVariables</key>
|
|
110
|
+
\t<dict>
|
|
111
|
+
\t\t<key>PATH</key>
|
|
112
|
+
\t\t<string>${escapeXml(envPath)}</string>
|
|
113
|
+
\t\t<key>HOME</key>
|
|
114
|
+
\t\t<string>${escapeXml(home)}</string>${anthropicKeyXml}
|
|
115
|
+
\t</dict>
|
|
116
|
+
|
|
117
|
+
\t<key>WorkingDirectory</key>
|
|
118
|
+
\t<string>${escapeXml(workDir)}</string>
|
|
119
|
+
|
|
120
|
+
\t<key>StandardOutPath</key>
|
|
121
|
+
\t<string>${escapeXml(stdoutPath)}</string>
|
|
122
|
+
|
|
123
|
+
\t<key>StandardErrorPath</key>
|
|
124
|
+
\t<string>${escapeXml(stderrPath)}</string>
|
|
125
|
+
</dict>
|
|
126
|
+
</plist>
|
|
127
|
+
`;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// --------------- install / uninstall / status ---------------
|
|
131
|
+
|
|
132
|
+
/** Default runCommand using execSync. */
|
|
133
|
+
function defaultRunCommand(cmd: string): string {
|
|
134
|
+
return execSync(cmd, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Install the launchd agent: write plist and load it.
|
|
139
|
+
* Idempotent — unloads first if already loaded.
|
|
140
|
+
*/
|
|
141
|
+
export function install(
|
|
142
|
+
opts: PlistOptions,
|
|
143
|
+
runCommand: RunCommandFn = defaultRunCommand,
|
|
144
|
+
): void {
|
|
145
|
+
const plistPath = getPlistPath();
|
|
146
|
+
const xml = generatePlist(opts);
|
|
147
|
+
|
|
148
|
+
// Unload first if already present (ignore errors)
|
|
149
|
+
if (existsSync(plistPath)) {
|
|
150
|
+
try {
|
|
151
|
+
runCommand(`launchctl unload ${plistPath}`);
|
|
152
|
+
} catch {
|
|
153
|
+
// already unloaded — fine
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
writeFileSync(plistPath, xml, 'utf-8');
|
|
158
|
+
chmodSync(plistPath, 0o644);
|
|
159
|
+
|
|
160
|
+
runCommand(`launchctl load ${plistPath}`);
|
|
161
|
+
|
|
162
|
+
// Verify it loaded
|
|
163
|
+
try {
|
|
164
|
+
runCommand(`launchctl list ${LABEL}`);
|
|
165
|
+
} catch {
|
|
166
|
+
throw new Error(
|
|
167
|
+
`Plist was written to ${plistPath} and launchctl load succeeded, but launchctl list ${LABEL} failed. The agent may not have started.`,
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Uninstall the launchd agent: unload and remove plist.
|
|
174
|
+
* Graceful — does not throw if already uninstalled.
|
|
175
|
+
*/
|
|
176
|
+
export function uninstall(runCommand: RunCommandFn = defaultRunCommand): void {
|
|
177
|
+
const plistPath = getPlistPath();
|
|
178
|
+
|
|
179
|
+
if (existsSync(plistPath)) {
|
|
180
|
+
try {
|
|
181
|
+
runCommand(`launchctl unload ${plistPath}`);
|
|
182
|
+
} catch {
|
|
183
|
+
// already unloaded — that's fine
|
|
184
|
+
}
|
|
185
|
+
unlinkSync(plistPath);
|
|
186
|
+
}
|
|
187
|
+
// If plist doesn't exist, nothing to do — already uninstalled
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Query launchd for the daemon's status.
|
|
192
|
+
* Returns structured information about registration, PID, and last exit code.
|
|
193
|
+
*
|
|
194
|
+
* Handles two launchctl output formats:
|
|
195
|
+
* 1. Tabular: "PID\tStatus\tLabel" (older macOS)
|
|
196
|
+
* 2. JSON-style dict: `"PID" = 1234;` / `"LastExitStatus" = 0;` (newer macOS)
|
|
197
|
+
*/
|
|
198
|
+
export function status(runCommand: RunCommandFn = defaultRunCommand): LaunchdStatus {
|
|
199
|
+
try {
|
|
200
|
+
const output = runCommand(`launchctl list ${LABEL}`);
|
|
201
|
+
|
|
202
|
+
// --- Try tabular format first ---
|
|
203
|
+
const lines = output.trim().split('\n');
|
|
204
|
+
for (const line of lines) {
|
|
205
|
+
const parts = line.trim().split(/\t+/);
|
|
206
|
+
if (parts.length >= 3 && parts[2] === LABEL) {
|
|
207
|
+
const pidStr = parts[0];
|
|
208
|
+
const statusStr = parts[1];
|
|
209
|
+
|
|
210
|
+
const pid = pidStr === '-' ? null : parseInt(pidStr, 10);
|
|
211
|
+
const lastExitStatus = statusStr != null ? parseInt(statusStr, 10) : null;
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
registered: true,
|
|
215
|
+
pid: Number.isNaN(pid!) ? null : pid,
|
|
216
|
+
lastExitStatus: Number.isNaN(lastExitStatus!) ? null : lastExitStatus,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// --- Try JSON-style dict format ---
|
|
222
|
+
// Matches: "PID" = 1234; or "LastExitStatus" = 0;
|
|
223
|
+
const pidMatch = output.match(/"PID"\s*=\s*(\d+)\s*;/);
|
|
224
|
+
const exitMatch = output.match(/"LastExitStatus"\s*=\s*(\d+)\s*;/);
|
|
225
|
+
|
|
226
|
+
if (pidMatch || exitMatch) {
|
|
227
|
+
const pid = pidMatch ? parseInt(pidMatch[1], 10) : null;
|
|
228
|
+
const lastExitStatus = exitMatch ? parseInt(exitMatch[1], 10) : null;
|
|
229
|
+
return {
|
|
230
|
+
registered: true,
|
|
231
|
+
pid: Number.isNaN(pid!) ? null : pid,
|
|
232
|
+
lastExitStatus: Number.isNaN(lastExitStatus!) ? null : lastExitStatus,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Label resolved (no error) but no parseable output — still registered
|
|
237
|
+
return { registered: true, pid: null, lastExitStatus: null };
|
|
238
|
+
} catch {
|
|
239
|
+
// launchctl list exits non-zero when the label isn't found
|
|
240
|
+
return { registered: false, pid: null, lastExitStatus: null };
|
|
241
|
+
}
|
|
242
|
+
}
|
package/pkg/package.json
CHANGED
|
@@ -1061,6 +1061,11 @@ export async function startAuto(
|
|
|
1061
1061
|
verboseMode: boolean,
|
|
1062
1062
|
options?: { step?: boolean },
|
|
1063
1063
|
): Promise<void> {
|
|
1064
|
+
if (s.active) {
|
|
1065
|
+
debugLog("startAuto", { phase: "already-active", skipping: true });
|
|
1066
|
+
return;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1064
1069
|
const requestedStepMode = options?.step ?? false;
|
|
1065
1070
|
|
|
1066
1071
|
// Escape stale worktree cwd from a previous milestone (#608).
|
|
@@ -1233,6 +1233,24 @@ test("startAuto calls selfHealRuntimeRecords before autoLoop (#1727)", { skip: "
|
|
|
1233
1233
|
);
|
|
1234
1234
|
});
|
|
1235
1235
|
|
|
1236
|
+
test("startAuto guards against concurrent invocation (#2923)", () => {
|
|
1237
|
+
const src = readFileSync(
|
|
1238
|
+
resolve(import.meta.dirname, "..", "auto.ts"),
|
|
1239
|
+
"utf-8",
|
|
1240
|
+
);
|
|
1241
|
+
const fnIdx = src.indexOf("export async function startAuto");
|
|
1242
|
+
assert.ok(fnIdx > -1, "startAuto must exist in auto.ts");
|
|
1243
|
+
// The guard must appear before any other logic in the function body
|
|
1244
|
+
const fnBody = src.slice(fnIdx, fnIdx + 500);
|
|
1245
|
+
const activeGuard = fnBody.indexOf("if (s.active)");
|
|
1246
|
+
assert.ok(activeGuard > -1, "startAuto must check s.active to prevent concurrent auto-loops");
|
|
1247
|
+
const returnIdx = fnBody.indexOf("return;", activeGuard);
|
|
1248
|
+
assert.ok(
|
|
1249
|
+
returnIdx > -1 && returnIdx < activeGuard + 120,
|
|
1250
|
+
"s.active guard must early-return to prevent a second concurrent loop",
|
|
1251
|
+
);
|
|
1252
|
+
});
|
|
1253
|
+
|
|
1236
1254
|
test("agent_end handler calls resolveAgentEnd (not handleAgentEnd)", () => {
|
|
1237
1255
|
const hooksSrc = readFileSync(
|
|
1238
1256
|
resolve(import.meta.dirname, "..", "bootstrap", "register-hooks.ts"),
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[8974],{2600:(e,t,n)=>{Promise.resolve().then(n.bind(n,66919))},5214:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"workAsyncStorage",{enumerable:!0,get:function(){return r.workAsyncStorageInstance}});let r=n(17828)},17828:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"workAsyncStorageInstance",{enumerable:!0,get:function(){return r}});let r=(0,n(64054).createAsyncLocalStorage)()},21957:(e,t,n)=>{"use strict";function r({moduleIds:e}){return null}Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"PreloadChunks",{enumerable:!0,get:function(){return r}}),n(95155),n(47650),n(5214),n(2451),n(53887)},37206:(e,t,n)=>{"use strict";n.d(t,{default:()=>u.a});var r=n(75707),u=n.n(r)},41112:(e,t,n)=>{"use strict";function r({reason:e,children:t}){return t}Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"BailoutToCSR",{enumerable:!0,get:function(){return r}}),n(1980)},64054:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n={bindSnapshot:function(){return s},createAsyncLocalStorage:function(){return a},createSnapshot:function(){return i}};for(var r in n)Object.defineProperty(t,r,{enumerable:!0,get:n[r]});let u=Object.defineProperty(Error("Invariant: AsyncLocalStorage accessed in runtime where it is not available"),"__NEXT_ERROR_CODE",{value:"E504",enumerable:!1,configurable:!0});class l{disable(){throw u}getStore(){}run(){throw u}exit(){throw u}enterWith(){throw u}static bind(e){return e}}let o="u">typeof globalThis&&globalThis.AsyncLocalStorage;function a(){return o?new o:new l}function s(e){return o?o.bind(e):l.bind(e)}function i(){return o?o.snapshot():function(e,...t){return e(...t)}}},66919:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>l});var r=n(95155);let u=(0,n(37206).default)(()=>Promise.all([n.e(1838),n.e(6079),n.e(4986),n.e(2008),n.e(6502)]).then(n.bind(n,46502)).then(e=>e.GSDAppShell),{loadableGenerated:{webpack:()=>[46502]},ssr:!1,loading:()=>(0,r.jsx)("div",{className:"flex h-screen items-center justify-center bg-background text-sm text-muted-foreground",children:"Loading workspace…"})});function l(){return(0,r.jsx)(u,{})}},68635:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return s}});let r=n(95155),u=n(12115),l=n(41112);function o(e){return{default:e&&"default"in e?e.default:e}}n(21957);let a={loader:()=>Promise.resolve(o(()=>null)),loading:null,ssr:!0},s=function(e){let t={...a,...e},n=(0,u.lazy)(()=>t.loader().then(o)),s=t.loading;function i(e){let o=s?(0,r.jsx)(s,{isLoading:!0,pastDelay:!0,error:null}):null,a=!t.ssr||!!t.loading,i=a?u.Suspense:u.Fragment,c=t.ssr?(0,r.jsxs)(r.Fragment,{children:[null,(0,r.jsx)(n,{...e})]}):(0,r.jsx)(l.BailoutToCSR,{reason:"next/dynamic",children:(0,r.jsx)(n,{...e})});return(0,r.jsx)(i,{...a?{fallback:o}:{},children:c})}return i.displayName="LoadableComponent",i}},75707:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return u}});let r=n(73623)._(n(68635));function u(e,t){let n={};"function"==typeof e&&(n.loader=e);let u={...n,...t};return(0,r.default)({...u,modules:u.loadableGenerated?.modules})}("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)}},e=>{e.O(0,[8441,3794,7358],()=>e(e.s=2600)),_N_E=e.O()}]);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[7358],{19393:()=>{},55548:(e,s,n)=>{Promise.resolve().then(n.t.bind(n,27123,23)),Promise.resolve().then(n.t.bind(n,61304,23)),Promise.resolve().then(n.t.bind(n,78616,23)),Promise.resolve().then(n.t.bind(n,64777,23)),Promise.resolve().then(n.t.bind(n,57121,23)),Promise.resolve().then(n.t.bind(n,74581,23)),Promise.resolve().then(n.t.bind(n,90484,23)),Promise.resolve().then(n.bind(n,86869))}},e=>{var s=s=>e(e.s=s);e.O(0,[8441,3794],()=>(s(83861),s(55548))),_N_E=e.O()}]);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[9337],{43946:(e,s,_)=>{Promise.resolve().then(_.t.bind(_,27123,23))}},e=>{e.O(0,[8441,3794,7358],()=>e(e.s=43946)),_N_E=e.O()}]);
|
|
File without changes
|
|
File without changes
|