@tmustier/pi-agent-teams 0.5.2 → 0.5.3
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/CHANGELOG.md +6 -0
- package/extensions/teams/leader.ts +18 -4
- package/extensions/teams/session-parent.ts +24 -0
- package/package.json +1 -1
- package/scripts/smoke-test.mts +64 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.3
|
|
4
|
+
|
|
5
|
+
### Fixes
|
|
6
|
+
|
|
7
|
+
- **Inherited parent-team attach warnings** — forked/branched child sessions now silently detach back to their own session team when they briefly inherit a parent team id without any attach claim. This removes the noisy warning seen in subagent-style flows while preserving normal `not_owner` warnings for real claim conflicts.
|
|
8
|
+
|
|
3
9
|
## 0.5.2
|
|
4
10
|
|
|
5
11
|
### Fixes
|
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
} from "./hooks.js";
|
|
34
34
|
import { handleTeamCommand } from "./leader-team-command.js";
|
|
35
35
|
import { registerTeamsTool } from "./leader-teams-tool.js";
|
|
36
|
+
import { getParentSessionId, shouldSilenceInheritedParentAttachClaimWarning } from "./session-parent.js";
|
|
36
37
|
import type { ContextMode, SpawnTeammateFn, SpawnTeammateResult, WorkspaceMode } from "./spawn-types.js";
|
|
37
38
|
|
|
38
39
|
function getTeamsExtensionEntryPath(): string | null {
|
|
@@ -155,6 +156,7 @@ export function runLeader(pi: ExtensionAPI): void {
|
|
|
155
156
|
let delegateMode = process.env.PI_TEAMS_DELEGATE_MODE === "1";
|
|
156
157
|
let style: TeamsStyle = getTeamsStyleFromEnv();
|
|
157
158
|
let lastAttachClaimHeartbeatMs = 0;
|
|
159
|
+
let inheritedParentTeamId: string | null = null;
|
|
158
160
|
|
|
159
161
|
const stopLoops = () => {
|
|
160
162
|
if (refreshTimer) clearInterval(refreshTimer);
|
|
@@ -180,13 +182,22 @@ export function runLeader(pi: ExtensionAPI): void {
|
|
|
180
182
|
const result = await heartbeatTeamAttachClaim(getTeamDir(currentTeamId), sessionTeamId);
|
|
181
183
|
if (result === "updated") return;
|
|
182
184
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
185
|
+
const lostTeamId = currentTeamId;
|
|
186
|
+
const shouldSilenceWarning = shouldSilenceInheritedParentAttachClaimWarning({
|
|
187
|
+
currentTeamId: lostTeamId,
|
|
188
|
+
parentSessionId: inheritedParentTeamId,
|
|
189
|
+
result,
|
|
190
|
+
});
|
|
191
|
+
inheritedParentTeamId = null;
|
|
187
192
|
currentTeamId = sessionTeamId;
|
|
188
193
|
taskListId = sessionTeamId;
|
|
189
194
|
delegationTracker.clear();
|
|
195
|
+
if (!shouldSilenceWarning) {
|
|
196
|
+
ctx.ui.notify(
|
|
197
|
+
`Attach claim for team ${lostTeamId} is no longer owned by this session; detaching to session team.`,
|
|
198
|
+
"warning",
|
|
199
|
+
);
|
|
200
|
+
}
|
|
190
201
|
await refreshTasks();
|
|
191
202
|
renderWidget();
|
|
192
203
|
};
|
|
@@ -709,6 +720,7 @@ export function runLeader(pi: ExtensionAPI): void {
|
|
|
709
720
|
pi.on("session_start", async (_event, ctx) => {
|
|
710
721
|
currentCtx = ctx;
|
|
711
722
|
currentTeamId = currentCtx.sessionManager.getSessionId();
|
|
723
|
+
inheritedParentTeamId = getParentSessionId(currentCtx.sessionManager);
|
|
712
724
|
// Keep the task list aligned with the active session. If you want a shared namespace,
|
|
713
725
|
// use `/team task use <taskListId>` after switching.
|
|
714
726
|
taskListId = currentTeamId;
|
|
@@ -792,6 +804,7 @@ export function runLeader(pi: ExtensionAPI): void {
|
|
|
792
804
|
|
|
793
805
|
currentCtx = ctx;
|
|
794
806
|
currentTeamId = currentCtx.sessionManager.getSessionId();
|
|
807
|
+
inheritedParentTeamId = getParentSessionId(currentCtx.sessionManager);
|
|
795
808
|
// Keep the task list aligned with the active session. If you want a shared namespace,
|
|
796
809
|
// use `/team task use <taskListId>` after switching.
|
|
797
810
|
taskListId = currentTeamId;
|
|
@@ -1072,6 +1085,7 @@ export function runLeader(pi: ExtensionAPI): void {
|
|
|
1072
1085
|
getActiveTeamId: () => currentTeamId ?? ctx.sessionManager.getSessionId(),
|
|
1073
1086
|
setActiveTeamId: (teamId) => {
|
|
1074
1087
|
currentTeamId = teamId;
|
|
1088
|
+
inheritedParentTeamId = null;
|
|
1075
1089
|
delegationTracker.clear();
|
|
1076
1090
|
},
|
|
1077
1091
|
pendingPlanApprovals,
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { SessionManager } from "@mariozechner/pi-coding-agent";
|
|
2
|
+
import type { TeamAttachClaimHeartbeatResult } from "./team-attach-claim.js";
|
|
3
|
+
|
|
4
|
+
interface SessionManagerWithHeader {
|
|
5
|
+
getHeader(): { parentSession?: string } | null;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function getParentSessionId(sessionManager: SessionManagerWithHeader): string | null {
|
|
9
|
+
const parentSessionPath = sessionManager.getHeader()?.parentSession;
|
|
10
|
+
if (!parentSessionPath) return null;
|
|
11
|
+
try {
|
|
12
|
+
return SessionManager.open(parentSessionPath).getSessionId();
|
|
13
|
+
} catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function shouldSilenceInheritedParentAttachClaimWarning(opts: {
|
|
19
|
+
currentTeamId: string;
|
|
20
|
+
parentSessionId: string | null;
|
|
21
|
+
result: TeamAttachClaimHeartbeatResult;
|
|
22
|
+
}): boolean {
|
|
23
|
+
return opts.result === "missing" && opts.parentSessionId !== null && opts.currentTeamId === opts.parentSessionId;
|
|
24
|
+
}
|
package/package.json
CHANGED
package/scripts/smoke-test.mts
CHANGED
|
@@ -70,7 +70,9 @@ import {
|
|
|
70
70
|
isPlanRejectedMessage,
|
|
71
71
|
} from "../extensions/teams/protocol.js";
|
|
72
72
|
import { pollLeaderInbox } from "../extensions/teams/leader-inbox.js";
|
|
73
|
-
import
|
|
73
|
+
import { getParentSessionId, shouldSilenceInheritedParentAttachClaimWarning } from "../extensions/teams/session-parent.js";
|
|
74
|
+
import { SessionManager, type ExtensionContext } from "@mariozechner/pi-coding-agent";
|
|
75
|
+
import type { AssistantMessage } from "@mariozechner/pi-ai";
|
|
74
76
|
|
|
75
77
|
// ── helpers ──────────────────────────────────────────────────────────
|
|
76
78
|
let passed = 0;
|
|
@@ -845,6 +847,67 @@ console.log("\n10. team discovery + attach claims");
|
|
|
845
847
|
}
|
|
846
848
|
}
|
|
847
849
|
|
|
850
|
+
// ── 10b. branched sessions + inherited attach claims ────────────────
|
|
851
|
+
console.log("\n10b. branched sessions + inherited attach claims");
|
|
852
|
+
{
|
|
853
|
+
const sessionsDir = path.join(tmpRoot, "branch-session-test");
|
|
854
|
+
const parent = SessionManager.create(tmpRoot, sessionsDir);
|
|
855
|
+
const assistantMessage: AssistantMessage = {
|
|
856
|
+
role: "assistant",
|
|
857
|
+
content: [{ type: "text", text: "ok" }],
|
|
858
|
+
api: "test",
|
|
859
|
+
provider: "test",
|
|
860
|
+
model: "test",
|
|
861
|
+
usage: {
|
|
862
|
+
input: 0,
|
|
863
|
+
output: 0,
|
|
864
|
+
cacheRead: 0,
|
|
865
|
+
cacheWrite: 0,
|
|
866
|
+
totalTokens: 0,
|
|
867
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
868
|
+
},
|
|
869
|
+
stopReason: "stop",
|
|
870
|
+
timestamp: Date.now(),
|
|
871
|
+
};
|
|
872
|
+
parent.appendMessage(assistantMessage);
|
|
873
|
+
const parentLeafId = parent.getLeafId();
|
|
874
|
+
const originalParentSessionId = parent.getSessionId();
|
|
875
|
+
assert(parentLeafId !== null, "branch test parent has a leaf entry");
|
|
876
|
+
if (parentLeafId) {
|
|
877
|
+
const branchedPath = parent.createBranchedSession(parentLeafId);
|
|
878
|
+
assert(branchedPath !== null, "createBranchedSession returns child session path");
|
|
879
|
+
if (branchedPath) {
|
|
880
|
+
const child = SessionManager.open(branchedPath, sessionsDir);
|
|
881
|
+
const parentSessionId = getParentSessionId(child);
|
|
882
|
+
assertEq(parentSessionId, originalParentSessionId, "getParentSessionId resolves branch parent session id");
|
|
883
|
+
assert(
|
|
884
|
+
shouldSilenceInheritedParentAttachClaimWarning({
|
|
885
|
+
currentTeamId: originalParentSessionId,
|
|
886
|
+
parentSessionId,
|
|
887
|
+
result: "missing",
|
|
888
|
+
}),
|
|
889
|
+
"silences missing inherited parent-team claim warnings",
|
|
890
|
+
);
|
|
891
|
+
assert(
|
|
892
|
+
!shouldSilenceInheritedParentAttachClaimWarning({
|
|
893
|
+
currentTeamId: originalParentSessionId,
|
|
894
|
+
parentSessionId,
|
|
895
|
+
result: "not_owner",
|
|
896
|
+
}),
|
|
897
|
+
"keeps non-owner inherited parent-team warnings visible",
|
|
898
|
+
);
|
|
899
|
+
assert(
|
|
900
|
+
!shouldSilenceInheritedParentAttachClaimWarning({
|
|
901
|
+
currentTeamId: child.getSessionId(),
|
|
902
|
+
parentSessionId,
|
|
903
|
+
result: "missing",
|
|
904
|
+
}),
|
|
905
|
+
"does not silence unrelated missing-claim warnings",
|
|
906
|
+
);
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
|
|
848
911
|
// ── 11. /team done (end-of-run cleanup) ──────────────────────────────
|
|
849
912
|
console.log("\n11. /team done (end-of-run)");
|
|
850
913
|
{
|