@agent-link/agent 0.1.272 → 0.1.273

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.
@@ -11,6 +11,8 @@ import { handleCreateLoop, handleUpdateLoop, handleDeleteLoop, handleListLoops,
11
11
  import { loadSessionMetadata, loadAllSessionMetadata, deleteSessionMetadata } from './session-metadata.js';
12
12
  import { listRecaps, listRecapsWithStatus, getRecapDetail, runActionItemsCli } from './recap.js';
13
13
  import { listActions, getActionDetail } from './action.js';
14
+ import { bindActionDraftSession, commitActionDraft, createActionDraft, discardActionDraft, getActionDraft, listActionDrafts, validateActionDraftId, } from './action-drafts.js';
15
+ import { resolveNewActionDraftSessionDir } from './action-draft-session.js';
14
16
  import { listIcms } from './playground-icm.js';
15
17
  import { listBriefings, getBriefingDetail } from './briefing.js';
16
18
  import { listDevops, getDevopsDetail } from './devops.js';
@@ -136,7 +138,7 @@ export function connect(config) {
136
138
  }
137
139
  catch { /* ignore */ }
138
140
  }
139
- unsubscribeSessionStarted = addOnSessionStarted(checkPendingActionItem);
141
+ unsubscribeSessionStarted = addOnSessionStarted(checkPendingSessionLinks);
140
142
  // Initialize the tunnel handler for port proxy
141
143
  tunnelHandler = createTunnelHandler(send);
142
144
  // Initialize the terminal manager for web terminal
@@ -514,10 +516,12 @@ function scheduleReconnect(config) {
514
516
  }, delay);
515
517
  }
516
518
  const BRAIN_DATA_DIR = getBrainDataDir();
519
+ const FOLLOW_THROUGH_SESSION_DIR = path.join(BRAIN_DATA_DIR, 'reports', 'follow-through');
517
520
  const BRAIN_SERVER = 'http://localhost:8001';
518
521
  // Pending action item IDs: conversationId → actionItemId
519
522
  // Used to link a chat's Claude session to an action item for CLI start
520
523
  const pendingActionItems = new Map();
