@scotthuang/agent-knock-knock 0.12.25 → 0.12.26

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.
@@ -10,6 +10,7 @@ import { resolveSessionSelector, sessionShortRef } from "./session-selector.js";
10
10
  import { projectSessionSelectorCandidate } from "./terminal-selector-projection-service.js";
11
11
  import { listManagedSessions, loadNativeThreadTransition, nativeThreadTransitionsDir, tryLoadManagedSession } from "./session-store.js";
12
12
  import { defaultStoreDir, ensureStoreWritable, inspectStoreCompatibility, listConversations, storeManifestPath, STORE_SESSION_AUTHORITY_PROTOCOL } from "./store.js";
13
+ import { parseTerminalConversationId } from "./terminal-agent-adapter.js";
13
14
  import { exactCodexReadyStyledComposerCapture } from "./terminal-agent-bridge.js";
14
15
  import { captureCodexHumanStartedActiveTaskAnchor } from "./terminal-submission-acceptance.js";
15
16
  import { applySessionAuthorityToDispatch, authoritativeTerminalIdentity, compareManagedConversationRecency, decideManagedTerminalAssociation, decideLocalTerminalDispatchOwnership, decideTerminalSendAuthority, decideTerminalSessionAuthorityConflict, decideTerminalUserExplicitSendAuthority, managedTurnNeedsAttention as terminalManagedTurnNeedsAttention, nonOwnerTerminalActions, projectBlockingTurn, projectHandoffDecision, projectHandoffPresentation, projectPublicManagementConflict, projectReconcileBindingAction, projectTerminalDispatchConflict, projectTerminalManagement, selectManagedTerminalHistory, selectTerminalAvailableActions } from "./terminal-action-projection.js";
