@h-rig/planning-plugin 0.0.6-alpha.155 → 0.0.6-alpha.156

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.
package/dist/src/cli.js CHANGED
@@ -18,6 +18,85 @@ async function specClarifyPlan(input, context, ports) {
18
18
  return plan(await clarify(await spec(input, ports), context, ports), ports);
19
19
  }
20
20
 
21
+ // packages/planning-plugin/src/workspace-planning.ts
22
+ function taskByLocalId(spec2) {
23
+ return new Map(spec2.tasks.map((task) => [task.localId, task]));
24
+ }
25
+ function planTaskCreationOrder(spec2) {
26
+ const tasks = taskByLocalId(spec2);
27
+ const visiting = new Set;
28
+ const visited = new Set;
29
+ const ordered = [];
30
+ const visit = (task, stack) => {
31
+ if (visited.has(task.localId))
32
+ return;
33
+ if (visiting.has(task.localId))
34
+ throw new Error(`Plan task cycle detected: ${[...stack, task.localId].join(" -> ")}`);
35
+ visiting.add(task.localId);
36
+ const refs = [...task.dependsOn, ...task.parent ? [task.parent] : []];
37
+ for (const ref of refs) {
38
+ const dependency = tasks.get(ref);
39
+ if (dependency)
40
+ visit(dependency, [...stack, task.localId]);
41
+ }
42
+ visiting.delete(task.localId);
43
+ visited.add(task.localId);
44
+ ordered.push(task);
45
+ };
46
+ for (const task of spec2.tasks)
47
+ visit(task, []);
48
+ return ordered;
49
+ }
50
+ function taskPayload(task, localIdToTaskId) {
51
+ return {
52
+ title: task.title,
53
+ description: task.description,
54
+ acceptance: [...task.acceptance],
55
+ scope: [...task.scope],
56
+ validationKeys: [...task.validationKeys],
57
+ dependencies: task.dependsOn.map((id) => localIdToTaskId.get(id) ?? id),
58
+ parent: task.parent ? localIdToTaskId.get(task.parent) ?? task.parent : null,
59
+ metadata: { localId: task.localId, parallelizable: task.parallelizable }
60
+ };
61
+ }
62
+ async function runPlanningDryRun(projectRoot, prd, deps, options = {}) {
63
+ return deps.generatePlan({ projectRoot, prd, ...options.title !== undefined ? { title: options.title } : {} });
64
+ }
65
+ async function materializePlanSpec(projectRoot, spec2, deps, options = {}) {
66
+ if (!deps.createTask)
67
+ throw new Error("materializePlanSpec requires createTask.");
68
+ const localIdToTaskId = new Map(options.existingLocalIdToTaskId ?? []);
69
+ const created = [];
70
+ for (const task of planTaskCreationOrder(spec2)) {
71
+ if (localIdToTaskId.has(task.localId))
72
+ continue;
73
+ const result = await deps.createTask(projectRoot, taskPayload(task, localIdToTaskId));
74
+ if (result.taskId)
75
+ localIdToTaskId.set(task.localId, result.taskId);
76
+ created.push({ localId: task.localId, taskId: result.taskId });
77
+ }
78
+ if (deps.updateTask) {
79
+ for (const task of spec2.tasks) {
80
+ const taskId = localIdToTaskId.get(task.localId);
81
+ if (!taskId)
82
+ continue;
83
+ await deps.updateTask(projectRoot, taskId, taskPayload(task, localIdToTaskId));
84
+ }
85
+ }
86
+ return {
87
+ created,
88
+ localIdToTaskId,
89
+ deferredQuestions: spec2.openQuestions.filter((question) => question.status === "deferred" || question.status === "open").map((question) => question.id)
90
+ };
91
+ }
92
+ async function planWorkspace(projectRoot, prd, deps, options = {}) {
93
+ const spec2 = await runPlanningDryRun(projectRoot, prd, deps, options.title !== undefined ? { title: options.title } : {});
94
+ return {
95
+ spec: spec2,
96
+ materialized: options.materialize ? await materializePlanSpec(projectRoot, spec2, deps, options.existingLocalIdToTaskId !== undefined ? { existingLocalIdToTaskId: options.existingLocalIdToTaskId } : {}) : null
97
+ };
98
+ }
99
+
21
100
  // packages/planning-plugin/src/cli.ts