524
+ const pendingActionDrafts = new Map();
521
525
  function handleServerMessage(msg) {
522
526
  console.log(`[AgentLink] ← ${msg.type}`);
523
527
  switch (msg.type) {
@@ -556,9 +560,21 @@ function handleServerMessage(msg) {
556
560
  const projectName = msg.projectName;
557
561
  const icmId = msg.icmId;
558
562
  const actionItemId = msg.actionItemId;
563
+ const actionDraftId = msg.actionDraftId;
559
564
  const explicitWorkDir = msg.workDir;
565
+ if (actionDraftId) {
566
+ try {
567
+ validateActionDraftId(actionDraftId);
568
+ }
569
+ catch (err) {
570
+ send({ type: 'error', message: String(err), conversationId: chatConvId });
571
+ break;
572
+ }
573
+ }
560
574
  // Backward compat: brainMode: true without providerId → "brain"
561
- const effectiveProviderId = msgProviderId || (isBrainMode ? 'brain' : undefined);
575
+ const effectiveProviderId = actionDraftId
576
+ ? 'brain'
577
+ : (msgProviderId || (isBrainMode ? 'brain' : undefined));
562
578
  console.log(`[AgentLink] chat: conversationId=${chatConvId}, existingConv.planMode=${existingConv?.planMode}, providerId=${effectiveProviderId || '(default)'}`);
563
579
  const chatOptions = {
564
580
  resumeSessionId: msg.resumeSessionId,
@@ -587,13 +603,19 @@ function handleServerMessage(msg) {
587
603
  if (icmId) {
588
604
  chatOptions.icmId = String(icmId);
589
605
  }
606
+ if (actionDraftId) {
607
+ chatOptions.actionDraftId = actionDraftId;
608
+ }
590
609
  // Determine the working directory for this chat. For resumed sessions
591
610
  // the JSONL may live in a different cwd than the agent's current workDir
592
611
  // (e.g. action-item sessions spawned by BrainCore live in $HOME). When
593
612
  // no existingConv is found (agent restarted, or cache-hit skipped
594
613
  // resume_conversation), probe the filesystem to find the right directory.
595
- let chatDir = explicitWorkDir ?? existingConv?.workDir;
596
- if (!chatDir && (recapId || briefingDate || devopsEntityType || projectName || icmId)) {
614
+ const newActionDraftSessionDir = resolveNewActionDraftSessionDir(BRAIN_DATA_DIR, actionDraftId, explicitWorkDir, chatOptions.resumeSessionId, existingConv);
615
+ let chatDir = newActionDraftSessionDir ?? explicitWorkDir ?? existingConv?.workDir;
616
+ if (newActionDraftSessionDir)
617
+ mkdirSync(FOLLOW_THROUGH_SESSION_DIR, { recursive: true });
618
+ if (!chatDir && (recapId || briefingDate || devopsEntityType || projectName || icmId || actionDraftId)) {
597
619
  // Brain-mode session: try BRAIN_DATA_DIR first, then homedir fallback
598
620
  const probeSessionId = chatOptions.resumeSessionId
599
621
  || existingConv?.claudeSessionId;
@@ -617,6 +639,9 @@ function handleServerMessage(msg) {
617
639
  if (actionItemId && chatConvId) {
618
640
  pendingActionItems.set(chatConvId, actionItemId);
619
641
  }
642
+ if (actionDraftId && chatConvId) {
643
+ pendingActionDrafts.set(chatConvId, { draftId: actionDraftId, sessionCwd: chatDir });
644
+ }
620
645
  // Auto-switch backend if chat message's providerId requires a different backend
621
646
  if (effectiveProviderId) {
622
647
  const requiredBt = getBackendTypeForProvider(effectiveProviderId);
@@ -1612,6 +1637,21 @@ function handleServerMessage(msg) {
1612
1637
  case 'complete_action_item':
1613
1638
  handleCompleteActionItem(msg);
1614
1639
  break;
1640
+ case 'create_action_draft':
1641
+ handleCreateActionDraft(msg);
1642
+ break;
1643
+ case 'list_action_drafts':
1644
+ handleListActionDrafts(msg);
1645
+ break;
1646
+ case 'get_action_draft':
1647
+ handleGetActionDraft(msg);
1648
+ break;
1649
+ case 'commit_action_draft':
1650
+ handleCommitActionDraft(msg);
1651
+ break;
1652
+ case 'discard_action_draft':
1653
+ handleDiscardActionDraft(msg);
1654
+ break;
1615
1655
  case 'list_briefings':
1616
1656
  handleListBriefings();
1617
1657
  break;
@@ -2381,6 +2421,78 @@ async function handleCompleteActionItem(msg) {
2381
2421
  send({ type: 'action_item_completed', actionItemId: msg.actionItemId, error: String(err) });
2382
2422
  }
2383
2423
  }
2424
+ async function handleCreateActionDraft(msg) {
2425
+ try {
2426
+ const draft = await createActionDraft();
2427
+ send({ type: 'action_draft_created', requestId: msg.requestId, draft });
2428
+ }
2429
+ catch (err) {
2430
+ console.error('[AgentLink] createActionDraft failed:', err);
2431
+ send({
2432
+ type: 'action_draft_created',
2433
+ requestId: msg.requestId,
2434
+ draft: null,
2435
+ error: String(err),
2436
+ });
2437
+ }
2438
+ }
2439
+ async function handleListActionDrafts(msg) {
2440
+ try {
2441
+ const drafts = await listActionDrafts(msg.status);
2442
+ send({ type: 'action_drafts_list', drafts });
2443
+ }
2444
+ catch (err) {
2445
+ console.error('[AgentLink] listActionDrafts failed:', err);
2446
+ send({ type: 'action_drafts_list', drafts: [], error: String(err) });
2447
+ }
2448
+ }
2449
+ async function handleGetActionDraft(msg) {
2450
+ try {
2451
+ const draft = await getActionDraft(msg.draftId);
2452
+ send({ type: 'action_draft', draftId: msg.draftId, draft });
2453
+ }
2454
+ catch (err) {
2455
+ console.error(`[AgentLink] getActionDraft failed for ${msg.draftId}:`, err);
2456
+ send({ type: 'action_draft', draftId: msg.draftId, draft: null, error: String(err) });
2457
+ }
2458
+ }
2459
+ async function handleCommitActionDraft(msg) {
2460
+ try {
2461
+ const result = await commitActionDraft(msg.draftId, msg.expectedRevision);
2462
+ const actionItemId = String(result.action.action_item_id || result.draft.action_item_id || '');
2463
+ send({
2464
+ type: 'action_draft_committed',
2465
+ draftId: msg.draftId,
2466
+ actionItemId,
2467
+ draft: result.draft,
2468
+ action: result.action,
2469
+ });
2470
+ }
2471
+ catch (err) {
2472
+ console.error(`[AgentLink] commitActionDraft failed for ${msg.draftId}:`, err);
2473
+ send({
2474
+ type: 'action_draft_committed',
2475
+ draftId: msg.draftId,
2476
+ actionItemId: null,
2477
+ error: String(err),
2478
+ });
2479
+ }
2480
+ }
2481
+ async function handleDiscardActionDraft(msg) {
2482
+ try {
2483
+ const draft = await discardActionDraft(msg.draftId);
2484
+ send({ type: 'action_draft_discarded', draftId: msg.draftId, draft });
2485
+ }
2486
+ catch (err) {
2487
+ console.error(`[AgentLink] discardActionDraft failed for ${msg.draftId}:`, err);
2488
+ send({
2489
+ type: 'action_draft_discarded',
2490
+ draftId: msg.draftId,
2491
+ draft: null,
2492
+ error: String(err),
2493
+ });
2494
+ }
2495
+ }
2384
2496
  /**
2385
2497
  * Called when a recap chat session starts to check if it's linked to an action item.
2386
2498
  * If so, calls CLI `start` to transition the action item to 'running' status.
@@ -2400,4 +2512,35 @@ export function checkPendingActionItem(conversationId, claudeSessionId) {
2400
2512
  send({ type: 'action_item_started', actionItemId, sessionId: claudeSessionId, error: String(err) });
2401
2513
  });
2402
2514
  }
2515
+ function checkPendingActionDraft(conversationId, claudeSessionId) {
2516
+ const pending = pendingActionDrafts.get(conversationId);
2517
+ if (!pending)
2518
+ return;
2519
+ pendingActionDrafts.delete(conversationId);
2520
+ const bind = (attempt) => {
2521
+ console.log(`[AgentLink] Binding action draft ${pending.draftId} to session ${claudeSessionId} (attempt ${attempt + 1})`);
2522
+ bindActionDraftSession(pending.draftId, claudeSessionId, pending.sessionCwd)
2523
+ .then((draft) => {
2524
+ send({ type: 'action_draft', draftId: pending.draftId, draft });
2525
+ })
2526
+ .catch((err) => {
2527
+ if (attempt < 2) {
2528
+ setTimeout(() => bind(attempt + 1), 500 * (attempt + 1));
2529
+ return;
2530
+ }
2531
+ console.error('[AgentLink] bind action draft session failed:', err);
2532
+ send({
2533
+ type: 'action_draft',
2534
+ draftId: pending.draftId,
2535
+ draft: null,
2536
+ error: String(err),
2537
+ });
2538
+ });
2539
+ };
2540
+ bind(0);
2541
+ }
2542
+ export function checkPendingSessionLinks(conversationId, claudeSessionId) {
2543
+ checkPendingActionItem(conversationId, claudeSessionId);
2544
+ checkPendingActionDraft(conversationId, claudeSessionId);
2545
+ }
2403
2546
  //# sourceMappingURL=connection.js.map