@sjawhar/opencode-legion-envoy 4.1.1 → 5.0.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/src/server.js
CHANGED
|
@@ -14394,168 +14394,6 @@ var EnvelopeSchema = exports_external.object({
|
|
|
14394
14394
|
});
|
|
14395
14395
|
var MINTED_DEDUPE_KEY_PATTERN = "^(?:envoy\\.role\\.forward\\.)?(?:publish|agent\\.[^.]+)\\.(?:[0-9a-f]{32}|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$";
|
|
14396
14396
|
var mintedDedupeKey = new RegExp(MINTED_DEDUPE_KEY_PATTERN);
|
|
14397
|
-
// ../contracts/src/handoff-schema.ts
|
|
14398
|
-
var HANDOFF_SCHEMA_VERSION = 1;
|
|
14399
|
-
var HANDOFF_PHASES = ["architect", "plan", "implement", "test", "review"];
|
|
14400
|
-
var PLAN_REVIEW_MAX_ROUNDS = 3;
|
|
14401
|
-
var PLAN_REVIEW_VERDICTS = ["approved", "rejected", "failed"];
|
|
14402
|
-
var isoTimestamp = exports_external.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/);
|
|
14403
|
-
var handoffPhase = exports_external.enum(HANDOFF_PHASES);
|
|
14404
|
-
var nonEmpty = exports_external.string().trim().min(1);
|
|
14405
|
-
var proofSchema = exports_external.object({
|
|
14406
|
-
criterion: nonEmpty,
|
|
14407
|
-
surface: nonEmpty,
|
|
14408
|
-
command: nonEmpty,
|
|
14409
|
-
observed: nonEmpty,
|
|
14410
|
-
headSha: nonEmpty,
|
|
14411
|
-
negativeControl: nonEmpty
|
|
14412
|
-
}).passthrough();
|
|
14413
|
-
var routingHintsSchema = exports_external.object({
|
|
14414
|
-
skipArchitect: exports_external.boolean().optional(),
|
|
14415
|
-
complexity: exports_external.enum(["trivial", "small", "medium", "large"]).optional(),
|
|
14416
|
-
estimatedImplementers: exports_external.number().optional()
|
|
14417
|
-
}).passthrough().optional();
|
|
14418
|
-
var baseHandoffSchema = exports_external.object({
|
|
14419
|
-
schemaVersion: exports_external.literal(HANDOFF_SCHEMA_VERSION),
|
|
14420
|
-
phase: handoffPhase,
|
|
14421
|
-
completed: isoTimestamp,
|
|
14422
|
-
learningsInjected: exports_external.array(exports_external.string()).optional(),
|
|
14423
|
-
learningsHelpful: exports_external.array(exports_external.string()).optional()
|
|
14424
|
-
}).passthrough();
|
|
14425
|
-
var architectSchema = baseHandoffSchema.extend({
|
|
14426
|
-
phase: exports_external.literal("architect"),
|
|
14427
|
-
scope: exports_external.enum(["trivial", "small", "medium", "large"]).optional(),
|
|
14428
|
-
components: exports_external.array(exports_external.string()).optional(),
|
|
14429
|
-
subIssues: exports_external.array(exports_external.string()).optional(),
|
|
14430
|
-
routingHints: routingHintsSchema,
|
|
14431
|
-
concerns: exports_external.array(exports_external.string()).optional()
|
|
14432
|
-
});
|
|
14433
|
-
var requiredSkillsSchema = exports_external.object({
|
|
14434
|
-
implement: exports_external.array(exports_external.string()).optional(),
|
|
14435
|
-
test: exports_external.array(exports_external.string()).optional(),
|
|
14436
|
-
review: exports_external.array(exports_external.string()).optional()
|
|
14437
|
-
}).passthrough().optional();
|
|
14438
|
-
var gapAnalysisSchema = exports_external.object({
|
|
14439
|
-
findings: exports_external.array(exports_external.object({ finding: exports_external.string(), answer: exports_external.string() }).passthrough()).optional(),
|
|
14440
|
-
error: exports_external.string().optional()
|
|
14441
|
-
}).passthrough().optional();
|
|
14442
|
-
var planReviewSchema = exports_external.object({
|
|
14443
|
-
verdict: exports_external.enum(PLAN_REVIEW_VERDICTS),
|
|
14444
|
-
rounds: exports_external.number(),
|
|
14445
|
-
remainingIssues: exports_external.array(exports_external.object({ issue: exports_external.string(), evidence: exports_external.string() }).passthrough()).optional(),
|
|
14446
|
-
error: exports_external.string().optional()
|
|
14447
|
-
}).passthrough().optional();
|
|
14448
|
-
var planSchema = baseHandoffSchema.extend({
|
|
14449
|
-
phase: exports_external.literal("plan"),
|
|
14450
|
-
taskCount: exports_external.number().optional(),
|
|
14451
|
-
independentTasks: exports_external.number().optional(),
|
|
14452
|
-
routingHints: routingHintsSchema,
|
|
14453
|
-
concerns: exports_external.array(exports_external.string()).optional(),
|
|
14454
|
-
workflowRecommendation: exports_external.string().optional(),
|
|
14455
|
-
requiredSkills: requiredSkillsSchema,
|
|
14456
|
-
gapAnalysis: gapAnalysisSchema,
|
|
14457
|
-
planReview: planReviewSchema
|
|
14458
|
-
});
|
|
14459
|
-
var implementSchema = baseHandoffSchema.extend({
|
|
14460
|
-
phase: exports_external.literal("implement"),
|
|
14461
|
-
filesChanged: exports_external.array(exports_external.string()).optional(),
|
|
14462
|
-
proof: exports_external.array(proofSchema).min(1),
|
|
14463
|
-
trickyParts: exports_external.array(exports_external.string()).optional(),
|
|
14464
|
-
deviations: exports_external.array(exports_external.string()).optional(),
|
|
14465
|
-
openQuestions: exports_external.array(exports_external.string()).optional(),
|
|
14466
|
-
subPlanningNeeded: exports_external.boolean().optional(),
|
|
14467
|
-
discoveredComplexity: exports_external.array(exports_external.string()).optional(),
|
|
14468
|
-
suggestedSubWorkers: exports_external.number().optional()
|
|
14469
|
-
});
|
|
14470
|
-
var testSchema = baseHandoffSchema.extend({
|
|
14471
|
-
phase: exports_external.literal("test"),
|
|
14472
|
-
passed: exports_external.number().optional(),
|
|
14473
|
-
failed: exports_external.number().optional(),
|
|
14474
|
-
failures: exports_external.array(exports_external.object({ criterion: exports_external.string(), evidence: exports_external.string() }).passthrough()).optional(),
|
|
14475
|
-
implementerProof: exports_external.object({ verdict: exports_external.enum(["verified", "rejected"]), how: nonEmpty }).passthrough(),
|
|
14476
|
-
proof: exports_external.array(proofSchema).min(1).optional(),
|
|
14477
|
-
documentationFeedback: exports_external.string().optional(),
|
|
14478
|
-
observations: exports_external.array(exports_external.string()).optional()
|
|
14479
|
-
}).refine((handoff) => (handoff.failures?.length ?? 0) > 0 || (handoff.failed ?? 0) > 0 || (handoff.proof?.length ?? 0) > 0, {
|
|
14480
|
-
path: ["proof"],
|
|
14481
|
-
message: "a passing test handoff needs the tester's own production-like proof"
|
|
14482
|
-
}).refine((handoff) => (handoff.failed ?? 0) === 0 || (handoff.failures?.length ?? 0) > 0, {
|
|
14483
|
-
path: ["failures"],
|
|
14484
|
-
message: "a test handoff that reports failed > 0 records at least one failure"
|
|
14485
|
-
}).refine((handoff) => handoff.implementerProof.verdict !== "rejected" || (handoff.failures?.length ?? 0) > 0, {
|
|
14486
|
-
path: ["failures"],
|
|
14487
|
-
message: "a rejected implementer proof is a recorded failure"
|
|
14488
|
-
});
|
|
14489
|
-
var reviewSchema = baseHandoffSchema.extend({
|
|
14490
|
-
phase: exports_external.literal("review"),
|
|
14491
|
-
critical: exports_external.number().optional(),
|
|
14492
|
-
important: exports_external.number().optional(),
|
|
14493
|
-
minor: exports_external.number().optional(),
|
|
14494
|
-
verdict: exports_external.enum(["approved", "changes_requested"]).optional(),
|
|
14495
|
-
keyFindings: exports_external.array(exports_external.object({ severity: exports_external.string(), file: exports_external.string(), description: exports_external.string() }).passthrough()).optional()
|
|
14496
|
-
});
|
|
14497
|
-
var nonEmptySkillList = exports_external.array(nonEmpty).min(1);
|
|
14498
|
-
var recorded = (shape, whatToRecord) => exports_external.object(shape, {
|
|
14499
|
-
error: (issue2) => issue2.input === undefined ? `missing \u2014 record ${whatToRecord}` : undefined
|
|
14500
|
-
}).passthrough();
|
|
14501
|
-
var gapAnalysisWriteSchema = recorded({
|
|
14502
|
-
findings: exports_external.array(exports_external.object({ finding: nonEmpty, answer: nonEmpty }).passthrough()).optional(),
|
|
14503
|
-
error: nonEmpty.optional()
|
|
14504
|
-
}, "the gap analyst's `findings`, each with how the plan answers it (`[]` when it found none), or its failed call's `error`").refine((analysis) => analysis.findings === undefined !== (analysis.error === undefined), {
|
|
14505
|
-
message: "record exactly one of `findings` or the failed call's `error`"
|
|
14506
|
-
});
|
|
14507
|
-
var planReviewWriteSchema = recorded({
|
|
14508
|
-
verdict: exports_external.enum(PLAN_REVIEW_VERDICTS),
|
|
14509
|
-
rounds: exports_external.number().int().min(1).max(PLAN_REVIEW_MAX_ROUNDS),
|
|
14510
|
-
remainingIssues: exports_external.array(exports_external.object({ issue: nonEmpty, evidence: nonEmpty }).passthrough()).optional(),
|
|
14511
|
-
error: nonEmpty.optional()
|
|
14512
|
-
}, "the plan review's `verdict` and `rounds`, with `remainingIssues` when it was rejected or `error` when a review's call failed").superRefine((review, ctx) => {
|
|
14513
|
-
const remaining = review.remainingIssues?.length ?? 0;
|
|
14514
|
-
if (review.verdict === "rejected" && remaining === 0) {
|
|
14515
|
-
ctx.addIssue({
|
|
14516
|
-
code: "custom",
|
|
14517
|
-
path: ["remainingIssues"],
|
|
14518
|
-
message: "a rejected review records the blocking issues its last round named"
|
|
14519
|
-
});
|
|
14520
|
-
}
|
|
14521
|
-
if (review.verdict === "rejected" && review.rounds < PLAN_REVIEW_MAX_ROUNDS) {
|
|
14522
|
-
ctx.addIssue({
|
|
14523
|
-
code: "custom",
|
|
14524
|
-
path: ["rounds"],
|
|
14525
|
-
message: `a review still rejecting after ${review.rounds} of ${PLAN_REVIEW_MAX_ROUNDS} rounds is revised and reviewed again, not recorded`
|
|
14526
|
-
});
|
|
14527
|
-
}
|
|
14528
|
-
if (review.verdict === "approved" && remaining > 0) {
|
|
14529
|
-
ctx.addIssue({
|
|
14530
|
-
code: "custom",
|
|
14531
|
-
path: ["remainingIssues"],
|
|
14532
|
-
message: "an approved review leaves no blocking issue standing"
|
|
14533
|
-
});
|
|
14534
|
-
}
|
|
14535
|
-
if (review.verdict === "failed" !== (review.error !== undefined)) {
|
|
14536
|
-
ctx.addIssue({
|
|
14537
|
-
code: "custom",
|
|
14538
|
-
path: ["error"],
|
|
14539
|
-
message: "a failed review records its call's error, and only a failed review does"
|
|
14540
|
-
});
|
|
14541
|
-
}
|
|
14542
|
-
});
|
|
14543
|
-
var planWriteSchema = planSchema.extend({
|
|
14544
|
-
requiredSkills: exports_external.object({
|
|
14545
|
-
implement: nonEmptySkillList,
|
|
14546
|
-
test: nonEmptySkillList,
|
|
14547
|
-
review: nonEmptySkillList
|
|
14548
|
-
}).passthrough(),
|
|
14549
|
-
gapAnalysis: gapAnalysisWriteSchema,
|
|
14550
|
-
planReview: planReviewWriteSchema
|
|
14551
|
-
});
|
|
14552
|
-
var phaseHandoffSchema = exports_external.discriminatedUnion("phase", [
|
|
14553
|
-
architectSchema,
|
|
14554
|
-
planSchema,
|
|
14555
|
-
implementSchema,
|
|
14556
|
-
testSchema,
|
|
14557
|
-
reviewSchema
|
|
14558
|
-
]);
|
|
14559
14397
|
// ../contracts/src/subject.ts
|
|
14560
14398
|
var AGENT_TOPIC_PREFIX = "notifications.agent.";
|
|
14561
14399
|
var DISPATCH_TOPIC_PREFIX = "notifications.dispatch.";
|
|
@@ -14570,283 +14408,6 @@ function dispatchDocumentSubject(project, slug, type) {
|
|
|
14570
14408
|
function agentSubject(session) {
|
|
14571
14409
|
return `${AGENT_TOPIC_PREFIX}${session}`;
|
|
14572
14410
|
}
|
|
14573
|
-
|
|
14574
|
-
// ../contracts/src/legion-roles.ts
|
|
14575
|
-
var LEGION_ROLES = [
|
|
14576
|
-
"architect",
|
|
14577
|
-
"planner",
|
|
14578
|
-
"implementer",
|
|
14579
|
-
"tester",
|
|
14580
|
-
"reviewer",
|
|
14581
|
-
"merger"
|
|
14582
|
-
];
|
|
14583
|
-
|
|
14584
|
-
// ../contracts/src/legion-daemon-api.ts
|
|
14585
|
-
var nonEmptyString = exports_external.string().min(1);
|
|
14586
|
-
var appLogin = exports_external.string().regex(/^[^[\]]+\[bot\]$/);
|
|
14587
|
-
var legionRole = exports_external.enum(LEGION_ROLES);
|
|
14588
|
-
var requiredUnknown = exports_external.unknown().refine((value) => value !== undefined, {
|
|
14589
|
-
message: "Required"
|
|
14590
|
-
});
|
|
14591
|
-
var architectCapability = exports_external.strictObject({
|
|
14592
|
-
tree: nonEmptyString,
|
|
14593
|
-
sessionId: nonEmptyString,
|
|
14594
|
-
secret: nonEmptyString
|
|
14595
|
-
});
|
|
14596
|
-
var controllerIssue = exports_external.strictObject({
|
|
14597
|
-
secret: nonEmptyString,
|
|
14598
|
-
issue: nonEmptyString
|
|
14599
|
-
});
|
|
14600
|
-
var TREE_STATUSES = ["queued", "active", "lingering", "dead", "launch-failed", "closed"];
|
|
14601
|
-
var stateTmuxLocator = exports_external.strictObject({
|
|
14602
|
-
runtime: exports_external.literal("tmux"),
|
|
14603
|
-
tmuxSession: nonEmptyString,
|
|
14604
|
-
tmuxWindowId: nonEmptyString,
|
|
14605
|
-
tmuxPaneId: nonEmptyString.optional()
|
|
14606
|
-
});
|
|
14607
|
-
var stateK8sLocator = exports_external.strictObject({
|
|
14608
|
-
runtime: exports_external.literal("kubernetes"),
|
|
14609
|
-
namespace: nonEmptyString,
|
|
14610
|
-
podName: nonEmptyString,
|
|
14611
|
-
podUid: nonEmptyString,
|
|
14612
|
-
pvcName: nonEmptyString
|
|
14613
|
-
});
|
|
14614
|
-
var stateLocator = exports_external.discriminatedUnion("runtime", [stateTmuxLocator, stateK8sLocator]);
|
|
14615
|
-
var stateTreeLocator = exports_external.discriminatedUnion("runtime", [
|
|
14616
|
-
stateTmuxLocator.extend({ ompSessionFile: nonEmptyString.optional() }),
|
|
14617
|
-
stateK8sLocator.extend({ ompSessionFile: nonEmptyString.optional() })
|
|
14618
|
-
]);
|
|
14619
|
-
var stateExternalControllerLocator = exports_external.strictObject({
|
|
14620
|
-
runtime: exports_external.literal("kubernetes"),
|
|
14621
|
-
external: exports_external.literal(true),
|
|
14622
|
-
sessionId: nonEmptyString,
|
|
14623
|
-
registeredAt: exports_external.number().int().nonnegative()
|
|
14624
|
-
});
|
|
14625
|
-
var stateIssue = exports_external.strictObject({
|
|
14626
|
-
key: nonEmptyString,
|
|
14627
|
-
title: exports_external.string(),
|
|
14628
|
-
status: exports_external.enum(ISSUE_STATUSES).optional(),
|
|
14629
|
-
children: exports_external.array(nonEmptyString),
|
|
14630
|
-
parent: nonEmptyString.optional(),
|
|
14631
|
-
lastAppliedSeq: exports_external.number().int().nonnegative().optional()
|
|
14632
|
-
});
|
|
14633
|
-
var stateWorkspaceLost = exports_external.strictObject({
|
|
14634
|
-
at: nonEmptyString,
|
|
14635
|
-
generation: exports_external.number().int().nonnegative(),
|
|
14636
|
-
fromRef: nonEmptyString,
|
|
14637
|
-
previousSessionId: nonEmptyString.optional()
|
|
14638
|
-
});
|
|
14639
|
-
var stateTree = exports_external.strictObject({
|
|
14640
|
-
status: exports_external.enum(TREE_STATUSES),
|
|
14641
|
-
generation: exports_external.number().int().nonnegative(),
|
|
14642
|
-
launchFailures: exports_external.number().int().nonnegative(),
|
|
14643
|
-
readyConfirmedAt: exports_external.number().optional(),
|
|
14644
|
-
locator: stateTreeLocator.optional(),
|
|
14645
|
-
workspaceLost: stateWorkspaceLost.optional()
|
|
14646
|
-
});
|
|
14647
|
-
var stateGate = exports_external.strictObject({
|
|
14648
|
-
artifactId: nonEmptyString,
|
|
14649
|
-
latestVersion: exports_external.number().int().positive(),
|
|
14650
|
-
approvedVersion: exports_external.number().int().positive().optional()
|
|
14651
|
-
});
|
|
14652
|
-
var stateRole = exports_external.strictObject({
|
|
14653
|
-
role: nonEmptyString,
|
|
14654
|
-
issue: nonEmptyString.optional(),
|
|
14655
|
-
generation: exports_external.number().int().nonnegative().optional(),
|
|
14656
|
-
sessionId: nonEmptyString.optional(),
|
|
14657
|
-
readyConfirmedAt: exports_external.number().optional(),
|
|
14658
|
-
launchFailures: exports_external.number().int().nonnegative().optional(),
|
|
14659
|
-
locator: stateLocator.optional(),
|
|
14660
|
-
workspaceLost: stateWorkspaceLost.optional()
|
|
14661
|
-
});
|
|
14662
|
-
var stateQueuedWorkerIdentity = {
|
|
14663
|
-
roleToken: nonEmptyString,
|
|
14664
|
-
issue: nonEmptyString,
|
|
14665
|
-
role: nonEmptyString
|
|
14666
|
-
};
|
|
14667
|
-
var stateQueuedWorker = exports_external.union([
|
|
14668
|
-
exports_external.strictObject(stateQueuedWorkerIdentity),
|
|
14669
|
-
exports_external.strictObject({
|
|
14670
|
-
...stateQueuedWorkerIdentity,
|
|
14671
|
-
kind: exports_external.enum(["assignment", "catchup"]),
|
|
14672
|
-
queuedAt: nonEmptyString
|
|
14673
|
-
})
|
|
14674
|
-
]);
|
|
14675
|
-
var LegionDaemonApi = {
|
|
14676
|
-
State: {
|
|
14677
|
-
response: exports_external.strictObject({
|
|
14678
|
-
project: nonEmptyString,
|
|
14679
|
-
version: exports_external.number().int(),
|
|
14680
|
-
issues: exports_external.record(exports_external.string(), stateIssue),
|
|
14681
|
-
trees: exports_external.record(exports_external.string(), stateTree),
|
|
14682
|
-
admission: exports_external.strictObject({
|
|
14683
|
-
cap: exports_external.number().int().nonnegative(),
|
|
14684
|
-
active: exports_external.array(nonEmptyString),
|
|
14685
|
-
queue: exports_external.array(nonEmptyString)
|
|
14686
|
-
}),
|
|
14687
|
-
gates: exports_external.record(exports_external.string(), stateGate),
|
|
14688
|
-
controllerLocator: exports_external.union([stateTreeLocator, stateExternalControllerLocator]).optional(),
|
|
14689
|
-
roles: exports_external.record(exports_external.string(), stateRole),
|
|
14690
|
-
controllerPendingNotices: exports_external.number().int().nonnegative(),
|
|
14691
|
-
pendingStatusWrites: exports_external.array(nonEmptyString),
|
|
14692
|
-
workerAdmission: exports_external.strictObject({ queue: exports_external.array(stateQueuedWorker) })
|
|
14693
|
-
})
|
|
14694
|
-
},
|
|
14695
|
-
ControllerReady: {
|
|
14696
|
-
request: exports_external.strictObject({
|
|
14697
|
-
secret: nonEmptyString,
|
|
14698
|
-
sessionId: nonEmptyString,
|
|
14699
|
-
ompSessionFile: nonEmptyString.optional(),
|
|
14700
|
-
pluginVersion: nonEmptyString
|
|
14701
|
-
}),
|
|
14702
|
-
response: exports_external.object({})
|
|
14703
|
-
},
|
|
14704
|
-
ControllerSecret: {
|
|
14705
|
-
request: exports_external.strictObject({}),
|
|
14706
|
-
response: exports_external.object({ secret: nonEmptyString })
|
|
14707
|
-
},
|
|
14708
|
-
ProcessStarted: {
|
|
14709
|
-
request: exports_external.strictObject({
|
|
14710
|
-
tree: nonEmptyString,
|
|
14711
|
-
generation: exports_external.number().int(),
|
|
14712
|
-
rootSessionId: nonEmptyString,
|
|
14713
|
-
agentId: nonEmptyString,
|
|
14714
|
-
bootToken: nonEmptyString,
|
|
14715
|
-
ompSessionFile: nonEmptyString,
|
|
14716
|
-
pluginVersion: nonEmptyString
|
|
14717
|
-
}),
|
|
14718
|
-
response: exports_external.object({
|
|
14719
|
-
roleTokens: exports_external.record(exports_external.string(), exports_external.string()),
|
|
14720
|
-
controlSubject: nonEmptyString,
|
|
14721
|
-
gates: exports_external.object({
|
|
14722
|
-
design: exports_external.enum(["root-issues", "off"])
|
|
14723
|
-
}).optional(),
|
|
14724
|
-
secret: nonEmptyString
|
|
14725
|
-
})
|
|
14726
|
-
},
|
|
14727
|
-
ProcessReady: {
|
|
14728
|
-
request: architectCapability.extend({ generation: exports_external.number().int() }),
|
|
14729
|
-
response: exports_external.object({})
|
|
14730
|
-
},
|
|
14731
|
-
ProcessExit: {
|
|
14732
|
-
request: architectCapability.extend({ generation: exports_external.number().int() }),
|
|
14733
|
-
response: exports_external.object({})
|
|
14734
|
-
},
|
|
14735
|
-
WaveRelease: {
|
|
14736
|
-
request: architectCapability.extend({ issues: exports_external.array(nonEmptyString).optional() }),
|
|
14737
|
-
response: exports_external.object({ released: exports_external.array(nonEmptyString) })
|
|
14738
|
-
},
|
|
14739
|
-
Escalate: {
|
|
14740
|
-
request: architectCapability.extend({
|
|
14741
|
-
kind: exports_external.enum(["re-file", "capacity", "cross-tree"]),
|
|
14742
|
-
context: requiredUnknown
|
|
14743
|
-
}),
|
|
14744
|
-
response: exports_external.object({})
|
|
14745
|
-
},
|
|
14746
|
-
ProvisioningCredential: {
|
|
14747
|
-
request: architectCapability.extend({ issue: nonEmptyString }),
|
|
14748
|
-
response: exports_external.object({ token: nonEmptyString })
|
|
14749
|
-
},
|
|
14750
|
-
WorkerStarted: {
|
|
14751
|
-
request: exports_external.strictObject({
|
|
14752
|
-
tree: nonEmptyString,
|
|
14753
|
-
issue: nonEmptyString,
|
|
14754
|
-
role: legionRole,
|
|
14755
|
-
bootToken: nonEmptyString,
|
|
14756
|
-
sessionId: nonEmptyString,
|
|
14757
|
-
agentId: nonEmptyString,
|
|
14758
|
-
ompSessionFile: nonEmptyString,
|
|
14759
|
-
pluginVersion: nonEmptyString
|
|
14760
|
-
}),
|
|
14761
|
-
response: exports_external.object({
|
|
14762
|
-
roleToken: nonEmptyString,
|
|
14763
|
-
secret: nonEmptyString,
|
|
14764
|
-
gitName: nonEmptyString,
|
|
14765
|
-
gitEmail: nonEmptyString
|
|
14766
|
-
})
|
|
14767
|
-
},
|
|
14768
|
-
WorkerReady: {
|
|
14769
|
-
request: exports_external.strictObject({
|
|
14770
|
-
tree: nonEmptyString,
|
|
14771
|
-
issue: nonEmptyString,
|
|
14772
|
-
role: legionRole,
|
|
14773
|
-
sessionId: nonEmptyString,
|
|
14774
|
-
generation: exports_external.number().int().nonnegative(),
|
|
14775
|
-
secret: nonEmptyString
|
|
14776
|
-
}),
|
|
14777
|
-
response: exports_external.object({})
|
|
14778
|
-
},
|
|
14779
|
-
PhaseComplete: {
|
|
14780
|
-
request: exports_external.strictObject({
|
|
14781
|
-
grantId: nonEmptyString,
|
|
14782
|
-
summary: nonEmptyString
|
|
14783
|
-
}),
|
|
14784
|
-
response: exports_external.object({})
|
|
14785
|
-
},
|
|
14786
|
-
SpawnWorker: {
|
|
14787
|
-
request: architectCapability.extend({
|
|
14788
|
-
issue: nonEmptyString,
|
|
14789
|
-
role: legionRole,
|
|
14790
|
-
task: nonEmptyString,
|
|
14791
|
-
requestId: exports_external.uuid()
|
|
14792
|
-
}),
|
|
14793
|
-
response: exports_external.object({
|
|
14794
|
-
status: exports_external.enum(["spawned", "resumed", "queued"]),
|
|
14795
|
-
roleToken: nonEmptyString
|
|
14796
|
-
})
|
|
14797
|
-
},
|
|
14798
|
-
WorkerSession: {
|
|
14799
|
-
request: exports_external.strictObject({
|
|
14800
|
-
sessionId: nonEmptyString,
|
|
14801
|
-
recoveryToken: nonEmptyString
|
|
14802
|
-
}),
|
|
14803
|
-
response: exports_external.object({
|
|
14804
|
-
tree: nonEmptyString,
|
|
14805
|
-
issue: nonEmptyString,
|
|
14806
|
-
role: legionRole,
|
|
14807
|
-
secret: nonEmptyString
|
|
14808
|
-
})
|
|
14809
|
-
},
|
|
14810
|
-
IssueStatus: {
|
|
14811
|
-
request: controllerIssue.extend({
|
|
14812
|
-
status: exports_external.enum(ISSUE_STATUSES),
|
|
14813
|
-
tree: nonEmptyString.optional(),
|
|
14814
|
-
sessionId: nonEmptyString.optional()
|
|
14815
|
-
}),
|
|
14816
|
-
response: exports_external.object({})
|
|
14817
|
-
},
|
|
14818
|
-
GatesRegister: {
|
|
14819
|
-
request: architectCapability.extend({
|
|
14820
|
-
issue: nonEmptyString,
|
|
14821
|
-
artifactId: exports_external.uuid(),
|
|
14822
|
-
version: exports_external.number().int().positive()
|
|
14823
|
-
}),
|
|
14824
|
-
response: exports_external.object({})
|
|
14825
|
-
},
|
|
14826
|
-
Grant: {
|
|
14827
|
-
request: exports_external.union([
|
|
14828
|
-
exports_external.strictObject({
|
|
14829
|
-
sessionId: nonEmptyString,
|
|
14830
|
-
secret: nonEmptyString,
|
|
14831
|
-
tree: nonEmptyString,
|
|
14832
|
-
issue: nonEmptyString
|
|
14833
|
-
}),
|
|
14834
|
-
exports_external.strictObject({ sessionId: nonEmptyString, secret: nonEmptyString })
|
|
14835
|
-
]),
|
|
14836
|
-
response: exports_external.object({ grantId: nonEmptyString, expiresAt: nonEmptyString })
|
|
14837
|
-
},
|
|
14838
|
-
GitHubToken: {
|
|
14839
|
-
request: exports_external.strictObject({ grantId: nonEmptyString }),
|
|
14840
|
-
response: exports_external.object({
|
|
14841
|
-
token: nonEmptyString,
|
|
14842
|
-
appLogin: exports_external.string().endsWith("[bot]"),
|
|
14843
|
-
legionAppLogins: exports_external.object({ implement: appLogin, review: appLogin }).optional()
|
|
14844
|
-
})
|
|
14845
|
-
},
|
|
14846
|
-
GitCredential: {
|
|
14847
|
-
request: exports_external.strictObject({ grantId: nonEmptyString })
|
|
14848
|
-
}
|
|
14849
|
-
};
|
|
14850
14411
|
// ../contracts/src/repo.ts
|
|
14851
14412
|
function canonicalRepo(owner, repo) {
|
|
14852
14413
|
return `${owner.trim().toLowerCase()}/${repo.trim().toLowerCase().replace(/\.git$/, "")}`;
|
package/package.json
CHANGED
package/skills/AGENTS.md
CHANGED
|
@@ -21,6 +21,6 @@ event intake, process lifecycle, credentials, and role delivery.
|
|
|
21
21
|
The owning skill above is where each contract is defined; a role prompt that needs a contract from its own seat points there or restates only its own step. This file lists and does not restate.
|
|
22
22
|
A Legion prompt (a skill here, a role prompt, or an agent definition in `packages/pi-envoy/agents/`) names a task agent only as `task(agent="<name>")` and a skill it tells the model to load only as `skill://<name>`. Those are the two forms the Go daemon's boot gate and `legion probe-image` resolve through Oh My Pi, refusing by name one it cannot find; a dispatch or a load written any other way goes unchecked. An agent or skill Legion's prompts name is shipped here or in `packages/pi-envoy/agents/`, unless Oh My Pi bundles it.
|
|
23
23
|
A skill file an agent loads stays under 51,200 bytes, Oh My Pi's spill threshold (a longer one arrives with its middle cut out), and a skill's detail lives in `references/` files linked as `skill://<name>/references/<file>.md`, never by relative path, which a read by path cuts at 300 lines. `packages/pi-envoy/src/skills-guard.test.ts` fails on a file at the threshold, on any `SKILL.md` body of 500 lines or more, on a skill whose frontmatter `name` is not its directory's name, on a `dispatch-first` over its budget, on a `skill://<name>/<path>` link that names a missing file or a missing `#heading`, and on a `legion-worker` reference nothing links.
|
|
24
|
-
The text a worker boots with (its role prompt) lives in `packages/
|
|
25
|
-
composed per role
|
|
26
|
-
holds the structural rules for those parts.
|
|
24
|
+
The text a worker boots with (its role prompt) lives in `packages/daemon/internal/prompts/roles/`,
|
|
25
|
+
embedded in the `legion` binary and composed per role by `packages/daemon/internal/prompts/prompts.go`;
|
|
26
|
+
`packages/daemon/internal/prompts/roles_test.go` holds the structural rules for those parts.
|
|
@@ -125,12 +125,10 @@ committed predecessor handoffs in lifecycle order from `$LEGION_WORKSPACE/.legio
|
|
|
125
125
|
4. `test.json`
|
|
126
126
|
5. `review.json`
|
|
127
127
|
|
|
128
|
-
Read only files that precede the assigned phase.
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
Undeclared fields pass validation untouched and reach the next worker; a declared field of the
|
|
133
|
-
wrong type fails the whole file, so the `legion` tool's `handoff_read` returns null for that phase.
|
|
128
|
+
Read only files that precede the assigned phase. Each was held to its phase's rules when it was
|
|
129
|
+
written (`handoff_write`, in the completion gate below): fields the phase does not declare passed
|
|
130
|
+
untouched and reach the next worker. The `legion` tool's `handoff_read` returns each file as it
|
|
131
|
+
stands in the workspace.
|
|
134
132
|
Write the phase-specific fields the next phase and the architect need, consistent with what
|
|
135
133
|
predecessor phases already wrote. The durable copy lives in
|
|
136
134
|
`$LEGION_WORKSPACE/.legion/<phase>.json`. If a committed handoff conflicts with memory or a prior
|
|
@@ -319,7 +317,7 @@ line), the full definition of a proof, what the tester verifies, and the simplif
|
|
|
319
317
|
## Completion gate: handoff write, verification, and persistence
|
|
320
318
|
|
|
321
319
|
The merger writes no handoff and pushes nothing, so this gate does not apply to it
|
|
322
|
-
(`packages/
|
|
320
|
+
(`packages/daemon/internal/prompts/roles/merger.md`).
|
|
323
321
|
|
|
324
322
|
Write the phase-specific handoff: call the `legion` tool with `op: "handoff_write"`, `phase: "<p>"`,
|
|
325
323
|
and `data`: a JSON object of the phase-specific fields only. It runs `legion handoff write` in
|
|
@@ -73,12 +73,12 @@ completion leaves the issue in reviewing until you finish.
|
|
|
73
73
|
in READY (an empty output is quoted as `no file changes above the approved head`); then the same
|
|
74
74
|
with `'~docs/solutions'` appended, which must print nothing. *The READY packet*: the merger
|
|
75
75
|
always posts `READY #<n> at <current sha> (approved at <approved sha>) for <KEY> (<pr url>)`
|
|
76
|
-
(the shape `packages/
|
|
77
|
-
its `Not proven / risk:` value — every bullet under that label joined with
|
|
78
|
-
READY line, or `none` — quoted from the `## For the reviewer` block at that same
|
|
79
|
-
line saying the body carries no brief — the packet still publishes), then the
|
|
80
|
-
output and the PR body's gate facts, as a `dispatch_message` on the issue. When the
|
|
81
|
-
addressing` line names a merge queue, it also publishes the same packet there with
|
|
76
|
+
(the shape `packages/daemon/internal/prompts/roles/merger.md` defines), then the PR body's
|
|
77
|
+
`Outcome:` line and its `Not proven / risk:` value — every bullet under that label joined with
|
|
78
|
+
`; ` on the one READY line, or `none` — quoted from the `## For the reviewer` block at that same
|
|
79
|
+
head (or one line saying the body carries no brief — the packet still publishes), then the
|
|
80
|
+
`--summary` output and the PR body's gate facts, as a `dispatch_message` on the issue. When the
|
|
81
|
+
`Legion addressing` line names a merge queue, it also publishes the same packet there with
|
|
82
82
|
`envoy_publish`; a 404 means the Dispatch message remains the durable notice and the merger
|
|
83
83
|
stays idle. The READY packet names both the implementer's and tester's `E2E` lines; a missing
|
|
84
84
|
one is reported to the architect instead of published. Legion never merges.
|
|
@@ -13,7 +13,8 @@ reviewer on every re-review, the merger before READY. Every path it cites is in
|
|
|
13
13
|
`Accepted:` — the opener's own follow-up included — leaves the thread open, because resolution
|
|
14
14
|
considers only the newest comment). The review App can reply on a thread but cannot resolve it:
|
|
15
15
|
GitHub grants resolving a review thread to the pull request's author, and the implementer opens
|
|
16
|
-
every Legion pull request (`
|
|
16
|
+
every Legion pull request (`docs/site/src/content/docs/legion/running-legion.md`, "The two
|
|
17
|
+
GitHub Apps").
|
|
17
18
|
When `LEGION_GRANT_FILE` or `LEGION_GRANT` is set, use `legion threads resolve --pr <number> --repo <owner>/<repo>`.
|
|
18
19
|
When neither is set, add `--gh` to that command, which applies the fallback's rule below through
|
|
19
20
|
your own `gh`; where no `legion` command is installed, use `gh api graphql` with the session's
|