fraim-hub 2.0.332 → 2.0.335

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.
@@ -80,7 +80,7 @@ function probeCommandResolvesNonInteractively(runner, commandName) {
80
80
  result = null;
81
81
  }
82
82
  else {
83
- const r = (0, child_process_1.spawnSync)('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', `Get-Command -Name ${JSON.stringify(commandName)} -ErrorAction Stop`], { encoding: 'utf8', timeout: NON_INTERACTIVE_PROBE_TIMEOUT_MS });
83
+ const r = (0, child_process_1.spawnSync)('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', `Get-Command -Name ${JSON.stringify(commandName)} -ErrorAction Stop`], { encoding: 'utf8', timeout: NON_INTERACTIVE_PROBE_TIMEOUT_MS, windowsHide: true });
84
84
  result = r.error || r.status !== 0
85
85
  ? `Command '${commandName}' not found in non-interactive PowerShell (powershell -NoProfile). ` +
86
86
  `This command may be a PowerShell profile function or alias that is unavailable without a profile. ` +
@@ -92,6 +92,7 @@ function probeCommandResolvesNonInteractively(runner, commandName) {
92
92
  const r = (0, child_process_1.spawnSync)('bash', ['--noprofile', '--norc', '-c', `command -v ${commandName}`], {
93
93
  encoding: 'utf8',
94
94
  timeout: NON_INTERACTIVE_PROBE_TIMEOUT_MS,
95
+ windowsHide: true,
95
96
  });
96
97
  result = r.error || r.status !== 0
97
98
  ? `Command '${commandName}' not found in non-interactive bash (bash --noprofile --norc). ` +
@@ -34,6 +34,7 @@ exports.detectCodexCompactTaskFailure = detectCodexCompactTaskFailure;
34
34
  exports.describeSpawnError = describeSpawnError;
35
35
  exports.hostDefaultUnsetEnv = hostDefaultUnsetEnv;
36
36
  exports.buildHostSpawnEnv = buildHostSpawnEnv;
37
+ exports.spawnHostProcess = spawnHostProcess;
37
38
  exports.findGeminiSessionIdForPrompt = findGeminiSessionIdForPrompt;
38
39
  exports.checkFraimMcpAttachReadiness = checkFraimMcpAttachReadiness;
39
40
  const crypto_1 = require("crypto");
@@ -134,7 +134,7 @@ function writeWindowsShortcutScript(lnkPath, target, workingDir = os_1.default.h
134
134
  '$sc.Save()',
135
135
  ].join('; ');
136
136
  try {
137
- (0, child_process_1.execFileSync)('powershell', ['-NoProfile', '-NonInteractive', '-Command', ps], { stdio: 'pipe' });
137
+ (0, child_process_1.execFileSync)('powershell', ['-NoProfile', '-NonInteractive', '-Command', ps], { stdio: 'pipe', windowsHide: true });
138
138
  }
139
139
  catch {
140
140
  // PowerShell unavailable (e.g. minimal CI image) — write a plain .cmd launcher as fallback.
@@ -3176,14 +3176,17 @@ class AiHubServer {
3176
3176
  resolveRunProjectPath(bodyProjectPath, scope) {
3177
3177
  return (0, run_working_directory_1.resolveRunWorkingDirectory)(scope, bodyProjectPath, this.defaultProjectPath());
3178
3178
  }
3179
- // Resolve latest outside the Hub process; sync also updates the MCP launcher record (#1354).
3180
- refreshLocalCatalogInBackground(global, projectRoot) {
3179
+ // Refresh at startup/restart, independently of jobs. Sync also updates the MCP launcher record (#1354).
3180
+ refreshLocalCatalogInBackground() {
3181
3181
  if (process.env.NODE_ENV === 'test' || this.catalogSyncChild)
3182
3182
  return;
3183
- const args = ['--yes', 'fraim@latest', 'sync', ...(global ? ['--global'] : [])];
3183
+ const args = ['--yes', 'fraim@latest', 'sync', '--global'];
3184
3184
  try {
3185
- // Windows npx is a .cmd shim. Only fixed arguments enter cmd; projectRoot stays in cwd.
3186
- const child = catalogSyncSpawn(process.platform === 'win32' ? (process.env.ComSpec || 'cmd.exe') : 'npx', process.platform === 'win32' ? ['/d', '/s', '/c', 'npx', ...args] : args, { cwd: projectRoot, detached: true, stdio: 'ignore', windowsHide: true });
3185
+ // Windows npx is a .cmd shim. Only fixed arguments enter cmd.
3186
+ const child = catalogSyncSpawn(process.platform === 'win32' ? (process.env.ComSpec || 'cmd.exe') : 'npx', process.platform === 'win32' ? ['/d', '/s', '/c', 'npx', ...args] : args,
3187
+ // On Windows, detachment lets descendants allocate visible consoles despite
3188
+ // windowsHide. Ignored stdio and unref still keep this refresh non-blocking.
3189
+ { detached: process.platform !== 'win32', stdio: 'ignore', windowsHide: true });
3187
3190
  this.catalogSyncChild = child;
3188
3191
  const release = () => {
3189
3192
  if (this.catalogSyncChild === child)
@@ -3243,7 +3246,7 @@ class AiHubServer {
3243
3246
  });
3244
3247
  }
3245
3248
  // Refresh the machine-level job list without delaying Hub startup.
3246
- this.refreshLocalCatalogInBackground(true);
3249
+ this.refreshLocalCatalogInBackground();
3247
3250
  // Update-badge freshness: refresh the npm-latest cache on our own clock, not just when
3248
3251
  // a page load or relaunch decision happens to ask for it. Without this, a Hub that's
3249
3252
  // resident in the tray for days with no window reload and no tray re-click never learns
@@ -7051,9 +7054,6 @@ class AiHubServer {
7051
7054
  ? { ...fraimRunEnriched, compareRun: this.enrichRunForResponse(directRun) }
7052
7055
  : fraimRunEnriched;
7053
7056
  res.status(201).json(responsePayload);
7054
- // Background sync: refresh the local FRAIM catalog so the next job
7055
- // picker load sees any jobs that were added or updated since last run.
7056
- this.refreshLocalCatalogInBackground(false, projectPath);
7057
7057
  }
7058
7058
  catch (error) {
7059
7059
  for (const spawningRun of pendingSpawnRuns) {
@@ -44,7 +44,7 @@ function probeVersion(commandPath) {
44
44
  const args = process.platform === 'win32'
45
45
  ? ['/d', '/s', '/c', `${escapeWindowsArg(commandPath)} --version`]
46
46
  : ['--version'];
47
- const result = (0, child_process_1.spawnSync)(executable, args, { encoding: 'utf8', timeout: 5000 });
47
+ const result = (0, child_process_1.spawnSync)(executable, args, { encoding: 'utf8', timeout: 5000, windowsHide: true });
48
48
  if (result.status !== 0 || result.error)
49
49
  return null;
50
50
  // Issue #1256 (AC-D1/D2): only stdout counts as a version — see versionFromProbeOutput.
@@ -93,7 +93,7 @@ function runCommand(command, args, options) {
93
93
  return spawnSync(command, args, options);
94
94
  }
95
95
 
96
- return spawnSync(process.env.ComSpec || 'cmd.exe', ['/d', '/s', '/c', [command, ...args.map(quoteCmdArg)].join(' ')], options);
96
+ return spawnSync(process.env.ComSpec || 'cmd.exe', ['/d', '/s', '/c', [command, ...args.map(quoteCmdArg)].join(' ')], { ...options, windowsHide: true });
97
97
  }
98
98
 
99
99
  function ensureDir(dir) {
@@ -59,7 +59,7 @@ function persistShellPath() {
59
59
  // getUserFraimDirPath() in project-fraim-paths.ts) rather than a
60
60
  // dedicated flag for this call site.
61
61
  if (process.env.FRAIM_TEST_SANDBOX !== '1') {
62
- const result = (0, child_process_1.spawnSync)('powershell', ['-NoProfile', '-NonInteractive', '-Command', psCmd], { encoding: 'utf8', timeout: 10000 });
62
+ const result = (0, child_process_1.spawnSync)('powershell', ['-NoProfile', '-NonInteractive', '-Command', psCmd], { encoding: 'utf8', timeout: 10000, windowsHide: true });
63
63
  if (result.error || result.status !== 0) {
64
64
  throw new Error(`Could not register managed binaries on the User PATH: ${result.error?.message || result.stderr}`);
65
65
  }
@@ -19,6 +19,7 @@ function spawnViaCmdExe(command, args, options) {
19
19
  const cmdString = needsOuterQuote ? `"${innerCmd}"` : innerCmd;
20
20
  return (0, child_process_1.spawnSync)(comSpec, ['/d', '/s', '/c', cmdString], {
21
21
  ...options,
22
+ windowsHide: true,
22
23
  windowsVerbatimArguments: true,
23
24
  });
24
25
  }
@@ -38,6 +38,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.FIRST_RUN_ROW_IDS = exports.FirstRunSessionService = void 0;
40
40
  exports.commandVersion = commandVersion;
41
+ exports.runProcess = runProcess;
41
42
  exports.buildFirstRunHubLaunchArgs = buildFirstRunHubLaunchArgs;
42
43
  const fs_1 = __importDefault(require("fs"));
43
44
  const os_1 = __importDefault(require("os"));
@@ -77,6 +78,7 @@ function commandVersion(command, extraBinDirs, basePath) {
77
78
  const recoveredPath = (0, managed_agent_paths_1.buildRecoveredAgentPath)(pathValue ?? process.env.PATH ?? process.env.Path);
78
79
  const env = { ...process.env, PATH: recoveredPath, Path: recoveredPath };
79
80
  const result = (0, child_process_1.spawnSync)(executable, args, {
81
+ windowsHide: true,
80
82
  encoding: 'utf8',
81
83
  timeout: 5000,
82
84
  env,
@@ -133,6 +135,7 @@ function runProcess(command, args, env) {
133
135
  }
134
136
  const child = (0, child_process_1.spawn)(realCmd, realArgs, {
135
137
  env: childEnv,
138
+ windowsHide: true,
136
139
  shell: false,
137
140
  });
138
141
  let stdout = '';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fraim-hub",
3
- "version": "2.0.332",
3
+ "version": "2.0.335",
4
4
  "description": "FRAIM Hub local companion package.",
5
5
  "author": "Sid Mathur <sid.mathur@gmail.com>",
6
6
  "homepage": "https://github.com/mathursrus/FRAIM#readme",
@@ -221,7 +221,7 @@
221
221
  "electron-updater": "^6.8.9",
222
222
  "express": "^5.2.1",
223
223
  "extract-zip": "^2.0.1",
224
- "fraim": "2.0.332",
224
+ "fraim": "2.0.335",
225
225
  "mongodb": "^7.0.0",
226
226
  "node-cron": "4.2.1",
227
227
  "node-edge-tts": "^1.2.10",
@@ -437,12 +437,12 @@
437
437
  </div>
438
438
 
439
439
  <div class="manage-panel-shell">
440
- <details class="panel-details panel-details--thread" id="thread-panel" open>
441
- <summary>
440
+ <section class="panel-details panel-details--thread" id="thread-panel">
441
+ <div class="thread-header">
442
442
  <span class="panel-summary-copy">
443
443
  <span class="panel-kicker" id="thread-panel-kicker">Manage</span>
444
444
  </span>
445
- </summary>
445
+ </div>
446
446
  <!-- Issue #1065: find a passage inside the open conversation (R44-R46). A result that
447
447
  promises "+6 more matches" is an unkept promise without this: the manager lands in
448
448
  a thread that can run to hundreds of messages with no way to reach the match. -->
@@ -473,26 +473,13 @@
473
473
  </div>
474
474
  </div>
475
475
  </div>
476
- </details>
476
+ </section>
477
477
  <div class="manage-header-actions">
478
- <button class="conversation-focus-btn" id="conversation-focus-btn" type="button" aria-label="Expand conversation" title="Expand conversation">&#8599;</button>
479
478
  <button class="micro-manage-toggle" id="micro-manage-toggle" type="button" role="switch" aria-checked="false" aria-controls="manage-body"><span>Micro-Manage</span><span class="micro-switch-track" aria-hidden="true"></span></button>
480
479
  </div>
481
480
  </div>
482
481
 
483
482
  <div class="support-stack">
484
- <!-- Issue #770: single-run deliverables live here (a stable collapsible
485
- panel), not pinned to the bottom of the thread. Static-and-hidden,
486
- populated + toggled by renderDeliverablesPanel. -->
487
- <details class="panel-details panel-details--deliverables" id="deliverables-panel" hidden>
488
- <summary>
489
- <span class="panel-summary-copy">
490
- <span class="panel-kicker">Deliverables</span>
491
- <span class="panel-summary-text" id="deliverables-summary"></span>
492
- </span>
493
- </summary>
494
- <div class="panel-body" id="deliverables-body"></div>
495
- </details>
496
483
  <!-- Issue #1292: when this conversation's own agent stops being available,
497
484
  say so. The selector keeps holding that agent; it is never quietly
498
485
  swapped for another one. Lives outside the composer controls so
@@ -519,23 +506,23 @@
519
506
  </div>
520
507
  </div>
521
508
 
522
- <details class="panel-details panel-details--thread" id="ab-direct-thread-panel" open>
523
- <summary>
509
+ <section class="panel-details panel-details--thread" id="ab-direct-thread-panel">
510
+ <div class="thread-header">
524
511
  <span class="panel-summary-copy">
525
512
  <span class="panel-kicker">Direct output (raw)</span>
526
513
  </span>
527
- </summary>
514
+ </div>
528
515
  <pre class="ab-direct-log" id="ab-direct-log"></pre>
529
- </details>
516
+ </section>
530
517
 
531
518
  <div class="support-stack">
532
- <details class="panel-details panel-details--coach" id="ab-direct-reply-panel" open>
533
- <summary>
519
+ <section class="panel-details panel-details--coach" id="ab-direct-reply-panel">
520
+ <div class="thread-header">
534
521
  <span class="panel-summary-copy">
535
522
  <span class="panel-kicker">Reply to Direct agent</span>
536
- <span class="panel-summary-text" id="ab-direct-reply-summary">Open to send a follow-up</span>
523
+ <span class="panel-summary-text" id="ab-direct-reply-summary">Send a follow-up</span>
537
524
  </span>
538
- </summary>
525
+ </div>
539
526
  <div class="panel-body">
540
527
  <div class="coach">
541
528
  <div class="coach-input">
@@ -544,7 +531,7 @@
544
531
  </div>
545
532
  </div>
546
533
  </div>
547
- </details>
534
+ </section>
548
535
  </div>
549
536
  </div>
550
537
 
@@ -555,9 +542,7 @@
555
542
  visible even when no conversation is active"). Only the content
556
543
  ABOVE this div changes (idle placeholder, hire strip, thread, or
557
544
  the A/B compare panel); the composer itself never opens, closes,
558
- or relocates - except into #conversation-focus-panels during
559
- "expand conversation", handled by openConversationFocus/
560
- closeConversationFocus alongside #thread-panel. -->
545
+ or relocates. -->
561
546
  <div id="persistent-composer">
562
547
  <div class="composer-suggestions" id="composer-suggestions" hidden>
563
548
  <div id="cp-results" class="cp-results-scroll">
@@ -589,14 +574,10 @@
589
574
  <button type="button" id="cp-armed-job-clear" aria-label="Change job">&times;</button>
590
575
  </div>
591
576
  <div class="staged-attachments" id="staged-attachments"></div>
592
- <div class="review-actions" id="review-actions" hidden>
593
- <button class="rb-approve" type="button" id="review-approve">&#10003; Approve</button>
594
- <button class="rb-secondary" type="button" id="review-request-changes">&#8617; Request changes</button>
595
- <span class="rb-handoff" id="review-handoff">Comment on the doc to leave inline notes, or type below to coach.</span>
596
- </div>
577
+
597
578
  <div class="coach-input">
598
579
  <input type="file" id="attach-file-input" multiple accept="image/png,image/jpeg,image/gif,.pdf,.txt,.log" hidden>
599
- <textarea id="coach-text" aria-label="Type an instruction" placeholder="Type a job name, /handle, or describe what you need..." data-placeholder-idle="Type a job name, /handle, or describe what you need..." data-placeholder-active="Coach this run, or type new instructions..." data-placeholder-armed="Now type what you want done..."></textarea>
580
+ <textarea id="coach-text" aria-label="Type an instruction" placeholder="Type a job name, /handle, or describe what you need..." data-placeholder-idle="Type a job name, /handle, or describe what you need..." data-placeholder-review="Reply to continue the run, or use Approve / Request changes above..." data-placeholder-active="Coach this run, or type new instructions..." data-placeholder-armed="Now type what you want done..."></textarea>
600
581
  <div class="composer-footer">
601
582
  <button class="attach-btn" type="button" id="attach-btn" aria-label="Attach a file or screenshot" title="Attach a file or screenshot">&#128206;</button>
602
583
  <div class="quick-coach-row composer-coach-actions" id="quick-coach-btns" hidden>
@@ -683,7 +664,7 @@
683
664
  </main>
684
665
  </div>
685
666
 
686
- <p class="status-line" id="status-line" role="status" aria-live="polite"></p>
667
+
687
668
  </div>
688
669
 
689
670
  <!-- Issue #1065: search results replace the conversation panel while a query is active,
@@ -1130,19 +1111,6 @@
1130
1111
  </div>
1131
1112
  </div>
1132
1113
 
1133
- <!-- Issue #539: Command palette overlay — replaces 2-step modal as job-launch surface -->
1134
- <section class="conversation-focus-overlay" id="conversation-focus-overlay" role="dialog" aria-modal="true" aria-labelledby="conversation-focus-title" hidden>
1135
- <div class="conversation-focus-dialog">
1136
- <div class="conversation-focus-header">
1137
- <div class="conversation-focus-copy">
1138
- <strong id="conversation-focus-title">Focused conversation</strong>
1139
- <span id="conversation-focus-subtitle">Conversation thread and coaching</span>
1140
- </div>
1141
- <button class="conversation-focus-close" id="conversation-focus-close" type="button" aria-label="Close focused conversation">Close</button>
1142
- </div>
1143
- <div class="conversation-focus-panels" id="conversation-focus-panels"></div>
1144
- </div>
1145
- </section>
1146
1114
 
1147
1115
  <!-- Issue #1657 Treatment 3: #cp-modal is retired as a separate dialog.
1148
1116
  The ids below (cp-recent-list, cp-catalog-list, cp-agent-picker, etc.)
@@ -1265,7 +1233,15 @@
1265
1233
  </div>
1266
1234
  </div>
1267
1235
 
1236
+ <div id="review-action-storage" hidden>
1237
+ <div class="review-actions" id="review-actions" hidden>
1238
+ <button class="rb-approve" type="button" id="review-approve">&#10003; Approve</button>
1239
+ <button class="rb-secondary" type="button" id="review-request-changes">&#8617; Request changes</button>
1240
+ <span class="rb-handoff" id="review-handoff">Comment on the doc to leave inline notes, or type below to coach.</span>
1241
+ </div>
1242
+ </div>
1268
1243
  <script src="./script.js?v=dark-status-20260721"></script>
1269
1244
  <script src="./remote-ui-loader.js?v=server-driven-ui-20260724"></script>
1245
+
1270
1246
  </body>
1271
1247
  </html>
@@ -422,8 +422,6 @@
422
422
  .rev-item .rev-dismiss:hover { background: var(--soft); }
423
423
 
424
424
  /* ── #770: Deliverables panel body spacing for the relocated artifact strip. ── */
425
- #deliverables-panel .panel-body { padding-top: 8px; }
426
- #deliverables-panel .rc-artifact-strip { margin: 0; }
427
425
 
428
426
  /* ── R9: project-scoped learnings panel (over the workspace conversation) ── */
429
427
  .proj-learnings-panel {
@@ -633,3 +631,6 @@
633
631
  flex-direction: column;
634
632
  gap: 6px;
635
633
  }
634
+
635
+ .review-turn .review-actions { border: 0; margin: 0; padding: 0; }
636
+ .review-turn .rb-handoff { flex-basis: 100%; }