@jterrats/open-orchestra 0.1.0 → 0.2.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/CHANGELOG.md +53 -0
- package/README.md +17 -2
- package/dist/assets/web-console.js +743 -0
- package/dist/cli.js +157 -4
- package/dist/cli.js.map +1 -1
- package/dist/collaboration-flows.d.ts +5 -0
- package/dist/collaboration-flows.js +256 -0
- package/dist/collaboration-flows.js.map +1 -0
- package/dist/command-manifest.d.ts +11 -0
- package/dist/command-manifest.js +52 -0
- package/dist/command-manifest.js.map +1 -0
- package/dist/commands.d.ts +31 -0
- package/dist/commands.js +644 -2
- package/dist/commands.js.map +1 -1
- package/dist/constants.d.ts +4 -0
- package/dist/constants.js +22 -0
- package/dist/constants.js.map +1 -1
- package/dist/defaults.d.ts +7 -11
- package/dist/defaults.js +7 -625
- package/dist/defaults.js.map +1 -1
- package/dist/delegation-decision.d.ts +14 -0
- package/dist/delegation-decision.js +391 -0
- package/dist/delegation-decision.js.map +1 -0
- package/dist/detect-commands.d.ts +3 -0
- package/dist/detect-commands.js +28 -0
- package/dist/detect-commands.js.map +1 -0
- package/dist/diagram-validation.d.ts +36 -0
- package/dist/diagram-validation.js +118 -0
- package/dist/diagram-validation.js.map +1 -0
- package/dist/fs-utils.d.ts +2 -0
- package/dist/fs-utils.js +75 -6
- package/dist/fs-utils.js.map +1 -1
- package/dist/health-checks.d.ts +28 -0
- package/dist/health-checks.js +219 -0
- package/dist/health-checks.js.map +1 -0
- package/dist/health-commands.d.ts +2 -0
- package/dist/health-commands.js +18 -0
- package/dist/health-commands.js.map +1 -0
- package/dist/instruction-apply.d.ts +34 -0
- package/dist/instruction-apply.js +150 -0
- package/dist/instruction-apply.js.map +1 -0
- package/dist/instruction-blocks.d.ts +22 -0
- package/dist/instruction-blocks.js +120 -0
- package/dist/instruction-blocks.js.map +1 -0
- package/dist/instruction-imports.d.ts +12 -0
- package/dist/instruction-imports.js +45 -0
- package/dist/instruction-imports.js.map +1 -0
- package/dist/instruction-stale.d.ts +9 -0
- package/dist/instruction-stale.js +106 -0
- package/dist/instruction-stale.js.map +1 -0
- package/dist/instruction-types.d.ts +66 -0
- package/dist/instruction-types.js +2 -0
- package/dist/instruction-types.js.map +1 -0
- package/dist/instruction-updates.d.ts +4 -0
- package/dist/instruction-updates.js +5 -0
- package/dist/instruction-updates.js.map +1 -0
- package/dist/knowledge-base.d.ts +10 -0
- package/dist/knowledge-base.js +117 -0
- package/dist/knowledge-base.js.map +1 -0
- package/dist/mcp-oauth-proxy.d.ts +39 -0
- package/dist/mcp-oauth-proxy.js +80 -0
- package/dist/mcp-oauth-proxy.js.map +1 -0
- package/dist/pr-review.d.ts +20 -0
- package/dist/pr-review.js +142 -0
- package/dist/pr-review.js.map +1 -0
- package/dist/project-detection.d.ts +22 -0
- package/dist/project-detection.js +174 -0
- package/dist/project-detection.js.map +1 -0
- package/dist/prompt-registry.d.ts +56 -0
- package/dist/prompt-registry.js +163 -0
- package/dist/prompt-registry.js.map +1 -0
- package/dist/release-candidate.d.ts +41 -0
- package/dist/release-candidate.js +196 -0
- package/dist/release-candidate.js.map +1 -0
- package/dist/release-commands.d.ts +4 -0
- package/dist/release-commands.js +50 -0
- package/dist/release-commands.js.map +1 -0
- package/dist/roles/ai-support-roles.d.ts +11 -0
- package/dist/roles/ai-support-roles.js +67 -0
- package/dist/roles/ai-support-roles.js.map +1 -0
- package/dist/roles/core-roles.d.ts +11 -0
- package/dist/roles/core-roles.js +144 -0
- package/dist/roles/core-roles.js.map +1 -0
- package/dist/roles/engineering-roles.d.ts +11 -0
- package/dist/roles/engineering-roles.js +176 -0
- package/dist/roles/engineering-roles.js.map +1 -0
- package/dist/roles/governance-roles.d.ts +11 -0
- package/dist/roles/governance-roles.js +117 -0
- package/dist/roles/governance-roles.js.map +1 -0
- package/dist/roles/index.d.ts +11 -0
- package/dist/roles/index.js +17 -0
- package/dist/roles/index.js.map +1 -0
- package/dist/roles/platform-ops-roles.d.ts +11 -0
- package/dist/roles/platform-ops-roles.js +158 -0
- package/dist/roles/platform-ops-roles.js.map +1 -0
- package/dist/roles/qa-ux-roles.d.ts +11 -0
- package/dist/roles/qa-ux-roles.js +193 -0
- package/dist/roles/qa-ux-roles.js.map +1 -0
- package/dist/roles/release-ops-roles.d.ts +11 -0
- package/dist/roles/release-ops-roles.js +109 -0
- package/dist/roles/release-ops-roles.js.map +1 -0
- package/dist/runtime-adapters.d.ts +6 -0
- package/dist/runtime-adapters.js +88 -0
- package/dist/runtime-adapters.js.map +1 -0
- package/dist/runtime-bootstrap.d.ts +12 -0
- package/dist/runtime-bootstrap.js +85 -0
- package/dist/runtime-bootstrap.js.map +1 -0
- package/dist/skills.d.ts +36 -0
- package/dist/skills.js +665 -0
- package/dist/skills.js.map +1 -0
- package/dist/subagent-protocol.d.ts +41 -0
- package/dist/subagent-protocol.js +179 -0
- package/dist/subagent-protocol.js.map +1 -0
- package/dist/telemetry-consent.d.ts +24 -0
- package/dist/telemetry-consent.js +95 -0
- package/dist/telemetry-consent.js.map +1 -0
- package/dist/telemetry-export.d.ts +14 -0
- package/dist/telemetry-export.js +126 -0
- package/dist/telemetry-export.js.map +1 -0
- package/dist/telemetry-records.d.ts +3 -0
- package/dist/telemetry-records.js +96 -0
- package/dist/telemetry-records.js.map +1 -0
- package/dist/telemetry-redaction.d.ts +9 -0
- package/dist/telemetry-redaction.js +55 -0
- package/dist/telemetry-redaction.js.map +1 -0
- package/dist/telemetry-types.d.ts +52 -0
- package/dist/telemetry-types.js +2 -0
- package/dist/telemetry-types.js.map +1 -0
- package/dist/telemetry.d.ts +4 -0
- package/dist/telemetry.js +4 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/types.d.ts +176 -1
- package/dist/validation.d.ts +3 -1
- package/dist/validation.js +28 -5
- package/dist/validation.js.map +1 -1
- package/dist/web-api.js +167 -3
- package/dist/web-api.js.map +1 -1
- package/dist/web-console.js +6 -160
- package/dist/web-console.js.map +1 -1
- package/dist/workflow-gates.js +4 -2
- package/dist/workflow-gates.js.map +1 -1
- package/dist/workflow-services.js +125 -67
- package/dist/workflow-services.js.map +1 -1
- package/dist/workflow-templates.d.ts +10 -0
- package/dist/workflow-templates.js +141 -0
- package/dist/workflow-templates.js.map +1 -0
- package/dist/workspace-classification.d.ts +5 -0
- package/dist/workspace-classification.js +127 -0
- package/dist/workspace-classification.js.map +1 -0
- package/dist/workspace-validator.js +11 -1
- package/dist/workspace-validator.js.map +1 -1
- package/dist/workspace.d.ts +8 -4
- package/dist/workspace.js +111 -4
- package/dist/workspace.js.map +1 -1
- package/docs/dev-team-specialist-role-profiles.md +171 -0
- package/docs/mcp-oauth-proxy-evaluation.md +44 -0
- package/docs/multi-agent-orchestrator-backlog.md +413 -1
- package/docs/open-orchestra-dogfooding-findings.md +66 -0
- package/docs/orchestra-mvp.md +46 -1
- package/docs/runtime-adapters.md +86 -0
- package/docs/runtime-llm-flow.md +124 -0
- package/docs/setup-agents-dogfooding-findings.md +101 -0
- package/docs/skill-loading-strategy.md +114 -0
- package/docs/source-of-truth-and-agent-learning.md +83 -0
- package/package.json +9 -5
- package/rules/agent-roles.mdc +30 -0
- package/rules/ai-assisted-development.mdc +22 -0
- package/skills/agent-learning/SKILL.md +24 -0
- package/skills/agent-learning/manifest.json +40 -0
- package/skills/backlog-sync/SKILL.md +24 -0
- package/skills/backlog-sync/manifest.json +41 -0
- package/skills/diagram-export/SKILL.md +35 -0
- package/skills/diagram-export/manifest.json +40 -0
- package/skills/model-evaluation/SKILL.md +25 -0
- package/skills/model-evaluation/manifest.json +41 -0
- package/skills/playwright-evidence/SKILL.md +28 -0
- package/skills/playwright-evidence/manifest.json +46 -0
- package/skills/pr-review/SKILL.md +23 -0
- package/skills/pr-review/manifest.json +43 -0
- package/skills/prompt-registry/SKILL.md +24 -0
- package/skills/prompt-registry/manifest.json +45 -0
- package/skills/release-readiness/SKILL.md +25 -0
- package/skills/release-readiness/manifest.json +45 -0
- package/skills/source-of-truth/SKILL.md +24 -0
- package/skills/source-of-truth/manifest.json +47 -0
- package/skills/static-analysis/SKILL.md +26 -0
- package/skills/static-analysis/manifest.json +46 -0
package/dist/commands.js
CHANGED
|
@@ -1,11 +1,47 @@
|
|
|
1
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
1
3
|
import { initWorkspace } from "./workspace.js";
|
|
2
4
|
import { requireArg } from "./args.js";
|
|
5
|
+
import { resolveWorkspaceWritePath } from "./fs-utils.js";
|
|
3
6
|
import { addEvidence, addPlaywrightEvidence, addTask, approveApproval, checkUsageBudget, checkReadiness, checkTaskDependencies, claimLock, completeWithProviderFallback, createHandoff, evaluateWorkflowGate, executeNextReadyTask, executePlanWithBudgetPreflight, executeReadyTaskBatch, generateExecutionPlan, generatePlaywrightTestPlan, generatePullRequestSummary, generateTaskGraphPlan, getUsageReport, getWorkflowStatus, getWorkflowSummary, getTaskContext, getWorkflowConfig, listEvidence, listConfiguredModelProviders, listDecisions, listLocks, listApprovals, listReviews, listRoles, listTasks, rejectApproval, recordReview, recordModelProvenance, recordDecision, releaseLock, setRoleModelProvider, showApproval, updateTask, listModelProvenance, } from "./workflow-services.js";
|
|
4
7
|
import { validateWorkspace } from "./workspace-validator.js";
|
|
8
|
+
import { addAgentLesson, listAgentLessons, listSkills, planSkillsForTask, promoteAgentLessons, readSourceOfTruth, recordSkillPlan, recordSkillRender, renderSkills, validateSkills, } from "./skills.js";
|
|
5
9
|
import { getWebServerAddress, startWebApiServer } from "./web-api.js";
|
|
10
|
+
import { decideTaskDelegation } from "./delegation-decision.js";
|
|
11
|
+
import { lintMermaidDiagram, recordDiagramLintEvidence, } from "./diagram-validation.js";
|
|
12
|
+
import { evaluateMcpOAuthProxy, } from "./mcp-oauth-proxy.js";
|
|
13
|
+
import { detectStaleInstructionFilesFromManifest, resolveInstructionImportsFromFile, updateManagedInstructionFile, } from "./instruction-updates.js";
|
|
14
|
+
import { applyInstructionUpdatesFromManifest } from "./instruction-apply.js";
|
|
15
|
+
import { renderSubagentProtocol, upsertSubagentProtocolBlock, } from "./subagent-protocol.js";
|
|
16
|
+
import { listCollaborationFlows, recommendCollaborationFlow, } from "./collaboration-flows.js";
|
|
17
|
+
import { listWorkflowTemplates, renderWorkflowTemplates, selectWorkflowTemplates, validateWorkflowTemplates, } from "./workflow-templates.js";
|
|
18
|
+
import { listCommandManifest } from "./command-manifest.js";
|
|
19
|
+
import { listRuntimeAdapters, parseRuntimeTarget } from "./runtime-adapters.js";
|
|
20
|
+
import { renderRuntimeBootstrap, upsertRuntimeBootstrapBlock, } from "./runtime-bootstrap.js";
|
|
21
|
+
import { disableTelemetryConsent, enableTelemetryConsent, exportTelemetryDataset, exportTelemetryEvalDataset, getTelemetryConsent, parseTelemetryLevel, requiresSensitiveTelemetryOptIn, submitTelemetryDataset, } from "./telemetry.js";
|
|
6
22
|
export async function initCommand(options, io) {
|
|
7
|
-
const
|
|
23
|
+
const root = stringOption(options["target-dir"]) ?? process.cwd();
|
|
24
|
+
const input = {
|
|
25
|
+
root,
|
|
26
|
+
force: Boolean(options.force),
|
|
27
|
+
advisory: Boolean(options.advisory),
|
|
28
|
+
confirmUnknown: Boolean(options["confirm-unknown"]),
|
|
29
|
+
};
|
|
30
|
+
const bootstrapTargetFile = stringOption(options["bootstrap-file"]);
|
|
31
|
+
const runtimeTargets = parseRuntimeTargetOptions(options);
|
|
32
|
+
const base = await initWorkspace({
|
|
33
|
+
...input,
|
|
34
|
+
...(bootstrapTargetFile ? { bootstrapTargetFile } : {}),
|
|
35
|
+
...(runtimeTargets.length > 0 ? { runtimeTargets } : {}),
|
|
36
|
+
});
|
|
8
37
|
io.log(`Initialized ${base}`);
|
|
38
|
+
if (options.advisory) {
|
|
39
|
+
io.log("Advisory mode enabled; root instruction files were not written.");
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
io.log("Prompt registry scaffolded in .generated-prompts/");
|
|
43
|
+
}
|
|
44
|
+
io.log("Source catalog and agent lessons scaffolded in .agent-workflow/");
|
|
9
45
|
io.log("Next: add tasks to .agent-workflow/tasks.json and run orchestra status");
|
|
10
46
|
}
|
|
11
47
|
export async function statusCommand(options, io) {
|
|
@@ -166,7 +202,7 @@ export async function lockListCommand(options, io) {
|
|
|
166
202
|
}
|
|
167
203
|
export async function lockClaimCommand(options, io) {
|
|
168
204
|
const lock = await claimLock(removeUndefined({
|
|
169
|
-
id: stringOption(options.id)
|
|
205
|
+
id: stringOption(options.id),
|
|
170
206
|
taskId: requireArg(options, "task"),
|
|
171
207
|
ownerRole: requireArg(options, "role"),
|
|
172
208
|
path: requireArg(options, "path"),
|
|
@@ -363,6 +399,16 @@ export async function prSummaryCommand(options, io) {
|
|
|
363
399
|
}
|
|
364
400
|
io.log(renderPullRequestSummaryMarkdown(summary));
|
|
365
401
|
}
|
|
402
|
+
export async function delegationDecideCommand(options, io) {
|
|
403
|
+
const decision = await decideTaskDelegation(requireArg(options, "task"), process.cwd(), {
|
|
404
|
+
record: !options["no-record"],
|
|
405
|
+
});
|
|
406
|
+
if (options.json) {
|
|
407
|
+
io.log(JSON.stringify(decision, null, 2));
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
io.log(renderDelegationDecisionMarkdown(decision));
|
|
411
|
+
}
|
|
366
412
|
export async function contextCommand(options, io) {
|
|
367
413
|
const context = await getTaskContext(requireArg(options, "task"));
|
|
368
414
|
if (options.json) {
|
|
@@ -485,6 +531,539 @@ export async function modelCompleteFakeCommand(options, io) {
|
|
|
485
531
|
}
|
|
486
532
|
io.log(`Fake completion used ${result.provider}/${result.model} fallback=${String(result.fallbackUsed)}`);
|
|
487
533
|
}
|
|
534
|
+
export async function telemetryStatusCommand(options, io) {
|
|
535
|
+
const telemetry = await getTelemetryConsent();
|
|
536
|
+
if (options.json) {
|
|
537
|
+
io.log(JSON.stringify(telemetry, null, 2));
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
io.log("Telemetry: " + (telemetry.enabled ? "enabled" : "off"));
|
|
541
|
+
io.log("Level: " + telemetry.level);
|
|
542
|
+
io.log("Policy: " + telemetry.policyVersion);
|
|
543
|
+
}
|
|
544
|
+
export async function telemetryEnableCommand(options, io) {
|
|
545
|
+
const level = parseTelemetryLevel(stringOption(options.level) ?? "metadata");
|
|
546
|
+
if (requiresSensitiveTelemetryOptIn(level) && !options["confirm-sensitive"]) {
|
|
547
|
+
throw new Error("prompt-sample and eval-dataset telemetry require --confirm-sensitive");
|
|
548
|
+
}
|
|
549
|
+
const telemetry = await enableTelemetryConsent({
|
|
550
|
+
level,
|
|
551
|
+
actor: stringOption(options.actor) ?? "user",
|
|
552
|
+
});
|
|
553
|
+
if (options.json) {
|
|
554
|
+
io.log(JSON.stringify(telemetry, null, 2));
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
io.log("Telemetry enabled at level " + telemetry.level);
|
|
558
|
+
}
|
|
559
|
+
export async function telemetryExportCommand(options, io) {
|
|
560
|
+
const result = await exportTelemetryDataset({
|
|
561
|
+
dryRun: Boolean(options["dry-run"]),
|
|
562
|
+
});
|
|
563
|
+
if (options.json) {
|
|
564
|
+
io.log(JSON.stringify(result, null, 2));
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
io.log((result.dryRun ? "Telemetry export dry run" : "Telemetry exported") +
|
|
568
|
+
": " +
|
|
569
|
+
result.recordCount +
|
|
570
|
+
" record(s)");
|
|
571
|
+
if (result.file) {
|
|
572
|
+
io.log("File: " + result.file);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
export async function telemetrySubmitCommand(options, io) {
|
|
576
|
+
const result = await submitTelemetryDataset({
|
|
577
|
+
file: requireArg(options, "file"),
|
|
578
|
+
endpoint: requireArg(options, "endpoint"),
|
|
579
|
+
});
|
|
580
|
+
if (options.json) {
|
|
581
|
+
io.log(JSON.stringify(result, null, 2));
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
io.log("Telemetry submission recorded: " + result.fileHash);
|
|
585
|
+
}
|
|
586
|
+
export async function telemetryEvalDatasetCommand(options, io) {
|
|
587
|
+
const result = await exportTelemetryEvalDataset({
|
|
588
|
+
dryRun: Boolean(options["dry-run"]),
|
|
589
|
+
});
|
|
590
|
+
if (options.json) {
|
|
591
|
+
io.log(JSON.stringify(result, null, 2));
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
io.log((result.dryRun ? "Eval dataset dry run" : "Eval dataset exported") +
|
|
595
|
+
": " +
|
|
596
|
+
result.recordCount +
|
|
597
|
+
" record(s)");
|
|
598
|
+
if (result.file) {
|
|
599
|
+
io.log("File: " + result.file);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
export async function telemetryDisableCommand(options, io) {
|
|
603
|
+
const telemetry = await disableTelemetryConsent({
|
|
604
|
+
actor: stringOption(options.actor) ?? "user",
|
|
605
|
+
});
|
|
606
|
+
if (options.json) {
|
|
607
|
+
io.log(JSON.stringify(telemetry, null, 2));
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
io.log("Telemetry disabled");
|
|
611
|
+
}
|
|
612
|
+
export async function instructionsApplyCommand(options, io) {
|
|
613
|
+
const report = await applyInstructionUpdatesFromManifest({
|
|
614
|
+
manifestPath: requireArg(options, "manifest"),
|
|
615
|
+
check: Boolean(options.check),
|
|
616
|
+
dryRun: Boolean(options["dry-run"]),
|
|
617
|
+
force: Boolean(options.force),
|
|
618
|
+
});
|
|
619
|
+
if (options.json) {
|
|
620
|
+
io.log(JSON.stringify(report, null, 2));
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
io.log("Instruction update " +
|
|
624
|
+
report.mode +
|
|
625
|
+
": " +
|
|
626
|
+
report.totals.changed +
|
|
627
|
+
" changed, " +
|
|
628
|
+
report.totals.unchanged +
|
|
629
|
+
" unchanged, " +
|
|
630
|
+
report.totals.blocked +
|
|
631
|
+
" blocked");
|
|
632
|
+
for (const item of report.items) {
|
|
633
|
+
io.log(item.status +
|
|
634
|
+
" " +
|
|
635
|
+
item.filePath +
|
|
636
|
+
"#" +
|
|
637
|
+
item.blockId +
|
|
638
|
+
" - " +
|
|
639
|
+
item.reason);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
export async function instructionsStaleCommand(options, io) {
|
|
643
|
+
const report = await detectStaleInstructionFilesFromManifest({
|
|
644
|
+
manifestPath: requireArg(options, "manifest"),
|
|
645
|
+
});
|
|
646
|
+
if (options.json) {
|
|
647
|
+
io.log(JSON.stringify(report, null, 2));
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
650
|
+
io.log("Instruction file status:");
|
|
651
|
+
for (const item of report.items) {
|
|
652
|
+
io.log(item.status +
|
|
653
|
+
" " +
|
|
654
|
+
item.filePath +
|
|
655
|
+
"#" +
|
|
656
|
+
item.blockId +
|
|
657
|
+
" - " +
|
|
658
|
+
item.reason);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
export async function instructionsBlockCommand(options, io) {
|
|
662
|
+
const result = await updateManagedInstructionFile({
|
|
663
|
+
filePath: resolveWorkspaceWritePath(process.cwd(), requireArg(options, "file")),
|
|
664
|
+
contentPath: resolveWorkspaceWritePath(process.cwd(), requireArg(options, "content-file")),
|
|
665
|
+
input: {
|
|
666
|
+
blockId: requireArg(options, "block"),
|
|
667
|
+
generator: stringOption(options.generator) ?? "open-orchestra",
|
|
668
|
+
version: stringOption(options.version) ?? "1",
|
|
669
|
+
target: parseInstructionTarget(stringOption(options.target) ?? "generic"),
|
|
670
|
+
sourceManifest: stringOption(options["source-manifest"]) ?? "local",
|
|
671
|
+
},
|
|
672
|
+
check: Boolean(options.check),
|
|
673
|
+
dryRun: Boolean(options["dry-run"]),
|
|
674
|
+
force: Boolean(options.force),
|
|
675
|
+
});
|
|
676
|
+
if (options.json) {
|
|
677
|
+
io.log(JSON.stringify(result, null, 2));
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
680
|
+
if (result.drift) {
|
|
681
|
+
io.log("Drift detected for " + requireArg(options, "block"));
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
684
|
+
io.log(result.changed
|
|
685
|
+
? "Instruction block changed"
|
|
686
|
+
: "Instruction block unchanged");
|
|
687
|
+
}
|
|
688
|
+
export async function instructionsImportsCommand(options, io) {
|
|
689
|
+
const result = await resolveInstructionImportsFromFile({
|
|
690
|
+
registryPath: requireArg(options, "registry"),
|
|
691
|
+
entryId: requireArg(options, "entry"),
|
|
692
|
+
target: parseInstructionTarget(stringOption(options.target) ?? "generic"),
|
|
693
|
+
});
|
|
694
|
+
if (options.json) {
|
|
695
|
+
io.log(JSON.stringify(result, null, 2));
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
io.log(result.content);
|
|
699
|
+
}
|
|
700
|
+
function parseInstructionTarget(value) {
|
|
701
|
+
return parseRuntimeTarget(value);
|
|
702
|
+
}
|
|
703
|
+
export async function collaborationFlowsCommand(options, io) {
|
|
704
|
+
const flows = listCollaborationFlows();
|
|
705
|
+
if (options.json) {
|
|
706
|
+
io.log(JSON.stringify(flows, null, 2));
|
|
707
|
+
return;
|
|
708
|
+
}
|
|
709
|
+
for (const flow of flows) {
|
|
710
|
+
io.log(flow.id + " - " + flow.name);
|
|
711
|
+
io.log(" roles: " + flow.roles.join(", "));
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
export async function collaborationRecommendCommand(options, io) {
|
|
715
|
+
const context = await getTaskContext(requireArg(options, "task"));
|
|
716
|
+
const recommendation = recommendCollaborationFlow(context.task, [
|
|
717
|
+
...context.decisions,
|
|
718
|
+
...context.handoffs,
|
|
719
|
+
...context.reviews,
|
|
720
|
+
...context.evidence,
|
|
721
|
+
...context.gates,
|
|
722
|
+
]);
|
|
723
|
+
if (options.json) {
|
|
724
|
+
io.log(JSON.stringify(recommendation, null, 2));
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
if (!recommendation) {
|
|
728
|
+
io.log("No collaboration flow recommended");
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
io.log(recommendation.flow.id + " - " + recommendation.flow.name);
|
|
732
|
+
io.log("Missing artifacts: " +
|
|
733
|
+
(recommendation.missingArtifacts.join(", ") || "none"));
|
|
734
|
+
io.log("Reviewers: " + (recommendation.optionalReviewers.join(", ") || "none"));
|
|
735
|
+
}
|
|
736
|
+
export async function workflowTemplatesCommand(options, io) {
|
|
737
|
+
const templates = listWorkflowTemplates();
|
|
738
|
+
const validationErrors = validateWorkflowTemplates();
|
|
739
|
+
if (options.json) {
|
|
740
|
+
io.log(JSON.stringify({ templates, validationErrors }, null, 2));
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
for (const template of templates) {
|
|
744
|
+
io.log(template.id + " - " + template.name);
|
|
745
|
+
io.log(" roles: " + template.roles.join(", "));
|
|
746
|
+
}
|
|
747
|
+
if (validationErrors.length > 0) {
|
|
748
|
+
io.log("Validation errors: " + validationErrors.join("; "));
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
export async function workflowTemplateSelectCommand(options, io) {
|
|
752
|
+
const context = await getTaskContext(requireArg(options, "task"));
|
|
753
|
+
const events = [
|
|
754
|
+
...context.decisions,
|
|
755
|
+
...context.handoffs,
|
|
756
|
+
...context.reviews,
|
|
757
|
+
...context.evidence,
|
|
758
|
+
...context.gates,
|
|
759
|
+
];
|
|
760
|
+
const selection = selectWorkflowTemplates(context.task, events);
|
|
761
|
+
if (options.json) {
|
|
762
|
+
io.log(JSON.stringify(selection, null, 2));
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
for (const item of selection) {
|
|
766
|
+
io.log(item.template.id + " (score " + item.score + ")");
|
|
767
|
+
io.log(" missing evidence: " + (item.missingEvidence.join(", ") || "none"));
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
export async function workflowTemplateRenderCommand(options, io) {
|
|
771
|
+
const context = await getTaskContext(requireArg(options, "task"));
|
|
772
|
+
const rendered = renderWorkflowTemplates({
|
|
773
|
+
task: context.task,
|
|
774
|
+
target: parseSkillRenderTarget(stringOption(options.target) ?? "generic"),
|
|
775
|
+
templates: context.workflowTemplates,
|
|
776
|
+
});
|
|
777
|
+
if (options.json) {
|
|
778
|
+
io.log(JSON.stringify(rendered, null, 2));
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
io.log(rendered.content);
|
|
782
|
+
}
|
|
783
|
+
export async function commandsManifestCommand(options, io) {
|
|
784
|
+
const manifest = listCommandManifest();
|
|
785
|
+
if (options.json) {
|
|
786
|
+
io.log(JSON.stringify(manifest, null, 2));
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
for (const command of manifest) {
|
|
790
|
+
io.log(command.command + " - " + command.summary);
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
export async function runtimeAdaptersCommand(options, io) {
|
|
794
|
+
const adapters = listRuntimeAdapters();
|
|
795
|
+
if (options.json) {
|
|
796
|
+
io.log(JSON.stringify(adapters, null, 2));
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
799
|
+
for (const adapter of adapters) {
|
|
800
|
+
io.log(adapter.target +
|
|
801
|
+
" - " +
|
|
802
|
+
adapter.label +
|
|
803
|
+
" (" +
|
|
804
|
+
adapter.defaultInstructionFiles.join(", ") +
|
|
805
|
+
")");
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
export async function runtimeBootstrapCommand(options, io) {
|
|
809
|
+
const target = parseSkillRenderTarget(stringOption(options.target) ?? "generic");
|
|
810
|
+
const bootstrap = renderRuntimeBootstrap(target);
|
|
811
|
+
const filePath = stringOption(options.file);
|
|
812
|
+
if (filePath) {
|
|
813
|
+
const resolvedFilePath = resolveWorkspaceWritePath(process.cwd(), path.normalize(filePath));
|
|
814
|
+
const existing = await readFile(resolvedFilePath, "utf8").catch(() => "");
|
|
815
|
+
const result = upsertRuntimeBootstrapBlock(existing, bootstrap, {
|
|
816
|
+
force: Boolean(options.force),
|
|
817
|
+
});
|
|
818
|
+
if (!options.check && !options["dry-run"] && !result.drift) {
|
|
819
|
+
await writeFile(resolvedFilePath, result.content);
|
|
820
|
+
}
|
|
821
|
+
if (options.json) {
|
|
822
|
+
io.log(JSON.stringify(result, null, 2));
|
|
823
|
+
return;
|
|
824
|
+
}
|
|
825
|
+
io.log(result.changed
|
|
826
|
+
? "Runtime bootstrap changed"
|
|
827
|
+
: "Runtime bootstrap unchanged");
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
if (options.json) {
|
|
831
|
+
io.log(JSON.stringify(bootstrap, null, 2));
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
io.log(bootstrap.content);
|
|
835
|
+
}
|
|
836
|
+
export async function protocolRenderCommand(options, io) {
|
|
837
|
+
const protocol = await renderSubagentProtocol(removeUndefined({
|
|
838
|
+
target: parseSkillRenderTarget(stringOption(options.target) ?? "generic"),
|
|
839
|
+
taskId: stringOption(options.task),
|
|
840
|
+
}));
|
|
841
|
+
if (options.json) {
|
|
842
|
+
io.log(JSON.stringify(protocol, null, 2));
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
io.log(protocol.content);
|
|
846
|
+
}
|
|
847
|
+
export async function protocolBlockCommand(options, io) {
|
|
848
|
+
const filePath = requireArg(options, "file");
|
|
849
|
+
const protocol = await renderSubagentProtocol(removeUndefined({
|
|
850
|
+
target: parseSkillRenderTarget(stringOption(options.target) ?? "generic"),
|
|
851
|
+
taskId: stringOption(options.task),
|
|
852
|
+
}));
|
|
853
|
+
const existing = await readFile(filePath, "utf8").catch(() => "");
|
|
854
|
+
const result = upsertSubagentProtocolBlock(existing, protocol, {
|
|
855
|
+
force: Boolean(options.force),
|
|
856
|
+
});
|
|
857
|
+
const shouldWrite = !options.check && !options["dry-run"] && !result.drift && result.changed;
|
|
858
|
+
if (shouldWrite) {
|
|
859
|
+
await writeFile(filePath, result.content);
|
|
860
|
+
}
|
|
861
|
+
if (options.json) {
|
|
862
|
+
io.log(JSON.stringify(result, null, 2));
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
if (result.drift) {
|
|
866
|
+
io.log("Drift detected for subagent protocol block");
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
io.log(result.changed
|
|
870
|
+
? "Subagent protocol block changed"
|
|
871
|
+
: "Subagent protocol block unchanged");
|
|
872
|
+
}
|
|
873
|
+
export async function diagramsLintCommand(options, io) {
|
|
874
|
+
const result = await lintMermaidDiagram({
|
|
875
|
+
filePath: requireArg(options, "file"),
|
|
876
|
+
});
|
|
877
|
+
const evidence = stringOption(options.task)
|
|
878
|
+
? await recordDiagramLintEvidence({
|
|
879
|
+
taskId: stringOption(options.task) ?? "",
|
|
880
|
+
result,
|
|
881
|
+
})
|
|
882
|
+
: undefined;
|
|
883
|
+
const output = removeUndefined({ result, evidence });
|
|
884
|
+
if (options.json) {
|
|
885
|
+
io.log(JSON.stringify(output, null, 2));
|
|
886
|
+
}
|
|
887
|
+
else {
|
|
888
|
+
io.log(result.valid ? "Mermaid diagram valid" : "Mermaid diagram invalid");
|
|
889
|
+
if (result.installHint) {
|
|
890
|
+
io.log(result.installHint);
|
|
891
|
+
}
|
|
892
|
+
if (evidence) {
|
|
893
|
+
io.log("Created " + evidence.artifact);
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
if (!result.valid) {
|
|
897
|
+
throw new Error("diagram lint failed");
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
export async function mcpOAuthProxyEvaluateCommand(options, io) {
|
|
901
|
+
const evaluation = evaluateMcpOAuthProxy(removeUndefined({
|
|
902
|
+
enabled: Boolean(options.enable),
|
|
903
|
+
mode: parseMcpProxyMode(stringOption(options.mode) ?? "stdio-proxy"),
|
|
904
|
+
serverUrl: requireArg(options, "server-url"),
|
|
905
|
+
tokenStorage: parseMcpSecretStorage(stringOption(options["token-storage"]) ?? "keychain"),
|
|
906
|
+
tokenPath: stringOption(options["token-path"]),
|
|
907
|
+
refreshWindowSeconds: Number(stringOption(options["refresh-window"]) ?? 300),
|
|
908
|
+
approvedBy: options.approve
|
|
909
|
+
? (stringOption(options.approver) ?? "local-user")
|
|
910
|
+
: undefined,
|
|
911
|
+
}));
|
|
912
|
+
if (options.json) {
|
|
913
|
+
io.log(JSON.stringify(evaluation, null, 2));
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
916
|
+
io.log(evaluation.approved
|
|
917
|
+
? "MCP proxy plan approved"
|
|
918
|
+
: "MCP proxy plan has risks");
|
|
919
|
+
for (const risk of evaluation.risks) {
|
|
920
|
+
io.log("RISK: " + risk);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
function parseMcpProxyMode(value) {
|
|
924
|
+
if (["stdio-proxy", "direct-http", "tool-native-oauth"].includes(value)) {
|
|
925
|
+
return value;
|
|
926
|
+
}
|
|
927
|
+
throw new Error("unknown MCP proxy mode: " + value);
|
|
928
|
+
}
|
|
929
|
+
function parseMcpSecretStorage(value) {
|
|
930
|
+
if (["keychain", "libsecret", "windows-credential", "secure-file"].includes(value)) {
|
|
931
|
+
return value;
|
|
932
|
+
}
|
|
933
|
+
throw new Error("unknown MCP secret storage: " + value);
|
|
934
|
+
}
|
|
935
|
+
export async function skillsValidateCommand(options, io) {
|
|
936
|
+
const report = await validateSkills();
|
|
937
|
+
if (options.json) {
|
|
938
|
+
io.log(JSON.stringify(report, null, 2));
|
|
939
|
+
}
|
|
940
|
+
else {
|
|
941
|
+
io.log(report.valid ? "Skills valid" : "Skills invalid");
|
|
942
|
+
for (const error of report.errors) {
|
|
943
|
+
io.log(`ERROR: ${error}`);
|
|
944
|
+
}
|
|
945
|
+
for (const warning of report.warnings) {
|
|
946
|
+
io.log(`WARN: ${warning}`);
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
if (!report.valid) {
|
|
950
|
+
throw new Error("skills validation failed");
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
export async function sourcesListCommand(options, io) {
|
|
954
|
+
const sources = await readSourceOfTruth();
|
|
955
|
+
if (options.json) {
|
|
956
|
+
io.log(JSON.stringify(sources, null, 2));
|
|
957
|
+
return;
|
|
958
|
+
}
|
|
959
|
+
for (const source of sources) {
|
|
960
|
+
io.log(`${source.id ?? "unknown"} - ${source.name ?? "Unnamed source"}`);
|
|
961
|
+
io.log(` ${(source.locations ?? []).join(", ")}`);
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
export async function lessonsListCommand(options, io) {
|
|
965
|
+
const lessons = await listAgentLessons();
|
|
966
|
+
if (options.json) {
|
|
967
|
+
io.log(JSON.stringify(lessons, null, 2));
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
if (lessons.length === 0) {
|
|
971
|
+
io.log("No lessons");
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
for (const lesson of lessons) {
|
|
975
|
+
io.log(`${lesson.timestamp} ${lesson.operation}: ${lesson.errorSignature}`);
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
export async function lessonsAddCommand(options, io) {
|
|
979
|
+
const lesson = await addAgentLesson(removeUndefined({
|
|
980
|
+
taskId: stringOption(options.task),
|
|
981
|
+
actor: stringOption(options.actor) ?? "parent",
|
|
982
|
+
operation: requireArg(options, "operation"),
|
|
983
|
+
failedAction: requireArg(options, "failed-action"),
|
|
984
|
+
errorSignature: requireArg(options, "error-signature"),
|
|
985
|
+
rootCause: requireArg(options, "root-cause"),
|
|
986
|
+
fix: requireArg(options, "fix"),
|
|
987
|
+
prevention: requireArg(options, "prevention"),
|
|
988
|
+
appliesTo: parseCsv(options["applies-to"]),
|
|
989
|
+
verifiedBy: parseCsv(options["verified-by"]),
|
|
990
|
+
}));
|
|
991
|
+
if (options.json) {
|
|
992
|
+
io.log(JSON.stringify(lesson, null, 2));
|
|
993
|
+
return;
|
|
994
|
+
}
|
|
995
|
+
io.log(`Recorded lesson ${lesson.errorSignature}`);
|
|
996
|
+
}
|
|
997
|
+
export async function lessonsPromoteCommand(options, io) {
|
|
998
|
+
const result = await promoteAgentLessons(removeUndefined({
|
|
999
|
+
to: parsePromotionTarget(stringOption(options.to) ?? "doc"),
|
|
1000
|
+
filter: stringOption(options.filter),
|
|
1001
|
+
}));
|
|
1002
|
+
if (options.json) {
|
|
1003
|
+
io.log(JSON.stringify(result, null, 2));
|
|
1004
|
+
return;
|
|
1005
|
+
}
|
|
1006
|
+
io.log(`Created ${result.artifact}`);
|
|
1007
|
+
io.log(`Promoted lessons: ${result.lessons.length}`);
|
|
1008
|
+
}
|
|
1009
|
+
function parsePromotionTarget(value) {
|
|
1010
|
+
if (["skill", "rule", "doc"].includes(value)) {
|
|
1011
|
+
return value;
|
|
1012
|
+
}
|
|
1013
|
+
throw new Error(`unknown promotion target: ${value}`);
|
|
1014
|
+
}
|
|
1015
|
+
export async function skillsListCommand(options, io) {
|
|
1016
|
+
const skills = listSkills();
|
|
1017
|
+
if (options.json) {
|
|
1018
|
+
io.log(JSON.stringify(skills, null, 2));
|
|
1019
|
+
return;
|
|
1020
|
+
}
|
|
1021
|
+
for (const skill of skills) {
|
|
1022
|
+
io.log(`${skill.id} - ${skill.name} (${skill.loadBudget})`);
|
|
1023
|
+
io.log(` ${skill.summary}`);
|
|
1024
|
+
io.log(` sources: ${skill.sourceGroups.join(", ")}`);
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
export async function skillsPlanCommand(options, io) {
|
|
1028
|
+
const plan = await planSkillsForTask(requireArg(options, "task"));
|
|
1029
|
+
await recordSkillPlan(plan);
|
|
1030
|
+
if (options.json) {
|
|
1031
|
+
io.log(JSON.stringify(plan, null, 2));
|
|
1032
|
+
return;
|
|
1033
|
+
}
|
|
1034
|
+
io.log(`Skills for ${plan.taskId}:`);
|
|
1035
|
+
for (const item of plan.selected) {
|
|
1036
|
+
io.log(` ${item.skill.id} (score ${item.score})`);
|
|
1037
|
+
for (const reason of item.rationale) {
|
|
1038
|
+
io.log(` - ${reason}`);
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
io.log(`Source groups: ${plan.sourceGroups.join(", ")}`);
|
|
1042
|
+
}
|
|
1043
|
+
export async function skillsRenderCommand(options, io) {
|
|
1044
|
+
const target = parseSkillRenderTarget(stringOption(options.target) ?? "generic");
|
|
1045
|
+
const rendered = await renderSkills({
|
|
1046
|
+
target,
|
|
1047
|
+
taskId: stringOption(options.task),
|
|
1048
|
+
skillIds: parseCsv(options.skills),
|
|
1049
|
+
});
|
|
1050
|
+
await recordSkillRender(rendered);
|
|
1051
|
+
if (options.json) {
|
|
1052
|
+
io.log(JSON.stringify(rendered, null, 2));
|
|
1053
|
+
return;
|
|
1054
|
+
}
|
|
1055
|
+
io.log(rendered.content);
|
|
1056
|
+
}
|
|
1057
|
+
function parseSkillRenderTarget(value) {
|
|
1058
|
+
return parseRuntimeTarget(value);
|
|
1059
|
+
}
|
|
1060
|
+
function parseRuntimeTargetOptions(options) {
|
|
1061
|
+
const targetValues = [
|
|
1062
|
+
...parseCsv(options.target),
|
|
1063
|
+
...parseCsv(options.targets),
|
|
1064
|
+
];
|
|
1065
|
+
return [...new Set(targetValues)].map((target) => parseRuntimeTarget(target));
|
|
1066
|
+
}
|
|
488
1067
|
function parseCsv(value) {
|
|
489
1068
|
if (typeof value !== "string" || value.trim() === "") {
|
|
490
1069
|
return [];
|
|
@@ -759,6 +1338,20 @@ function renderPullRequestSummaryMarkdown(summary) {
|
|
|
759
1338
|
"## Risks",
|
|
760
1339
|
...listOrNone(summary.risks),
|
|
761
1340
|
"",
|
|
1341
|
+
"## Review Routing",
|
|
1342
|
+
`- Merge blocked: ${summary.review.mergeBlocked}`,
|
|
1343
|
+
`- Required reviewers: ${summary.review.requiredReviewers.join(", ") || "none"}`,
|
|
1344
|
+
`- Missing reviewers: ${summary.review.missingReviewers.join(", ") || "none"}`,
|
|
1345
|
+
"",
|
|
1346
|
+
"## Review Checklist",
|
|
1347
|
+
...listOrNone(summary.review.checklist),
|
|
1348
|
+
"",
|
|
1349
|
+
"## Evidence Gaps",
|
|
1350
|
+
...listOrNone(summary.review.evidenceGaps),
|
|
1351
|
+
"",
|
|
1352
|
+
"## Merge Blockers",
|
|
1353
|
+
...listOrNone(summary.review.mergeBlockers),
|
|
1354
|
+
"",
|
|
762
1355
|
"## Gates",
|
|
763
1356
|
...eventLines(summary.gates),
|
|
764
1357
|
"",
|
|
@@ -784,6 +1377,34 @@ function renderPullRequestSummaryMarkdown(summary) {
|
|
|
784
1377
|
"",
|
|
785
1378
|
].join("\n");
|
|
786
1379
|
}
|
|
1380
|
+
function renderDelegationDecisionMarkdown(decision) {
|
|
1381
|
+
return [
|
|
1382
|
+
`# Delegation Decision: ${decision.taskId}`,
|
|
1383
|
+
"",
|
|
1384
|
+
`- Recommendation: ${decision.recommendation}`,
|
|
1385
|
+
`- Complexity score: ${decision.complexityScore}`,
|
|
1386
|
+
`- Urgency: ${decision.urgency}`,
|
|
1387
|
+
`- Disjoint write scopes: ${String(decision.disjointWriteScopes)}`,
|
|
1388
|
+
"",
|
|
1389
|
+
"## Rationale",
|
|
1390
|
+
...listOrNone(decision.rationale),
|
|
1391
|
+
"",
|
|
1392
|
+
"## Blocking Conditions",
|
|
1393
|
+
...listOrNone(decision.blockingConditions),
|
|
1394
|
+
"",
|
|
1395
|
+
"## Context Bundle",
|
|
1396
|
+
...listOrNone(decision.contextBundle),
|
|
1397
|
+
"",
|
|
1398
|
+
"## Delegates",
|
|
1399
|
+
...(decision.delegates.length === 0
|
|
1400
|
+
? ["- none"]
|
|
1401
|
+
: decision.delegates.map((delegate) => `- ${delegate.role} [${delegate.mode}] scopes=${delegate.writeScopes.join(",") || "none"}`)),
|
|
1402
|
+
"",
|
|
1403
|
+
"## Expected Outputs",
|
|
1404
|
+
...listOrNone(decision.expectedOutputs),
|
|
1405
|
+
"",
|
|
1406
|
+
].join("\n");
|
|
1407
|
+
}
|
|
787
1408
|
function renderTaskContextMarkdown(context) {
|
|
788
1409
|
return [
|
|
789
1410
|
`# Task Context: ${context.task.id}`,
|
|
@@ -794,6 +1415,27 @@ function renderTaskContextMarkdown(context) {
|
|
|
794
1415
|
`- Dependencies: ${context.dependencies.isSatisfied ? "satisfied" : "blocked"}`,
|
|
795
1416
|
`- Locks: ${context.locks.length}`,
|
|
796
1417
|
`- Risks: ${context.risks.length}`,
|
|
1418
|
+
`- Delegation: ${context.delegation?.recommendation ?? "not decided"}`,
|
|
1419
|
+
"",
|
|
1420
|
+
"## Collaboration Flow",
|
|
1421
|
+
...(context.collaborationFlow
|
|
1422
|
+
? [
|
|
1423
|
+
`- ${context.collaborationFlow.flow.id}: ${context.collaborationFlow.flow.name}`,
|
|
1424
|
+
`- Missing artifacts: ${context.collaborationFlow.missingArtifacts.join(", ") || "none"}`,
|
|
1425
|
+
`- Reviewers: ${context.collaborationFlow.optionalReviewers.join(", ") || "none"}`,
|
|
1426
|
+
]
|
|
1427
|
+
: ["- none"]),
|
|
1428
|
+
"",
|
|
1429
|
+
"## Workflow Templates",
|
|
1430
|
+
...(context.workflowTemplates.length === 0
|
|
1431
|
+
? ["- none"]
|
|
1432
|
+
: context.workflowTemplates.map((item) => `- ${item.template.id} (score ${item.score}, missing evidence ${item.missingEvidence.join(", ") || "none"})`)),
|
|
1433
|
+
"",
|
|
1434
|
+
"## Skills",
|
|
1435
|
+
...(context.skills.selected.length === 0
|
|
1436
|
+
? ["- none"]
|
|
1437
|
+
: context.skills.selected.map((item) => `- ${item.skill.id} (score ${item.score}): ${item.rationale.join("; ")}`)),
|
|
1438
|
+
`- Source groups: ${context.skills.sourceGroups.join(", ") || "none"}`,
|
|
797
1439
|
"",
|
|
798
1440
|
"## Decisions",
|
|
799
1441
|
...eventLines(context.decisions),
|