gsd-pi 2.78.1-dev.8a893322c → 2.78.1-dev.a7b6e59b7
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/cli-auto-routing.d.ts +1 -0
- package/dist/cli-auto-routing.js +5 -0
- package/dist/cli.js +5 -14
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/gsd/auto/run-unit.js +23 -11
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +55 -21
- package/dist/resources/extensions/gsd/auto-prompts.js +6 -0
- package/dist/resources/extensions/gsd/auto-worktree.js +15 -0
- package/dist/resources/extensions/gsd/auto.js +25 -9
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
- package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +2 -0
- package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +2 -0
- package/dist/resources/extensions/gsd/worktree-resolver.js +24 -0
- package/dist/resources/skills/lint/SKILL.md +4 -0
- package/dist/resources/skills/review/SKILL.md +4 -0
- package/dist/resources/skills/test/SKILL.md +3 -0
- 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 +14 -14
- 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 +14 -14
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
- 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/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +278 -0
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +7 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +125 -55
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +319 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +128 -59
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/src/resources/extensions/gsd/auto/run-unit.ts +23 -11
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +60 -24
- package/src/resources/extensions/gsd/auto-prompts.ts +6 -0
- package/src/resources/extensions/gsd/auto-worktree.ts +15 -0
- package/src/resources/extensions/gsd/auto.ts +23 -6
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
- package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +2 -0
- package/src/resources/extensions/gsd/prompts/rewrite-docs.md +2 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +8 -2
- package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +12 -6
- package/src/resources/extensions/gsd/tests/worktree-path-injection.test.ts +235 -0
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +85 -0
- package/src/resources/extensions/gsd/worktree-resolver.ts +24 -0
- package/src/resources/skills/lint/SKILL.md +4 -0
- package/src/resources/skills/review/SKILL.md +4 -0
- package/src/resources/skills/test/SKILL.md +3 -0
- /package/dist/web/standalone/.next/static/{QK8fABiGPmonfTgboN0Y9 → GlYncvckBGG33CSoJaSnB}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{QK8fABiGPmonfTgboN0Y9 → GlYncvckBGG33CSoJaSnB}/_ssgManifest.js +0 -0
|
@@ -84,6 +84,12 @@ export class AgentSession {
|
|
|
84
84
|
// Extension system
|
|
85
85
|
this._extensionRunner = undefined;
|
|
86
86
|
this._turnIndex = 0;
|
|
87
|
+
this._processingAgentEnd = false;
|
|
88
|
+
/** True while newSession()/switchSession() is in progress; signals agent_end
|
|
89
|
+
* post-handlers to bail rather than corrupt new-session state. */
|
|
90
|
+
this._sessionSwitchPending = false;
|
|
91
|
+
this._processingQueuedAgentEnd = false;
|
|
92
|
+
this._sessionTransitionStartedDuringAgentEnd = false;
|
|
87
93
|
this._baseToolRegistry = new Map();
|
|
88
94
|
// Tool registry for extension getTools/setTools
|
|
89
95
|
this._toolRegistry = new Map();
|
|
@@ -201,7 +207,24 @@ export class AgentSession {
|
|
|
201
207
|
}
|
|
202
208
|
}
|
|
203
209
|
// Emit to extensions first
|
|
204
|
-
|
|
210
|
+
let skipAgentEndPostHandlers = false;
|
|
211
|
+
if (event.type === "agent_end") {
|
|
212
|
+
this._processingQueuedAgentEnd = true;
|
|
213
|
+
try {
|
|
214
|
+
await this._emitExtensionEvent(event);
|
|
215
|
+
}
|
|
216
|
+
finally {
|
|
217
|
+
this._processingQueuedAgentEnd = false;
|
|
218
|
+
skipAgentEndPostHandlers = this._sessionTransitionStartedDuringAgentEnd;
|
|
219
|
+
this._sessionTransitionStartedDuringAgentEnd = false;
|
|
220
|
+
}
|
|
221
|
+
if (skipAgentEndPostHandlers) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
await this._emitExtensionEvent(event);
|
|
227
|
+
}
|
|
205
228
|
// Notify all listeners
|
|
206
229
|
this._emit(event);
|
|
207
230
|
// Handle session persistence
|
|
@@ -245,6 +268,12 @@ export class AgentSession {
|
|
|
245
268
|
}
|
|
246
269
|
// Check auto-retry and auto-compaction after agent completes
|
|
247
270
|
if (event.type === "agent_end" && this._lastAssistantMessage) {
|
|
271
|
+
// A session transition started during agent_end handler execution -
|
|
272
|
+
// bail to avoid running retry/compaction against new-session state.
|
|
273
|
+
if (this._sessionSwitchPending) {
|
|
274
|
+
this._lastAssistantMessage = undefined;
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
248
277
|
const msg = this._lastAssistantMessage;
|
|
249
278
|
this._lastAssistantMessage = undefined;
|
|
250
279
|
// Check for retryable errors first (overloaded, rate limit, server errors)
|
|
@@ -361,26 +390,33 @@ export class AgentSession {
|
|
|
361
390
|
}
|
|
362
391
|
/** Emit extension events based on agent events */
|
|
363
392
|
async _emitExtensionEvent(event) {
|
|
364
|
-
|
|
393
|
+
const extensionRunner = this._extensionRunner;
|
|
394
|
+
if (!extensionRunner)
|
|
365
395
|
return;
|
|
366
396
|
if (event.type === "agent_start") {
|
|
367
397
|
this._turnIndex = 0;
|
|
368
|
-
await
|
|
398
|
+
await extensionRunner.emit({ type: "agent_start" });
|
|
369
399
|
}
|
|
370
400
|
else if (event.type === "agent_end") {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
? "
|
|
381
|
-
: "
|
|
382
|
-
|
|
383
|
-
|
|
401
|
+
this._processingAgentEnd = true;
|
|
402
|
+
try {
|
|
403
|
+
await extensionRunner.emit({ type: "agent_end", messages: event.messages });
|
|
404
|
+
// `stop` fires on true quiescence: the agent cleanly completed and is now
|
|
405
|
+
// waiting for the user. Use the last assistant message's stopReason to
|
|
406
|
+
// distinguish clean completion from error/cancellation.
|
|
407
|
+
const last = event.messages[event.messages.length - 1];
|
|
408
|
+
const stopReason = last?.role === "assistant"
|
|
409
|
+
? last.stopReason === "aborted"
|
|
410
|
+
? "cancelled"
|
|
411
|
+
: last.stopReason === "error"
|
|
412
|
+
? "error"
|
|
413
|
+
: "completed"
|
|
414
|
+
: "completed";
|
|
415
|
+
await extensionRunner.emitStop({ reason: stopReason, lastMessage: last });
|
|
416
|
+
}
|
|
417
|
+
finally {
|
|
418
|
+
this._processingAgentEnd = false;
|
|
419
|
+
}
|
|
384
420
|
}
|
|
385
421
|
else if (event.type === "turn_start") {
|
|
386
422
|
const extensionEvent = {
|
|
@@ -388,7 +424,7 @@ export class AgentSession {
|
|
|
388
424
|
turnIndex: this._turnIndex,
|
|
389
425
|
timestamp: Date.now(),
|
|
390
426
|
};
|
|
391
|
-
await
|
|
427
|
+
await extensionRunner.emit(extensionEvent);
|
|
392
428
|
}
|
|
393
429
|
else if (event.type === "turn_end") {
|
|
394
430
|
const extensionEvent = {
|
|
@@ -397,7 +433,7 @@ export class AgentSession {
|
|
|
397
433
|
message: event.message,
|
|
398
434
|
toolResults: event.toolResults,
|
|
399
435
|
};
|
|
400
|
-
await
|
|
436
|
+
await extensionRunner.emit(extensionEvent);
|
|
401
437
|
this._turnIndex++;
|
|
402
438
|
}
|
|
403
439
|
else if (event.type === "message_start") {
|
|
@@ -405,7 +441,7 @@ export class AgentSession {
|
|
|
405
441
|
type: "message_start",
|
|
406
442
|
message: event.message,
|
|
407
443
|
};
|
|
408
|
-
await
|
|
444
|
+
await extensionRunner.emit(extensionEvent);
|
|
409
445
|
}
|
|
410
446
|
else if (event.type === "message_update") {
|
|
411
447
|
const extensionEvent = {
|
|
@@ -413,14 +449,14 @@ export class AgentSession {
|
|
|
413
449
|
message: event.message,
|
|
414
450
|
assistantMessageEvent: event.assistantMessageEvent,
|
|
415
451
|
};
|
|
416
|
-
await
|
|
452
|
+
await extensionRunner.emit(extensionEvent);
|
|
417
453
|
}
|
|
418
454
|
else if (event.type === "message_end") {
|
|
419
455
|
const extensionEvent = {
|
|
420
456
|
type: "message_end",
|
|
421
457
|
message: event.message,
|
|
422
458
|
};
|
|
423
|
-
await
|
|
459
|
+
await extensionRunner.emit(extensionEvent);
|
|
424
460
|
}
|
|
425
461
|
else if (event.type === "tool_execution_start") {
|
|
426
462
|
const extensionEvent = {
|
|
@@ -429,7 +465,7 @@ export class AgentSession {
|
|
|
429
465
|
toolName: event.toolName,
|
|
430
466
|
args: event.args,
|
|
431
467
|
};
|
|
432
|
-
await
|
|
468
|
+
await extensionRunner.emit(extensionEvent);
|
|
433
469
|
}
|
|
434
470
|
else if (event.type === "tool_execution_update") {
|
|
435
471
|
const extensionEvent = {
|
|
@@ -439,7 +475,7 @@ export class AgentSession {
|
|
|
439
475
|
args: event.args,
|
|
440
476
|
partialResult: event.partialResult,
|
|
441
477
|
};
|
|
442
|
-
await
|
|
478
|
+
await extensionRunner.emit(extensionEvent);
|
|
443
479
|
}
|
|
444
480
|
else if (event.type === "tool_execution_end") {
|
|
445
481
|
const extensionEvent = {
|
|
@@ -449,7 +485,7 @@ export class AgentSession {
|
|
|
449
485
|
result: event.result,
|
|
450
486
|
isError: event.isError,
|
|
451
487
|
};
|
|
452
|
-
await
|
|
488
|
+
await extensionRunner.emit(extensionEvent);
|
|
453
489
|
}
|
|
454
490
|
}
|
|
455
491
|
/**
|
|
@@ -1175,21 +1211,49 @@ export class AgentSession {
|
|
|
1175
1211
|
// between tool execution and response processing. Also fire Stop so
|
|
1176
1212
|
// Layer 0 hooks see a consistent view of session quiescence.
|
|
1177
1213
|
if (!this.isStreaming && this._extensionRunner) {
|
|
1178
|
-
const
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
messages
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1214
|
+
const wasProcessingAgentEnd = this._processingAgentEnd;
|
|
1215
|
+
this._processingAgentEnd = true;
|
|
1216
|
+
try {
|
|
1217
|
+
const messages = this.agent.state.messages;
|
|
1218
|
+
await this._extensionRunner.emit({
|
|
1219
|
+
type: "agent_end",
|
|
1220
|
+
messages,
|
|
1221
|
+
});
|
|
1222
|
+
const last = messages[messages.length - 1];
|
|
1223
|
+
const stopReason = last?.role === "assistant"
|
|
1224
|
+
? last.stopReason === "aborted"
|
|
1225
|
+
? "cancelled"
|
|
1226
|
+
: last.stopReason === "error"
|
|
1227
|
+
? "error"
|
|
1228
|
+
: "completed"
|
|
1229
|
+
: "cancelled";
|
|
1230
|
+
await this._extensionRunner.emitStop({ reason: stopReason, lastMessage: last });
|
|
1231
|
+
}
|
|
1232
|
+
finally {
|
|
1233
|
+
this._processingAgentEnd = wasProcessingAgentEnd;
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
async _settleCurrentTurnForSessionTransition() {
|
|
1238
|
+
if (this._processingAgentEnd) {
|
|
1239
|
+
// Wait for the agent to fully settle. When called from inside an
|
|
1240
|
+
// agent_end extension handler, the agent may already be idle - but
|
|
1241
|
+
// _processAgentEvent still has retry/compaction tail work to run after
|
|
1242
|
+
// _emitExtensionEvent returns. waitForIdle() is effectively a no-op when
|
|
1243
|
+
// already idle, so awaiting it unconditionally is safe and ensures we
|
|
1244
|
+
// don't proceed into the session reset while that tail is still on the stack.
|
|
1245
|
+
await this.agent.waitForIdle();
|
|
1246
|
+
if (this._processingQueuedAgentEnd) {
|
|
1247
|
+
this._sessionTransitionStartedDuringAgentEnd = true;
|
|
1248
|
+
this._lastAssistantMessage = undefined;
|
|
1249
|
+
}
|
|
1250
|
+
return;
|
|
1192
1251
|
}
|
|
1252
|
+
// #4243: Normal session transitions must abort before disconnecting so
|
|
1253
|
+
// message_end/agent_end events fire while listeners are still connected.
|
|
1254
|
+
// During agent_end handling the turn is already ending; aborting there can
|
|
1255
|
+
// convert a successful auto-mode handoff into an aborted provider message.
|
|
1256
|
+
await this.abort();
|
|
1193
1257
|
}
|
|
1194
1258
|
/**
|
|
1195
1259
|
* Start a new session, optionally with initial messages and parent tracking.
|
|
@@ -1211,19 +1275,22 @@ export class AgentSession {
|
|
|
1211
1275
|
return false;
|
|
1212
1276
|
}
|
|
1213
1277
|
}
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1278
|
+
this._sessionSwitchPending = true;
|
|
1279
|
+
try {
|
|
1280
|
+
await this._settleCurrentTurnForSessionTransition();
|
|
1281
|
+
// #3731: If the caller aborted (e.g. runUnit() timed out and restored cwd to
|
|
1282
|
+
// project root), discard this session before capturing process.cwd() and
|
|
1283
|
+
// rebuilding the tool runtime. Without this check, the late newSession()
|
|
1284
|
+
// would rebuild tools with root cwd, breaking worktree isolation.
|
|
1285
|
+
if (options?.abortSignal?.aborted) {
|
|
1286
|
+
return false;
|
|
1287
|
+
}
|
|
1288
|
+
this._disconnectFromAgent();
|
|
1289
|
+
this.agent.reset();
|
|
1290
|
+
}
|
|
1291
|
+
finally {
|
|
1292
|
+
this._sessionSwitchPending = false;
|
|
1224
1293
|
}
|
|
1225
|
-
this._disconnectFromAgent();
|
|
1226
|
-
this.agent.reset();
|
|
1227
1294
|
// Update cwd to current process directory — auto-mode may have chdir'd
|
|
1228
1295
|
// into a worktree since the original session was created.
|
|
1229
1296
|
const previousCwd = this._cwd;
|
|
@@ -1949,11 +2016,14 @@ export class AgentSession {
|
|
|
1949
2016
|
return false;
|
|
1950
2017
|
}
|
|
1951
2018
|
}
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
2019
|
+
this._sessionSwitchPending = true;
|
|
2020
|
+
try {
|
|
2021
|
+
await this._settleCurrentTurnForSessionTransition();
|
|
2022
|
+
this._disconnectFromAgent();
|
|
2023
|
+
}
|
|
2024
|
+
finally {
|
|
2025
|
+
this._sessionSwitchPending = false;
|
|
2026
|
+
}
|
|
1957
2027
|
this._steeringMessages = [];
|
|
1958
2028
|
this._followUpMessages = [];
|
|
1959
2029
|
this._pendingNextTurnMessages = [];
|