@opengsd/gsd-pi 1.4.0-dev.5fc22c6f → 1.4.0-dev.c18009cd
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/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +58 -4
- package/dist/resources/extensions/gsd/artifact-verification.js +17 -5
- package/dist/resources/extensions/gsd/auto/closeout.js +45 -42
- package/dist/resources/extensions/gsd/auto/finalize.js +9 -0
- package/dist/resources/extensions/gsd/auto/orchestrator.js +1 -1
- package/dist/resources/extensions/gsd/auto/run-unit.js +5 -2
- package/dist/resources/extensions/gsd/auto/schedule-wakeup.js +3 -0
- package/dist/resources/extensions/gsd/auto.js +10 -3
- package/dist/resources/extensions/gsd/bootstrap/schedule-wakeup-tool.js +58 -9
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +174 -16
- package/dist/resources/extensions/gsd/gsd-db.js +52 -0
- package/dist/resources/extensions/gsd/migrate-external.js +13 -4
- package/dist/resources/extensions/gsd/milestone-merge-transaction.js +3 -3
- package/dist/resources/extensions/gsd/repo-identity.js +16 -0
- package/dist/resources/extensions/gsd/root-write-leak-guard.js +4 -2
- package/dist/resources/extensions/gsd/unit-registry.js +27 -2
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +67 -5
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +6 -6
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +6 -6
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/integrations/hermes/CONTEXT.md +47 -0
- package/integrations/hermes/README.md +21 -0
- package/integrations/hermes/docs/issue-1162-grilling.md +197 -0
- package/integrations/hermes/docs/setup.md +4 -0
- package/integrations/hermes/open_gsd_hermes/commands.py +141 -0
- package/integrations/hermes/open_gsd_hermes/config.py +2 -0
- package/integrations/hermes/open_gsd_hermes/gsd_client.py +594 -31
- package/integrations/hermes/open_gsd_hermes/notifications.py +10 -1
- package/integrations/hermes/plugin.yaml +4 -0
- package/integrations/hermes/tests/test_config.py +6 -0
- package/integrations/hermes/tests/test_gsd_client_cache.py +3 -0
- package/integrations/hermes/tests/test_gsd_client_execute.py +35 -0
- package/integrations/hermes/tests/test_gsd_client_process_cwd.py +22 -0
- package/integrations/hermes/tests/test_gsd_client_timeout.py +98 -0
- package/integrations/hermes/tests/test_milestone_client.py +447 -0
- package/integrations/hermes/tests/test_new_milestone_command.py +313 -0
- package/integrations/hermes/tests/test_supervisor_fsm.py +40 -0
- package/package.json +1 -1
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/dist/session-manager.js +1 -1
- package/packages/daemon/dist/session-manager.js.map +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/dist/session/agent-session-navigation.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-navigation.js +4 -1
- package/packages/gsd-agent-core/dist/session/agent-session-navigation.js.map +1 -1
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/server.d.ts +18 -5
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +46 -5
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/session-manager.js +1 -1
- package/packages/mcp-server/dist/session-manager.js.map +1 -1
- package/packages/mcp-server/package.json +4 -4
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager-types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.js +3 -0
- package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +64 -3
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +212 -39
- package/src/resources/extensions/gsd/artifact-verification.ts +16 -4
- package/src/resources/extensions/gsd/auto/closeout.ts +54 -56
- package/src/resources/extensions/gsd/auto/finalize.ts +8 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
- package/src/resources/extensions/gsd/auto/orchestrator.ts +1 -1
- package/src/resources/extensions/gsd/auto/run-unit.ts +5 -2
- package/src/resources/extensions/gsd/auto/schedule-wakeup.ts +8 -0
- package/src/resources/extensions/gsd/auto.ts +9 -3
- package/src/resources/extensions/gsd/bootstrap/schedule-wakeup-tool.ts +80 -12
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +230 -21
- package/src/resources/extensions/gsd/gsd-db.ts +72 -0
- package/src/resources/extensions/gsd/migrate-external.ts +14 -4
- package/src/resources/extensions/gsd/milestone-merge-transaction.ts +4 -4
- package/src/resources/extensions/gsd/repo-identity.ts +17 -0
- package/src/resources/extensions/gsd/root-write-leak-guard.ts +3 -2
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +131 -5
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +43 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +335 -0
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/migrate-external-worktree.test.ts +116 -0
- package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +152 -22
- package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +50 -6
- package/src/resources/extensions/gsd/tests/root-write-leak-guard.test.ts +31 -9
- package/src/resources/extensions/gsd/tests/schedule-wakeup-tool.test.ts +167 -0
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/unit-registry.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +2 -2
- package/src/resources/extensions/gsd/unit-registry.ts +34 -2
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +135 -11
- /package/dist/web/standalone/.next/static/{kIEFsCryyGy6RzifULbJl → L2UMqXELiDH3oz-7yguXp}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{kIEFsCryyGy6RzifULbJl → L2UMqXELiDH3oz-7yguXp}/_ssgManifest.js +0 -0
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import os
|
|
5
6
|
import shlex
|
|
6
7
|
from typing import Any, Callable
|
|
7
8
|
|
|
@@ -58,6 +59,7 @@ class GsdCommandRouter:
|
|
|
58
59
|
"auto": self._cmd_auto,
|
|
59
60
|
"cancel": self._cmd_cancel,
|
|
60
61
|
"reply": self._cmd_reply,
|
|
62
|
+
"new-milestone": self._cmd_new_milestone,
|
|
61
63
|
"help": self._cmd_help,
|
|
62
64
|
}
|
|
63
65
|
handler = handlers.get(sub, self._cmd_help)
|
|
@@ -69,6 +71,7 @@ class GsdCommandRouter:
|
|
|
69
71
|
"- `/gsd bind <path>` — bind this chat to a project\n"
|
|
70
72
|
"- `/gsd status` — show progress snapshot\n"
|
|
71
73
|
"- `/gsd auto` — start auto mode (MCP)\n"
|
|
74
|
+
"- `/gsd new-milestone <spec>` or `--file <path>` — create a milestone (then `/gsd auto`)\n"
|
|
72
75
|
"- `/gsd cancel` — cancel running session\n"
|
|
73
76
|
"- `/gsd reply <text>` — resolve blocker"
|
|
74
77
|
)
|
|
@@ -112,6 +115,15 @@ class GsdCommandRouter:
|
|
|
112
115
|
return f"GSD status unavailable: {e}"
|
|
113
116
|
|
|
114
117
|
async def _cmd_auto(self, _rest: list[str]) -> str:
|
|
118
|
+
# Symmetric co-run guard (issue #1162): refuse if a milestone run is
|
|
119
|
+
# in progress. The MCP server's "Session already active" rejection
|
|
120
|
+
# does NOT fire for a milestone subprocess (it's not registered and
|
|
121
|
+
# writes no auto.lock during planning), so this local gate is the
|
|
122
|
+
# only thing preventing an unsafe co-run.
|
|
123
|
+
if self._client.milestone_active():
|
|
124
|
+
return (
|
|
125
|
+
"Milestone creation is in progress. Run `/gsd cancel` first."
|
|
126
|
+
)
|
|
115
127
|
try:
|
|
116
128
|
project_dir = resolve_project_dir(
|
|
117
129
|
self._config, self._binding_ctx()
|
|
@@ -140,6 +152,18 @@ class GsdCommandRouter:
|
|
|
140
152
|
|
|
141
153
|
async def _cmd_cancel(self, _rest: list[str]) -> str:
|
|
142
154
|
ctx = self._get_supervisor_ctx()
|
|
155
|
+
# Milestone subprocess is locally owned (issue #1162); route to the
|
|
156
|
+
# local SIGTERM path instead of MCP cancel, which cannot see it.
|
|
157
|
+
if self._client.milestone_active():
|
|
158
|
+
self._client.cancel_milestone()
|
|
159
|
+
ctx.session_id = None
|
|
160
|
+
ctx.state = SupervisorState.CANCELLED
|
|
161
|
+
ctx.notified_terminal = True
|
|
162
|
+
self._set_supervisor_ctx(ctx)
|
|
163
|
+
self._supervisor.stop()
|
|
164
|
+
if self._notifications is not None:
|
|
165
|
+
self._notifications.notify_terminal("cancelled")
|
|
166
|
+
return "Cancel requested."
|
|
143
167
|
try:
|
|
144
168
|
try:
|
|
145
169
|
if ctx.session_id and ctx.project_dir:
|
|
@@ -175,6 +199,17 @@ class GsdCommandRouter:
|
|
|
175
199
|
if not rest:
|
|
176
200
|
return "Usage: `/gsd reply <your answer>`"
|
|
177
201
|
text = " ".join(rest)
|
|
202
|
+
# Milestone planning blocker (issue #1162): the subprocess is locally
|
|
203
|
+
# owned, so its blocker replies must go to its stdin, not MCP
|
|
204
|
+
# gsd_resolve_blocker (which can't see our session).
|
|
205
|
+
if self._client.milestone_active():
|
|
206
|
+
if not self._client.milestone_pending_blocker_id():
|
|
207
|
+
return "No pending blocker for the active milestone session."
|
|
208
|
+
try:
|
|
209
|
+
self._client.respond_to_milestone_blocker(text)
|
|
210
|
+
except Exception as e:
|
|
211
|
+
return f"Could not send blocker response: {e}"
|
|
212
|
+
return "Blocker response sent."
|
|
178
213
|
ctx = self._get_supervisor_ctx()
|
|
179
214
|
if not ctx.session_id:
|
|
180
215
|
return "No active GSD session. Run `/gsd auto` first."
|
|
@@ -184,3 +219,109 @@ class GsdCommandRouter:
|
|
|
184
219
|
except Exception as e:
|
|
185
220
|
return f"Could not send blocker response: {e}"
|
|
186
221
|
return "Blocker response sent."
|
|
222
|
+
|
|
223
|
+
async def _cmd_new_milestone(self, rest: list[str]) -> str:
|
|
224
|
+
"""Create a milestone via `gsd headless --supervised new-milestone`.
|
|
225
|
+
|
|
226
|
+
Planning-only: the plugin spawns the subprocess, owns its lifecycle,
|
|
227
|
+
and notifies on blocker/terminal events. Execution stays with
|
|
228
|
+
`/gsd auto`. See integrations/hermes/docs/issue-1162-grilling.md.
|
|
229
|
+
"""
|
|
230
|
+
if not rest:
|
|
231
|
+
return (
|
|
232
|
+
"Usage: `/gsd new-milestone <spec>` "
|
|
233
|
+
"(or `--file <path>`)"
|
|
234
|
+
)
|
|
235
|
+
# --auto is intentionally rejected (Q5): execution is /gsd auto's job.
|
|
236
|
+
if rest[0] == "--auto":
|
|
237
|
+
return (
|
|
238
|
+
"Execution isn't chained from `/gsd new-milestone`. "
|
|
239
|
+
"Create the milestone, then run `/gsd auto`."
|
|
240
|
+
)
|
|
241
|
+
# Co-run guard (Q2): refuse if a milestone or auto session is active.
|
|
242
|
+
if self._client.milestone_active():
|
|
243
|
+
return (
|
|
244
|
+
"Milestone creation is in progress. Run `/gsd cancel` first."
|
|
245
|
+
)
|
|
246
|
+
ctx = self._get_supervisor_ctx()
|
|
247
|
+
if ctx.state in (SupervisorState.RUNNING, SupervisorState.BLOCKED):
|
|
248
|
+
return (
|
|
249
|
+
"GSD auto is running. Run `/gsd cancel` first."
|
|
250
|
+
)
|
|
251
|
+
# Resolve the bound project.
|
|
252
|
+
try:
|
|
253
|
+
project_dir = resolve_project_dir(
|
|
254
|
+
self._config, self._binding_ctx()
|
|
255
|
+
)
|
|
256
|
+
except BindingError as e:
|
|
257
|
+
return str(e)
|
|
258
|
+
|
|
259
|
+
# Input shape (Q6): bare positional → context_text, `--file <path>`
|
|
260
|
+
# → context_file.
|
|
261
|
+
context_text: str | None = None
|
|
262
|
+
context_file: str | None = None
|
|
263
|
+
if rest[0] == "--file":
|
|
264
|
+
if len(rest) < 2:
|
|
265
|
+
return "Usage: `/gsd new-milestone --file <path>`"
|
|
266
|
+
context_file = rest[1]
|
|
267
|
+
resolved_file = (
|
|
268
|
+
context_file
|
|
269
|
+
if os.path.isabs(context_file)
|
|
270
|
+
else os.path.join(project_dir, context_file)
|
|
271
|
+
)
|
|
272
|
+
if not os.path.isfile(resolved_file):
|
|
273
|
+
return f"Context file not found: `{context_file}`"
|
|
274
|
+
if not os.access(resolved_file, os.R_OK):
|
|
275
|
+
return f"Context file is not readable: `{context_file}`"
|
|
276
|
+
context_file = resolved_file
|
|
277
|
+
else:
|
|
278
|
+
context_text = " ".join(rest)
|
|
279
|
+
|
|
280
|
+
def _on_milestone_terminal(status: str) -> None:
|
|
281
|
+
milestone_ctx = self._get_supervisor_ctx()
|
|
282
|
+
if milestone_ctx.session_id != session_id:
|
|
283
|
+
return
|
|
284
|
+
normalized = status.lower()
|
|
285
|
+
if normalized in ("complete", "completed", "done"):
|
|
286
|
+
milestone_ctx.state = SupervisorState.COMPLETE
|
|
287
|
+
elif normalized == "cancelled":
|
|
288
|
+
milestone_ctx.state = SupervisorState.CANCELLED
|
|
289
|
+
else:
|
|
290
|
+
milestone_ctx.state = SupervisorState.FAILED
|
|
291
|
+
milestone_ctx.session_id = None
|
|
292
|
+
milestone_ctx.pending_blocker_id = None
|
|
293
|
+
milestone_ctx.notified_terminal = True
|
|
294
|
+
self._set_supervisor_ctx(milestone_ctx)
|
|
295
|
+
|
|
296
|
+
# Spawn the supervised subprocess; create_milestone returns a local
|
|
297
|
+
# session id immediately and continues the stream reader in the
|
|
298
|
+
# background.
|
|
299
|
+
try:
|
|
300
|
+
session_id = self._client.create_milestone(
|
|
301
|
+
project_dir,
|
|
302
|
+
context_text=context_text,
|
|
303
|
+
context_file=context_file,
|
|
304
|
+
notifications=self._notifications,
|
|
305
|
+
on_terminal=_on_milestone_terminal,
|
|
306
|
+
)
|
|
307
|
+
except ValueError:
|
|
308
|
+
return "Usage: `/gsd new-milestone <spec>` (or `--file <path>`)"
|
|
309
|
+
except Exception as e:
|
|
310
|
+
return f"Could not start milestone creation: {e}"
|
|
311
|
+
|
|
312
|
+
# Record the active milestone run so /gsd status, /gsd cancel, and the
|
|
313
|
+
# co-run gate (in _cmd_auto) see it. The supervisor poll loop is NOT
|
|
314
|
+
# used (the stream reader drives notifications); we only carry state.
|
|
315
|
+
self._supervisor.stop()
|
|
316
|
+
ctx.session_id = session_id
|
|
317
|
+
ctx.project_dir = project_dir
|
|
318
|
+
ctx.state = SupervisorState.RUNNING
|
|
319
|
+
ctx.last_progress = None
|
|
320
|
+
ctx.last_status = None
|
|
321
|
+
ctx.pending_blocker_id = None
|
|
322
|
+
ctx.notified_terminal = False
|
|
323
|
+
self._set_supervisor_ctx(ctx)
|
|
324
|
+
return (
|
|
325
|
+
f"🚀 Milestone creation started (session `{session_id}`). "
|
|
326
|
+
"I'll notify you when it's ready; run `/gsd auto` to execute."
|
|
327
|
+
)
|
|
@@ -19,6 +19,7 @@ class GsdConfig:
|
|
|
19
19
|
bindings: dict[str, dict[str, str]] = field(default_factory=dict)
|
|
20
20
|
poll_interval_seconds: int = 12
|
|
21
21
|
cache_ttl_seconds: int = 45
|
|
22
|
+
mcp_read_timeout_seconds: float = 60.0
|
|
22
23
|
notification_level: str = "normal"
|
|
23
24
|
gsd_version_min: str = "2.53"
|
|
24
25
|
gsd_version_max: str = "3.0"
|
|
@@ -35,6 +36,7 @@ class GsdConfig:
|
|
|
35
36
|
bindings=dict(gsd.get("bindings") or {}),
|
|
36
37
|
poll_interval_seconds=int(gsd.get("poll_interval_seconds", 12)),
|
|
37
38
|
cache_ttl_seconds=int(gsd.get("cache_ttl_seconds", 45)),
|
|
39
|
+
mcp_read_timeout_seconds=float(gsd.get("mcp_read_timeout_seconds", 60.0)),
|
|
38
40
|
notification_level=str(gsd.get("notification_level", "normal")),
|
|
39
41
|
gsd_version_min=str(gsd.get("gsd_version_min", "2.53")),
|
|
40
42
|
gsd_version_max=str(gsd.get("gsd_version_max", "3.0")),
|