@sjawhar/pi-legion-envoy 7.6.5 → 7.7.1
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 +32 -2
- package/dist/legion.js +34 -4
- package/dist/skills/dispatch-first/SKILL.md +4 -0
- package/dist/skills/legion-architect/SKILL.md +4 -2
- package/dist/skills/legion-retro/SKILL.md +3 -1
- package/dist/skills/legion-worker/SKILL.md +5 -3
- package/dist/skills/legion-worker/references/merge-gate.md +7 -5
- package/package.json +1 -1
package/dist/envoy.js
CHANGED
|
@@ -32756,6 +32756,32 @@ function renderAdvice(tool, key, advice, opts) {
|
|
|
32756
32756
|
}
|
|
32757
32757
|
return lines;
|
|
32758
32758
|
}
|
|
32759
|
+
function renderSuggestions(suggestions, configUrl) {
|
|
32760
|
+
if (suggestions === undefined)
|
|
32761
|
+
return [];
|
|
32762
|
+
if (suggestions.missing !== undefined) {
|
|
32763
|
+
return [`Related-item search was skipped: ${suggestions.missing}.`];
|
|
32764
|
+
}
|
|
32765
|
+
const lines = [];
|
|
32766
|
+
if (suggestions.related.length > 0) {
|
|
32767
|
+
lines.push("Possibly related, found by search:");
|
|
32768
|
+
for (const item of suggestions.related) {
|
|
32769
|
+
lines.push(`- ${suggestionLabel(item)} \u2192 ${new URL(item.href, configUrl).toString()}`);
|
|
32770
|
+
}
|
|
32771
|
+
}
|
|
32772
|
+
if (suggestions.decision !== undefined) {
|
|
32773
|
+
const item = suggestions.decision;
|
|
32774
|
+
const when = item.answered_at === undefined ? "" : ` on ${item.answered_at}`;
|
|
32775
|
+
lines.push(`A past decision may already answer this: ${suggestionLabel(item)}, answered by ${item.answered_by}${when} \u2192 ${new URL(item.href, configUrl).toString()}`);
|
|
32776
|
+
}
|
|
32777
|
+
return lines;
|
|
32778
|
+
}
|
|
32779
|
+
function suggestionLabel(item) {
|
|
32780
|
+
if (item.owner.kind === "issue") {
|
|
32781
|
+
return `${item.owner.key} [${item.owner.status}] ${item.owner.title}`;
|
|
32782
|
+
}
|
|
32783
|
+
return `${item.owner.name} (${item.owner.project}/${item.owner.slug})`;
|
|
32784
|
+
}
|
|
32759
32785
|
function documentResultDetails(artifact) {
|
|
32760
32786
|
return {
|
|
32761
32787
|
project: artifact.project,
|
|
@@ -33936,7 +33962,8 @@ async function executeDispatchTool(input) {
|
|
|
33936
33962
|
...renderAdvice(input.tool, created.key, created.advice, {
|
|
33937
33963
|
isPrimarySpec: spec !== undefined
|
|
33938
33964
|
}),
|
|
33939
|
-
...componentGuidance === undefined ? [] : [componentGuidance]
|
|
33965
|
+
...componentGuidance === undefined ? [] : [componentGuidance],
|
|
33966
|
+
...renderSuggestions(created.advice?.suggestions, configUrl)
|
|
33940
33967
|
];
|
|
33941
33968
|
return {
|
|
33942
33969
|
text: [
|
|
@@ -34216,7 +34243,10 @@ async function executeDispatchTool(input) {
|
|
|
34216
34243
|
};
|
|
34217
34244
|
const ask = resolved?.owner.kind === "project" ? await client.artifactAsk(resolved.artifact.id, askInput) : await client.ask(issue2(), askInput);
|
|
34218
34245
|
const askOwner = ask.issue_key !== null ? issueTopic(ask.issue_key) : resolved === undefined ? issueTopic(issue2()) : documentTopic(resolved.artifact);
|
|
34219
|
-
const adviceLines =
|
|
34246
|
+
const adviceLines = [
|
|
34247
|
+
...renderAdvice(input.tool, askOwner.label, ask.advice, {}),
|
|
34248
|
+
...renderSuggestions(ask.advice?.suggestions, configUrl)
|
|
34249
|
+
];
|
|
34220
34250
|
return {
|
|
34221
34251
|
text: [
|
|
34222
34252
|
`Asked ${ask.id} on ${askOwner.label} (urgency ${ask.urgency}): ${ask.question}
|
package/dist/legion.js
CHANGED
|
@@ -15541,6 +15541,32 @@ function renderAdvice(tool, key, advice, opts) {
|
|
|
15541
15541
|
}
|
|
15542
15542
|
return lines;
|
|
15543
15543
|
}
|
|
15544
|
+
function renderSuggestions(suggestions, configUrl) {
|
|
15545
|
+
if (suggestions === undefined)
|
|
15546
|
+
return [];
|
|
15547
|
+
if (suggestions.missing !== undefined) {
|
|
15548
|
+
return [`Related-item search was skipped: ${suggestions.missing}.`];
|
|
15549
|
+
}
|
|
15550
|
+
const lines = [];
|
|
15551
|
+
if (suggestions.related.length > 0) {
|
|
15552
|
+
lines.push("Possibly related, found by search:");
|
|
15553
|
+
for (const item of suggestions.related) {
|
|
15554
|
+
lines.push(`- ${suggestionLabel(item)} \u2192 ${new URL(item.href, configUrl).toString()}`);
|
|
15555
|
+
}
|
|
15556
|
+
}
|
|
15557
|
+
if (suggestions.decision !== undefined) {
|
|
15558
|
+
const item = suggestions.decision;
|
|
15559
|
+
const when = item.answered_at === undefined ? "" : ` on ${item.answered_at}`;
|
|
15560
|
+
lines.push(`A past decision may already answer this: ${suggestionLabel(item)}, answered by ${item.answered_by}${when} \u2192 ${new URL(item.href, configUrl).toString()}`);
|
|
15561
|
+
}
|
|
15562
|
+
return lines;
|
|
15563
|
+
}
|
|
15564
|
+
function suggestionLabel(item) {
|
|
15565
|
+
if (item.owner.kind === "issue") {
|
|
15566
|
+
return `${item.owner.key} [${item.owner.status}] ${item.owner.title}`;
|
|
15567
|
+
}
|
|
15568
|
+
return `${item.owner.name} (${item.owner.project}/${item.owner.slug})`;
|
|
15569
|
+
}
|
|
15544
15570
|
function documentResultDetails(artifact) {
|
|
15545
15571
|
return {
|
|
15546
15572
|
project: artifact.project,
|
|
@@ -16721,7 +16747,8 @@ async function executeDispatchTool(input) {
|
|
|
16721
16747
|
...renderAdvice(input.tool, created.key, created.advice, {
|
|
16722
16748
|
isPrimarySpec: spec !== undefined
|
|
16723
16749
|
}),
|
|
16724
|
-
...componentGuidance === undefined ? [] : [componentGuidance]
|
|
16750
|
+
...componentGuidance === undefined ? [] : [componentGuidance],
|
|
16751
|
+
...renderSuggestions(created.advice?.suggestions, configUrl)
|
|
16725
16752
|
];
|
|
16726
16753
|
return {
|
|
16727
16754
|
text: [
|
|
@@ -17001,7 +17028,10 @@ async function executeDispatchTool(input) {
|
|
|
17001
17028
|
};
|
|
17002
17029
|
const ask = resolved?.owner.kind === "project" ? await client.artifactAsk(resolved.artifact.id, askInput) : await client.ask(issue2(), askInput);
|
|
17003
17030
|
const askOwner = ask.issue_key !== null ? issueTopic(ask.issue_key) : resolved === undefined ? issueTopic(issue2()) : documentTopic(resolved.artifact);
|
|
17004
|
-
const adviceLines =
|
|
17031
|
+
const adviceLines = [
|
|
17032
|
+
...renderAdvice(input.tool, askOwner.label, ask.advice, {}),
|
|
17033
|
+
...renderSuggestions(ask.advice?.suggestions, configUrl)
|
|
17034
|
+
];
|
|
17005
17035
|
return {
|
|
17006
17036
|
text: [
|
|
17007
17037
|
`Asked ${ask.id} on ${askOwner.label} (urgency ${ask.urgency}): ${ask.question}
|
|
@@ -17524,7 +17554,7 @@ function endInjectedUserTurns(sessionID) {
|
|
|
17524
17554
|
// package.json
|
|
17525
17555
|
var package_default = {
|
|
17526
17556
|
name: "@sjawhar/pi-legion-envoy",
|
|
17527
|
-
version: "7.
|
|
17557
|
+
version: "7.7.1",
|
|
17528
17558
|
license: "Apache-2.0",
|
|
17529
17559
|
type: "module",
|
|
17530
17560
|
omp: {
|
|
@@ -18460,7 +18490,7 @@ function handoffSchemaFields(z2) {
|
|
|
18460
18490
|
ready: z2.boolean().optional()
|
|
18461
18491
|
};
|
|
18462
18492
|
}
|
|
18463
|
-
var HANDOFF_DESCRIPTION = "Handoff actions (phase workers; the daemon accepts a completion only from the role working " + "the issue's current phase, never from an architect): handoff_write writes this phase's handoff " + "(`phase`, and `data`: the phase-specific fields as a JSON object, never the schemaVersion, " + "phase and
|
|
18493
|
+
var HANDOFF_DESCRIPTION = "Handoff actions (phase workers; the daemon accepts a completion only from the role working " + "the issue's current phase, never from an architect): handoff_write writes this phase's handoff " + "(`phase`, and `data`: the phase-specific fields as a JSON object, never the schemaVersion, " + "phase, completed and issue the command writes itself) to `.legion/<phase>.json` in " + "the issue workspace; handoff_read returns the handoffs (every phase, or `phase`); " + "handoff_complete reports this phase complete to the daemon (`summary`: two sentences for the " + "architect, or the merger's READY packet; `verdict` pass|fail when your role's instructions " + "require one; `ready: true` for the merger's READY; no `phase` is needed, and one other than " + "your own is refused). Each " + "returns the command's output; a failed action changed nothing. What a later phase needs goes " + "in your handoff; a question for another live role goes to its role topic with envoy_publish.";
|
|
18464
18494
|
function rootArchitectHandoffRefusal(operation) {
|
|
18465
18495
|
return `${operation} is not available to a root architect session; a root architect reads handoffs with \`legion handoff read [--phase <phase>]\` from bash`;
|
|
18466
18496
|
}
|
|
@@ -27,6 +27,10 @@ parent's children and the issue's `Components:` line show where the rest of that
|
|
|
27
27
|
|
|
28
28
|
## What to do with what you find
|
|
29
29
|
|
|
30
|
+
Filing an issue or opening an ask also searches for you: the result's `advice.suggestions` names
|
|
31
|
+
likely duplicates or a decision that may already settle it. Treat a hit there the same as one you
|
|
32
|
+
found yourself.
|
|
33
|
+
|
|
30
34
|
- **The work is already tracked: extend that issue.** Put the finding on it (a comment, a message,
|
|
31
35
|
or an edit to its spec) instead of filing another. File a new issue only when no hit covers the
|
|
32
36
|
work, and cite the nearest one you ruled out (`dispatch://KEY`).
|
|
@@ -250,8 +250,10 @@ The daemon keeps this order from its fixed table; you start none of its steps:
|
|
|
250
250
|
|
|
251
251
|
1. tester green and review cycles complete;
|
|
252
252
|
2. on a clean review, the reviewer approves the head by SHA, and the daemon moves the issue to
|
|
253
|
-
`retro`. No role pushes a `.legion/` deletion: the approved head still carries `.legion
|
|
254
|
-
|
|
253
|
+
`retro`. No role pushes a `.legion/` deletion: the approved head still carries `.legion/`. The
|
|
254
|
+
daemon strips whatever `.legion/` main still carries from the next issue's branch before any of
|
|
255
|
+
its roles start, so that tree's own merge carries the removal onto the default branch; no
|
|
256
|
+
operator sweep follows;
|
|
255
257
|
3. retro commits its learnings under `docs/solutions/` on top of the approved head; that
|
|
256
258
|
commit does not void the approval and never returns the tree to the tester or reviewer;
|
|
257
259
|
4. the merger verifies the current head is the reviewer-approved head plus only commits that
|
|
@@ -19,7 +19,9 @@ retrospective's durable output.
|
|
|
19
19
|
|
|
20
20
|
1. Tester green and all code-review cycles finish.
|
|
21
21
|
2. The reviewer approves the head. It still carries `.legion/`: no role removes it before the
|
|
22
|
-
merge
|
|
22
|
+
merge. The daemon strips whatever `.legion/` main still carries from the next issue's branch
|
|
23
|
+
before any of its roles start, so that tree's own merge carries the removal onto the default
|
|
24
|
+
branch; no operator sweep follows.
|
|
23
25
|
3. Run this retro: commit durable learnings to `docs/solutions/` and post the retro message on
|
|
24
26
|
the Dispatch issue.
|
|
25
27
|
Retro writes **no `.legion` file**, so it never changes the approved head's handoffs.
|
|
@@ -397,9 +397,11 @@ pushes nothing.
|
|
|
397
397
|
|
|
398
398
|
Do not report phase completion until the write, existence check, handoff commit, and push
|
|
399
399
|
succeed. This is the committed copy the next phase reads after revival. No phase removes
|
|
400
|
-
`.legion/`: the reviewer approves a head that carries it
|
|
401
|
-
|
|
402
|
-
|
|
400
|
+
`.legion/`: the reviewer approves a head that carries it. The daemon strips any `.legion/` still on
|
|
401
|
+
main from the next issue's branch before any of its roles start (dispatch://LEGION-565), so that
|
|
402
|
+
tree's own merge carries the removal onto the default branch; no operator sweep follows. Retro and
|
|
403
|
+
the post-merge production check write no `.legion/<phase>.json`, commit no handoff, and report with
|
|
404
|
+
`handoff_complete` alone (below).
|
|
403
405
|
|
|
404
406
|
## Completion: report to the architect, then stay
|
|
405
407
|
|
|
@@ -6,11 +6,13 @@ path it cites is in sjawhar/legion.
|
|
|
6
6
|
|
|
7
7
|
The order, in full: the tester's evidence green → the reviewer's approval of the head →
|
|
8
8
|
retro → the merger's READY → the human merge → the implementer's production check. No role
|
|
9
|
-
removes `.legion/` before the merge: the approved head carries it
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
removes `.legion/` before the merge: the approved head carries it. The daemon strips whatever
|
|
10
|
+
`.legion/` main still carries from the next issue's branch before any of its roles start
|
|
11
|
+
(dispatch://LEGION-565), so that tree's own merge carries the removal onto the default branch; no
|
|
12
|
+
operator sweep follows. After the approval, only retro's `docs/solutions/` commit leaves it
|
|
13
|
+
standing on its own (*Retro*, below). A conflict-forced merge goes back to the reviewer for a
|
|
14
|
+
confirmation or a new round, as the fingerprint decides (*The reviewer*, below, and
|
|
15
|
+
`skill://legion-worker/references/conflicts-and-rewrites.md`), and any other change voids it.
|
|
14
16
|
|
|
15
17
|
## The reviewer
|
|
16
18
|
|