flowviant 0.44.1 → 0.47.0

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.
@@ -123,9 +123,11 @@ function humanizeCodexItem(item = {}, cwd = '') {
123
123
  }
124
124
 
125
125
  /**
126
- * Codex `--json` emits JSONL of ThreadEvents. Returns `{ activity, text }` —
127
- * `text` accumulates the agent's own words, because the turn loop reads its
128
- * sentinels (NOTHING / BLOCKED:<id> / DONE) out of exactly that.
126
+ * Codex `--json` emits JSONL of ThreadEvents. Returns `{ activity, text,
127
+ * threadId }` — `text` accumulates the agent's own words, because the turn
128
+ * loop reads its sentinels (NOTHING / BLOCKED:<id> / DONE) out of exactly
129
+ * that; `threadId` surfaces once, off the lifecycle event, for callers that
130
+ * need to resume THIS conversation later (runTurn's onThreadId).
129
131
  */
130
132
  function parseCodexLine(line, cwd) {
131
133
  let ev;
@@ -135,6 +137,14 @@ function parseCodexLine(line, cwd) {
135
137
  return null; // not every line is JSON (warnings go to stderr, but be safe)
136
138
  }
137
139
  switch (ev.type) {
140
+ // The conversation's own id, announced before any item (`ThreadStarted` on
141
+ // the shipped 0.147 binary, like the measured events below). Surfaced so a
142
+ // SESSION turn can resume this exact thread next time: `resume --last` is
143
+ // a machine-global guess, and on a box running two tabs — or a tab plus a
144
+ // dispatch — it resumes someone else's conversation. No activity and no
145
+ // text: nothing here is the model speaking.
146
+ case 'thread.started':
147
+ return { activity: null, text: '', threadId: String(ev.thread_id ?? '') || null };
138
148
  case 'item.completed': {
139
149
  const item = ev.item ?? {};
140
150
  const activity = humanizeCodexItem(item, cwd);
@@ -165,7 +175,7 @@ function parseCodexLine(line, cwd) {
165
175
  text: `${ev.message ?? ''}\n`,
166
176
  };
167
177
  default:
168
- return null; // thread.started / turn.started / item.started / item.updated
178
+ return null; // turn.started / item.started / item.updated
169
179
  }
170
180
  }
171
181
 
@@ -310,9 +320,18 @@ export const RUNTIMES = {
310
320
  * strongest form of it available anywhere: `--append-system-prompt` sits
311
321
  * above the conversation rather than inside it.
312
322
  */
313
- args({ prompt, system, model, effort, resume, streamJson, perm, mcp = [], resultSchemaArgs = [] }) {
323
+ args({ prompt, system, model, effort, resume, streamJson, perm, mcp = [], resultSchemaArgs = [], adoptResumeId }) {
314
324
  const a = [];
315
- if (resume) a.push('--continue');
325
+ // ADOPTION — the first turn of a tab born from a terminal session.
326
+ // `--resume <id> --fork-session` finds the session globally (any cwd),
327
+ // carries its full context, and writes the FORK natively into THIS cwd's
328
+ // own store, leaving the original transcript untouched (measured on
329
+ // 2.1.234). From turn 2 on the plain `--continue` below resumes the fork
330
+ // where it now lives, so nothing downstream knows the tab was adopted.
331
+ // INSTEAD of --continue, never alongside it: they are the same decision
332
+ // ("what conversation is this?") answered two different ways.
333
+ if (adoptResumeId) a.push('--resume', adoptResumeId, '--fork-session');
334
+ else if (resume) a.push('--continue');
316
335
  a.push('-p', prompt, '--append-system-prompt', system);
317
336
  a.push(...mcp, ...resultSchemaArgs);
318
337
  a.push('--model', model || MODEL);
@@ -371,9 +390,22 @@ export const RUNTIMES = {
371
390
  * placed before it. Appending them after the positional is the kind of argv
372
391
  * that parses today and stops parsing on some future clap upgrade.
373
392
  */
374
- args({ prompt, system, model, effort, resume, profile = 'build', vaultDir, mcp = [], resultSchemaArgs = [] }) {
393
+ args({ prompt, system, model, effort, resume, resumeThreadId, profile = 'build', vaultDir, mcp = [], resultSchemaArgs = [], adoptResumeId }) {
394
+ // Adoption resumes a conversation in ITS OWN CLI's store (claude forks,
395
+ // agy moves) — codex has no adoptable store wired yet. Reaching here
396
+ // with an adopt id is a wiring mistake upstream, and it fails loudly on
397
+ // purpose: quietly dropping the flag would answer that session's held
398
+ // context with a different brain.
399
+ if (adoptResumeId) throw new Error("codex has no adoptable terminal store — an adopt id can't reach this builder");
375
400
  const a = ['exec'];
376
- if (resume) a.push('resume', '--last');
401
+ // BY ID when the caller knows WHICH conversation this is — a Workbench
402
+ // tab's held context, captured off thread.started and stored with its
403
+ // worktree. `--last` resumes the machine's most recent codex conversation,
404
+ // which is only safe on the dispatch path (one lane, one turn at a time,
405
+ // in its own worktree); for a session it is a machine-global guess that
406
+ // two tabs — or a tab plus a dispatch — would cross-resume.
407
+ if (resumeThreadId) a.push('resume', resumeThreadId);
408
+ else if (resume) a.push('resume', '--last');
377
409
  a.push('--json');
378
410
  if (model) a.push('--model', model);
379
411
  // Effort is a config value on Codex rather than a flag.
@@ -610,9 +642,18 @@ export const RUNTIMES = {
610
642
  */
611
643
  profiles: ['build', 'wiki', 'consult'],
612
644
  mcp: null,
613
- args({ prompt, system, model, effort, resume, profile = 'build', vaultDir, resultSchemaArgs = [] }) {
645
+ args({ prompt, system, model, effort, resume, resumeConversationId, profile = 'build', vaultDir, resultSchemaArgs = [], adoptResumeId }) {
614
646
  const a = [];
615
- if (resume) a.push('--continue');
647
+ // WHICH CONVERSATION IS THIS — one decision, answered one way (the same
648
+ // rule as Claude's --resume/--continue). By id when the caller knows:
649
+ // `--conversation <id>` resumes globally, any cwd (measured on 1.1.12).
650
+ // Adoption is the SAME argv because agy has no fork — the id in the db
651
+ // is the identity (a renamed copy fails "trajectory not found",
652
+ // measured), so adopting MOVES the conversation: the tab continues the
653
+ // terminal session itself, appending to its one store. `--continue` is
654
+ // the cwd-keyed fallback for a session whose id was never learned.
655
+ if (adoptResumeId || resumeConversationId) a.push('--conversation', adoptResumeId || resumeConversationId);
656
+ else if (resume) a.push('--continue');
616
657
  // No system-prompt flag, same weakening as Codex: the contract rides in
617
658
  // the prompt, fenced and first.
618
659
  a.push('-p', `${system}\n\n---\n\n${prompt}`);