harness-wingman 0.7.0 → 0.8.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.
@@ -13980,7 +13980,7 @@ function isRecord2(value) {
13980
13980
 
13981
13981
  // packages/narrative/dist/parse.js
13982
13982
  function isHarnessSystemNotice(text) {
13983
- return /^\s*<(task-notification|system-reminder)\b/u.test(text);
13983
+ return /^\s*<(task-notification|system-reminder|in-app-browser-context)\b/u.test(text);
13984
13984
  }
13985
13985
  function parseTranscriptLine(line) {
13986
13986
  const trimmed = line.trim();
@@ -15606,7 +15606,7 @@ function resolveWingmanVersion({ defined, moduleUrl = import.meta.url, readPacka
15606
15606
  return void 0;
15607
15607
  }
15608
15608
  function wingmanVersion() {
15609
- const defined = false ? void 0 : "0.7.0";
15609
+ const defined = false ? void 0 : "0.8.0";
15610
15610
  return resolveWingmanVersion({
15611
15611
  defined,
15612
15612
  readPackage: (url) => JSON.parse(readFileSync15(url, "utf8"))
@@ -16014,10 +16014,23 @@ function createNarrativeService(options = {}) {
16014
16014
  session.follows.set(path, followTranscript(path, (line) => {
16015
16015
  if (closed || generation !== session.generation)
16016
16016
  return;
16017
- if (harness === "codex")
16018
- session.codexLines.push(parseCodexRolloutLine(line));
16019
- else
16020
- session.lines.push(parseTranscriptLine(line));
16017
+ let timestamp;
16018
+ if (harness === "codex") {
16019
+ const parsed = parseCodexRolloutLine(line);
16020
+ session.codexLines.push(parsed);
16021
+ if (parsed.kind !== "unknown")
16022
+ timestamp = parsed.timestamp;
16023
+ } else {
16024
+ const parsed = parseTranscriptLine(line);
16025
+ session.lines.push(parsed);
16026
+ if (parsed.kind !== "unknown")
16027
+ timestamp = parsed.timestamp;
16028
+ }
16029
+ const endedAt = session.endedAt ?? session.stopAt;
16030
+ if (timestamp !== void 0 && endedAt !== void 0 && Date.parse(timestamp) > Date.parse(endedAt)) {
16031
+ session.endedAt = void 0;
16032
+ session.stopAt = void 0;
16033
+ }
16021
16034
  recordToolObservations(harness, session, extractRawToolObservations(harness, line));
16022
16035
  session.dirty = true;
16023
16036
  notify(harness);
@@ -16138,13 +16151,8 @@ function createNarrativeService(options = {}) {
16138
16151
  };
16139
16152
  }
16140
16153
  }
16141
- if (name === "SessionEnd") {
16142
- session.endedAt = event.received_at;
16143
- } else if (name === "Stop") {
16144
- session.stopAt = event.received_at;
16145
- } else {
16146
- session.stopAt = void 0;
16147
- }
16154
+ session.endedAt = name === "SessionEnd" ? event.received_at : void 0;
16155
+ session.stopAt = name === "Stop" ? event.received_at : void 0;
16148
16156
  session.lastEvent = { name, at: event.received_at };
16149
16157
  session.dirty = true;
16150
16158
  notify(event.harness);
@@ -16457,6 +16465,7 @@ function createNarrativeService(options = {}) {
16457
16465
  };
16458
16466
  }
16459
16467
  projects.push({
16468
+ firstScreen: deriveProjectFirstScreen(plan, parsed?.availability === "available" ? parsed.goal : void 0, summary.currentPoints, sessionViews),
16460
16469
  root,
16461
16470
  presence: members.length === 0 ? "remembered" : "active",
16462
16471
  seenSinceStart: seenProjectRoots.has(rootIdentity),
@@ -16479,7 +16488,11 @@ function createNarrativeService(options = {}) {
16479
16488
  sessions: sessionViews
16480
16489
  });
16481
16490
  }
16482
- projects.sort((left, right) => left.root.localeCompare(right.root));
16491
+ projects.sort((left, right) => {
16492
+ const decisionOrder = Number(right.firstScreen.action.kind === "decision") - Number(left.firstScreen.action.kind === "decision");
16493
+ const activityOrder = (right.firstScreen.lastActivity === void 0 ? 0 : Date.parse(right.firstScreen.lastActivity.at)) - (left.firstScreen.lastActivity === void 0 ? 0 : Date.parse(left.firstScreen.lastActivity.at));
16494
+ return decisionOrder || activityOrder || left.root.localeCompare(right.root);
16495
+ });
16483
16496
  return {
16484
16497
  projects,
16485
16498
  ...projectMemoryUnavailable === void 0 ? {} : { memory: { unavailable: projectMemoryUnavailable } }
@@ -16507,6 +16520,107 @@ function createNarrativeService(options = {}) {
16507
16520
  loadRememberedProjectRoots();
16508
16521
  return { handleEvent, getState, getOverview, getProjects, seedFixture, subscribe, close };
16509
16522
  }
16523
+ function deriveProjectFirstScreen(plan, goal, points, sessions) {
16524
+ const source = ".wingman/plan.md nodes(status, children)";
16525
+ const currentPoints = points.map((point) => ({ ...point, source }));
16526
+ const branch = [];
16527
+ const checkpoints = [];
16528
+ function visit(node, ancestors) {
16529
+ const path = [...ancestors, node];
16530
+ const childCurrent = node.children.map((child) => visit(child, path)).some(Boolean);
16531
+ const onCurrentPath = node.status === "in_progress" || childCurrent;
16532
+ if (onCurrentPath && (node.status === "checkpoint" || node.verification !== void 0)) {
16533
+ checkpoints.push({
16534
+ key: node.key,
16535
+ path: path.map((ancestor) => ancestor.text),
16536
+ text: node.text,
16537
+ source: `.wingman/plan.md:${node.line} status / verification`,
16538
+ ...node.verification === void 0 ? {} : { verification: node.verification }
16539
+ });
16540
+ }
16541
+ return onCurrentPath;
16542
+ }
16543
+ if (plan.availability === "available") {
16544
+ for (const node of plan.nodes) {
16545
+ if (visit(node, []))
16546
+ branch.push({
16547
+ key: node.key,
16548
+ path: [node.text],
16549
+ text: node.text,
16550
+ source: `.wingman/plan.md:${node.line} \u5F53\u524D\u70B9\u9876\u5C42\u7956\u5148`
16551
+ });
16552
+ }
16553
+ }
16554
+ const requests = [];
16555
+ for (const session of sessions) {
16556
+ if (session.feedback?.state !== "needs_user")
16557
+ continue;
16558
+ requests.push({
16559
+ harness: session.harness,
16560
+ sessionId: session.id,
16561
+ label: session.label,
16562
+ since: session.feedback.since,
16563
+ source: session.feedback.source,
16564
+ ...session.feedback.message === void 0 ? {} : { text: session.feedback.message }
16565
+ });
16566
+ }
16567
+ let action;
16568
+ if (requests.length > 0)
16569
+ action = { kind: "decision", items: requests, source: "sessions.feedback(state=needs_user)" };
16570
+ else if (checkpoints.length > 0)
16571
+ action = {
16572
+ kind: "checkpoint",
16573
+ items: checkpoints,
16574
+ source: ".wingman/plan.md \u5F53\u524D\u70B9\u7956\u5148\u8DEF\u5F84 status / verification"
16575
+ };
16576
+ else if (plan.availability === "missing")
16577
+ action = {
16578
+ kind: "insufficient",
16579
+ reason: "no_plan",
16580
+ source: "plan.availability=missing; plan.lookedUp"
16581
+ };
16582
+ else if (plan.availability === "unavailable")
16583
+ action = {
16584
+ kind: "insufficient",
16585
+ reason: "plan_unavailable",
16586
+ source: `plan.availability=unavailable; plan.reason: ${plan.reason}`
16587
+ };
16588
+ else if (sessions.length > 0 && sessions.every((session) => session.feedback === void 0 || session.feedback.state === "unavailable"))
16589
+ action = {
16590
+ kind: "insufficient",
16591
+ reason: "feedback_unavailable",
16592
+ source: "sessions.feedback.state=unavailable / feedback \u672A\u63D0\u4F9B"
16593
+ };
16594
+ else if (currentPoints.length > 0 && sessions.some((session) => !session.ended))
16595
+ action = {
16596
+ kind: "in_progress",
16597
+ source: ".wingman/plan.md currentPoints; sessions.ended=false"
16598
+ };
16599
+ else
16600
+ action = {
16601
+ kind: "insufficient",
16602
+ reason: "no_session",
16603
+ source: `currentPoints.length=${currentPoints.length}; sessions(ended=false).length=${sessions.filter((session) => !session.ended).length}`
16604
+ };
16605
+ const latest = sessions.filter((session) => session.lastActivity !== void 0 && Number.isFinite(Date.parse(session.lastActivity))).sort((left, right) => Date.parse(right.lastActivity) - Date.parse(left.lastActivity))[0];
16606
+ return {
16607
+ source,
16608
+ branch,
16609
+ currentPoints,
16610
+ action,
16611
+ ...goal === void 0 ? {} : { goal: { text: goal, source: ".wingman/plan.md \u76EE\u6807: / Goal:" } },
16612
+ ...latest === void 0 ? {} : {
16613
+ lastActivity: {
16614
+ at: latest.lastActivity,
16615
+ harness: latest.harness,
16616
+ sessionId: latest.id,
16617
+ label: latest.user.title ?? (latest.title.source === "plan.md \u6B65\u9AA4" ? latest.title.text : latest.label),
16618
+ source: "sessions.lastActivity\uFF08\u6700\u8FD1 hook received_at / transcript timestamp\uFF09\u6700\u5927\u503C",
16619
+ labelSource: latest.user.title !== void 0 ? "sessions.user.title" : latest.title.source === "plan.md \u6B65\u9AA4" ? "sessions.title\uFF08plan.md \u6B65\u9AA4\uFF09" : "sessions.label\uFF08\u4F1A\u8BDD\u5DE5\u4F5C\u76EE\u5F55\u540D / sessionId\uFF09"
16620
+ }
16621
+ }
16622
+ };
16623
+ }
16510
16624
  function lastActivityOf(session) {
16511
16625
  if (session.lastActivity !== void 0)
16512
16626
  return session.lastActivity;