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
package/README.md CHANGED
@@ -27,36 +27,43 @@ One command. Walk away. Come back to a built project with clean git history.
27
27
 
28
28
  ---
29
29
 
30
- ## What's New in v2.68
30
+ ## What's New in v2.71
31
31
 
32
- ### MCP Workflow Tools
32
+ ### MCP Secure Env Collect
33
33
 
34
- - **Full workflow over MCP** — slice replanning, milestone management, slice completion, task completion, and core planning tools are now exposed over MCP for external integrations.
35
- - **Transport-gated MCP** — workflow tool availability adapts to provider transport capabilities automatically.
36
- - **Write gate enforcement** — workflow MCP respects write gates, preventing unauthorized state mutations from external clients.
34
+ - **Secure credential collection over MCP** — the new `secure_env_collect` tool uses MCP form elicitation to collect secrets (API keys, tokens) from external clients without exposing values in tool output. Masks input in interactive mode.
35
+ - **Hardened elicitation schema** — MCP elicitation schema handling is stricter, with proper validation and fallback for providers that don't support forms.
37
36
 
38
- ### Reliability & Recovery
37
+ ### MCP Reliability
39
38
 
40
- - **False degraded-mode fix** — eliminates spurious degraded-mode warnings when the DB hasn't been initialized yet.
41
- - **Stale session resume suppression** — prevents stale interrupted-session resume prompts from hijacking fresh sessions.
42
- - **Merge conflict recovery** — `autoCommitDirtyState` guarded with cwd restore on `MergeConflictError`.
43
- - **Auto-resume hardening** — `autoStartTime` restored on resume, managed resources resynced on auto resume.
39
+ - **Stream ordering preserved** — MCP tool output now renders in the correct order, fixing interleaved output in Claude Code and other MCP clients.
40
+ - **isError flag propagation** — workflow tool execution failures now correctly return `isError: true`, so MCP clients can distinguish success from failure.
41
+ - **Multi-round discuss questions** — new-project discuss phase supports multi-round questioning with structured question gates.
44
42
 
45
- ### TUI & Developer Experience
43
+ ### TUI Fixes
46
44
 
47
- - **Contextual tips system** — TUI and web terminal now surface contextual tips based on workflow state.
48
- - **Claude Code MCP streaming** — real-time streaming and tool output rendering for Claude Code MCP connections.
45
+ - **Pinned output restored** — pinned output bar displays above the editor during tool execution again.
46
+ - **Turn completion cleanup** — pinned latest output is cleared on turn completion, preventing stale output from persisting.
47
+ - **Secure input masking** — extension input values are masked in interactive mode when collecting secrets.
49
48
 
50
- ### Infrastructure
49
+ ### Reliability & Internals
51
50
 
52
- - **Weekly model registry refresh** — CI workflow auto-regenerates the model registry on a weekly schedule.
53
- - **Codebase cache auto-refresh** — stale codebase cache is refreshed automatically without manual intervention.
51
+ - **TOCTOU file locking** — race conditions in event log and custom workflow graph file locking are fixed with proper atomic lock acquisition.
52
+ - **State derive refactor** — `deriveStateFromDb` god function extracted into composable, testable helpers.
53
+ - **Windows portability** — hardened cross-platform portability across runtime, tooling, and CI.
54
+ - **Model routing transparency** — dynamic routing is skipped for interactive dispatches; model changes are always shown in the banner.
55
+ - **Capability-aware routing (ADR-004)** — full implementation of capability scoring, `before_model_select` hook, and task metadata extraction.
56
+ - **Multi-model provider strategy (ADR-005)** — infrastructure for multi-provider model selection wired into live paths.
54
57
 
55
58
  See the full [Changelog](./CHANGELOG.md) for details on every release.
56
59
 
57
60
  <details>
58
- <summary>Previous highlights (v2.67 and earlier)</summary>
61
+ <summary>Previous highlights (v2.70 and earlier)</summary>
59
62
 
63
+ - **Full workflow over MCP (v2.68)** — slice replanning, milestone management, slice completion, task completion, and core planning tools exposed over MCP
64
+ - **Transport-gated MCP (v2.68)** — workflow tool availability adapts to provider transport capabilities automatically
65
+ - **Contextual tips system (v2.68)** — TUI and web terminal surface contextual tips based on workflow state
66
+ - **Ask user questions over MCP (v2.70)** — interactive questions exposed via elicitation for external integrations
60
67
  - **Tiered Context Injection (M005)** — relevance-scoped context with 65%+ token reduction