22
101
  var PLANNING_PLAN_CLI_ID = "planning.plan";
23
102
  function printJson(value) {
@@ -142,8 +221,9 @@ function defaultPlanningProvider(now) {
142
221
  plan: (planSpec) => planSpec
143
222
  };
144
223
  }
145
- async function loadPlanningClient() {
146
- return await import("@rig/client");
224
+ async function loadPlanningClientIo() {
225
+ const { createTask, getTask } = await import("@rig/core/task-io");
226
+ return { createTask, getTask };
147
227
  }
148
228
  async function readPrdText(context, args) {
149
229
  const title = takeOption(args, "--title");
@@ -154,7 +234,7 @@ async function readPrdText(context, args) {
154
234
  if (sources.length !== 1)
155
235
  throw new Error("rig plan requires exactly one of --text <prd>, --prd <file>, or --issue <id>.");
156
236
  if (issue.value) {
157
- const { getTask } = await loadPlanningClient();
237
+ const { getTask } = await loadPlanningClientIo();
158
238
  const task = await getTask(context.projectRoot, issue.value);
159
239
  if (!task)
160
240
  throw new Error(`No task found for issue ${issue.value}.`);
@@ -180,7 +260,7 @@ async function executePlan(context, args) {
180
260
  const willMaterialize = materialize.value && !dryRun.value;
181
261
  const now = () => new Date().toISOString();
182
262
  const provider = defaultPlanningProvider(now);
183
- const { createTask, planWorkspace } = await loadPlanningClient();
263
+ const { createTask } = await loadPlanningClientIo();
184
264
  const result = await planWorkspace(context.projectRoot, prd.body, {
185
265
  generatePlan: (input) => specClarifyPlan({ title: input.title ?? prd.title, body: input.prd }, {}, provider),
186
266
  createTask
package/dist/src/index.js CHANGED
@@ -119,6 +119,87 @@ async function materialize(planSpec, source, options = {}) {
119
119
  }
120
120
  // packages/planning-plugin/src/cli.ts
121
121
  import { readFileSync } from "fs";
122
+
123
+ // packages/planning-plugin/src/workspace-planning.ts
124
+ function taskByLocalId2(spec2) {
125
+ return new Map(spec2.tasks.map((task) => [task.localId, task]));
126
+ }
127
+ function planTaskCreationOrder(spec2) {
128
+ const tasks = taskByLocalId2(spec2);
129
+ const visiting = new Set;
130
+ const visited = new Set;
131
+ const ordered = [];
132
+ const visit = (task, stack) => {
133
+ if (visited.has(task.localId))
134
+ return;
135
+ if (visiting.has(task.localId))
136
+ throw new Error(`Plan task cycle detected: ${[...stack, task.localId].join(" -> ")}`);
137
+ visiting.add(task.localId);
138
+ const refs = [...task.dependsOn, ...task.parent ? [task.parent] : []];
139
+ for (const ref of refs) {
140
+ const dependency = tasks.get(ref);
141
+ if (dependency)
142
+ visit(dependency, [...stack, task.localId]);
143
+ }
144
+ visiting.delete(task.localId);
145
+ visited.add(task.localId);
146
+ ordered.push(task);
147
+ };
148
+ for (const task of spec2.tasks)
149
+ visit(task, []);
150
+ return ordered;
151
+ }
152
+ function taskPayload(task, localIdToTaskId) {
153
+ return {
154
+ title: task.title,
155
+ description: task.description,
156
+ acceptance: [...task.acceptance],
157
+ scope: [...task.scope],
158
+ validationKeys: [...task.validationKeys],
159
+ dependencies: task.dependsOn.map((id) => localIdToTaskId.get(id) ?? id),
160
+ parent: task.parent ? localIdToTaskId.get(task.parent) ?? task.parent : null,
161
+ metadata: { localId: task.localId, parallelizable: task.parallelizable }
162
+ };
163
+ }
164
+ async function runPlanningDryRun(projectRoot, prd, deps, options = {}) {
165
+ return deps.generatePlan({ projectRoot, prd, ...options.title !== undefined ? { title: options.title } : {} });
166
+ }
167
+ async function materializePlanSpec(projectRoot, spec2, deps, options = {}) {
168
+ if (!deps.createTask)
169
+ throw new Error("materializePlanSpec requires createTask.");
170
+ const localIdToTaskId = new Map(options.existingLocalIdToTaskId ?? []);
171
+ const created = [];
172
+ for (const task of planTaskCreationOrder(spec2)) {
173
+ if (localIdToTaskId.has(task.localId))
174
+ continue;
175
+ const result = await deps.createTask(projectRoot, taskPayload(task, localIdToTaskId));
176
+ if (result.taskId)
177
+ localIdToTaskId.set(task.localId, result.taskId);
178
+ created.push({ localId: task.localId, taskId: result.taskId });
179
+ }
180
+ if (deps.updateTask) {
181
+ for (const task of spec2.tasks) {
182
+ const taskId = localIdToTaskId.get(task.localId);
183
+ if (!taskId)
184
+ continue;
185
+ await deps.updateTask(projectRoot, taskId, taskPayload(task, localIdToTaskId));
186
+ }
187
+ }
188
+ return {
189
+ created,
190
+ localIdToTaskId,
191
+ deferredQuestions: spec2.openQuestions.filter((question) => question.status === "deferred" || question.status === "open").map((question) => question.id)
192
+ };
193
+ }
194
+ async function planWorkspace(projectRoot, prd, deps, options = {}) {
195
+ const spec2 = await runPlanningDryRun(projectRoot, prd, deps, options.title !== undefined ? { title: options.title } : {});
196
+ return {
197
+ spec: spec2,
198
+ materialized: options.materialize ? await materializePlanSpec(projectRoot, spec2, deps, options.existingLocalIdToTaskId !== undefined ? { existingLocalIdToTaskId: options.existingLocalIdToTaskId } : {}) : null
199
+ };
200
+ }
201
+
202
+ // packages/planning-plugin/src/cli.ts
122
203
  var PLANNING_PLAN_CLI_ID = "planning.plan";
123
204
  function printJson(value) {
124
205
  console.log(JSON.stringify(value, null, 2));
@@ -242,8 +323,9 @@ function defaultPlanningProvider(now) {
242
323
  plan: (planSpec) => planSpec
243
324
  };
244
325
  }
245
- async function loadPlanningClient() {
246
- return await import("@rig/client");
326
+ async function loadPlanningClientIo() {
327
+ const { createTask, getTask } = await import("@rig/core/task-io");
328
+ return { createTask, getTask };
247
329
  }
248
330
  async function readPrdText(context, args) {
249
331
  const title = takeOption(args, "--title");
@@ -254,7 +336,7 @@ async function readPrdText(context, args) {
254
336
  if (sources.length !== 1)
255
337
  throw new Error("rig plan requires exactly one of --text <prd>, --prd <file>, or --issue <id>.");
256
338
  if (issue.value) {
257
- const { getTask } = await loadPlanningClient();
339
+ const { getTask } = await loadPlanningClientIo();
258
340
  const task = await getTask(context.projectRoot, issue.value);
259
341
  if (!task)
260
342
  throw new Error(`No task found for issue ${issue.value}.`);
@@ -280,7 +362,7 @@ async function executePlan(context, args) {
280
362
  const willMaterialize = materialize2.value && !dryRun.value;
281
363
  const now = () => new Date().toISOString();
282
364
  const provider = defaultPlanningProvider(now);
283
- const { createTask, planWorkspace } = await loadPlanningClient();
365
+ const { createTask } = await loadPlanningClientIo();
284
366
  const result = await planWorkspace(context.projectRoot, prd.body, {
285
367
  generatePlan: (input) => specClarifyPlan({ title: input.title ?? prd.title, body: input.prd }, {}, provider),
286
368
  createTask
@@ -321,13 +403,8 @@ var planningPlugin = definePlugin({
321
403
  panels: [
322
404
  { id: PLANNING_PLAN_PANEL_ID, slot: "capability", title: "Plan intake", capabilityId: "planning.plan" }
323
405
  ],
324
- cliCommands: planningCliCommands.map(({ run: _run, ...metadata }) => metadata)
406
+ cliCommands: planningCliCommands
325
407
  }
326
- }, {
327
- featureCapabilities: [
328
- { id: "planning.plan", title: "PRD-to-task planning", commandId: PLANNING_PLAN_CLI_ID, panelId: PLANNING_PLAN_PANEL_ID }
329
- ],
330
- cliCommands: planningCliCommands
331
408
  });
332
409
  function createPlanningPlugin() {
333
410
  return planningPlugin;
@@ -1,5 +1,5 @@
1
1
  export declare const PLANNING_PLUGIN_NAME = "@rig/planning-plugin";
2
2
  export declare const PLANNING_PLAN_PANEL_ID = "plan-intake";
3
- export declare const planningPlugin: import("@rig/core").RigPluginWithRuntime;
4
- export declare function createPlanningPlugin(): import("@rig/core").RigPluginWithRuntime;
3
+ export declare const planningPlugin: import("@rig/core/config").RigPlugin;
4
+ export declare function createPlanningPlugin(): import("@rig/core/config").RigPlugin;
5
5
  export default planningPlugin;
@@ -21,6 +21,85 @@ async function specClarifyPlan(input, context, ports) {
21
21
  return plan(await clarify(await spec(input, ports), context, ports), ports);
22
22
  }
23
23
 
24
+ // packages/planning-plugin/src/workspace-planning.ts
25
+ function taskByLocalId(spec2) {
26
+ return new Map(spec2.tasks.map((task) => [task.localId, task]));
27
+ }
28
+ function planTaskCreationOrder(spec2) {
29
+ const tasks = taskByLocalId(spec2);
30
+ const visiting = new Set;
31
+ const visited = new Set;
32
+ const ordered = [];
33
+ const visit = (task, stack) => {
34
+ if (visited.has(task.localId))
35
+ return;
36
+ if (visiting.has(task.localId))
37
+ throw new Error(`Plan task cycle detected: ${[...stack, task.localId].join(" -> ")}`);
38
+ visiting.add(task.localId);
39
+ const refs = [...task.dependsOn, ...task.parent ? [task.parent] : []];
40
+ for (const ref of refs) {
41
+ const dependency = tasks.get(ref);
42
+ if (dependency)
43
+ visit(dependency, [...stack, task.localId]);
44
+ }
45
+ visiting.delete(task.localId);
46
+ visited.add(task.localId);
47
+ ordered.push(task);
48
+ };
49
+ for (const task of spec2.tasks)
50
+ visit(task, []);
51
+ return ordered;
52
+ }
53
+ function taskPayload(task, localIdToTaskId) {
54
+ return {
55
+ title: task.title,
56
+ description: task.description,
57
+ acceptance: [...task.acceptance],
58
+ scope: [...task.scope],
59
+ validationKeys: [...task.validationKeys],
60
+ dependencies: task.dependsOn.map((id) => localIdToTaskId.get(id) ?? id),
61
+ parent: task.parent ? localIdToTaskId.get(task.parent) ?? task.parent : null,
62
+ metadata: { localId: task.localId, parallelizable: task.parallelizable }
63
+ };
64
+ }
65
+ async function runPlanningDryRun(projectRoot, prd, deps, options = {}) {
66
+ return deps.generatePlan({ projectRoot, prd, ...options.title !== undefined ? { title: options.title } : {} });
67
+ }
68
+ async function materializePlanSpec(projectRoot, spec2, deps, options = {}) {
69
+ if (!deps.createTask)
70
+ throw new Error("materializePlanSpec requires createTask.");
71
+ const localIdToTaskId = new Map(options.existingLocalIdToTaskId ?? []);
72
+ const created = [];
73
+ for (const task of planTaskCreationOrder(spec2)) {
74
+ if (localIdToTaskId.has(task.localId))
75
+ continue;
76
+ const result = await deps.createTask(projectRoot, taskPayload(task, localIdToTaskId));
77
+ if (result.taskId)
78
+ localIdToTaskId.set(task.localId, result.taskId);
79
+ created.push({ localId: task.localId, taskId: result.taskId });
80
+ }
81
+ if (deps.updateTask) {
82
+ for (const task of spec2.tasks) {
83
+ const taskId = localIdToTaskId.get(task.localId);
84
+ if (!taskId)
85
+ continue;
86
+ await deps.updateTask(projectRoot, taskId, taskPayload(task, localIdToTaskId));
87
+ }
88
+ }
89
+ return {
90
+ created,
91
+ localIdToTaskId,
92
+ deferredQuestions: spec2.openQuestions.filter((question) => question.status === "deferred" || question.status === "open").map((question) => question.id)
93
+ };
94
+ }
95
+ async function planWorkspace(projectRoot, prd, deps, options = {}) {
96
+ const spec2 = await runPlanningDryRun(projectRoot, prd, deps, options.title !== undefined ? { title: options.title } : {});
97
+ return {
98
+ spec: spec2,
99
+ materialized: options.materialize ? await materializePlanSpec(projectRoot, spec2, deps, options.existingLocalIdToTaskId !== undefined ? { existingLocalIdToTaskId: options.existingLocalIdToTaskId } : {}) : null
100
+ };
101
+ }
102
+
24
103
  // packages/planning-plugin/src/cli.ts
25
104
  var PLANNING_PLAN_CLI_ID = "planning.plan";
26
105
  function printJson(value) {
@@ -145,8 +224,9 @@ function defaultPlanningProvider(now) {
145
224
  plan: (planSpec) => planSpec
146
225
  };
147
226
  }
148
- async function loadPlanningClient() {
149
- return await import("@rig/client");
227
+ async function loadPlanningClientIo() {
228
+ const { createTask, getTask } = await import("@rig/core/task-io");
229
+ return { createTask, getTask };
150
230
  }
151
231
  async function readPrdText(context, args) {
152
232
  const title = takeOption(args, "--title");
@@ -157,7 +237,7 @@ async function readPrdText(context, args) {
157
237
  if (sources.length !== 1)
158
238
  throw new Error("rig plan requires exactly one of --text <prd>, --prd <file>, or --issue <id>.");
159
239
  if (issue.value) {
160
- const { getTask } = await loadPlanningClient();
240
+ const { getTask } = await loadPlanningClientIo();
161
241
  const task = await getTask(context.projectRoot, issue.value);
162
242
  if (!task)
163
243
  throw new Error(`No task found for issue ${issue.value}.`);
@@ -183,7 +263,7 @@ async function executePlan(context, args) {
183
263
  const willMaterialize = materialize.value && !dryRun.value;
184
264
  const now = () => new Date().toISOString();
185
265
  const provider = defaultPlanningProvider(now);
186
- const { createTask, planWorkspace } = await loadPlanningClient();
266
+ const { createTask } = await loadPlanningClientIo();
187
267
  const result = await planWorkspace(context.projectRoot, prd.body, {
188
268
  generatePlan: (input) => specClarifyPlan({ title: input.title ?? prd.title, body: input.prd }, {}, provider),
189
269
  createTask
@@ -224,13 +304,8 @@ var planningPlugin = definePlugin({
224
304
  panels: [
225
305
  { id: PLANNING_PLAN_PANEL_ID, slot: "capability", title: "Plan intake", capabilityId: "planning.plan" }
226
306
  ],
227
- cliCommands: planningCliCommands.map(({ run: _run, ...metadata }) => metadata)
307
+ cliCommands: planningCliCommands
228
308
  }
229
- }, {
230
- featureCapabilities: [
231
- { id: "planning.plan", title: "PRD-to-task planning", commandId: PLANNING_PLAN_CLI_ID, panelId: PLANNING_PLAN_PANEL_ID }
232
- ],
233
- cliCommands: planningCliCommands
234
309
  });
235
310
  function createPlanningPlugin() {
236
311
  return planningPlugin;
@@ -0,0 +1,39 @@
1
+ import type { PlanSpec, PlanTask } from "@rig/contracts";
2
+ export interface PlanningDeps {
3
+ readonly generatePlan: (input: PlanningInput) => Promise<PlanSpec> | PlanSpec;
4
+ readonly createTask?: (projectRoot: string, task: Record<string, unknown>) => Promise<{
5
+ readonly taskId: string | null;
6
+ readonly result?: unknown;
7
+ }>;
8
+ readonly updateTask?: (projectRoot: string, taskId: string, patch: Record<string, unknown>) => Promise<unknown>;
9
+ readonly now?: () => string;
10
+ }
11
+ export interface PlanningInput {
12
+ readonly projectRoot: string;
13
+ readonly prd: string;
14
+ readonly title?: string;
15
+ }
16
+ export interface WorkspaceMaterializePlanResult {
17
+ readonly created: readonly {
18
+ readonly localId: string;
19
+ readonly taskId: string | null;
20
+ }[];
21
+ readonly localIdToTaskId: ReadonlyMap<string, string>;
22
+ readonly deferredQuestions: readonly string[];
23
+ }
24
+ export interface PlanWorkspaceResult {
25
+ readonly spec: PlanSpec;
26
+ readonly materialized: WorkspaceMaterializePlanResult | null;
27
+ }
28
+ export declare function planTaskCreationOrder(spec: PlanSpec): readonly PlanTask[];
29
+ export declare function runPlanningDryRun(projectRoot: string, prd: string, deps: Pick<PlanningDeps, "generatePlan">, options?: {
30
+ readonly title?: string;
31
+ }): Promise<PlanSpec>;
32
+ export declare function materializePlanSpec(projectRoot: string, spec: PlanSpec, deps: Pick<PlanningDeps, "createTask" | "updateTask">, options?: {
33
+ readonly existingLocalIdToTaskId?: ReadonlyMap<string, string>;
34
+ }): Promise<WorkspaceMaterializePlanResult>;
35
+ export declare function planWorkspace(projectRoot: string, prd: string, deps: PlanningDeps, options?: {
36
+ readonly title?: string;
37
+ readonly materialize?: boolean;
38
+ readonly existingLocalIdToTaskId?: ReadonlyMap<string, string>;
39
+ }): Promise<PlanWorkspaceResult>;
@@ -0,0 +1,85 @@
1
+ // @bun
2
+ // packages/planning-plugin/src/workspace-planning.ts
3
+ function taskByLocalId(spec) {
4
+ return new Map(spec.tasks.map((task) => [task.localId, task]));
5
+ }
6
+ function planTaskCreationOrder(spec) {
7
+ const tasks = taskByLocalId(spec);
8
+ const visiting = new Set;
9
+ const visited = new Set;
10
+ const ordered = [];
11
+ const visit = (task, stack) => {
12
+ if (visited.has(task.localId))
13
+ return;
14
+ if (visiting.has(task.localId))
15
+ throw new Error(`Plan task cycle detected: ${[...stack, task.localId].join(" -> ")}`);
16
+ visiting.add(task.localId);
17
+ const refs = [...task.dependsOn, ...task.parent ? [task.parent] : []];
18
+ for (const ref of refs) {
19
+ const dependency = tasks.get(ref);
20
+ if (dependency)
21
+ visit(dependency, [...stack, task.localId]);
22
+ }
23
+ visiting.delete(task.localId);
24
+ visited.add(task.localId);
25
+ ordered.push(task);
26
+ };
27
+ for (const task of spec.tasks)
28
+ visit(task, []);
29
+ return ordered;
30
+ }
31
+ function taskPayload(task, localIdToTaskId) {
32
+ return {
33
+ title: task.title,
34
+ description: task.description,
35
+ acceptance: [...task.acceptance],
36
+ scope: [...task.scope],
37
+ validationKeys: [...task.validationKeys],
38
+ dependencies: task.dependsOn.map((id) => localIdToTaskId.get(id) ?? id),
39
+ parent: task.parent ? localIdToTaskId.get(task.parent) ?? task.parent : null,
40
+ metadata: { localId: task.localId, parallelizable: task.parallelizable }
41
+ };
42
+ }
43
+ async function runPlanningDryRun(projectRoot, prd, deps, options = {}) {
44
+ return deps.generatePlan({ projectRoot, prd, ...options.title !== undefined ? { title: options.title } : {} });
45
+ }
46
+ async function materializePlanSpec(projectRoot, spec, deps, options = {}) {
47
+ if (!deps.createTask)
48
+ throw new Error("materializePlanSpec requires createTask.");
49
+ const localIdToTaskId = new Map(options.existingLocalIdToTaskId ?? []);
50
+ const created = [];
51
+ for (const task of planTaskCreationOrder(spec)) {
52
+ if (localIdToTaskId.has(task.localId))
53
+ continue;
54
+ const result = await deps.createTask(projectRoot, taskPayload(task, localIdToTaskId));
55
+ if (result.taskId)
56
+ localIdToTaskId.set(task.localId, result.taskId);
57
+ created.push({ localId: task.localId, taskId: result.taskId });
58
+ }
59
+ if (deps.updateTask) {
60
+ for (const task of spec.tasks) {
61
+ const taskId = localIdToTaskId.get(task.localId);
62
+ if (!taskId)
63
+ continue;
64
+ await deps.updateTask(projectRoot, taskId, taskPayload(task, localIdToTaskId));
65
+ }
66
+ }
67
+ return {
68
+ created,
69
+ localIdToTaskId,
70
+ deferredQuestions: spec.openQuestions.filter((question) => question.status === "deferred" || question.status === "open").map((question) => question.id)
71
+ };
72
+ }
73
+ async function planWorkspace(projectRoot, prd, deps, options = {}) {
74
+ const spec = await runPlanningDryRun(projectRoot, prd, deps, options.title !== undefined ? { title: options.title } : {});
75
+ return {
76
+ spec,
77
+ materialized: options.materialize ? await materializePlanSpec(projectRoot, spec, deps, options.existingLocalIdToTaskId !== undefined ? { existingLocalIdToTaskId: options.existingLocalIdToTaskId } : {}) : null
78
+ };
79
+ }
80
+ export {
81
+ runPlanningDryRun,
82
+ planWorkspace,
83
+ planTaskCreationOrder,
84
+ materializePlanSpec
85
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@h-rig/planning-plugin",
3
- "version": "0.0.6-alpha.155",
3
+ "version": "0.0.6-alpha.156",
4
4
  "type": "module",
5
5
  "description": "First-party PRD-to-plan plugin for Rig task sources.",
6
6
  "license": "UNLICENSED",
@@ -29,8 +29,7 @@
29
29
  "module": "./dist/src/index.js",
30
30
  "types": "./dist/src/index.d.ts",
31
31
  "dependencies": {
32
- "@rig/client": "npm:@h-rig/client@0.0.6-alpha.155",
33
- "@rig/contracts": "npm:@h-rig/contracts@0.0.6-alpha.155",
34
- "@rig/core": "npm:@h-rig/core@0.0.6-alpha.155"
32
+ "@rig/contracts": "npm:@h-rig/contracts@0.0.6-alpha.156",
33
+ "@rig/core": "npm:@h-rig/core@0.0.6-alpha.156"
35
34
  }
36
35
  }