@sjawhar/pi-legion 10.7.2 → 10.8.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/legion.js
CHANGED
|
@@ -16171,7 +16171,7 @@ function ompCapabilityHost() {
|
|
|
16171
16171
|
// package.json
|
|
16172
16172
|
var package_default = {
|
|
16173
16173
|
name: "@sjawhar/pi-legion",
|
|
16174
|
-
version: "10.
|
|
16174
|
+
version: "10.8.1",
|
|
16175
16175
|
license: "Apache-2.0",
|
|
16176
16176
|
type: "module",
|
|
16177
16177
|
omp: {
|
|
@@ -16183,7 +16183,7 @@ var package_default = {
|
|
|
16183
16183
|
]
|
|
16184
16184
|
},
|
|
16185
16185
|
legion: {
|
|
16186
|
-
daemonApiVersion:
|
|
16186
|
+
daemonApiVersion: 30
|
|
16187
16187
|
},
|
|
16188
16188
|
repository: {
|
|
16189
16189
|
type: "git",
|
|
@@ -16461,8 +16461,11 @@ var LegionControllerSecretResponse = exports_external.strictObject({
|
|
|
16461
16461
|
designGate: exports_external.enum(["root-issues", "off"])
|
|
16462
16462
|
});
|
|
16463
16463
|
var LegionControllerCredentialResponse = exports_external.strictObject({
|
|
16464
|
-
|
|
16465
|
-
|
|
16464
|
+
owners: exports_external.record(nonEmptyString, exports_external.strictObject({
|
|
16465
|
+
hosts: nonEmptyString,
|
|
16466
|
+
config: nonEmptyString
|
|
16467
|
+
})),
|
|
16468
|
+
default: nonEmptyString,
|
|
16466
16469
|
app: exports_external.enum(["implement", "review"]),
|
|
16467
16470
|
expiresAt: timestamp
|
|
16468
16471
|
});
|
|
@@ -17125,16 +17128,18 @@ function stepPhaseStall(state, input) {
|
|
|
17125
17128
|
case "handoff-complete":
|
|
17126
17129
|
return { state: "closed" };
|
|
17127
17130
|
case "inbound-event":
|
|
17128
|
-
return { state: state === "quiet" ? "open" : state };
|
|
17129
|
-
case "settle":
|
|
17130
|
-
if (state !== "open")
|
|
17131
|
+
return { state: state === "quiet" || state === "text-call" ? "open" : state };
|
|
17132
|
+
case "settle": {
|
|
17133
|
+
if (state !== "open" && state !== "text-call")
|
|
17131
17134
|
return { state };
|
|
17132
17135
|
if (WAITING_REPLY.test(input.lastAssistantText))
|
|
17133
17136
|
return { state: "quiet" };
|
|
17134
|
-
|
|
17135
|
-
|
|
17136
|
-
|
|
17137
|
-
}
|
|
17137
|
+
const textCall = TOOL_CALL_SHAPED.test(input.lastAssistantText);
|
|
17138
|
+
if (state === "text-call") {
|
|
17139
|
+
return textCall ? { state: "quiet", followUp: TEXT_TOOL_CALL + FOLLOW_UP } : { state: "quiet" };
|
|
17140
|
+
}
|
|
17141
|
+
return textCall ? { state: "text-call", followUp: TEXT_TOOL_CALL + FOLLOW_UP } : { state: "quiet", followUp: FOLLOW_UP };
|
|
17142
|
+
}
|
|
17138
17143
|
}
|
|
17139
17144
|
}
|
|
17140
17145
|
function inboundKind(message) {
|
|
@@ -17157,7 +17162,7 @@ function assistantText(message) {
|
|
|
17157
17162
|
`);
|
|
17158
17163
|
}
|
|
17159
17164
|
function isPhaseStall(value) {
|
|
17160
|
-
return value === "closed" || value === "open" || value === "quiet";
|
|
17165
|
+
return value === "closed" || value === "open" || value === "text-call" || value === "quiet";
|
|
17161
17166
|
}
|
|
17162
17167
|
function restorePhaseStall(branch) {
|
|
17163
17168
|
for (let index = branch.length - 1;index >= 0; index -= 1) {
|
|
@@ -17295,7 +17300,7 @@ function createLegionTool(deps) {
|
|
|
17295
17300
|
return {
|
|
17296
17301
|
name: "legion",
|
|
17297
17302
|
label: "legion",
|
|
17298
|
-
description: "Perform the workflow operation the Legion daemon assigned this role. The daemon advances phases; this tool cannot spawn workers. " + "handoff_complete (phase workers and sub-architects; the daemon accepts a completion only from the role working the issue's current phase) " + "reports this phase complete: `summary` (two sentences for the architect, or the merger's READY packet), `verdict` pass|fail
|
|
17303
|
+
description: "Perform the workflow operation the Legion daemon assigned this role. The daemon advances phases; this tool cannot spawn workers. " + "handoff_complete (phase workers and sub-architects; the daemon accepts a completion only from the role working the issue's current phase) " + "reports this phase complete: `summary` (two sentences for the architect, or the merger's READY packet), `verdict` pass|fail from the tester alone " + "(the daemon refuses a verdict from any other role), `ready: true` for the merger's READY. A handoff is a committed file, `.legion/<issue>/<phase>.json`: the pushed commit " + "carrying it is found here, with the pane's jj, and reported, so write it, commit it and push the branch (`jj git push`) before calling; this call " + "refuses, posting nothing, a handoff still in the working copy, missing, not committed on this branch, carried by another pane's commit, or not yet " + "on `legion/<issue>@origin`, each naming the remedy. The daemon refuses HANDOFF_NOT_NEW (the commit is the one you reported for your previous " + "phase: write and commit this phase's handoff) and, for READY, each refusal the merger's role names; a refused completion changed " + "nothing, so fix what it names and complete again. An accepted READY whose `note` begins MANUAL_MERGE_REQUIRED: is one a person merges: arm nothing. " + "The controller's read_state returns the daemon's whole state and set_status moves an issue to todo, backlog or icebox. " + "What a later phase needs goes in your handoff; a question for another live role goes to its role topic with envoy_publish.",
|
|
17299
17304
|
defaultInactive: true,
|
|
17300
17305
|
parameters: toolSchema(pi),
|
|
17301
17306
|
execute: async (_id, parameters, _signal, _onUpdate, context) => {
|
|
@@ -16,13 +16,15 @@ The Legion extension registers this session with the daemon as the controller an
|
|
|
16
16
|
`legion-<project>-controller` during session startup. Do not handle a wake unless that startup
|
|
17
17
|
succeeded.
|
|
18
18
|
|
|
19
|
-
The session's `gh` acts as the review App's bot account (`gh api graphql -f query='{viewer{login}}'`
|
|
20
|
-
`
|
|
21
|
-
|
|
22
|
-
through
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
The session's `gh` acts as the review App's bot account (`gh api graphql -f query='{viewer{login}}'`
|
|
20
|
+
names it) from `LEGION_GH_OWNERS_DIR`, one read-only directory per GitHub owner of the project,
|
|
21
|
+
which Legion refreshes every minute (the daemon through the controller pod's role Secret, `legion
|
|
22
|
+
controller start` through its own loop). That `gh` is Legion's wrapper: it reads with the token of
|
|
23
|
+
the owner a command names (`-R owner/repo`, `repos/owner/repo` in `gh api`, a GitHub URL) and with
|
|
24
|
+
the first owner's (`GH_CONFIG_DIR`) otherwise, so name the repository. Against a daemon with no
|
|
25
|
+
GitHub App, `legion controller start` says so when it starts (`[legion] the daemon has no GitHub
|
|
26
|
+
App to act as; the controller's gh acts as nobody`), and `gh` acts as nobody. The controller reads
|
|
27
|
+
Dispatch and the daemon's state, and applies its controller
|
|
26
28
|
capability, through the `legion` tool alone: `op: "read_state"` returns the daemon's whole state
|
|
27
29
|
(`issues.<KEY>.phase`, `issues.<KEY>.holdReason`, `issues.<KEY>.architect`, `admission.cap`,
|
|
28
30
|
`admission.active`, `admission.waiting`, `capabilities[]`, `daemon.project`), and `op: "set_status"`
|
|
@@ -58,7 +60,7 @@ The command checks that `LEGION_PROJECT` is the daemon's project, registers this
|
|
|
58
60
|
daemon, and claims the Envoy role for it; the `legion` tool's controller operations then work in
|
|
59
61
|
this session, each `set_status` minting its grant in-process from the registration's secret. A
|
|
60
62
|
takeover session gets no token file from Legion: `legion controller start` and the pod write
|
|
61
|
-
`
|
|
63
|
+
`LEGION_GH_OWNERS_DIR`'s tokens, but a hand-started session's `gh` is what its environment gives it.
|
|
62
64
|
The takeover moves the role and the daemon's recorded session id to this session. Never pass a
|
|
63
65
|
secret as a command argument or copy it into a transcript. The Envoy
|
|
64
66
|
registration heartbeat keeps the role afterwards, so `/legion-claim-controller` is the manual
|
|
@@ -198,21 +198,21 @@ Your pane's `gh` and `git` already carry your role's GitHub identity; invoke Git
|
|
|
198
198
|
gh <gh args…>
|
|
199
199
|
```
|
|
200
200
|
|
|
201
|
-
How `gh` works in a worker pane. `
|
|
202
|
-
`hosts.yml
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
`
|
|
208
|
-
|
|
201
|
+
How `gh` works in a worker pane. `LEGION_GH_OWNERS_DIR` holds one read-only gh directory per
|
|
202
|
+
GitHub owner of the project (`hosts.yml`, an App installation token, and `config.yml`), which the
|
|
203
|
+
daemon rewrites in place so no token expires under you: your issue's owner's, which `GH_CONFIG_DIR`
|
|
204
|
+
names, holds your role's App token; every other owner's the same App's, read-only. Your `gh` picks
|
|
205
|
+
the directory of the owner a command names (`-R owner/repo`, `repos/owner/repo` in `gh api`, a
|
|
206
|
+
GitHub URL), your issue's owner's otherwise, so name the repository whenever it is not your
|
|
207
|
+
issue's; `git` picks by the remote URL's owner (`!legion git-credential`). `GH_TOKEN`,
|
|
208
|
+
`GITHUB_TOKEN` and `GH_HOST` are empty so nothing outranks the files. Never run `gh auth login`,
|
|
209
|
+
`gh auth switch`, `gh auth setup-git`, `gh config set` or `gh alias set`: there is no login state
|
|
210
|
+
to create. One rule nothing enforces: **Legion's issues live on Dispatch, never on
|
|
209
211
|
GitHub issues** — no `gh issue` write and no non-GET `gh api` call to an `/issues` path
|
|
210
212
|
(pull-request conversation comments live on that path too; edit them with `gh pr comment`); use
|
|
211
213
|
`dispatch message` or `dispatch comment` on your `LEGION_ISSUE`. The `legion` tool's own daemon
|
|
212
214
|
calls carry a credential of their own, minted in-process; `gh` and `git` never see it, and you
|
|
213
|
-
never `cat`, `echo`, copy, or `export` a token
|
|
214
|
-
background job in your pane inherits the same `GH_CONFIG_DIR` and so the same credential, for as
|
|
215
|
-
long as it runs.
|
|
215
|
+
never `cat`, `echo`, copy, or `export` a token; a `task` subagent or background job inherits them.
|
|
216
216
|
|
|
217
217
|
**Other credentials your pod may already carry.** Before reporting that a read is unreachable,
|
|
218
218
|
check for them rather than assuming none exist: `AGENT_SECRETS_URL` and `AGENT_SECRETS_KEY_DIR`
|
|
@@ -265,8 +265,8 @@ The implementer opens the pull request. After its implementation commit and veri
|
|
|
265
265
|
pushes the issue branch under this exact name with the one push procedure every role uses
|
|
266
266
|
(*Every role pushes its own commits*, below).
|
|
267
267
|
|
|
268
|
-
|
|
269
|
-
|
|
268
|
+
`jj git push` authenticates as your role's App through the clone's `!legion git-credential`, from
|
|
269
|
+
the file your `gh` reads for your issue's repository. Never handle a token.
|
|
270
270
|
|
|
271
271
|
Then open the pull request with `gh pr create`. The PR body **must** contain the
|
|
272
272
|
line `Dispatch: <KEY>` — the daemon's fallback link from a PR to its Dispatch issue when the
|
|
@@ -328,7 +328,7 @@ or `review`), with the ordinary `write` tool: a JSON object with `schemaVersion:
|
|
|
328
328
|
phase's own fields exactly as your role prompt spells them — the planner's `requiredSkills`,
|
|
329
329
|
`gapAnalysis`, `planReview` and `specDepartures` records; the implementer's `proof` array; the
|
|
330
330
|
tester's `implementerProof`, `failures` and, whenever it reports no failure, its own `proof`; the
|
|
331
|
-
reviewer's `
|
|
331
|
+
reviewer's `decision`, counts and `keyFindings`. Nothing stamps the first four for you. Each `proof`
|
|
332
332
|
entry, in either phase, is an object of six non-empty strings: `criterion` (the acceptance line it
|
|
333
333
|
proves), `surface`, `command`, `observed`, `headSha` (the commit it ran at) and `negativeControl`.
|
|
334
334
|
A handoff built from the one already on disk (a test handoff that accumulates review rounds) is
|
|
@@ -342,10 +342,10 @@ cd -- "$LEGION_WORKSPACE" && \
|
|
|
342
342
|
```
|
|
343
343
|
|
|
344
344
|
Then push (below) and report completion: call the `legion` tool with `op: "handoff_complete"` and
|
|
345
|
-
`summary` (two sentences for the architect; the tester adds `verdict: "pass"`
|
|
346
|
-
merger `ready: true`). **Push before you complete is a hard rule.**
|
|
347
|
-
your pane's jj, the newest commit on the issue branch that carries
|
|
348
|
-
and reports it to the daemon, and refuses — posting nothing — while:
|
|
345
|
+
`summary` (two sentences for the architect; the tester, and no other role, adds `verdict: "pass"`
|
|
346
|
+
or `"fail"`; the merger `ready: true`). **Push before you complete is a hard rule.**
|
|
347
|
+
`handoff_complete` finds, with your pane's jj, the newest commit on the issue branch that carries
|
|
348
|
+
`.legion/<KEY>/<phase>.json` and reports it to the daemon, and refuses — posting nothing — while:
|
|
349
349
|
|
|
350
350
|
- the file has a change still in the working copy: commit it, then complete again;
|
|
351
351
|
- the file is missing from the workspace: write it, then commit and push it;
|
|
@@ -429,8 +429,9 @@ Report completion to the architect: call the `legion` tool with `op: "handoff_co
|
|
|
429
429
|
(`handoff_complete`; `read_record`, your issue's record, which is what "re-read your issue
|
|
430
430
|
record" means; and `request_backward_move`), and nothing of yours runs `legion` from bash. The
|
|
431
431
|
tool call is what the extension's phase stall records, and a turn that ends with the phase still
|
|
432
|
-
open gets one reminder
|
|
433
|
-
|
|
432
|
+
open gets one reminder (two when the first is answered with the tool call written as text again);
|
|
433
|
+
do not complete again on a reminder when your first completion was accepted — it stands, and a
|
|
434
|
+
second is refused because the issue has already left your phase.
|
|
434
435
|
|
|
435
436
|
This publishes your phase's completion to the architect's role and clears the daemon's
|
|
436
437
|
record of this issue's active phase. Do not add pipeline labels, run a controller loop, or
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sjawhar/pi-legion",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.8.1",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"omp": {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
]
|
|
13
13
|
},
|
|
14
14
|
"legion": {
|
|
15
|
-
"daemonApiVersion":
|
|
15
|
+
"daemonApiVersion": 30
|
|
16
16
|
},
|
|
17
17
|
"repository": {
|
|
18
18
|
"type": "git",
|