61
68
  - **Resilient transient error recovery** — defers to Core RetryHandler and fixes cmdCtx race conditions
62
69
  - **Anthropic subscription routing** — auto-routed through Claude Code CLI provider with proper display names
@@ -17,6 +17,7 @@ import { parse } from "yaml";
17
17
  import { readGraph, writeGraph, getNextPendingStep, markStepComplete, expandIteration, } from "./graph.js";
18
18
  import { injectContext } from "./context-injector.js";
19
19
  import { parseUnitId } from "./unit-id.js";
20
+ import { withFileLock } from "./file-lock.js";
20
21
  /** Read and parse the frozen DEFINITION.yaml from a run directory. */
21
22
  export function readFrozenDefinition(runDir) {
22
23
  const defPath = join(runDir, "DEFINITION.yaml");
@@ -135,18 +136,21 @@ export class CustomWorkflowEngine {
135
136
  * Returns "milestone-complete" when all steps are now done, "continue" otherwise.
136
137
  */
137
138
  async reconcile(state, completedStep) {
138
- // Re-read the graph from disk so we do not overwrite concurrent
139
- // workflow edits with a stale in-memory snapshot from deriveState().
140
- const graph = readGraph(this.runDir);
141
- // Extract stepId from "<workflowName>/<stepId>"
142
- const { milestone, slice, task } = parseUnitId(completedStep.unitId);
143
- const stepId = task ?? slice ?? milestone;
144
- const updatedGraph = markStepComplete(graph, stepId);
145
- writeGraph(this.runDir, updatedGraph);
146
- const allDone = updatedGraph.steps.every((s) => s.status === "complete" || s.status === "expanded");
147
- return {
148
- outcome: allDone ? "milestone-complete" : "continue",
149
- };
139
+ const graphPath = join(this.runDir, "GRAPH.yaml");
140
+ return await withFileLock(graphPath, () => {
141
+ // Re-read the graph from disk so we do not overwrite concurrent
142
+ // workflow edits with a stale in-memory snapshot from deriveState().
143
+ const graph = readGraph(this.runDir);
144
+ // Extract stepId from "<workflowName>/<stepId>"
145
+ const { milestone, slice, task } = parseUnitId(completedStep.unitId);
146
+ const stepId = task ?? slice ?? milestone;
147
+ const updatedGraph = markStepComplete(graph, stepId);
148
+ writeGraph(this.runDir, updatedGraph);
149
+ const allDone = updatedGraph.steps.every((s) => s.status === "complete" || s.status === "expanded");
150
+ return {
151
+ outcome: allDone ? "milestone-complete" : "continue",
152
+ };
153
+ });
150
154
  }
151
155
  /**
152
156
  * Return UI-facing metadata for progress display.
@@ -0,0 +1,60 @@
1
+ import { existsSync } from "node:fs";
2
+ function _require(name) {
3
+ try {
4
+ return require(name);
5
+ }
6
+ catch {
7
+ try {
8
+ const gsdPiRequire = require("module").createRequire(require("path").join(process.cwd(), "node_modules", "gsd-pi", "index.js"));
9
+ return gsdPiRequire(name);
10
+ }
11
+ catch {
12
+ return null;
13
+ }
14
+ }
15
+ }
16
+ export function withFileLockSync(filePath, fn) {
17
+ const lockfile = _require("proper-lockfile");
18
+ if (!lockfile)
19
+ return fn();
20
+ if (!existsSync(filePath))
21
+ return fn();
22
+ try {
23
+ const release = lockfile.lockSync(filePath, { retries: 5, stale: 10000 });
24
+ try {
25
+ return fn();
26
+ }
27
+ finally {
28
+ release();
29
+ }
30
+ }
31
+ catch (err) {
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
+ export async function withFileLock(filePath, fn) {
40
+ const lockfile = _require("proper-lockfile");
41
+ if (!lockfile)
42
+ return await fn();
43
+ if (!existsSync(filePath))
44
+ return await fn();
45
+ try {
46
+ const release = await lockfile.lock(filePath, { retries: 5, stale: 10000 });
47
+ try {
48
+ return await fn();
49
+ }
50
+ finally {
51
+ await release();
52
+ }
53
+ }
54
+ catch (err) {
55
+ if (err.code === "ELOCKED") {
56
+ return await fn();
57
+ }
58
+ throw err;
59
+ }
60
+ }