gsd-pi 2.70.1-dev.ec24142 → 2.71.0-dev.977c553

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.
Files changed (81) hide show
  1. package/README.md +24 -17
  2. package/dist/resources/extensions/gsd/custom-workflow-engine.js +16 -12
  3. package/dist/resources/extensions/gsd/file-lock.js +60 -0
  4. package/dist/resources/extensions/gsd/state.js +234 -332
  5. package/dist/resources/extensions/gsd/workflow-events.js +25 -13
  6. package/dist/web/standalone/.next/BUILD_ID +1 -1
  7. package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
  8. package/dist/web/standalone/.next/build-manifest.json +2 -2
  9. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  10. package/dist/web/standalone/.next/required-server-files.json +1 -1
  11. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  12. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  13. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  14. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  15. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  16. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  17. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  18. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  19. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  20. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  21. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  22. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  23. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  24. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  25. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  26. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  27. package/dist/web/standalone/.next/server/app/index.html +1 -1
  28. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  29. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  30. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  31. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  32. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  33. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  34. package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
  35. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  36. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  37. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  38. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  39. package/dist/web/standalone/server.js +1 -1
  40. package/package.json +1 -1
  41. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +202 -1
  42. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  43. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts +19 -2
  44. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  45. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js +50 -1
  46. package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  47. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  48. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +90 -2
  49. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  50. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +1 -0
  51. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  52. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  53. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +6 -0
  54. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  55. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +57 -1
  56. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  57. package/packages/pi-coding-agent/package.json +1 -1
  58. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +249 -1
  59. package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.ts +58 -2
  60. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +96 -2
  61. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +1 -0
  62. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +65 -1
  63. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.d.ts +2 -0
  64. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.d.ts.map +1 -0
  65. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +66 -0
  66. package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -0
  67. package/packages/pi-tui/dist/components/markdown.d.ts +3 -0
  68. package/packages/pi-tui/dist/components/markdown.d.ts.map +1 -1
  69. package/packages/pi-tui/dist/components/markdown.js +17 -1
  70. package/packages/pi-tui/dist/components/markdown.js.map +1 -1
  71. package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +75 -0
  72. package/packages/pi-tui/src/components/markdown.ts +22 -1
  73. package/pkg/package.json +1 -1
  74. package/src/resources/extensions/gsd/custom-workflow-engine.ts +19 -14
  75. package/src/resources/extensions/gsd/file-lock.ts +59 -0
  76. package/src/resources/extensions/gsd/state.ts +274 -344
  77. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +436 -0
  78. package/src/resources/extensions/gsd/tests/file-lock.test.ts +103 -0
  79. package/src/resources/extensions/gsd/workflow-events.ts +34 -25
  80. /package/dist/web/standalone/.next/static/{20e8bFnNjxQJflHNodEve → 4xyaXTn7-shVHaGMcl75o}/_buildManifest.js +0 -0
  81. /package/dist/web/standalone/.next/static/{20e8bFnNjxQJflHNodEve → 4xyaXTn7-shVHaGMcl75o}/_ssgManifest.js +0 -0
@@ -34,6 +34,7 @@ import {
34
34
  import { injectContext } from "./context-injector.js";
35
35
  import type { WorkflowDefinition, StepDefinition } from "./definition-loader.js";
36
36
  import { parseUnitId } from "./unit-id.js";
37
+ import { withFileLock } from "./file-lock.js";
37
38
 
38
39
  /** Read and parse the frozen DEFINITION.yaml from a run directory. */
39
40
  export function readFrozenDefinition(runDir: string): WorkflowDefinition {
@@ -179,24 +180,28 @@ export class CustomWorkflowEngine implements WorkflowEngine {
179
180
  state: EngineState,
180
181
  completedStep: CompletedStep,
181
182
  ): Promise<ReconcileResult> {
182
- // Re-read the graph from disk so we do not overwrite concurrent
183
- // workflow edits with a stale in-memory snapshot from deriveState().
184
- const graph = readGraph(this.runDir);
183
+ const graphPath = join(this.runDir, "GRAPH.yaml");
185
184
 
186
- // Extract stepId from "<workflowName>/<stepId>"
187
- const { milestone, slice, task } = parseUnitId(completedStep.unitId);
188
- const stepId = task ?? slice ?? milestone;
185
+ return await withFileLock(graphPath, () => {
186
+ // Re-read the graph from disk so we do not overwrite concurrent
187
+ // workflow edits with a stale in-memory snapshot from deriveState().
188
+ const graph = readGraph(this.runDir);
189
189
 
190
- const updatedGraph = markStepComplete(graph, stepId);
191
- writeGraph(this.runDir, updatedGraph);
190
+ // Extract stepId from "<workflowName>/<stepId>"
191
+ const { milestone, slice, task } = parseUnitId(completedStep.unitId);
192
+ const stepId = task ?? slice ?? milestone;
192
193
 
193
- const allDone = updatedGraph.steps.every(
194
- (s) => s.status === "complete" || s.status === "expanded",
195
- );
194
+ const updatedGraph = markStepComplete(graph, stepId);
195
+ writeGraph(this.runDir, updatedGraph);
196
196
 
197
- return {
198
- outcome: allDone ? "milestone-complete" : "continue",
199
- };
197
+ const allDone = updatedGraph.steps.every(
198
+ (s) => s.status === "complete" || s.status === "expanded",
199
+ );
200
+
201
+ return {
202
+ outcome: allDone ? "milestone-complete" : "continue",
203
+ };
204
+ });
200
205
  }
201
206
 
202
207
  /**
@@ -0,0 +1,59 @@
1
+ import { existsSync } from "node:fs";
2
+
3
+ function _require(name: string) {
4
+ try {
5
+ return require(name);
6
+ } catch {
7
+ try {
8
+ const gsdPiRequire = require("module").createRequire(
9
+ require("path").join(process.cwd(), "node_modules", "gsd-pi", "index.js")
10
+ );
11
+ return gsdPiRequire(name);
12
+ } catch {
13
+ return null;
14
+ }
15
+ }
16
+ }
17
+
18
+ export function withFileLockSync<T>(filePath: string, fn: () => T): T {
19
+ const lockfile = _require("proper-lockfile");
20
+ if (!lockfile) return fn();
21
+
22
+ if (!existsSync(filePath)) return fn();
23
+
24
+ try {
25
+ const release = lockfile.lockSync(filePath, { retries: 5, stale: 10000 });
26
+ try {
27
+ return fn();
28
+ } finally {
29
+ release();
30
+ }
31
+ } catch (err: any) {
32
+ if (err.code === "ELOCKED") {
33
+ // Could not get lock after retries, let's fallback to un-locked instead of crashing the whole state machine
34
+ return fn();
35
+ }
36
+ throw err;
37
+ }
38
+ }
39
+
40
+ export async function withFileLock<T>(filePath: string, fn: () => Promise<T> | T): Promise<T> {
41
+ const lockfile = _require("proper-lockfile");
42
+ if (!lockfile) return await fn();
43
+
44
+ if (!existsSync(filePath)) return await fn();
45
+
46
+ try {
47
+ const release = await lockfile.lock(filePath, { retries: 5, stale: 10000 });
48
+ try {
49
+ return await fn();
50
+ } finally {
51
+ await release();
52
+ }
53
+ } catch (err: any) {
54
+ if (err.code === "ELOCKED") {
55
+ return await fn();
56
+ }
57
+ throw err;
58
+ }
59
+ }