@exaudeus/workrail 3.32.0 → 3.34.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/cli/commands/index.d.ts +1 -0
- package/dist/cli/commands/index.js +3 -1
- package/dist/cli/commands/worktrain-await.js +11 -9
- package/dist/cli/commands/worktrain-daemon-install.d.ts +35 -0
- package/dist/cli/commands/worktrain-daemon-install.js +291 -0
- package/dist/cli/commands/worktrain-daemon.d.ts +31 -0
- package/dist/cli/commands/worktrain-daemon.js +272 -0
- package/dist/cli/commands/worktrain-spawn.js +11 -9
- package/dist/cli-worktrain.js +488 -0
- package/dist/cli.js +1 -22
- package/dist/console/standalone-console.d.ts +28 -0
- package/dist/console/standalone-console.js +142 -0
- package/dist/{console/assets/index-Cb_LO718.js → console-ui/assets/index-C1JXnwZS.js} +1 -1
- package/dist/{console → console-ui}/index.html +1 -1
- package/dist/daemon/agent-loop.d.ts +27 -0
- package/dist/daemon/agent-loop.js +39 -1
- package/dist/daemon/daemon-events.d.ts +63 -1
- package/dist/daemon/workflow-runner.d.ts +3 -2
- package/dist/daemon/workflow-runner.js +285 -46
- package/dist/infrastructure/session/HttpServer.js +133 -34
- package/dist/manifest.json +136 -104
- package/dist/mcp/handlers/v2-error-mapping.d.ts +3 -0
- package/dist/mcp/handlers/v2-error-mapping.js +2 -0
- package/dist/mcp/handlers/v2-execution/advance.js +25 -0
- package/dist/mcp/handlers/v2-execution/continue-advance.js +7 -0
- package/dist/mcp/output-schemas.d.ts +30 -30
- package/dist/mcp/transports/fatal-exit.js +4 -0
- package/dist/mcp/transports/http-entry.js +0 -5
- package/dist/mcp/transports/stdio-entry.js +24 -12
- package/dist/mcp/v2/tools.d.ts +4 -4
- package/dist/mcp-server.d.ts +0 -2
- package/dist/mcp-server.js +1 -42
- package/dist/trigger/adapters/github-poller.d.ts +44 -0
- package/dist/trigger/adapters/github-poller.js +190 -0
- package/dist/trigger/adapters/gitlab-poller.d.ts +27 -0
- package/dist/trigger/adapters/gitlab-poller.js +81 -0
- package/dist/trigger/index.d.ts +4 -1
- package/dist/trigger/index.js +5 -1
- package/dist/trigger/polled-event-store.d.ts +22 -0
- package/dist/trigger/polled-event-store.js +173 -0
- package/dist/trigger/polling-scheduler.d.ts +20 -0
- package/dist/trigger/polling-scheduler.js +249 -0
- package/dist/trigger/trigger-listener.d.ts +3 -0
- package/dist/trigger/trigger-listener.js +47 -3
- package/dist/trigger/trigger-store.js +114 -33
- package/dist/trigger/types.d.ts +17 -1
- package/dist/v2/durable-core/domain/observation-builder.d.ts +3 -0
- package/dist/v2/durable-core/domain/observation-builder.js +2 -2
- package/dist/v2/durable-core/domain/prompt-renderer.d.ts +2 -1
- package/dist/v2/durable-core/domain/prompt-renderer.js +10 -0
- package/dist/v2/durable-core/schemas/export-bundle/index.d.ts +224 -224
- package/dist/v2/durable-core/schemas/session/events.d.ts +42 -42
- package/dist/v2/durable-core/schemas/session/manifest.d.ts +6 -6
- package/dist/v2/durable-core/schemas/session/validation-event.d.ts +2 -2
- package/dist/v2/durable-core/tokens/payloads.d.ts +52 -52
- package/dist/v2/usecases/console-routes.js +3 -3
- package/dist/v2/usecases/console-service.js +185 -10
- package/dist/v2/usecases/console-types.d.ts +8 -0
- package/docs/design/bridge-removal-pr-a-candidates.md +115 -0
- package/docs/design/bridge-removal-pr-a-design-review.md +79 -0
- package/docs/design/bridge-removal-pr-a-implementation-plan.md +203 -0
- package/docs/design/daemon-conversation-logging-plan.md +98 -0
- package/docs/design/daemon-conversation-logging-review.md +55 -0
- package/docs/design/daemon-conversation-logging.md +129 -0
- package/docs/design/github-polling-adapter-design-candidates.md +226 -0
- package/docs/design/github-polling-adapter-design-review-findings.md +131 -0
- package/docs/design/github-polling-adapter-implementation-plan.md +284 -0
- package/docs/design/implementation_plan.md +192 -0
- package/docs/design/workflow-id-validation-at-startup.md +146 -0
- package/docs/design/workflow-id-validation-design-review.md +87 -0
- package/docs/design/workflow-id-validation-implementation-plan.md +185 -0
- package/docs/design/worktrain-system-prompt-report-issue-candidates.md +135 -0
- package/docs/design/worktrain-system-prompt-report-issue-design-review.md +73 -0
- package/docs/discovery/design-candidates.md +180 -0
- package/docs/discovery/design-review-findings.md +110 -0
- package/docs/discovery/wr-discovery-goal-reframing.md +303 -0
- package/docs/ideas/backlog.md +627 -0
- package/package.json +1 -1
- package/workflows/architecture-scalability-audit.json +1 -1
- package/workflows/bug-investigation.agentic.v2.json +3 -3
- package/workflows/coding-task-workflow-agentic.json +32 -32
- package/workflows/coding-task-workflow-agentic.lean.v2.json +1 -1
- package/workflows/coding-task-workflow-agentic.v2.json +7 -7
- package/workflows/mr-review-workflow.agentic.v2.json +21 -12
- package/workflows/personal-learning-materials-creation-branched.json +2 -2
- package/workflows/production-readiness-audit.json +1 -1
- package/workflows/relocation-workflow-us.json +2 -2
- package/workflows/ui-ux-design-workflow.json +14 -14
- package/workflows/workflow-for-workflows.json +3 -3
- package/workflows/workflow-for-workflows.v2.json +2 -2
- package/workflows/wr.discovery.json +59 -8
- package/dist/mcp/transports/bridge-entry.d.ts +0 -102
- package/dist/mcp/transports/bridge-entry.js +0 -454
- package/dist/mcp/transports/bridge-events.d.ts +0 -51
- package/dist/mcp/transports/bridge-events.js +0 -24
- package/dist/mcp/transports/primary-tombstone.d.ts +0 -21
- package/dist/mcp/transports/primary-tombstone.js +0 -51
- /package/dist/{console → console-ui}/assets/index-8dh0Psu-.css +0 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.executeWorktrainDaemonCommand = executeWorktrainDaemonCommand;
|
|
4
|
+
const cli_result_js_1 = require("../types/cli-result.js");
|
|
5
|
+
const LAUNCHD_LABEL = 'io.worktrain.daemon';
|
|
6
|
+
const PLIST_FILENAME = `${LAUNCHD_LABEL}.plist`;
|
|
7
|
+
const CAPTURED_ENV_VARS = [
|
|
8
|
+
'AWS_PROFILE',
|
|
9
|
+
'AWS_ACCESS_KEY_ID',
|
|
10
|
+
'AWS_SECRET_ACCESS_KEY',
|
|
11
|
+
'AWS_SESSION_TOKEN',
|
|
12
|
+
'ANTHROPIC_API_KEY',
|
|
13
|
+
'WORKRAIL_TRIGGERS_ENABLED',
|
|
14
|
+
'WORKRAIL_DEFAULT_WORKSPACE',
|
|
15
|
+
'GITHUB_TOKEN',
|
|
16
|
+
'GITLAB_TOKEN',
|
|
17
|
+
'HOME',
|
|
18
|
+
'USER',
|
|
19
|
+
'PATH',
|
|
20
|
+
'WORKRAIL_DEV',
|
|
21
|
+
'WORKRAIL_LOG_LEVEL',
|
|
22
|
+
'WORKRAIL_VERBOSE_LOGGING',
|
|
23
|
+
];
|
|
24
|
+
function buildPlist(nodeBinPath, worktrainBinPath, envVars, logDir, homeDir) {
|
|
25
|
+
const envEntries = Object.entries(envVars)
|
|
26
|
+
.map(([k, v]) => ` <key>${escapeXml(k)}</key>\n <string>${escapeXml(v)}</string>`)
|
|
27
|
+
.join('\n');
|
|
28
|
+
const stdoutLog = `${logDir}/daemon.stdout.log`;
|
|
29
|
+
const stderrLog = `${logDir}/daemon.stderr.log`;
|
|
30
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
31
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
|
|
32
|
+
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
33
|
+
<plist version="1.0">
|
|
34
|
+
<dict>
|
|
35
|
+
<key>Label</key>
|
|
36
|
+
<string>${LAUNCHD_LABEL}</string>
|
|
37
|
+
|
|
38
|
+
<key>ProgramArguments</key>
|
|
39
|
+
<array>
|
|
40
|
+
<string>${escapeXml(nodeBinPath)}</string>
|
|
41
|
+
<string>${escapeXml(worktrainBinPath)}</string>
|
|
42
|
+
<string>daemon</string>
|
|
43
|
+
</array>
|
|
44
|
+
|
|
45
|
+
<key>WorkingDirectory</key>
|
|
46
|
+
<string>${escapeXml(homeDir)}</string>
|
|
47
|
+
|
|
48
|
+
<key>EnvironmentVariables</key>
|
|
49
|
+
<dict>
|
|
50
|
+
${envEntries}
|
|
51
|
+
</dict>
|
|
52
|
+
|
|
53
|
+
<key>StandardOutPath</key>
|
|
54
|
+
<string>${escapeXml(stdoutLog)}</string>
|
|
55
|
+
|
|
56
|
+
<key>StandardErrorPath</key>
|
|
57
|
+
<string>${escapeXml(stderrLog)}</string>
|
|
58
|
+
|
|
59
|
+
<key>RunAtLoad</key>
|
|
60
|
+
<true/>
|
|
61
|
+
|
|
62
|
+
<key>KeepAlive</key>
|
|
63
|
+
<true/>
|
|
64
|
+
|
|
65
|
+
<!--
|
|
66
|
+
ThrottleInterval: minimum seconds between launchd restarts.
|
|
67
|
+
WHY 30s: prevents launchd from spinning in a tight restart loop if the daemon
|
|
68
|
+
exits immediately (e.g., missing credentials or invalid workspace path).
|
|
69
|
+
Without this, a misconfigured service consumes CPU and spams logs.
|
|
70
|
+
-->
|
|
71
|
+
<key>ThrottleInterval</key>
|
|
72
|
+
<integer>30</integer>
|
|
73
|
+
</dict>
|
|
74
|
+
</plist>
|
|
75
|
+
`;
|
|
76
|
+
}
|
|
77
|
+
function escapeXml(s) {
|
|
78
|
+
return s
|
|
79
|
+
.replace(/&/g, '&')
|
|
80
|
+
.replace(/</g, '<')
|
|
81
|
+
.replace(/>/g, '>')
|
|
82
|
+
.replace(/"/g, '"')
|
|
83
|
+
.replace(/'/g, ''');
|
|
84
|
+
}
|
|
85
|
+
function captureEnvVars(env, warn) {
|
|
86
|
+
const captured = {};
|
|
87
|
+
for (const key of CAPTURED_ENV_VARS) {
|
|
88
|
+
const value = env[key];
|
|
89
|
+
if (value !== undefined && value !== '') {
|
|
90
|
+
captured[key] = value;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const existing = captured['WORKRAIL_TRIGGERS_ENABLED'];
|
|
94
|
+
if (!existing) {
|
|
95
|
+
captured['WORKRAIL_TRIGGERS_ENABLED'] = 'true';
|
|
96
|
+
}
|
|
97
|
+
else if (existing !== 'true') {
|
|
98
|
+
warn(`[worktrain daemon --install] WORKRAIL_TRIGGERS_ENABLED is set to '${existing}' in your environment. ` +
|
|
99
|
+
`The plist will override this with 'true' so the daemon can start. ` +
|
|
100
|
+
`Remove WORKRAIL_TRIGGERS_ENABLED from your shell environment if you do not want this warning.`);
|
|
101
|
+
captured['WORKRAIL_TRIGGERS_ENABLED'] = 'true';
|
|
102
|
+
}
|
|
103
|
+
return captured;
|
|
104
|
+
}
|
|
105
|
+
function parseLaunchctlList(stdout, exitCode) {
|
|
106
|
+
if (exitCode !== 0) {
|
|
107
|
+
return { running: false, pid: null, loaded: false };
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
const parsed = JSON.parse(stdout);
|
|
111
|
+
const pid = typeof parsed['PID'] === 'number' ? parsed['PID'] : null;
|
|
112
|
+
return { running: pid !== null, pid, loaded: true };
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return { running: false, pid: null, loaded: false };
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async function runInstall(deps) {
|
|
119
|
+
const home = deps.homedir();
|
|
120
|
+
const plistDir = deps.joinPath(home, 'Library', 'LaunchAgents');
|
|
121
|
+
const plistPath = deps.joinPath(plistDir, PLIST_FILENAME);
|
|
122
|
+
const logDir = deps.joinPath(home, '.workrail', 'logs');
|
|
123
|
+
const env = deps.env;
|
|
124
|
+
const hasBedrock = !!(env['AWS_PROFILE'] || env['AWS_ACCESS_KEY_ID']);
|
|
125
|
+
const hasAnthropic = !!env['ANTHROPIC_API_KEY'];
|
|
126
|
+
if (!hasBedrock && !hasAnthropic) {
|
|
127
|
+
return (0, cli_result_js_1.failure)('No LLM credentials found in the current environment. ' +
|
|
128
|
+
'Set AWS_PROFILE (for Bedrock) or ANTHROPIC_API_KEY (for Anthropic) ' +
|
|
129
|
+
'before running --install so the daemon can authenticate.', {
|
|
130
|
+
suggestions: [
|
|
131
|
+
'export AWS_PROFILE=your-sso-profile',
|
|
132
|
+
'export ANTHROPIC_API_KEY=sk-ant-...',
|
|
133
|
+
],
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
deps.print('Installing WorkTrain daemon as a launchd service...');
|
|
137
|
+
await deps.mkdir(plistDir, { recursive: true });
|
|
138
|
+
await deps.mkdir(logDir, { recursive: true });
|
|
139
|
+
const alreadyInstalled = await deps.exists(plistPath);
|
|
140
|
+
if (alreadyInstalled) {
|
|
141
|
+
deps.print(' Existing service found -- unloading before reinstall...');
|
|
142
|
+
await deps.exec('launchctl', ['unload', plistPath]);
|
|
143
|
+
}
|
|
144
|
+
const capturedEnv = captureEnvVars(env, (msg) => console.warn(msg));
|
|
145
|
+
const plist = buildPlist(deps.nodeBinPath, deps.worktrainBinPath, capturedEnv, logDir, home);
|
|
146
|
+
await deps.writeFile(plistPath, plist);
|
|
147
|
+
await deps.chmod(plistPath, 0o600);
|
|
148
|
+
deps.print(` Plist written: ${plistPath}`);
|
|
149
|
+
const loadResult = await deps.exec('launchctl', ['load', plistPath]);
|
|
150
|
+
if (loadResult.exitCode !== 0) {
|
|
151
|
+
return (0, cli_result_js_1.failure)(`launchctl load failed (exit ${loadResult.exitCode}): ${loadResult.stderr.trim() || loadResult.stdout.trim()}`, {
|
|
152
|
+
suggestions: [
|
|
153
|
+
`Check the plist manually: plutil -lint ${plistPath}`,
|
|
154
|
+
`View daemon logs: tail -f ${logDir}/daemon.stderr.log`,
|
|
155
|
+
],
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
await deps.sleep(1500);
|
|
159
|
+
const listResult = await deps.exec('launchctl', ['list', LAUNCHD_LABEL]);
|
|
160
|
+
const status = parseLaunchctlList(listResult.stdout, listResult.exitCode);
|
|
161
|
+
if (!status.loaded) {
|
|
162
|
+
return (0, cli_result_js_1.failure)(`Service loaded but launchctl cannot find it. This may be a transient issue.`, {
|
|
163
|
+
suggestions: [
|
|
164
|
+
`Check: launchctl list ${LAUNCHD_LABEL}`,
|
|
165
|
+
`View daemon logs: tail -f ${logDir}/daemon.stderr.log`,
|
|
166
|
+
],
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
deps.print('');
|
|
170
|
+
if (status.running) {
|
|
171
|
+
deps.print(`WorkTrain daemon installed and running (PID ${status.pid}).`);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
deps.print(`WorkTrain daemon installed. Service loaded but not yet running.`);
|
|
175
|
+
deps.print(`This may be normal if WORKRAIL_TRIGGERS_ENABLED was not set.`);
|
|
176
|
+
}
|
|
177
|
+
deps.print(`Logs: ${logDir}/daemon.stdout.log`);
|
|
178
|
+
deps.print(` ${logDir}/daemon.stderr.log`);
|
|
179
|
+
return (0, cli_result_js_1.success)({
|
|
180
|
+
message: status.running
|
|
181
|
+
? `WorkTrain daemon installed and running (PID ${status.pid})`
|
|
182
|
+
: 'WorkTrain daemon installed (service loaded, not yet running)',
|
|
183
|
+
details: [
|
|
184
|
+
`Plist: ${plistPath}`,
|
|
185
|
+
`Logs: ${logDir}/daemon.stdout.log`,
|
|
186
|
+
` ${logDir}/daemon.stderr.log`,
|
|
187
|
+
],
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
async function runUninstall(deps) {
|
|
191
|
+
const home = deps.homedir();
|
|
192
|
+
const plistPath = deps.joinPath(home, 'Library', 'LaunchAgents', PLIST_FILENAME);
|
|
193
|
+
const exists = await deps.exists(plistPath);
|
|
194
|
+
if (!exists) {
|
|
195
|
+
return (0, cli_result_js_1.failure)('WorkTrain daemon is not installed (plist not found).', { suggestions: [`Expected: ${plistPath}`] });
|
|
196
|
+
}
|
|
197
|
+
deps.print('Uninstalling WorkTrain daemon...');
|
|
198
|
+
const unloadResult = await deps.exec('launchctl', ['unload', plistPath]);
|
|
199
|
+
if (unloadResult.exitCode !== 0) {
|
|
200
|
+
deps.print(` Warning: launchctl unload returned non-zero: ${unloadResult.stderr.trim()}`);
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
deps.print(' Service unloaded.');
|
|
204
|
+
}
|
|
205
|
+
await deps.removeFile(plistPath);
|
|
206
|
+
deps.print(` Plist removed: ${plistPath}`);
|
|
207
|
+
return (0, cli_result_js_1.success)({ message: 'WorkTrain daemon uninstalled successfully.' });
|
|
208
|
+
}
|
|
209
|
+
async function runStatus(deps) {
|
|
210
|
+
const home = deps.homedir();
|
|
211
|
+
const plistPath = deps.joinPath(home, 'Library', 'LaunchAgents', PLIST_FILENAME);
|
|
212
|
+
const logDir = deps.joinPath(home, '.workrail', 'logs');
|
|
213
|
+
const plistExists = await deps.exists(plistPath);
|
|
214
|
+
const listResult = await deps.exec('launchctl', ['list', LAUNCHD_LABEL]);
|
|
215
|
+
const status = parseLaunchctlList(listResult.stdout, listResult.exitCode);
|
|
216
|
+
deps.print('');
|
|
217
|
+
deps.print('WorkTrain daemon status:');
|
|
218
|
+
deps.print(` Plist installed : ${plistExists ? `yes (${plistPath})` : 'no'}`);
|
|
219
|
+
deps.print(` Service loaded : ${status.loaded ? 'yes' : 'no'}`);
|
|
220
|
+
deps.print(` Running : ${status.running ? `yes (PID ${status.pid})` : 'no'}`);
|
|
221
|
+
if (plistExists || status.loaded) {
|
|
222
|
+
deps.print(` Logs (stdout) : ${logDir}/daemon.stdout.log`);
|
|
223
|
+
deps.print(` Logs (stderr) : ${logDir}/daemon.stderr.log`);
|
|
224
|
+
}
|
|
225
|
+
if (!plistExists && !status.loaded) {
|
|
226
|
+
deps.print('');
|
|
227
|
+
deps.print('Daemon is not installed. Run: worktrain daemon --install');
|
|
228
|
+
}
|
|
229
|
+
else if (plistExists && !status.running) {
|
|
230
|
+
deps.print('');
|
|
231
|
+
deps.print(`Daemon installed but not running. Check logs: tail -f ${logDir}/daemon.stderr.log`);
|
|
232
|
+
}
|
|
233
|
+
deps.print('');
|
|
234
|
+
return (0, cli_result_js_1.success)({
|
|
235
|
+
message: status.running
|
|
236
|
+
? `WorkTrain daemon is running (PID ${status.pid})`
|
|
237
|
+
: plistExists
|
|
238
|
+
? 'WorkTrain daemon is installed but not running'
|
|
239
|
+
: 'WorkTrain daemon is not installed',
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
async function executeWorktrainDaemonCommand(deps, opts) {
|
|
243
|
+
const flagCount = [opts.install, opts.uninstall, opts.status].filter(Boolean).length;
|
|
244
|
+
if (flagCount === 0) {
|
|
245
|
+
if (deps.startDaemon) {
|
|
246
|
+
await deps.startDaemon();
|
|
247
|
+
return (0, cli_result_js_1.success)({ message: 'WorkTrain daemon stopped.' });
|
|
248
|
+
}
|
|
249
|
+
return (0, cli_result_js_1.misuse)('Specify one of: --install, --uninstall, or --status', [
|
|
250
|
+
'worktrain daemon --install Install and start as a launchd service',
|
|
251
|
+
'worktrain daemon --uninstall Stop and remove the launchd service',
|
|
252
|
+
'worktrain daemon --status Show service status',
|
|
253
|
+
]);
|
|
254
|
+
}
|
|
255
|
+
if (flagCount > 1) {
|
|
256
|
+
return (0, cli_result_js_1.misuse)('--install, --uninstall, and --status are mutually exclusive. Specify only one.');
|
|
257
|
+
}
|
|
258
|
+
if (deps.platform !== 'darwin') {
|
|
259
|
+
return (0, cli_result_js_1.failure)(`worktrain daemon --install requires macOS (launchd). ` +
|
|
260
|
+
`Current platform: ${deps.platform}.`, {
|
|
261
|
+
suggestions: [
|
|
262
|
+
'On Linux, use systemd: create a user service with systemctl --user.',
|
|
263
|
+
'See docs/daemon-service.md for platform-specific instructions.',
|
|
264
|
+
],
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
if (opts.install)
|
|
268
|
+
return runInstall(deps);
|
|
269
|
+
if (opts.uninstall)
|
|
270
|
+
return runUninstall(deps);
|
|
271
|
+
return runStatus(deps);
|
|
272
|
+
}
|
|
@@ -3,20 +3,22 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.executeWorktrainSpawnCommand = executeWorktrainSpawnCommand;
|
|
4
4
|
const cli_result_js_1 = require("../types/cli-result.js");
|
|
5
5
|
const DEFAULT_CONSOLE_PORT = 3456;
|
|
6
|
-
const
|
|
6
|
+
const LOCK_FILE_NAMES = ['daemon-console.lock', 'dashboard.lock'];
|
|
7
7
|
async function discoverConsolePort(deps, portOverride) {
|
|
8
8
|
if (portOverride !== undefined && portOverride > 0) {
|
|
9
9
|
return portOverride;
|
|
10
10
|
}
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
for (const lockFileName of LOCK_FILE_NAMES) {
|
|
12
|
+
const lockPath = deps.joinPath(deps.homedir(), '.workrail', lockFileName);
|
|
13
|
+
try {
|
|
14
|
+
const raw = await deps.readFile(lockPath);
|
|
15
|
+
const parsed = JSON.parse(raw);
|
|
16
|
+
if (typeof parsed.port === 'number' && parsed.port > 0) {
|
|
17
|
+
return parsed.port;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
17
21
|
}
|
|
18
|
-
}
|
|
19
|
-
catch {
|
|
20
22
|
}
|
|
21
23
|
return DEFAULT_CONSOLE_PORT;
|
|
22
24
|
}
|