@indigoai-us/hq-cli 5.193.0 → 5.194.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.
@@ -0,0 +1,22 @@
1
+ export declare const BOARD_STORY_STATUSES: readonly ["queued", "in_progress", "review", "done"];
2
+ export type BoardStoryStatus = (typeof BOARD_STORY_STATUSES)[number];
3
+ /**
4
+ * The ledger has more states than the Board. `blocked` and the review states
5
+ * need attention, while `dropped` is terminal; the Board has only one terminal
6
+ * column (`done`).
7
+ */
8
+ export declare const LEDGER_STATE_TO_BOARD_STATUS: Readonly<Record<string, BoardStoryStatus>>;
9
+ export declare function mapSourceStoryStatus(story: {
10
+ status?: unknown;
11
+ state?: unknown;
12
+ }, source: string): BoardStoryStatus | undefined;
13
+ /**
14
+ * Read a status from an existing PRD or Board response without imposing the
15
+ * stricter `--stories-file` contract. Before state mapping was added, these
16
+ * readers passed explicit status strings through and ignored state.
17
+ */
18
+ export declare function mapReaderStoryStatus(story: {
19
+ status?: unknown;
20
+ state?: unknown;
21
+ }): string | undefined;
22
+ //# sourceMappingURL=story-status.d.ts.map
@@ -0,0 +1,49 @@
1
+ export const BOARD_STORY_STATUSES = ["queued", "in_progress", "review", "done"];
2
+ const boardStoryStatusSet = new Set(BOARD_STORY_STATUSES);
3
+ /**
4
+ * The ledger has more states than the Board. `blocked` and the review states
5
+ * need attention, while `dropped` is terminal; the Board has only one terminal
6
+ * column (`done`).
7
+ */
8
+ export const LEDGER_STATE_TO_BOARD_STATUS = {
9
+ todo: "queued",
10
+ in_progress: "in_progress",
11
+ in_review: "review",
12
+ verification: "review",
13
+ blocked: "review",
14
+ done: "done",
15
+ dropped: "done",
16
+ };
17
+ export function mapSourceStoryStatus(story, source) {
18
+ if (story.status !== undefined && story.status !== null) {
19
+ if (typeof story.status !== "string" || !boardStoryStatusSet.has(story.status.trim())) {
20
+ throw new Error(`${source}.status must be queued|in_progress|review|done.`);
21
+ }
22
+ return story.status.trim();
23
+ }
24
+ if (Object.hasOwn(story, "state")) {
25
+ if (typeof story.state !== "string" ||
26
+ !Object.hasOwn(LEDGER_STATE_TO_BOARD_STATUS, story.state.trim())) {
27
+ throw new Error(`${source}.state must be todo|in_progress|in_review|verification|blocked|done|dropped.`);
28
+ }
29
+ return LEDGER_STATE_TO_BOARD_STATUS[story.state.trim()];
30
+ }
31
+ return undefined;
32
+ }
33
+ /**
34
+ * Read a status from an existing PRD or Board response without imposing the
35
+ * stricter `--stories-file` contract. Before state mapping was added, these
36
+ * readers passed explicit status strings through and ignored state.
37
+ */
38
+ export function mapReaderStoryStatus(story) {
39
+ if (story.status !== undefined && story.status !== null) {
40
+ return typeof story.status === "string" ? story.status : undefined;
41
+ }
42
+ if (typeof story.state !== "string")
43
+ return undefined;
44
+ const state = story.state.trim();
45
+ return Object.hasOwn(LEDGER_STATE_TO_BOARD_STATUS, state)
46
+ ? LEDGER_STATE_TO_BOARD_STATUS[state]
47
+ : undefined;
48
+ }
49
+ //# sourceMappingURL=story-status.js.map
@@ -8,7 +8,7 @@
8
8
  import { type SessionStateFile } from "./state.js";
9
9
  export interface PrdStatusEvent {
10
10
  taskId: string;
11
- status: "done" | "in_progress";
11
+ status: "done" | "in_progress" | "review";
12
12
  }
13
13
  export interface PrdSnapshot {
14
14
  stories: Record<string, {
@@ -8,6 +8,7 @@
8
8
  import * as fs from "node:fs";
9
9
  import * as path from "node:path";
10
10
  import { readSessionState, updateSessionState } from "./state.js";
11
+ import { mapReaderStoryStatus } from "../mesh/story-status.js";
11
12
  export function prdSnapshotPath(sessionId, root) {
12
13
  return path.join(root, "sessions", `${sessionId}.prd-snapshot.json`);
13
14
  }
@@ -87,11 +88,12 @@ function storiesFromPrd(file) {
87
88
  const id = row.id;
88
89
  if (typeof id !== "string" || !id.trim())
89
90
  continue;
90
- const status = row.status;
91
+ const rawStatus = mapReaderStoryStatus(row);
92
+ const status = rawStatus?.trim() ? rawStatus.trim() : undefined;
91
93
  out.push({
92
94
  id: id.trim(),
93
95
  passes: row.passes === true,
94
- ...(typeof status === "string" && status.trim() ? { status: status.trim() } : {}),
96
+ ...(status ? { status } : {}),
95
97
  });
96
98
  }
97
99
  return out;
@@ -144,7 +146,7 @@ export function planPrdSync(input) {
144
146
  ...(story.status ? { status: story.status } : {}),
145
147
  };
146
148
  const prior = previous ? before[story.id] : undefined;
147
- if (story.passes && !prior?.passes) {
149
+ if ((story.passes || story.status === "done") && !prior?.passes && prior?.status !== "done") {
148
150
  events.push({ taskId: story.id, status: "done" });
149
151
  continue;
150
152
  }
@@ -152,6 +154,9 @@ export function planPrdSync(input) {
152
154
  events.push({ taskId: story.id, status: "in_progress" });
153
155
  taskId = story.id;
154
156
  }
157
+ if (story.status === "review" && prior?.status !== "review") {
158
+ events.push({ taskId: story.id, status: "review" });
159
+ }
155
160
  }
156
161
  const snapshot = {
157
162
  stories: nextStories,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.193.0",
3
+ "version": "5.194.0",
4
4
  "description": "HQ by Indigo management CLI — modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {