@sjawhar/pi-legion 8.6.0 → 8.7.0

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/legion.js CHANGED
@@ -15309,7 +15309,7 @@ function onEnvoyRoleRegained(listener) {
15309
15309
  // package.json
15310
15310
  var package_default = {
15311
15311
  name: "@sjawhar/pi-legion",
15312
- version: "8.6.0",
15312
+ version: "8.7.0",
15313
15313
  license: "Apache-2.0",
15314
15314
  type: "module",
15315
15315
  omp: {
@@ -16495,6 +16495,42 @@ function createLegionTool(deps) {
16495
16495
  };
16496
16496
  }
16497
16497
 
16498
+ // src/workspace-recreated.ts
16499
+ var WORKSPACE_RECREATED_VARIABLE = "LEGION_WORKSPACE_RECREATED";
16500
+ var WORKSPACE_RECREATED_MESSAGE = "legion-workspace-recreated";
16501
+ function workspaceRecreatedNotice(environment, issue2) {
16502
+ if (environment[WORKSPACE_RECREATED_VARIABLE] !== "true")
16503
+ return;
16504
+ return {
16505
+ id: crypto.randomUUID(),
16506
+ content: `Your workspace was recreated since your last turn: it holds what was pushed to legion/${issue2} ` + "(main if nothing was), and anything you had not pushed is gone. Before you continue, check " + "the workspace against what you remember doing and re-read your last handoff."
16507
+ };
16508
+ }
16509
+ function workspaceRecreatedMessage(notice) {
16510
+ return {
16511
+ customType: WORKSPACE_RECREATED_MESSAGE,
16512
+ content: notice.content,
16513
+ display: true,
16514
+ details: { id: notice.id }
16515
+ };
16516
+ }
16517
+ function isNoticeCopy(value, kind, id) {
16518
+ if (typeof value !== "object" || value === null)
16519
+ return false;
16520
+ const typed = kind === "entry" ? "type" in value && value.type === "custom_message" : ("role" in value) && value.role === "custom";
16521
+ return typed && "customType" in value && value.customType === WORKSPACE_RECREATED_MESSAGE && "details" in value && typeof value.details === "object" && value.details !== null && "id" in value.details && value.details.id === id;
16522
+ }
16523
+ function branchHoldsWorkspaceRecreatedNotice(branch, id) {
16524
+ return branch.some((entry) => isNoticeCopy(entry, "entry", id));
16525
+ }
16526
+ function withoutRepeatedWorkspaceRecreatedNotice(messages, id) {
16527
+ const first = messages.findIndex((message) => isNoticeCopy(message, "message", id));
16528
+ if (first === -1)
16529
+ return;
16530
+ const kept = messages.filter((message, index) => index <= first || !isNoticeCopy(message, "message", id));
16531
+ return kept.length === messages.length ? undefined : kept;
16532
+ }
16533
+
16498
16534
  // extensions/legion.ts
16499
16535
  var exitProcess = (code) => process.exit(code);
16500
16536
  function setLegionBootstrapExitForTests(hook) {
@@ -16762,27 +16798,54 @@ function legionExtension(pi) {
16762
16798
  return;
16763
16799
  writeSessionTitle(sessionDirectory(process.env, sessionID), context.sessionManager.getSessionName?.() ?? title);
16764
16800
  };
16801
+ let recreatedNotice;
16765
16802
  pi.on("session_start", async (_event, context) => {
16766
16803
  if (await checkSubagentSession(context))
16767
16804
  return;
16768
16805
  await titleSession(context);
16769
16806
  phaseStall = restorePhaseStall(context.sessionManager.getBranch?.() ?? []);
16770
- const { kind } = classifySession(process.env);
16771
- if (kind === "not-legion")
16807
+ const session = classifySession(process.env);
16808
+ if (session.kind === "not-legion")
16772
16809
  return;
16773
16810
  const refusal = envoyPluginRefusal();
16774
16811
  if (refusal !== undefined) {
16775
16812
  logger3.error(refusal);
16776
16813
  exitProcess(1);
16777
16814
  }
16778
- if (kind === "controller") {
16815
+ if (session.kind === "controller") {
16779
16816
  await controllerSession.handleSessionStart(context);
16780
16817
  return;
16781
16818
  }
16819
+ recreatedNotice = workspaceRecreatedNotice(process.env, session.kind === "root-architect" ? session.tree : session.issue);
16820
+ if (recreatedNotice !== undefined) {
16821
+ pi.sendMessage(workspaceRecreatedMessage(recreatedNotice), {
16822
+ deliverAs: "steer",
16823
+ triggerTurn: false
16824
+ });
16825
+ }
16782
16826
  await claimSession.bootstrap(context);
16783
16827
  registerLegionTool();
16784
16828
  await activateLegionTool();
16785
16829
  });
16830
+ let resentNoticeId;
16831
+ pi.on("before_agent_start", async (_event, context) => {
16832
+ if (recreatedNotice === undefined)
16833
+ return;
16834
+ const branch = context.sessionManager.getBranch?.() ?? [];
16835
+ if (branchHoldsWorkspaceRecreatedNotice(branch, recreatedNotice.id))
16836
+ return;
16837
+ resentNoticeId = recreatedNotice.id;
16838
+ return { message: workspaceRecreatedMessage(recreatedNotice) };
16839
+ });
16840
+ pi.on("agent_start", async () => {
16841
+ recreatedNotice = undefined;
16842
+ });
16843
+ pi.on("context", async (event) => {
16844
+ if (resentNoticeId === undefined)
16845
+ return;
16846
+ const messages = withoutRepeatedWorkspaceRecreatedNotice(event.messages, resentNoticeId);
16847
+ return messages === undefined ? undefined : { messages };
16848
+ });
16786
16849
  const afterSessionChange = async (context) => {
16787
16850
  if (await checkSubagentSession(context))
16788
16851
  return;
@@ -142,9 +142,9 @@ predecessor phases already wrote. The durable copy lives in
142
142
  `$LEGION_WORKSPACE/.legion/<issue>/<phase>.json`. If a committed handoff conflicts with memory or a prior
143
143
  transcript, the committed file wins: it is the copy that survived.
144
144
 
145
- If your system prompt begins with `Your workspace was recreated…`, read
146
- `.legion/<issue>/workspace-recovered.json`, then your phase's committed handoff, and reconcile before any
147
- new work.
145
+ If your task, prompt, or a message since your last turn begins `Your workspace was recreated…`, read
146
+ your phase's committed handoff and any `.legion/<issue>/workspace-recovered.json`, and reconcile
147
+ before new work: anything unpushed is gone. That message stays in history; reconciled, it is done.
148
148
 
149
149
  ## jj Safety Rules
150
150
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjawhar/pi-legion",
3
- "version": "8.6.0",
3
+ "version": "8.7.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "omp": {