@@ -262,6 +263,14 @@ async function observeExactTerminal(request) {
262
263
  const scan = await buildTerminalListGroup({ options, terminalId });
263
264
  const matches = scan.terminalControlled.filter((terminal) => stringValue(terminal.id) === terminalId);
264
265
  if (matches.length !== 1) {
266
+ const state = scan.summary.error ? "unavailable" : "absent";
267
+ runtimeLog("info", "terminal_exact_observation", {
268
+ terminal_id: terminalId,
269
+ state,
270
+ matching_terminal_count: matches.length,
271
+ observed_terminal_ids: scan.terminalControlled.map((terminal) => terminal.id),
272
+ scan_summary: scan.summary
273
+ });
265
274
  return scan.summary.error
266
275
  ? {
267
276
  state: "unavailable",
@@ -279,12 +288,25 @@ async function observeExactTerminal(request) {
279
288
  });
280
289
  const projectedMatches = projected.terminals.filter((terminal) => stringValue(terminal.id) === terminalId);
281
290
  if (projectedMatches.length !== 1) {
291
+ runtimeLog("info", "terminal_exact_observation", {
292
+ terminal_id: terminalId,
293
+ state: "unavailable",
294
+ stage: "projection",
295
+ matching_terminal_count: projectedMatches.length,
296
+ scan_summary: scan.summary
297
+ });
282
298
  return {
283
299
  state: "unavailable",
284
300
  reason: "the exact terminal could not be projected authoritatively",
285
301
  summary: scan.summary
286
302
  };
287
303
  }
304
+ runtimeLog("info", "terminal_exact_observation", {
305
+ terminal_id: terminalId,
306
+ state: "available",
307
+ matching_terminal_count: 1,
308
+ scan_summary: scan.summary
309
+ });
288
310
  return {
289
311
  state: "available",
290
312
  rawTerminal: matches[0],
@@ -359,18 +381,74 @@ async function buildTerminalListGroup({ options, agentFilter, statusFilter, term
359
381
  const terminalDiagnostics = options.terminalDebug
360
382
  ? await terminalControlDiagnostics(terminalProvider)
361
383
  : undefined;
384
+ const exactTarget = terminalId
385
+ ? exactTerminalTargetDiagnostic(terminalId)
386
+ : undefined;
387
+ if (terminalId) {
388
+ runtimeLog("info", "terminal_exact_scan", {
389
+ stage: "started",
390
+ terminal_id: terminalId,
391
+ target: exactTarget
392
+ });
393
+ }
362
394
  const terminalControlled = [];
363
395
  let activeCount = 0;
364
396
  const errors = [];
365
397
  try {
366
398
  const processSource = terminalListRuntime().createTerminalProcessSource(options);
367
399
  const snapshots = await processSource.listProcessSnapshots((snapshot) => adapters.some((adapter) => adapter.capabilities.processDiscovery && adapter.classifyProcess(snapshot) !== undefined), { includeAncestors: true });
400
+ if (terminalId) {
401
+ const targetPid = exactTarget?.pid;
402
+ runtimeLog("info", "terminal_exact_scan", {
403
+ stage: "process_inventory",
404
+ terminal_id: terminalId,
405
+ target_pid: targetPid,
406
+ snapshot_count: snapshots.length,
407
+ target_process_found: targetPid === undefined
408
+ ? undefined
409
+ : snapshots.some((snapshot) => snapshot.pid === targetPid),
410
+ target_process_snapshots: targetPid === undefined
411
+ ? []
412
+ : snapshots
413
+ .filter((snapshot) => snapshot.pid === targetPid)
414
+ .map((snapshot) => ({ pid: snapshot.pid, ppid: snapshot.ppid }))
415
+ });
416
+ }
368
417
  const activeSessions = await bridge.listProcesses(snapshots, adapters.map((adapter) => adapter.agent));
369
- const rootSessions = selectRootTerminalProcesses(activeSessions);
418
+ const rootSessions = selectRootTerminalProcesses(activeSessions, snapshots);
370
419
  const controlledSessions = rootSessions.filter((session) => session.terminalControl !== undefined);
420
+ if (terminalId) {
421
+ const targetPid = exactTarget?.pid;
422
+ const targetSessions = targetPid === undefined
423
+ ? []
424
+ : activeSessions.filter((session) => session.pid === targetPid);
425
+ runtimeLog("info", "terminal_exact_scan", {
426
+ stage: "process_classification_and_association",
427
+ terminal_id: terminalId,
428
+ target_pid: targetPid,
429
+ classified_process_count: activeSessions.length,
430
+ root_process_count: rootSessions.length,
431
+ controlled_process_count: controlledSessions.length,
432
+ target_classified_count: targetSessions.length,
433
+ target_controlled_count: targetSessions.filter((session) => session.terminalControl !== undefined).length,
434
+ target_sessions: targetSessions.map((session) => ({
435
+ agent: session.agent,
436
+ pid: session.pid,
437
+ ppid: session.ppid,
438
+ kind: session.kind,
439
+ confidence: session.confidence,
440
+ selected_as_root: rootSessions.includes(session),
441
+ terminal_conversation_id: session.terminalControl
442
+ ? bridge.terminalConversationId(session)
443
+ : undefined,
444
+ terminal_control: terminalControlScanDiagnostic(session.terminalControl)
445
+ }))
446
+ });
447
+ }
371
448
  activeCount = controlledSessions.length;
372
449
  const selectedSessions = terminalId
373
- ? controlledSessions.filter((session) => bridge.terminalConversationId(session) === terminalId)
450
+ ? activeSessions.filter((session) => session.terminalControl !== undefined &&
451
+ bridge.terminalConversationId(session) === terminalId)
374
452
  : controlledSessions;
375
453
  for (const session of selectedSessions) {
376
454
  try {
@@ -385,6 +463,16 @@ async function buildTerminalListGroup({ options, agentFilter, statusFilter, term
385
463
  catch (error) {
386
464
  errors.push(error instanceof Error ? error.message : String(error));
387
465
  }
466
+ if (terminalId) {
467
+ runtimeLog("info", "terminal_exact_scan", {
468
+ stage: "complete",
469
+ terminal_id: terminalId,
470
+ controlled_process_count: activeCount,
471
+ terminal_row_count: terminalControlled.length,
472
+ terminal_row_ids: terminalControlled.map((terminal) => terminal.id),
473
+ errors
474
+ });
475
+ }
388
476
  return {
389
477
  terminalControlled,
390
478
  summary: {
@@ -398,6 +486,37 @@ async function buildTerminalListGroup({ options, agentFilter, statusFilter, term
398
486
  }
399
487
  };
400
488
  }
489
+ function exactTerminalTargetDiagnostic(terminalId) {
490
+ try {
491
+ const parsed = parseTerminalConversationId(terminalId);
492
+ return parsed ? {
493
+ provider: parsed.kind,
494
+ agent: parsed.agent,
495
+ route: parsed.target,
496
+ pid: parsed.pid
497
+ } : undefined;
498
+ }
499
+ catch (error) {
500
+ return {
501
+ parse_error: error instanceof Error ? error.message : String(error)
502
+ };
503
+ }
504
+ }
505
+ function terminalControlScanDiagnostic(terminalControl) {
506
+ if (!terminalControl) {
507
+ return undefined;
508
+ }
509
+ const control = terminalControl;
510
+ return {
511
+ kind: terminalControl.kind,
512
+ target: terminalControl.target,
513
+ pane_pid: control.panePid,
514
+ process_anchor_pid: control.processAnchorPid,
515
+ endpoint_key: control.endpointKey,
516
+ resource_key: control.resourceKey,
517
+ terminal_id: control.terminalId
518
+ };
519
+ }
401
520
  async function terminalControlDiagnostics(provider) {
402
521
  return provider.diagnostics();
403
522
  }
@@ -459,7 +578,7 @@ async function terminalControlledListEntry(session, activeSessions, options, bri
459
578
  : { sessionId: session.sessionId }),
460
579
  terminalTarget: terminalControl.target
461
580
  });
462
- const { orphanedDispatch, nativeIdentityObservation, nativeAgentIdentity, codexOpenRootRolloutInventory, nativeProcessUuid, nativeProcessBirth, nativeProcessEvidence } = await observeTerminalNativeListIdentity(session, terminalControl, options, bridge);
581
+ const { orphanedDispatch, nativeIdentityObservation, nativeAgentIdentity, authorityNativeIdentityObservation, authorityNativeAgentIdentity, codexOpenRootRolloutInventory, nativeProcessUuid, nativeProcessBirth, nativeProcessEvidence } = await observeTerminalNativeListIdentity(session, terminalControl, options, bridge);
463
582
  const effectiveTerminalState = effectiveTerminalListState({
464
583
  session,
465
584
  terminalState,
@@ -522,6 +641,17 @@ async function terminalControlledListEntry(session, activeSessions, options, bri
522
641
  processBirth: nativeProcessBirth,
523
642
  rollout: nativeAgentIdentity?.rollout
524
643
  });
644
+ const authorityLifecycleBindingToken = unmanagedTerminalBindingToken({
645
+ terminalId: bridge.terminalConversationId(session),
646
+ terminalControl,
647
+ agent: session.agent,
648
+ pid: session.pid,
649
+ workspace: session.cwd ?? terminalControl.currentPath ?? cliCwd(),
650
+ nativeThreadId: authorityNativeAgentIdentity?.sessionId,
651
+ processUuid: nativeProcessUuid,
652
+ processBirth: nativeProcessBirth,
653
+ rollout: authorityNativeAgentIdentity?.rollout
654
+ });
525
655
  const codexLifecycleIncarnationAvailable = session.agent !== "codex" ||
526
656
  Boolean(nativeProcessUuid && nativeProcessBirth);
527
657
  let terminalHasBlockingTurn = true;
@@ -605,6 +735,11 @@ async function terminalControlledListEntry(session, activeSessions, options, bri
605
735
  // human native-thread switch.
606
736
  _automated_input_composer_ready: automatedInputComposerReady,
607
737
  _user_explicit_composer_ready: userExplicitComposerReady,
738
+ _native_identity_authority: {
739
+ observation: authorityNativeIdentityObservation,
740
+ identity: authorityNativeAgentIdentity,
741
+ lifecycle_binding_token: authorityLifecycleBindingToken
742
+ },
608
743
  ...(codexLatentClearResumeObservationValue
609
744
  ? {
610
745
  _codex_latent_clear_resume: {
@@ -639,7 +774,7 @@ async function terminalControlledListEntry(session, activeSessions, options, bri
639
774
  terminalState: effectiveTerminalState,
640
775
  lifecycleCapability,
641
776
  nativeInspectionCapability,
642
- nativeAgentIdentity,
777
+ nativeAgentIdentity: authorityNativeAgentIdentity,
643
778
  nativeProcessUuid,
644
779
  nativeProcessBirth,
645
780
  codexLifecycleIncarnationAvailable,
@@ -821,8 +956,9 @@ async function observeTerminalNativeListIdentity(session, terminalControl, optio
821
956
  }
822
957
  catch (error) {
823
958
  // Preserve generic discovery when Store hints are unavailable. Once an
824
- // exact hint exists, however, the constrained resolver below must fail
825
- // closed rather than retrying without its managed lineage fences.
959
+ // exact hint exists, the constrained resolver below still evaluates it;
960
+ // a separate complete root inventory may later describe the physical
961
+ // read-only identity without granting managed mutation authority.
826
962
  runtimeLog("warn", "terminal_managed_identity_context_unavailable", {
827
963
  agent: session.agent,
828
964
  terminal_target: terminalControl.target,
@@ -850,8 +986,9 @@ async function observeTerminalNativeListIdentity(session, terminalControl, optio
850
986
  reason: error instanceof Error ? error.message : String(error)
851
987
  };
852
988
  }
853
- const nativeAgentIdentity = nativeIdentityObservation.status === "resolved"
854
- ? nativeIdentityObservation.identity
989
+ const authorityNativeIdentityObservation = nativeIdentityObservation;
990
+ const authorityNativeAgentIdentity = authorityNativeIdentityObservation.status === "resolved"
991
+ ? authorityNativeIdentityObservation.identity
855
992
  : undefined;
856
993
  let codexOpenRootRolloutInventory;
857
994
  if (session.agent === "codex") {
@@ -874,6 +1011,29 @@ async function observeTerminalNativeListIdentity(session, terminalControl, optio
874
1011
  });
875
1012
  }
876
1013
  }
1014
+ if (session.agent === "codex" &&
1015
+ nativeIdentityObservation.status === "unavailable" &&
1016
+ codexOpenRootRolloutInventory?.status === "resolved" &&
1017
+ codexOpenRootRolloutInventory.pid === session.pid) {
1018
+ const constrainedReason = nativeIdentityObservation.reason;
1019
+ const [identity] = codexOpenRootRolloutInventory.roots;
1020
+ if (identity.processUuid === codexOpenRootRolloutInventory.processUuid &&
1021
+ identity.processBirth === codexOpenRootRolloutInventory.processBirth) {
1022
+ nativeIdentityObservation = {
1023
+ status: "resolved",
1024
+ identity
1025
+ };
1026
+ runtimeLog("info", "terminal_native_session_identity_resolved_from_unique_root_inventory", {
1027
+ agent: session.agent,
1028
+ terminal_target: terminalControl.target,
1029
+ pid: session.pid,
1030
+ preferred_session_id: codexIdentityContext?.preferredSessionId,
1031
+ resolved_session_id: identity.sessionId,
1032
+ constrained_error: constrainedReason,
1033
+ inventory_fingerprint: codexOpenRootRolloutInventory.inventoryFingerprint
1034
+ });
1035
+ }
1036
+ }
877
1037
  if (nativeIdentityObservation.status === "unavailable") {
878
1038
  runtimeLog("warn", "terminal_native_session_identity_unavailable", {
879
1039
  agent: session.agent,
@@ -882,6 +1042,9 @@ async function observeTerminalNativeListIdentity(session, terminalControl, optio
882
1042
  error: nativeIdentityObservation.reason
883
1043
  });
884
1044
  }
1045
+ const nativeAgentIdentity = nativeIdentityObservation.status === "resolved"
1046
+ ? nativeIdentityObservation.identity
1047
+ : undefined;
885
1048
  let nativeProcessUuid = nativeAgentIdentity?.processUuid;
886
1049
  let nativeProcessBirth = nativeAgentIdentity?.processBirth;
887
1050
  let nativeProcessEvidence = nativeAgentIdentity?.evidence;
@@ -911,6 +1074,8 @@ async function observeTerminalNativeListIdentity(session, terminalControl, optio
911
1074
  orphanedDispatch,
912
1075
  nativeIdentityObservation,
913
1076
  nativeAgentIdentity,
1077
+ authorityNativeIdentityObservation,
1078
+ authorityNativeAgentIdentity,
914
1079
  codexOpenRootRolloutInventory,
915
1080
  nativeProcessUuid,
916
1081
  nativeProcessBirth,
@@ -953,9 +1118,10 @@ async function observeAutomatedInputComposerReady({ session, terminalControl, te
953
1118
  userExplicitComposerReady: userExplicitReady
954
1119
  };
955
1120
  }
956
- function observeTerminalListBindingAuthority(terminal, context) {
1121
+ function observeTerminalListBindingAuthority(listedTerminal, context) {
957
1122
  const { storeDir, managedSessions, allConversations, displayedConversations, mutationsAllowed, nonterminalDeferredTransfers } = context;
958
- const { _automated_input_composer_ready: automatedInputComposerReady, _user_explicit_composer_ready: _userExplicitComposerReady, _codex_open_root_rollout_inventory: codexOpenRootRolloutInventoryValue, _codex_latent_clear_resume: codexLatentClearResumeValue, _terminal_user_explicit_send_action: terminalUserExplicitSendAction, _terminal_status_snapshot: _terminalStatusSnapshot, ...publicTerminal } = terminal;
1123
+ const { _automated_input_composer_ready: automatedInputComposerReady, _user_explicit_composer_ready: _userExplicitComposerReady, _codex_open_root_rollout_inventory: codexOpenRootRolloutInventoryValue, _codex_latent_clear_resume: codexLatentClearResumeValue, _terminal_user_explicit_send_action: terminalUserExplicitSendAction, _terminal_status_snapshot: _terminalStatusSnapshot, _native_identity_authority: nativeIdentityAuthorityValue, ...publicTerminal } = listedTerminal;
1124
+ const terminal = terminalIdentityAuthorityView(listedTerminal, nativeIdentityAuthorityValue);
959
1125
  const codexOpenRootRolloutInventory = isRecord(codexOpenRootRolloutInventoryValue)
960
1126
  ? codexOpenRootRolloutInventoryValue
961
1127
  : undefined;
@@ -1111,6 +1277,7 @@ function observeTerminalListBindingAuthority(terminal, context) {
1111
1277
  }
1112
1278
  : undefined;
1113
1279
  return {
1280
+ authorityTerminal: terminal,
1114
1281
  automatedInputComposerReady,
1115
1282
  codexOpenRootRolloutInventory,
1116
1283
  codexLatentClearResumeValue,
@@ -1149,12 +1316,33 @@ function observeTerminalListBindingAuthority(terminal, context) {
1149
1316
  codexSendAuthorityContext
1150
1317
  };
1151
1318
  }
1319
+ function terminalIdentityAuthorityView(terminal, authorityValue) {
1320
+ if (!isRecord(authorityValue)) {
1321
+ return terminal;
1322
+ }
1323
+ const observation = isRecord(authorityValue.observation)
1324
+ ? authorityValue.observation
1325
+ : { status: "not_observed" };
1326
+ const identity = isRecord(authorityValue.identity)
1327
+ ? authorityValue.identity
1328
+ : undefined;
1329
+ return {
1330
+ ...terminal,
1331
+ native_agent_session_id: stringValue(identity?.sessionId),
1332
+ native_agent_rollout: isRecord(identity?.rollout)
1333
+ ? identity.rollout
1334
+ : undefined,
1335
+ native_agent_identity_observation: observation,
1336
+ lifecycle_binding_token: stringValue(authorityValue.lifecycle_binding_token) ??
1337
+ terminal.lifecycle_binding_token
1338
+ };
1339
+ }
1152
1340
  function observeVerifiedEmptyTerminalAuthority(terminal, context, binding) {
1153
1341
  const { storeDir, terminals, mutationsAllowed } = context;
1154
1342
  const { automatedInputComposerReady, terminalControl, matchingSessions, unresolvedSessionClaims, discoveredOwnership, rawActions, soleBindingConflict, blockingHandoffTurns, terminalBlockingTurns, nativeIdentityObservation, codexProcessUuid, codexProcessBirth, codexWorkspace, codexSendAuthorityContext } = binding;
1155
1343
  const verifiedEmptySourceNativeThreadId = stringValue(soleBindingConflict?.session.binding?.native_thread_id)?.toLowerCase();
1156
1344
  const verifiedEmptySourceActiveElsewhere = Boolean(verifiedEmptySourceNativeThreadId &&
1157
- terminals.some((candidate) => candidate !== terminal &&
1345
+ terminals.some((candidate) => stringValue(candidate.id) !== stringValue(terminal.id) &&
1158
1346
  candidate.agent === "codex" &&
1159
1347
  stringValue(candidate.native_agent_session_id)?.toLowerCase() ===
1160
1348
  verifiedEmptySourceNativeThreadId));
@@ -1254,7 +1442,7 @@ function observeDeferredSourceAuthority(terminal, context, observation) {
1254
1442
  });
1255
1443
  }
1256
1444
  const deferredCodexSourceActiveElsewhere = Boolean(deferredCodexSourceNativeThreadId &&
1257
- terminals.some((candidate) => candidate !== terminal &&
1445
+ terminals.some((candidate) => stringValue(candidate.id) !== stringValue(terminal.id) &&
1258
1446
  candidate.agent === "codex" &&
1259
1447
  stringValue(candidate.native_agent_session_id)?.toLowerCase() ===
1260
1448
  deferredCodexSourceNativeThreadId));
@@ -1735,7 +1923,10 @@ function terminalFirstListProjection({ storeDir, terminals, managedSessions, ses
1735
1923
  nonterminalDeferredTransfers,
1736
1924
  conversationHasNonterminalDeferredTransfer
1737
1925
  };
1738
- const projectedTerminals = terminals.map((terminal) => renderTerminalFirstListEntry(terminal, projectionContext, observeTerminalListActionAuthority(terminal, projectionContext, observeTerminalListBindingAuthority(terminal, projectionContext))));
1926
+ const projectedTerminals = terminals.map((terminal) => {
1927
+ const binding = observeTerminalListBindingAuthority(terminal, projectionContext);
1928
+ return renderTerminalFirstListEntry(binding.authorityTerminal, projectionContext, observeTerminalListActionAuthority(binding.authorityTerminal, projectionContext, binding));
1929
+ });
1739
1930
  const unavailableManagedTurns = displayedConversations
1740
1931
  .filter((conversation) => {
1741
1932
  const managedControl = terminalControlForManagedConversation(conversation);