@sjawhar/pi-legion-envoy 5.4.2 → 5.4.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/dist/envoy.js +67 -11
- package/dist/legion.js +27 -6
- package/dist/skills/legion-controller/SKILL.md +21 -3
- package/package.json +2 -2
package/dist/envoy.js
CHANGED
|
@@ -30520,6 +30520,9 @@ var LEGION_NOTICE_TOPIC_PREFIX = "notifications.legion.";
|
|
|
30520
30520
|
function legionNoticeSubject(project, issue2) {
|
|
30521
30521
|
return `${LEGION_NOTICE_TOPIC_PREFIX}${project}.${issue2}`;
|
|
30522
30522
|
}
|
|
30523
|
+
function legionControllerNoticeSubject(project) {
|
|
30524
|
+
return legionNoticeSubject(project, "controller");
|
|
30525
|
+
}
|
|
30523
30526
|
var DISPATCH_TOPIC_PREFIX = "notifications.dispatch.";
|
|
30524
30527
|
var DISPATCH_ISSUE_TOPIC_PREFIX = `${DISPATCH_TOPIC_PREFIX}issue.`;
|
|
30525
30528
|
var DISPATCH_DOCUMENT_TOPIC_PREFIX = `${DISPATCH_TOPIC_PREFIX}document.`;
|
|
@@ -30549,6 +30552,12 @@ function isLegionRole(role) {
|
|
|
30549
30552
|
function isLegionProjectToken(project) {
|
|
30550
30553
|
return PROJECT_TOKEN.test(project);
|
|
30551
30554
|
}
|
|
30555
|
+
function legionProjectToken(value, field) {
|
|
30556
|
+
const project = value.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
30557
|
+
if (!project)
|
|
30558
|
+
throw new Error(`${field} must include at least one alphanumeric character`);
|
|
30559
|
+
return project;
|
|
30560
|
+
}
|
|
30552
30561
|
function assertLegionProjectToken(project) {
|
|
30553
30562
|
if (!isLegionProjectToken(project)) {
|
|
30554
30563
|
throw new Error(`Invalid Legion project token: ${project}`);
|
|
@@ -34916,12 +34925,12 @@ async function claimEnvoyRole(sessionID, role, context) {
|
|
|
34916
34925
|
throw new Error("Envoy has no bound instance for a role claim");
|
|
34917
34926
|
await instance.claim(sessionID, role, context);
|
|
34918
34927
|
}
|
|
34919
|
-
async function subscribeLegionNotice(sessionID, topic, context) {
|
|
34928
|
+
async function subscribeLegionNotice(sessionID, topic, context, whileHolding) {
|
|
34920
34929
|
const bridge = legionRoleClaimBridge();
|
|
34921
34930
|
const instance = bridge.instances.findLast((candidate) => candidate.sessionID() === sessionID) ?? bridge.instances.at(-1);
|
|
34922
34931
|
if (instance === undefined)
|
|
34923
34932
|
throw new Error("Envoy has no bound instance for a notice subscription");
|
|
34924
|
-
await instance.subscribe(sessionID, topic, context);
|
|
34933
|
+
await instance.subscribe(sessionID, topic, context, whileHolding);
|
|
34925
34934
|
}
|
|
34926
34935
|
function onEnvoyRoleRegained(listener) {
|
|
34927
34936
|
legionRoleClaimBridge().regained = listener;
|
|
@@ -35104,6 +35113,9 @@ function envoyExtension(pi) {
|
|
|
35104
35113
|
let recordedSessionKey;
|
|
35105
35114
|
let heartbeatRegistered = false;
|
|
35106
35115
|
let claimedRoleTopic;
|
|
35116
|
+
let claimedRoleSessionID;
|
|
35117
|
+
const roleNoticeSubjects = new Set;
|
|
35118
|
+
let roleEnds = 0;
|
|
35107
35119
|
let activeSessionContext;
|
|
35108
35120
|
const inbox = [];
|
|
35109
35121
|
let askAwareness = {
|
|
@@ -35302,6 +35314,7 @@ function envoyExtension(pi) {
|
|
|
35302
35314
|
return;
|
|
35303
35315
|
if (intentionallyClosed.delete(topic))
|
|
35304
35316
|
return;
|
|
35317
|
+
const snapshot = roleSnapshot(topic);
|
|
35305
35318
|
const retry = (delayMs) => {
|
|
35306
35319
|
awaitingRetry.add(topic);
|
|
35307
35320
|
setTimeout(() => {
|
|
@@ -35310,7 +35323,7 @@ function envoyExtension(pi) {
|
|
|
35310
35323
|
return;
|
|
35311
35324
|
if (intentionallyClosed.delete(topic))
|
|
35312
35325
|
return;
|
|
35313
|
-
|
|
35326
|
+
subscribeUnlessRoleEnds(topic, snapshot).catch(() => retry(NATS_RETRY_INTERVAL_MS));
|
|
35314
35327
|
}, delayMs);
|
|
35315
35328
|
};
|
|
35316
35329
|
retry(RESUBSCRIBE_DELAY_MS);
|
|
@@ -35328,10 +35341,42 @@ function envoyExtension(pi) {
|
|
|
35328
35341
|
}
|
|
35329
35342
|
return true;
|
|
35330
35343
|
};
|
|
35344
|
+
const endRole = () => {
|
|
35345
|
+
claimedRoleTopic = undefined;
|
|
35346
|
+
claimedRoleSessionID = undefined;
|
|
35347
|
+
roleEnds += 1;
|
|
35348
|
+
for (const subject2 of roleNoticeSubjects)
|
|
35349
|
+
closeIntentionally(subject2);
|
|
35350
|
+
roleNoticeSubjects.clear();
|
|
35351
|
+
};
|
|
35352
|
+
const endOutgoingRole = () => {
|
|
35353
|
+
if (claimedRoleSessionID !== sessionID)
|
|
35354
|
+
endRole();
|
|
35355
|
+
};
|
|
35356
|
+
const roleSnapshot = (topic) => ({
|
|
35357
|
+
roleBound: expandSubscriptionTopics([topic]).some((subject2) => roleNoticeSubjects.has(subject2)),
|
|
35358
|
+
endsBefore: roleEnds
|
|
35359
|
+
});
|
|
35360
|
+
const subscribeUnlessRoleEnds = async (topic, snapshot) => {
|
|
35361
|
+
const roleEnded = () => snapshot.roleBound && roleEnds !== snapshot.endsBefore;
|
|
35362
|
+
if (roleEnded())
|
|
35363
|
+
return false;
|
|
35364
|
+
await subscribe(topic);
|
|
35365
|
+
if (!roleEnded())
|
|
35366
|
+
return true;
|
|
35367
|
+
for (const subject2 of expandSubscriptionTopics([topic]))
|
|
35368
|
+
closeIntentionally(subject2);
|
|
35369
|
+
return false;
|
|
35370
|
+
};
|
|
35331
35371
|
const registerSession = () => client.subscribe({
|
|
35332
35372
|
sessionID,
|
|
35333
35373
|
directory: sessionDirectory,
|
|
35334
|
-
topics: [
|
|
35374
|
+
topics: [
|
|
35375
|
+
...new Set([
|
|
35376
|
+
agentSubject(sessionID),
|
|
35377
|
+
...[...subscriptions.keys()].filter((subject2) => !roleNoticeSubjects.has(subject2))
|
|
35378
|
+
])
|
|
35379
|
+
],
|
|
35335
35380
|
port: 0,
|
|
35336
35381
|
title: activeSessionContext?.sessionManager.getSessionName?.() ?? "",
|
|
35337
35382
|
capabilities: typeof pi.askEphemeral === "function" ? DELIVERY_CAPABILITIES : CAPABILITIES_WITHOUT_BTW,
|
|
@@ -35362,7 +35407,7 @@ function envoyExtension(pi) {
|
|
|
35362
35407
|
return;
|
|
35363
35408
|
}
|
|
35364
35409
|
if (!result.claimed) {
|
|
35365
|
-
|
|
35410
|
+
endRole();
|
|
35366
35411
|
logger.warn("envoy: role re-assertion refused; held by another live session", {
|
|
35367
35412
|
role,
|
|
35368
35413
|
sessionID: id,
|
|
@@ -35444,10 +35489,13 @@ function envoyExtension(pi) {
|
|
|
35444
35489
|
sessionID,
|
|
35445
35490
|
holder: result.holder
|
|
35446
35491
|
});
|
|
35447
|
-
|
|
35492
|
+
endRole();
|
|
35448
35493
|
return false;
|
|
35449
35494
|
}
|
|
35495
|
+
if (previousTopic !== undefined && previousTopic !== topic)
|
|
35496
|
+
endRole();
|
|
35450
35497
|
claimedRoleTopic = topic;
|
|
35498
|
+
claimedRoleSessionID = sessionID;
|
|
35451
35499
|
pi.appendEntry(ROLE_CLAIM_ENTRY, { role });
|
|
35452
35500
|
if (activeSessionContext !== undefined)
|
|
35453
35501
|
ensureHeartbeat(activeSessionContext);
|
|
@@ -35468,10 +35516,10 @@ function envoyExtension(pi) {
|
|
|
35468
35516
|
const roleSources = (previousSessionID, carryPreviousSessionRole) => previousSessionID === "" || previousSessionID === sessionID || !carryPreviousSessionRole ? [sessionID] : [sessionID, previousSessionID];
|
|
35469
35517
|
const reclaimHeldRoles = async (previousSessionID, branch, carryPreviousSessionRole) => {
|
|
35470
35518
|
if (!carryPreviousSessionRole)
|
|
35471
|
-
|
|
35519
|
+
endOutgoingRole();
|
|
35472
35520
|
const remembered = transcriptClaimedRole(branch);
|
|
35473
35521
|
if (remembered === null) {
|
|
35474
|
-
|
|
35522
|
+
endRole();
|
|
35475
35523
|
return;
|
|
35476
35524
|
}
|
|
35477
35525
|
let role = remembered ?? claimedRoleTopic?.slice(ROLE_TOPIC_PREFIX.length);
|
|
@@ -35498,7 +35546,7 @@ function envoyExtension(pi) {
|
|
|
35498
35546
|
const establishSessionNow = async (context, options = {}, previousSessionID = sessionID) => {
|
|
35499
35547
|
const previousTopic = previousSessionID === "" ? undefined : agentSubject(previousSessionID);
|
|
35500
35548
|
if (options.carryPreviousSessionRole === false)
|
|
35501
|
-
|
|
35549
|
+
endOutgoingRole();
|
|
35502
35550
|
restoreLocalSessionState(context);
|
|
35503
35551
|
const branch = context.sessionManager.getBranch?.() ?? [];
|
|
35504
35552
|
const resumed = branch.length > 0;
|
|
@@ -35542,14 +35590,22 @@ function envoyExtension(pi) {
|
|
|
35542
35590
|
await registerSession();
|
|
35543
35591
|
await setEnvoyRole(role);
|
|
35544
35592
|
};
|
|
35545
|
-
const subscribeNotice = async (targetSessionID, topic, callerContext) => {
|
|
35593
|
+
const subscribeNotice = async (targetSessionID, topic, callerContext, whileHolding) => {
|
|
35546
35594
|
const context = callerContext ?? activeSessionContext;
|
|
35547
35595
|
if (context === undefined || context.sessionManager.getSessionId() !== targetSessionID) {
|
|
35548
35596
|
throw new Error(`Envoy has no active session for Legion notice subscription: ${targetSessionID}`);
|
|
35549
35597
|
}
|
|
35550
35598
|
if (sessionID !== targetSessionID)
|
|
35551
35599
|
await establishSession(context);
|
|
35552
|
-
|
|
35600
|
+
if (whileHolding !== undefined) {
|
|
35601
|
+
if (claimedRoleTopic !== ROLE_TOPIC_PREFIX + whileHolding) {
|
|
35602
|
+
throw new Error(`Envoy session ${targetSessionID} does not hold role ${whileHolding} for a notice subscription`);
|
|
35603
|
+
}
|
|
35604
|
+
for (const subject2 of expandSubscriptionTopics([topic]))
|
|
35605
|
+
roleNoticeSubjects.add(subject2);
|
|
35606
|
+
}
|
|
35607
|
+
if (!await subscribeUnlessRoleEnds(topic, roleSnapshot(topic)))
|
|
35608
|
+
return;
|
|
35553
35609
|
await registerSession();
|
|
35554
35610
|
};
|
|
35555
35611
|
const claimInstance = {
|
package/dist/legion.js
CHANGED
|
@@ -16142,7 +16142,7 @@ import { logger } from "@oh-my-pi/pi-utils";
|
|
|
16142
16142
|
// package.json
|
|
16143
16143
|
var package_default = {
|
|
16144
16144
|
name: "@sjawhar/pi-legion-envoy",
|
|
16145
|
-
version: "5.4.
|
|
16145
|
+
version: "5.4.3",
|
|
16146
16146
|
type: "module",
|
|
16147
16147
|
omp: {
|
|
16148
16148
|
extensions: [
|
|
@@ -16155,7 +16155,7 @@ var package_default = {
|
|
|
16155
16155
|
},
|
|
16156
16156
|
legion: {
|
|
16157
16157
|
daemonApiVersion: 8,
|
|
16158
|
-
goDaemonApiVersion:
|
|
16158
|
+
goDaemonApiVersion: 7
|
|
16159
16159
|
},
|
|
16160
16160
|
repository: {
|
|
16161
16161
|
type: "git",
|
|
@@ -30593,6 +30593,9 @@ var LEGION_NOTICE_TOPIC_PREFIX = "notifications.legion.";
|
|
|
30593
30593
|
function legionNoticeSubject(project, issue2) {
|
|
30594
30594
|
return `${LEGION_NOTICE_TOPIC_PREFIX}${project}.${issue2}`;
|
|
30595
30595
|
}
|
|
30596
|
+
function legionControllerNoticeSubject(project) {
|
|
30597
|
+
return legionNoticeSubject(project, "controller");
|
|
30598
|
+
}
|
|
30596
30599
|
var DISPATCH_TOPIC_PREFIX = "notifications.dispatch.";
|
|
30597
30600
|
var DISPATCH_ISSUE_TOPIC_PREFIX = `${DISPATCH_TOPIC_PREFIX}issue.`;
|
|
30598
30601
|
var DISPATCH_DOCUMENT_TOPIC_PREFIX = `${DISPATCH_TOPIC_PREFIX}document.`;
|
|
@@ -30622,6 +30625,12 @@ function isLegionRole(role) {
|
|
|
30622
30625
|
function isLegionProjectToken(project) {
|
|
30623
30626
|
return PROJECT_TOKEN.test(project);
|
|
30624
30627
|
}
|
|
30628
|
+
function legionProjectToken(value, field) {
|
|
30629
|
+
const project = value.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
30630
|
+
if (!project)
|
|
30631
|
+
throw new Error(`${field} must include at least one alphanumeric character`);
|
|
30632
|
+
return project;
|
|
30633
|
+
}
|
|
30625
30634
|
function assertLegionProjectToken(project) {
|
|
30626
30635
|
if (!isLegionProjectToken(project)) {
|
|
30627
30636
|
throw new Error(`Invalid Legion project token: ${project}`);
|
|
@@ -31234,12 +31243,12 @@ async function claimEnvoyRole(sessionID, role, context) {
|
|
|
31234
31243
|
throw new Error("Envoy has no bound instance for a role claim");
|
|
31235
31244
|
await instance.claim(sessionID, role, context);
|
|
31236
31245
|
}
|
|
31237
|
-
async function subscribeLegionNotice(sessionID, topic, context) {
|
|
31246
|
+
async function subscribeLegionNotice(sessionID, topic, context, whileHolding) {
|
|
31238
31247
|
const bridge = legionRoleClaimBridge();
|
|
31239
31248
|
const instance = bridge.instances.findLast((candidate) => candidate.sessionID() === sessionID) ?? bridge.instances.at(-1);
|
|
31240
31249
|
if (instance === undefined)
|
|
31241
31250
|
throw new Error("Envoy has no bound instance for a notice subscription");
|
|
31242
|
-
await instance.subscribe(sessionID, topic, context);
|
|
31251
|
+
await instance.subscribe(sessionID, topic, context, whileHolding);
|
|
31243
31252
|
}
|
|
31244
31253
|
function onEnvoyRoleRegained(listener) {
|
|
31245
31254
|
legionRoleClaimBridge().regained = listener;
|
|
@@ -31429,6 +31438,7 @@ var legionGoIssue = exports_external.strictObject({
|
|
|
31429
31438
|
generation: exports_external.number().int().nonnegative(),
|
|
31430
31439
|
phase: exports_external.enum(LEGION_GO_PHASES),
|
|
31431
31440
|
status: nonEmptyString2,
|
|
31441
|
+
holdReason: exports_external.literal("escalated").optional(),
|
|
31432
31442
|
architect: legionGoClaimView.optional(),
|
|
31433
31443
|
workers: exports_external.partialRecord(exports_external.enum(LEGION_ROLES), legionGoPhaseView),
|
|
31434
31444
|
pullRequest: legionGoPullRequestView.optional(),
|
|
@@ -31765,8 +31775,14 @@ async function callGoReadyWithRetry(label, call) {
|
|
|
31765
31775
|
function goControllerDaemon(daemon, transcript) {
|
|
31766
31776
|
return {
|
|
31767
31777
|
claim: async ({ sessionID, capability, context }) => {
|
|
31768
|
-
const
|
|
31778
|
+
const project = requiredEnvironment(process.env, "LEGION_PROJECT");
|
|
31769
31779
|
const client = daemon();
|
|
31780
|
+
const { daemon: served } = await client.state();
|
|
31781
|
+
const servedRole = controllerToken(legionProjectToken(served.project, "the daemon's project"));
|
|
31782
|
+
if (controllerToken(project) !== servedRole) {
|
|
31783
|
+
throw new Error(`LEGION_PROJECT ${project} names controller role ${controllerToken(project)}, but the daemon at ${requiredEnvironment(process.env, "LEGION_DAEMON_URL")} serves project ${served.project}, whose controller role is ${servedRole}`);
|
|
31784
|
+
}
|
|
31785
|
+
const { sessionFile, agentId } = await transcript(context);
|
|
31770
31786
|
const registration = await client.registerController({
|
|
31771
31787
|
bootToken: capability,
|
|
31772
31788
|
sessionId: sessionID,
|
|
@@ -31779,7 +31795,12 @@ function goControllerDaemon(daemon, transcript) {
|
|
|
31779
31795
|
}
|
|
31780
31796
|
throw error48;
|
|
31781
31797
|
});
|
|
31782
|
-
|
|
31798
|
+
if (controllerToken(project) !== registration.claimToken) {
|
|
31799
|
+
throw new Error(`LEGION_PROJECT ${project} names controller role ${controllerToken(project)}, but the daemon registered this controller as ${registration.claimToken}`);
|
|
31800
|
+
}
|
|
31801
|
+
const envoyContext = "setInterval" in context ? context : undefined;
|
|
31802
|
+
await claimEnvoyRole(sessionID, registration.claimToken, envoyContext);
|
|
31803
|
+
await subscribeLegionNotice(sessionID, legionControllerNoticeSubject(project), envoyContext, registration.claimToken);
|
|
31783
31804
|
return () => client.controllerGrant({ sessionId: sessionID, secret: registration.secret });
|
|
31784
31805
|
}
|
|
31785
31806
|
};
|
|
@@ -71,9 +71,11 @@ launcher, and started you with `LEGION_CONTROLLER=1` and the same environment a
|
|
|
71
71
|
carries, so nothing changes in how you handle wakes. Under the TypeScript daemon the extension
|
|
72
72
|
claims the role and calls `/controller/ready` exactly as under tmux; under the Go daemon
|
|
73
73
|
(`LEGION_DAEMON_API=go` in your environment) it registers on `/legion/v1/claims/register` with the
|
|
74
|
-
secret,
|
|
75
|
-
|
|
76
|
-
|
|
74
|
+
secret, claims the role, then subscribes to `notifications.legion.<project>.controller`, where the
|
|
75
|
+
Go daemon publishes the two Go rows of the wake routing table. The daemon records you as
|
|
76
|
+
`controllerLocator: {runtime, external: true, sessionId, registeredAt}`, `runtime` being the
|
|
77
|
+
daemon's own (`kubernetes`, or `tmux` under the Go daemon). The TypeScript daemon reads your
|
|
78
|
+
liveness from the Envoy role registry (the holder of
|
|
77
79
|
`legion-<project>-controller` and its `last_seen`), not from a pane: keep the session running.
|
|
78
80
|
Exiting it leaves the project without a controller until the operator runs the command again —
|
|
79
81
|
the TypeScript daemon logs `controller not registered; run legion controller start` once per
|
|
@@ -81,6 +83,20 @@ boot-timeout interval and launches nothing itself. `legion state` and `legion st
|
|
|
81
83
|
<status>` work here over `LEGION_DAEMON_URL`. A second `legion controller start` replaces you: it
|
|
82
84
|
mints a new secret, so your grants stop working and the role moves to the new session.
|
|
83
85
|
|
|
86
|
+
### What happened before you started (Go daemon)
|
|
87
|
+
|
|
88
|
+
The Go daemon's controller topic is a wake for a session that is running when it is published.
|
|
89
|
+
Envoy hands an Oh My Pi session no retained copy of a notice published before it subscribed, so a
|
|
90
|
+
hold or a tree architect's failed claim from while no controller ran never arrives as a wake. At
|
|
91
|
+
every start, before anything else, read `legion state --json` and handle each issue whose
|
|
92
|
+
`issues.<KEY>.phase` is `held` (its `issues.<KEY>.holdReason` is `escalated` when its architect
|
|
93
|
+
sent it to you, and absent while the architect is still deciding or while its tree lingers or is
|
|
94
|
+
closed, where the hold waits for the tree's re-admission and needs nothing from you), and each
|
|
95
|
+
tree root whose `issues.<KEY>.architect.state` is `failed` and whose `issues.<KEY>.phase` is not
|
|
96
|
+
`done`, exactly as the matching wake below. A parked tree (root phase `done`: it lingers or is
|
|
97
|
+
closed) needs nothing from you: a failed architect ignores the park and reads `failed` until the
|
|
98
|
+
tree closes. The issue record is the truth; the topic is the wake.
|
|
99
|
+
|
|
84
100
|
## Deployment instructions
|
|
85
101
|
|
|
86
102
|
Deployment instructions, when present, are the operator's standing rules for this repository —
|
|
@@ -116,6 +132,8 @@ quoted here.
|
|
|
116
132
|
| Mention | Slack/GitHub PR @mention text | Answer, or route to the owning issue's architect role |
|
|
117
133
|
| READY packet seen on a Dispatch issue (via issue subscription) | READY line + gate facts | No action: a human merges; the merger has already notified the queue role if the project has one |
|
|
118
134
|
| `worker-recovered` (role `architect`) from the daemon | issue, fromRef | A root architect's tree volume was lost; it restarted as a new session. Verify the tree is active in `legion state` and that the architect posts its next step on the issue within one resync interval; otherwise treat it as an anomaly. |
|
|
135
|
+
| `held on <KEY>` from the Go daemon (payload `{kind: "held", phase, role?, reason?}`) | the held issue, the phase it left, and the role whose claim failed, or `reason: "escalated"` | Verify the hold in `legion state` (the issue's phase is `held`). Without `reason`, a phase worker's launches or prompts ran out and the tree's architect decides retry or escalate: no action. With `reason: "escalated"` (on the record, `issues.<KEY>.holdReason` is `escalated`), the architect sent it to you: handle it as an architect escalation below. Parking the tree is `legion status <root> backlog`; setting the root back to `todo` later re-admits it as a new generation, which starts again from its architect |
|
|
136
|
+
| `worker-died on <KEY>` from the Go daemon with `role: "architect"` | the tree root whose architect's claim failed, and the phase the root was in | The tree's architect ran out of launches or prompts and the daemon relaunches nothing; every other notice of the tree goes to that architect, so nobody inside the tree can act. Verify in `legion state` (`issues.<KEY>.architect.state` is `failed`); if the root's phase is `done`, the tree is already parked: no action. Otherwise re-admit the tree (`legion status <root> backlog`, then `todo`: a new generation, whose architect starts again with fresh budgets) or leave it parked and say why on the issue |
|
|
119
137
|
| Closed-tree activity (comment, review, CI on a closed tree) | issue, root, event summary | Read the artifact; if work should resume, `legion status <root> todo`; otherwise no action — the event is not held or redelivered |
|
|
120
138
|
| Direct user message | — | Always first |
|
|
121
139
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sjawhar/pi-legion-envoy",
|
|
3
|
-
"version": "5.4.
|
|
3
|
+
"version": "5.4.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"omp": {
|
|
6
6
|
"extensions": [
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
},
|
|
14
14
|
"legion": {
|
|
15
15
|
"daemonApiVersion": 8,
|
|
16
|
-
"goDaemonApiVersion":
|
|
16
|
+
"goDaemonApiVersion": 7
|
|
17
17
|
},
|
|
18
18
|
"repository": {
|
|
19
19
|
"type": "git",
|