@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.
Files changed (30) hide show
  1. package/dist/engineering-pa-cli/src/pa/cli.mjs +47 -1
  2. package/dist/engineering-pa-cli/src/pa/onboard.mjs +114 -0
  3. package/dist/engineering-pa-core/docs/commands/onboard.md +20 -20
  4. package/dist/engineering-pa-core/src/distill/health.mjs +170 -6
  5. package/dist/engineering-pa-core/src/distill/run.mjs +19 -0
  6. package/dist/engineering-pa-core/src/instance-root/find.mjs +104 -0
  7. package/dist/engineering-pa-core/src/knowledge/retrieval/backlink-indexer.mjs +6 -1
  8. package/dist/engineering-pa-core/src/knowledge/retrieval/graph-builder.mjs +6 -1
  9. package/dist/engineering-pa-core/src/knowledge/retrieval/index-builder.mjs +4 -1
  10. package/dist/engineering-pa-core/src/knowledge/retrieval/query.mjs +6 -1
  11. package/dist/engineering-pa-core/src/scheduler/install.mjs +41 -4
  12. package/dist/engineering-pa-core/src/scheduler/list.mjs +34 -13
  13. package/dist/engineering-pa-core/src/scheduler/remove.mjs +2 -1
  14. package/dist/engineering-pa-core-extensions-atlassian/package.json +3 -0
  15. package/dist/engineering-pa-core-extensions-atlassian/src/confluence/commands/mirror-folder.mjs +4 -2
  16. package/dist/engineering-pa-core-extensions-atlassian/src/jira/commands/link.mjs +4 -2
  17. package/dist/engineering-pa-core-extensions-atlassian/src/jira/commands/sync-statuses.mjs +6 -2
  18. package/dist/engineering-pa-core-extensions-atlassian/src/jira/workflow-chains.mjs +7 -3
  19. package/dist/engineering-pa-core-extensions-atlassian/src/jira/workflow-map.mjs +9 -3
  20. package/dist/engineering-pa-scaffold/src/generator.mjs +3 -1
  21. package/dist/engineering-pa-workspace/app/notes.html +1 -1
  22. package/dist/engineering-pa-workspace/app/project-detail.html +17 -1
  23. package/dist/engineering-pa-workspace/app/projects.html +1 -1
  24. package/dist/engineering-pa-workspace/app/tasks.html +1 -1
  25. package/dist/engineering-pa-workspace/src/install-daemon.mjs +2 -2
  26. package/dist/engineering-pa-workspace/src/repo-root.mjs +13 -100
  27. package/dist/engineering-pa-workspace/src/server.mjs +2 -2
  28. package/dist/engineering-pa-workspace/src/ws.mjs +79 -10
  29. package/docs/onboarding-solo.md +1 -1
  30. 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 port = resolvePort();
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
- console.error(`Error: Port ${port} is already in use by another process.`);
348
- console.error('Hint: run `pa workspace start --port <N>` with a free port, or set `workspacePort` in operator/config/preferences.json.');
349
- process.exit(1);
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.`);
@@ -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`) with your identity already configured
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stravica-ai/digital-operator-pa",
3
- "version": "0.1.49",
3
+ "version": "0.1.50",
4
4
  "description": "Digital Operator PA — single-bundled public package surface (bins + library) for the platform.",
5
5
  "type": "module",
6
6
  "main": "./index.mjs",