@stravica-ai/digital-operator-pa 0.1.49 → 0.1.50
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/engineering-pa-cli/src/pa/cli.mjs +47 -1
- package/dist/engineering-pa-cli/src/pa/onboard.mjs +114 -0
- package/dist/engineering-pa-core/docs/commands/onboard.md +20 -20
- package/dist/engineering-pa-core/src/distill/health.mjs +170 -6
- package/dist/engineering-pa-core/src/distill/run.mjs +19 -0
- package/dist/engineering-pa-core/src/instance-root/find.mjs +104 -0
- package/dist/engineering-pa-core/src/knowledge/retrieval/backlink-indexer.mjs +6 -1
- package/dist/engineering-pa-core/src/knowledge/retrieval/graph-builder.mjs +6 -1
- package/dist/engineering-pa-core/src/knowledge/retrieval/index-builder.mjs +4 -1
- package/dist/engineering-pa-core/src/knowledge/retrieval/query.mjs +6 -1
- package/dist/engineering-pa-core/src/scheduler/install.mjs +41 -4
- package/dist/engineering-pa-core/src/scheduler/list.mjs +34 -13
- package/dist/engineering-pa-core/src/scheduler/remove.mjs +2 -1
- package/dist/engineering-pa-core-extensions-atlassian/package.json +3 -0
- package/dist/engineering-pa-core-extensions-atlassian/src/confluence/commands/mirror-folder.mjs +4 -2
- package/dist/engineering-pa-core-extensions-atlassian/src/jira/commands/link.mjs +4 -2
- package/dist/engineering-pa-core-extensions-atlassian/src/jira/commands/sync-statuses.mjs +6 -2
- package/dist/engineering-pa-core-extensions-atlassian/src/jira/workflow-chains.mjs +7 -3
- package/dist/engineering-pa-core-extensions-atlassian/src/jira/workflow-map.mjs +9 -3
- package/dist/engineering-pa-scaffold/src/generator.mjs +3 -1
- package/dist/engineering-pa-workspace/app/notes.html +1 -1
- package/dist/engineering-pa-workspace/app/project-detail.html +17 -1
- package/dist/engineering-pa-workspace/app/projects.html +1 -1
- package/dist/engineering-pa-workspace/app/tasks.html +1 -1
- package/dist/engineering-pa-workspace/src/install-daemon.mjs +2 -2
- package/dist/engineering-pa-workspace/src/repo-root.mjs +13 -100
- package/dist/engineering-pa-workspace/src/server.mjs +2 -2
- package/dist/engineering-pa-workspace/src/ws.mjs +79 -10
- package/docs/onboarding-solo.md +1 -1
- package/package.json +1 -1
|
@@ -96,6 +96,7 @@ function hasFlag(name) {
|
|
|
96
96
|
function resolvePort() {
|
|
97
97
|
// 1. Default
|
|
98
98
|
let port = 4200;
|
|
99
|
+
let explicit = false;
|
|
99
100
|
|
|
100
101
|
// 2. Preferences override — device-local overlay wins over the shared base
|
|
101
102
|
// (see @stravica-ai/engineering-pa-core/src/preferences.mjs).
|
|
@@ -104,7 +105,9 @@ function resolvePort() {
|
|
|
104
105
|
if (prefs && prefs.workspacePort) port = prefs.workspacePort;
|
|
105
106
|
} catch { /* no prefs — use default */ }
|
|
106
107
|
|
|
107
|
-
// 3. CLI flag override
|
|
108
|
+
// 3. CLI flag override — an explicit `--port` disables the auto-probe
|
|
109
|
+
// (item 3, 0.1.50). The operator asked for this exact port, so we
|
|
110
|
+
// hard-fail on collision rather than picking a different one silently.
|
|
108
111
|
const flagPort = getFlag('--port');
|
|
109
112
|
if (flagPort) {
|
|
110
113
|
const parsed = parseInt(flagPort, 10);
|
|
@@ -113,9 +116,10 @@ function resolvePort() {
|
|
|
113
116
|
process.exit(1);
|
|
114
117
|
}
|
|
115
118
|
port = parsed;
|
|
119
|
+
explicit = true;
|
|
116
120
|
}
|
|
117
121
|
|
|
118
|
-
return port;
|
|
122
|
+
return { port, explicit };
|
|
119
123
|
}
|
|
120
124
|
|
|
121
125
|
// --- PID file helpers ---
|
|
@@ -148,6 +152,45 @@ function isProcessAlive(pid) {
|
|
|
148
152
|
}
|
|
149
153
|
}
|
|
150
154
|
|
|
155
|
+
// 0.1.50 (item 3): probe upward from `startPort` until a free port is
|
|
156
|
+
// found or `maxAttempts` is exhausted. Returns the chosen port or null
|
|
157
|
+
// when the whole window is busy. Bounded so a runaway loop cannot
|
|
158
|
+
// happen; 20 attempts is plenty for a solo instance's usual crowding.
|
|
159
|
+
async function probeFreePortUpward(startPort, maxAttempts) {
|
|
160
|
+
for (let i = 0; i < maxAttempts; i++) {
|
|
161
|
+
const p = startPort + i;
|
|
162
|
+
if (p > 65535) return null;
|
|
163
|
+
// eslint-disable-next-line no-await-in-loop
|
|
164
|
+
const busy = await checkPort(p);
|
|
165
|
+
if (!busy) return p;
|
|
166
|
+
}
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// 0.1.50 (item 3): write the chosen workspace port back to
|
|
171
|
+
// `operator/config/preferences.json:workspacePort`. Preserves field
|
|
172
|
+
// order and 2-space indent so a git diff of preferences shows only
|
|
173
|
+
// the port change.
|
|
174
|
+
function writeWorkspacePortToPreferences(repoRoot, port) {
|
|
175
|
+
const path = join(repoRoot, 'operator', 'config', 'preferences.json');
|
|
176
|
+
let raw;
|
|
177
|
+
try {
|
|
178
|
+
raw = readFileSync(path, 'utf8');
|
|
179
|
+
} catch (e) {
|
|
180
|
+
if (e && e.code === 'ENOENT') {
|
|
181
|
+
// No preferences at all yet — write a minimal file. The scaffold
|
|
182
|
+
// ships one for every solo instance so this branch is rare.
|
|
183
|
+
writeFileSync(path, JSON.stringify({ workspacePort: port }, null, 2) + '\n');
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
throw e;
|
|
187
|
+
}
|
|
188
|
+
const parsed = JSON.parse(raw);
|
|
189
|
+
parsed.workspacePort = port;
|
|
190
|
+
const hadTrailingNewline = raw.endsWith('\n');
|
|
191
|
+
writeFileSync(path, JSON.stringify(parsed, null, 2) + (hadTrailingNewline ? '\n' : ''));
|
|
192
|
+
}
|
|
193
|
+
|
|
151
194
|
function checkPort(port, timeoutMs = 1000) {
|
|
152
195
|
return new Promise((resolve) => {
|
|
153
196
|
const sock = createConnection({ host: '127.0.0.1', port }, () => {
|
|
@@ -282,7 +325,10 @@ function formatUptime(ms) {
|
|
|
282
325
|
// --- Commands ---
|
|
283
326
|
|
|
284
327
|
async function cmdStart() {
|
|
285
|
-
const
|
|
328
|
+
const resolved = resolvePort();
|
|
329
|
+
let { port } = resolved;
|
|
330
|
+
const explicitPort = resolved.explicit;
|
|
331
|
+
const noProbe = hasFlag('--no-probe');
|
|
286
332
|
const noOpen = hasFlag('--no-open');
|
|
287
333
|
|
|
288
334
|
// Supervisor-aware short-circuit. When launchd / systemd is managing the
|
|
@@ -342,11 +388,34 @@ async function cmdStart() {
|
|
|
342
388
|
removePid();
|
|
343
389
|
}
|
|
344
390
|
|
|
345
|
-
// Check if port is already in use by something else
|
|
391
|
+
// Check if port is already in use by something else.
|
|
392
|
+
//
|
|
393
|
+
// 0.1.50 (item 3): when neither `--port <N>` nor `--no-probe` was
|
|
394
|
+
// passed, probe upward from max(configured+1, 4210) up to 20
|
|
395
|
+
// attempts. Persist the chosen port back to
|
|
396
|
+
// `operator/config/preferences.json:workspacePort` so subsequent
|
|
397
|
+
// `pa status` / `pa workspace open` calls read the same port. An
|
|
398
|
+
// explicit `--port` or `--no-probe` keeps the strict hard-fail.
|
|
346
399
|
if (await checkPort(port)) {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
400
|
+
if (explicitPort || noProbe) {
|
|
401
|
+
console.error(`Error: Port ${port} is already in use by another process.`);
|
|
402
|
+
console.error('Hint: run `pa workspace start --port <N>` with a free port, or set `workspacePort` in operator/config/preferences.json.');
|
|
403
|
+
process.exit(1);
|
|
404
|
+
}
|
|
405
|
+
const configuredPort = port;
|
|
406
|
+
const chosen = await probeFreePortUpward(Math.max(port + 1, 4210), 20);
|
|
407
|
+
if (chosen === null) {
|
|
408
|
+
console.error(`Error: Port ${configuredPort} is busy and no free port was found in 20 attempts starting from ${Math.max(configuredPort + 1, 4210)}.`);
|
|
409
|
+
console.error('Hint: run `pa workspace start --port <N>` with a free port, or set `workspacePort` in operator/config/preferences.json.');
|
|
410
|
+
process.exit(1);
|
|
411
|
+
}
|
|
412
|
+
port = chosen;
|
|
413
|
+
try {
|
|
414
|
+
writeWorkspacePortToPreferences(REPO_ROOT, port);
|
|
415
|
+
} catch (e) {
|
|
416
|
+
console.error(`Warning: failed to persist chosen port to preferences: ${e.message}`);
|
|
417
|
+
}
|
|
418
|
+
console.log(`Port ${configuredPort} busy; started on ${port} instead (persisted to operator/config/preferences.json).`);
|
|
350
419
|
}
|
|
351
420
|
|
|
352
421
|
// Build spawn args
|
|
@@ -473,7 +542,7 @@ async function cmdRestart() {
|
|
|
473
542
|
// launchctl kickstart -k can return before the new PID is published.
|
|
474
543
|
console.log(`Workspace server restart requested (supervised by ${supervisor.kind}).`);
|
|
475
544
|
}
|
|
476
|
-
const port = resolvePort();
|
|
545
|
+
const { port } = resolvePort();
|
|
477
546
|
console.log(` http://127.0.0.1:${port}`);
|
|
478
547
|
return;
|
|
479
548
|
}
|
|
@@ -489,7 +558,7 @@ async function cmdStatus() {
|
|
|
489
558
|
// itself spawned the server, so a supervised process is invisible to the
|
|
490
559
|
// pidfile-only check (bug 1 of 2 in this PR).
|
|
491
560
|
if (supervisor.kind) {
|
|
492
|
-
const port = resolvePort();
|
|
561
|
+
const { port } = resolvePort();
|
|
493
562
|
const sup = readSupervisorState(supervisor);
|
|
494
563
|
const listener = findPortListener(port);
|
|
495
564
|
const portUp = await checkPort(port);
|
|
@@ -574,7 +643,7 @@ async function cmdOpen() {
|
|
|
574
643
|
// socket directly.
|
|
575
644
|
const supervisor = getSupervisor();
|
|
576
645
|
if (supervisor.kind) {
|
|
577
|
-
const port = resolvePort();
|
|
646
|
+
const { port } = resolvePort();
|
|
578
647
|
const portUp = await checkPort(port);
|
|
579
648
|
if (!portUp) {
|
|
580
649
|
console.error(`Error: Workspace is ${supervisor.kind}-managed but port ${port} is not responding.`);
|
package/docs/onboarding-solo.md
CHANGED
|
@@ -8,7 +8,7 @@ Working installs of the following, then sign in to Claude Code:
|
|
|
8
8
|
|
|
9
9
|
- Node.js 24 or newer: https://nodejs.org (or your platform's Node 24 channel; on macOS `brew install node@24`)
|
|
10
10
|
- pnpm: https://pnpm.io/installation (or `brew install pnpm`)
|
|
11
|
-
- git: https://git-scm.com (or `brew install git`)
|
|
11
|
+
- git: https://git-scm.com (or `brew install git`). `pa-init` runs `git init` inside the instance; you will need `user.name` and `user.email` set globally (via `git config --global user.name / user.email`) before your first commit, but the scaffold itself does not commit.
|
|
12
12
|
- Claude Code CLI: https://claude.ai/install (or `brew install --cask claude-code`). Run `claude` once, sign in, then Ctrl-C.
|
|
13
13
|
|
|
14
14
|
Do not install Claude Code with `npm -g` or `sudo npm -g`.
|
package/package.json
CHANGED