@jterrats/open-orchestra 0.4.0 → 0.4.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 +21 -0
- package/dist/autonomous-phase-lifecycle.d.ts +25 -0
- package/dist/autonomous-phase-lifecycle.js +194 -0
- package/dist/autonomous-phase-lifecycle.js.map +1 -0
- package/dist/autonomous-run-state.d.ts +6 -0
- package/dist/autonomous-run-state.js +91 -0
- package/dist/autonomous-run-state.js.map +1 -0
- package/dist/autonomous-run-store.d.ts +12 -0
- package/dist/autonomous-run-store.js +64 -0
- package/dist/autonomous-run-store.js.map +1 -0
- package/dist/autonomous-workflow-constants.d.ts +6 -0
- package/dist/autonomous-workflow-constants.js +36 -0
- package/dist/autonomous-workflow-constants.js.map +1 -0
- package/dist/autonomous-workflow.d.ts +6 -45
- package/dist/autonomous-workflow.js +4 -394
- package/dist/autonomous-workflow.js.map +1 -1
- package/dist/cli.js +13 -1
- package/dist/cli.js.map +1 -1
- package/dist/command-utils.d.ts +6 -0
- package/dist/command-utils.js +19 -0
- package/dist/command-utils.js.map +1 -0
- package/dist/commands.d.ts +8 -43
- package/dist/commands.js +13 -868
- package/dist/commands.js.map +1 -1
- package/dist/constants.js +9 -0
- package/dist/constants.js.map +1 -1
- package/dist/defaults.d.ts +11 -0
- package/dist/defaults.js +11 -0
- package/dist/defaults.js.map +1 -1
- package/dist/instruction-commands.d.ts +5 -0
- package/dist/instruction-commands.js +98 -0
- package/dist/instruction-commands.js.map +1 -0
- package/dist/metrics-commands.d.ts +3 -0
- package/dist/metrics-commands.js +114 -0
- package/dist/metrics-commands.js.map +1 -0
- package/dist/model-commands.d.ts +13 -0
- package/dist/model-commands.js +199 -0
- package/dist/model-commands.js.map +1 -0
- package/dist/runtime-adapters.d.ts +5 -1
- package/dist/runtime-adapters.js +27 -0
- package/dist/runtime-adapters.js.map +1 -1
- package/dist/runtime-commands.d.ts +9 -0
- package/dist/runtime-commands.js +156 -0
- package/dist/runtime-commands.js.map +1 -0
- package/dist/runtime-execution-adapters.d.ts +2 -0
- package/dist/runtime-execution-adapters.js +163 -0
- package/dist/runtime-execution-adapters.js.map +1 -0
- package/dist/runtime-execution-renderer.d.ts +10 -0
- package/dist/runtime-execution-renderer.js +110 -0
- package/dist/runtime-execution-renderer.js.map +1 -0
- package/dist/runtime-execution.d.ts +27 -0
- package/dist/runtime-execution.js +147 -0
- package/dist/runtime-execution.js.map +1 -0
- package/dist/skills-commands.d.ts +9 -0
- package/dist/skills-commands.js +130 -0
- package/dist/skills-commands.js.map +1 -0
- package/dist/sprint-commands.d.ts +5 -0
- package/dist/sprint-commands.js +120 -0
- package/dist/sprint-commands.js.map +1 -0
- package/dist/telemetry-commands.d.ts +7 -0
- package/dist/telemetry-commands.js +82 -0
- package/dist/telemetry-commands.js.map +1 -0
- package/dist/tool-commands.d.ts +3 -0
- package/dist/tool-commands.js +67 -0
- package/dist/tool-commands.js.map +1 -0
- package/dist/types.d.ts +79 -0
- package/dist/types.js.map +1 -1
- package/docs/runtime-llm-flow.md +46 -0
- package/package.json +1 -1
package/dist/commands.js
CHANGED
|
@@ -1,31 +1,23 @@
|
|
|
1
|
-
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
1
|
import { initWorkspace } from "./workspace.js";
|
|
4
2
|
import { requireArg } from "./args.js";
|
|
5
3
|
import { AUTONOMOUS_PHASE_SEQUENCE, autonomousRunsPath, checkArchitectSizing, closePhase, createAutonomousRun, initPhase, listAutonomousRuns, markRunDone, markRunFailed, readAutonomousRun, resumePhaseIndex, suspendPhaseForClarification, resumePhaseFromClarification, } from "./autonomous-workflow.js";
|
|
6
4
|
import { listClarifications, openClarification, answerClarification, } from "./clarification.js";
|
|
7
|
-
import { computeBenchmark, computeVelocity, recordEstimate, summarizeBenchmark, } from "./benchmark.js";
|
|
8
|
-
import { computeSprintBurndown, renderBurndownAscii } from "./burndown.js";
|
|
9
|
-
import { calibrationReport, closeSprint, startSprint, velocityTrend, } from "./sprint-metrics.js";
|
|
10
5
|
import { executePhaseWithLlm } from "./phase-executor.js";
|
|
11
|
-
import {
|
|
12
|
-
import { resolveWorkspaceWritePath } from "./fs-utils.js";
|
|
13
|
-
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";
|
|
6
|
+
import { addEvidence, addPlaywrightEvidence, addTask, checkReadiness, checkTaskDependencies, claimLock, createHandoff, evaluateWorkflowGate, executeNextReadyTask, executePlanWithBudgetPreflight, executeReadyTaskBatch, generateExecutionPlan, generatePlaywrightTestPlan, generatePullRequestSummary, generateTaskGraphPlan, getWorkflowStatus, getWorkflowSummary, getTaskContext, getWorkflowConfig, listEvidence, listDecisions, listLocks, listReviews, listRoles, listTasks, recordReview, recordDecision, releaseLock, updateTask, } from "./workflow-services.js";
|
|
14
7
|
import { validateWorkspace } from "./workspace-validator.js";
|
|
15
|
-
import { addAgentLesson, listAgentLessons, listSkills, planSkillsForTask, promoteAgentLessons, readSourceOfTruth, recordSkillPlan, recordSkillRender, renderSkills, validateSkills, } from "./skills.js";
|
|
16
8
|
import { getWebServerAddress, startWebApiServer } from "./web-api.js";
|
|
17
9
|
import { decideTaskDelegation } from "./delegation-decision.js";
|
|
18
|
-
import { lintMermaidDiagram, recordDiagramLintEvidence, } from "./diagram-validation.js";
|
|
19
|
-
import { evaluateMcpOAuthProxy, } from "./mcp-oauth-proxy.js";
|
|
20
|
-
import { detectStaleInstructionFilesFromManifest, resolveInstructionImportsFromFile, updateManagedInstructionFile, } from "./instruction-updates.js";
|
|
21
|
-
import { applyInstructionUpdatesFromManifest } from "./instruction-apply.js";
|
|
22
|
-
import { renderSubagentProtocol, upsertSubagentProtocolBlock, } from "./subagent-protocol.js";
|
|
23
10
|
import { listCollaborationFlows, recommendCollaborationFlow, } from "./collaboration-flows.js";
|
|
24
11
|
import { listWorkflowTemplates, renderWorkflowTemplates, selectWorkflowTemplates, validateWorkflowTemplates, } from "./workflow-templates.js";
|
|
25
|
-
import {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
12
|
+
import { parseRuntimeTarget } from "./runtime-adapters.js";
|
|
13
|
+
export { instructionsApplyCommand, instructionsBlockCommand, instructionsImportsCommand, instructionsStaleCommand, } from "./instruction-commands.js";
|
|
14
|
+
export { benchmarkCommand, estimateCommand } from "./metrics-commands.js";
|
|
15
|
+
export { burndownCommand, calibrationCommand, sprintCommand, velocityCommand, } from "./sprint-commands.js";
|
|
16
|
+
export { approvalsApproveCommand, approvalsListCommand, approvalsRejectCommand, approvalsShowCommand, budgetCheckCommand, configShowCommand, modelCompleteFakeCommand, modelProvidersCommand, modelProvenanceAddCommand, modelProvenanceListCommand, modelSetRoleCommand, usageCommand, } from "./model-commands.js";
|
|
17
|
+
export { commandsManifestCommand, protocolBlockCommand, protocolRenderCommand, runtimeAdaptersCommand, runtimeBootstrapCommand, runtimeBriefCommand, runtimeDelegatePlanCommand, runtimeHandoffCommand, } from "./runtime-commands.js";
|
|
18
|
+
export { lessonsAddCommand, lessonsListCommand, lessonsPromoteCommand, skillsListCommand, skillsPlanCommand, skillsRenderCommand, skillsValidateCommand, sourcesListCommand, } from "./skills-commands.js";
|
|
19
|
+
export { diagramsLintCommand, mcpOAuthProxyEvaluateCommand, } from "./tool-commands.js";
|
|
20
|
+
export { telemetryDisableCommand, telemetryEnableCommand, telemetryEvalDatasetCommand, telemetryExportCommand, telemetryStatusCommand, telemetrySubmitCommand, } from "./telemetry-commands.js";
|
|
29
21
|
import { buildPrBody, createPullRequest } from "./github.js";
|
|
30
22
|
export async function initCommand(options, io) {
|
|
31
23
|
const root = stringOption(options["target-dir"]) ?? process.cwd();
|
|
@@ -349,56 +341,6 @@ export async function summaryCommand(options, io) {
|
|
|
349
341
|
}
|
|
350
342
|
io.log(renderSummaryMarkdown(summary));
|
|
351
343
|
}
|
|
352
|
-
export async function usageCommand(options, io) {
|
|
353
|
-
const report = await getUsageReport(stringOption(options.task));
|
|
354
|
-
if (options.json) {
|
|
355
|
-
io.log(JSON.stringify(report, null, 2));
|
|
356
|
-
return;
|
|
357
|
-
}
|
|
358
|
-
io.log(renderUsageReport(report));
|
|
359
|
-
}
|
|
360
|
-
export async function budgetCheckCommand(options, io) {
|
|
361
|
-
const result = await checkUsageBudget(stringOption(options.task));
|
|
362
|
-
if (options.json) {
|
|
363
|
-
io.log(JSON.stringify(result, null, 2));
|
|
364
|
-
}
|
|
365
|
-
else {
|
|
366
|
-
io.log(renderBudgetCheck(result));
|
|
367
|
-
}
|
|
368
|
-
if (!result.passed) {
|
|
369
|
-
throw new Error("budget check failed");
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
export async function approvalsListCommand(options, io) {
|
|
373
|
-
const approvals = await listApprovals(stringOption(options.task));
|
|
374
|
-
if (options.json) {
|
|
375
|
-
io.log(JSON.stringify(approvals, null, 2));
|
|
376
|
-
return;
|
|
377
|
-
}
|
|
378
|
-
if (approvals.length === 0) {
|
|
379
|
-
io.log("No approvals");
|
|
380
|
-
return;
|
|
381
|
-
}
|
|
382
|
-
for (const approval of approvals) {
|
|
383
|
-
io.log(`${approval.id} [${approval.status}] ${approval.taskId ?? "no-task"} ${approval.artifact}`);
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
export async function approvalsShowCommand(options, io) {
|
|
387
|
-
const approval = await showApproval(requireArg(options, "id"));
|
|
388
|
-
if (options.json) {
|
|
389
|
-
io.log(JSON.stringify(approval, null, 2));
|
|
390
|
-
return;
|
|
391
|
-
}
|
|
392
|
-
io.log(approval.content);
|
|
393
|
-
}
|
|
394
|
-
export async function approvalsApproveCommand(options, io) {
|
|
395
|
-
const approval = await approveApproval(parseApprovalDecision(options));
|
|
396
|
-
io.log(`Approved ${approval.id}`);
|
|
397
|
-
}
|
|
398
|
-
export async function approvalsRejectCommand(options, io) {
|
|
399
|
-
const approval = await rejectApproval(parseApprovalDecision(options));
|
|
400
|
-
io.log(`Rejected ${approval.id}`);
|
|
401
|
-
}
|
|
402
344
|
export async function prSummaryCommand(options, io) {
|
|
403
345
|
const summary = await generatePullRequestSummary(requireArg(options, "task"));
|
|
404
346
|
if (options.json) {
|
|
@@ -460,254 +402,6 @@ export async function playwrightEvidenceCommand(options, io) {
|
|
|
460
402
|
}));
|
|
461
403
|
io.log(`Created ${artifact}`);
|
|
462
404
|
}
|
|
463
|
-
export async function configShowCommand(options, io) {
|
|
464
|
-
const config = await getWorkflowConfig();
|
|
465
|
-
if (options.json) {
|
|
466
|
-
io.log(JSON.stringify(config, null, 2));
|
|
467
|
-
return;
|
|
468
|
-
}
|
|
469
|
-
io.log(`Tools: ${Object.keys(config.tools ?? {}).length}`);
|
|
470
|
-
io.log(`Role routes: ${Object.keys(config.providers?.byRole ?? {}).length}`);
|
|
471
|
-
}
|
|
472
|
-
export async function modelProvidersCommand(options, io) {
|
|
473
|
-
const providers = await listConfiguredModelProviders();
|
|
474
|
-
if (options.json) {
|
|
475
|
-
io.log(JSON.stringify(providers, null, 2));
|
|
476
|
-
return;
|
|
477
|
-
}
|
|
478
|
-
if (providers.length === 0) {
|
|
479
|
-
io.log("No configured model providers");
|
|
480
|
-
return;
|
|
481
|
-
}
|
|
482
|
-
for (const provider of providers) {
|
|
483
|
-
io.log(`${provider.scope}: ${provider.provider}/${provider.model} (${provider.timeoutMs}ms)`);
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
export async function modelSetRoleCommand(options, io) {
|
|
487
|
-
const role = requireArg(options, "role");
|
|
488
|
-
const routing = parseProviderRouting(options);
|
|
489
|
-
await setRoleModelProvider(role, routing);
|
|
490
|
-
io.log(`Configured model provider for ${role}`);
|
|
491
|
-
}
|
|
492
|
-
export async function modelProvenanceAddCommand(options, io) {
|
|
493
|
-
const record = await recordModelProvenance({
|
|
494
|
-
task: requireArg(options, "task"),
|
|
495
|
-
role: requireArg(options, "role"),
|
|
496
|
-
provider: requireArg(options, "provider"),
|
|
497
|
-
model: requireArg(options, "model"),
|
|
498
|
-
promptId: requireArg(options, "prompt-id"),
|
|
499
|
-
responseId: requireArg(options, "response-id"),
|
|
500
|
-
inputTokens: numberOption(options["input-tokens"], 0),
|
|
501
|
-
outputTokens: numberOption(options["output-tokens"], 0),
|
|
502
|
-
estimatedCostUsd: numberOption(options["estimated-cost-usd"], 0),
|
|
503
|
-
finishReason: requireArg(options, "finish-reason"),
|
|
504
|
-
});
|
|
505
|
-
io.log(`Recorded model provenance ${record.responseId}`);
|
|
506
|
-
}
|
|
507
|
-
export async function modelProvenanceListCommand(options, io) {
|
|
508
|
-
const records = await listModelProvenance(stringOption(options.task));
|
|
509
|
-
if (options.json) {
|
|
510
|
-
io.log(JSON.stringify(records, null, 2));
|
|
511
|
-
return;
|
|
512
|
-
}
|
|
513
|
-
if (records.length === 0) {
|
|
514
|
-
io.log("No model provenance");
|
|
515
|
-
return;
|
|
516
|
-
}
|
|
517
|
-
for (const record of records) {
|
|
518
|
-
io.log(`${record.task} ${record.role} ${record.provider}/${record.model} ${record.responseId}`);
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
export async function modelCompleteFakeCommand(options, io) {
|
|
522
|
-
const result = await completeWithProviderFallback({
|
|
523
|
-
provider: requireArg(options, "provider"),
|
|
524
|
-
model: requireArg(options, "model"),
|
|
525
|
-
fallbacks: parseCsv(options.fallbacks),
|
|
526
|
-
maxTokens: 0,
|
|
527
|
-
maxCostUsd: 0,
|
|
528
|
-
timeoutMs: 30000,
|
|
529
|
-
retries: 0,
|
|
530
|
-
requiredCapabilities: [],
|
|
531
|
-
}, requireArg(options, "prompt"), removeUndefined({
|
|
532
|
-
failingProviders: parseCsv(options["fail-provider"]),
|
|
533
|
-
taskId: stringOption(options.task),
|
|
534
|
-
role: stringOption(options.role) ?? "parent",
|
|
535
|
-
}));
|
|
536
|
-
if (options.json) {
|
|
537
|
-
io.log(JSON.stringify(result, null, 2));
|
|
538
|
-
return;
|
|
539
|
-
}
|
|
540
|
-
io.log(`Fake completion used ${result.provider}/${result.model} fallback=${String(result.fallbackUsed)}`);
|
|
541
|
-
}
|
|
542
|
-
export async function telemetryStatusCommand(options, io) {
|
|
543
|
-
const telemetry = await getTelemetryConsent();
|
|
544
|
-
if (options.json) {
|
|
545
|
-
io.log(JSON.stringify(telemetry, null, 2));
|
|
546
|
-
return;
|
|
547
|
-
}
|
|
548
|
-
io.log("Telemetry: " + (telemetry.enabled ? "enabled" : "off"));
|
|
549
|
-
io.log("Level: " + telemetry.level);
|
|
550
|
-
io.log("Policy: " + telemetry.policyVersion);
|
|
551
|
-
}
|
|
552
|
-
export async function telemetryEnableCommand(options, io) {
|
|
553
|
-
const level = parseTelemetryLevel(stringOption(options.level) ?? "metadata");
|
|
554
|
-
if (requiresSensitiveTelemetryOptIn(level) && !options["confirm-sensitive"]) {
|
|
555
|
-
throw new Error("prompt-sample and eval-dataset telemetry require --confirm-sensitive");
|
|
556
|
-
}
|
|
557
|
-
const telemetry = await enableTelemetryConsent({
|
|
558
|
-
level,
|
|
559
|
-
actor: stringOption(options.actor) ?? "user",
|
|
560
|
-
});
|
|
561
|
-
if (options.json) {
|
|
562
|
-
io.log(JSON.stringify(telemetry, null, 2));
|
|
563
|
-
return;
|
|
564
|
-
}
|
|
565
|
-
io.log("Telemetry enabled at level " + telemetry.level);
|
|
566
|
-
}
|
|
567
|
-
export async function telemetryExportCommand(options, io) {
|
|
568
|
-
const result = await exportTelemetryDataset({
|
|
569
|
-
dryRun: Boolean(options["dry-run"]),
|
|
570
|
-
});
|
|
571
|
-
if (options.json) {
|
|
572
|
-
io.log(JSON.stringify(result, null, 2));
|
|
573
|
-
return;
|
|
574
|
-
}
|
|
575
|
-
io.log((result.dryRun ? "Telemetry export dry run" : "Telemetry exported") +
|
|
576
|
-
": " +
|
|
577
|
-
result.recordCount +
|
|
578
|
-
" record(s)");
|
|
579
|
-
if (result.file) {
|
|
580
|
-
io.log("File: " + result.file);
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
export async function telemetrySubmitCommand(options, io) {
|
|
584
|
-
const result = await submitTelemetryDataset({
|
|
585
|
-
file: requireArg(options, "file"),
|
|
586
|
-
endpoint: requireArg(options, "endpoint"),
|
|
587
|
-
});
|
|
588
|
-
if (options.json) {
|
|
589
|
-
io.log(JSON.stringify(result, null, 2));
|
|
590
|
-
return;
|
|
591
|
-
}
|
|
592
|
-
io.log("Telemetry submission recorded: " + result.fileHash);
|
|
593
|
-
}
|
|
594
|
-
export async function telemetryEvalDatasetCommand(options, io) {
|
|
595
|
-
const result = await exportTelemetryEvalDataset({
|
|
596
|
-
dryRun: Boolean(options["dry-run"]),
|
|
597
|
-
});
|
|
598
|
-
if (options.json) {
|
|
599
|
-
io.log(JSON.stringify(result, null, 2));
|
|
600
|
-
return;
|
|
601
|
-
}
|
|
602
|
-
io.log((result.dryRun ? "Eval dataset dry run" : "Eval dataset exported") +
|
|
603
|
-
": " +
|
|
604
|
-
result.recordCount +
|
|
605
|
-
" record(s)");
|
|
606
|
-
if (result.file) {
|
|
607
|
-
io.log("File: " + result.file);
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
export async function telemetryDisableCommand(options, io) {
|
|
611
|
-
const telemetry = await disableTelemetryConsent({
|
|
612
|
-
actor: stringOption(options.actor) ?? "user",
|
|
613
|
-
});
|
|
614
|
-
if (options.json) {
|
|
615
|
-
io.log(JSON.stringify(telemetry, null, 2));
|
|
616
|
-
return;
|
|
617
|
-
}
|
|
618
|
-
io.log("Telemetry disabled");
|
|
619
|
-
}
|
|
620
|
-
export async function instructionsApplyCommand(options, io) {
|
|
621
|
-
const report = await applyInstructionUpdatesFromManifest({
|
|
622
|
-
manifestPath: requireArg(options, "manifest"),
|
|
623
|
-
check: Boolean(options.check),
|
|
624
|
-
dryRun: Boolean(options["dry-run"]),
|
|
625
|
-
force: Boolean(options.force),
|
|
626
|
-
});
|
|
627
|
-
if (options.json) {
|
|
628
|
-
io.log(JSON.stringify(report, null, 2));
|
|
629
|
-
return;
|
|
630
|
-
}
|
|
631
|
-
io.log("Instruction update " +
|
|
632
|
-
report.mode +
|
|
633
|
-
": " +
|
|
634
|
-
report.totals.changed +
|
|
635
|
-
" changed, " +
|
|
636
|
-
report.totals.unchanged +
|
|
637
|
-
" unchanged, " +
|
|
638
|
-
report.totals.blocked +
|
|
639
|
-
" blocked");
|
|
640
|
-
for (const item of report.items) {
|
|
641
|
-
io.log(item.status +
|
|
642
|
-
" " +
|
|
643
|
-
item.filePath +
|
|
644
|
-
"#" +
|
|
645
|
-
item.blockId +
|
|
646
|
-
" - " +
|
|
647
|
-
item.reason);
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
export async function instructionsStaleCommand(options, io) {
|
|
651
|
-
const report = await detectStaleInstructionFilesFromManifest({
|
|
652
|
-
manifestPath: requireArg(options, "manifest"),
|
|
653
|
-
});
|
|
654
|
-
if (options.json) {
|
|
655
|
-
io.log(JSON.stringify(report, null, 2));
|
|
656
|
-
return;
|
|
657
|
-
}
|
|
658
|
-
io.log("Instruction file status:");
|
|
659
|
-
for (const item of report.items) {
|
|
660
|
-
io.log(item.status +
|
|
661
|
-
" " +
|
|
662
|
-
item.filePath +
|
|
663
|
-
"#" +
|
|
664
|
-
item.blockId +
|
|
665
|
-
" - " +
|
|
666
|
-
item.reason);
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
export async function instructionsBlockCommand(options, io) {
|
|
670
|
-
const result = await updateManagedInstructionFile({
|
|
671
|
-
filePath: resolveWorkspaceWritePath(process.cwd(), requireArg(options, "file")),
|
|
672
|
-
contentPath: resolveWorkspaceWritePath(process.cwd(), requireArg(options, "content-file")),
|
|
673
|
-
input: {
|
|
674
|
-
blockId: requireArg(options, "block"),
|
|
675
|
-
generator: stringOption(options.generator) ?? "open-orchestra",
|
|
676
|
-
version: stringOption(options.version) ?? "1",
|
|
677
|
-
target: parseInstructionTarget(stringOption(options.target) ?? "generic"),
|
|
678
|
-
sourceManifest: stringOption(options["source-manifest"]) ?? "local",
|
|
679
|
-
},
|
|
680
|
-
check: Boolean(options.check),
|
|
681
|
-
dryRun: Boolean(options["dry-run"]),
|
|
682
|
-
force: Boolean(options.force),
|
|
683
|
-
});
|
|
684
|
-
if (options.json) {
|
|
685
|
-
io.log(JSON.stringify(result, null, 2));
|
|
686
|
-
return;
|
|
687
|
-
}
|
|
688
|
-
if (result.drift) {
|
|
689
|
-
io.log("Drift detected for " + requireArg(options, "block"));
|
|
690
|
-
return;
|
|
691
|
-
}
|
|
692
|
-
io.log(result.changed
|
|
693
|
-
? "Instruction block changed"
|
|
694
|
-
: "Instruction block unchanged");
|
|
695
|
-
}
|
|
696
|
-
export async function instructionsImportsCommand(options, io) {
|
|
697
|
-
const result = await resolveInstructionImportsFromFile({
|
|
698
|
-
registryPath: requireArg(options, "registry"),
|
|
699
|
-
entryId: requireArg(options, "entry"),
|
|
700
|
-
target: parseInstructionTarget(stringOption(options.target) ?? "generic"),
|
|
701
|
-
});
|
|
702
|
-
if (options.json) {
|
|
703
|
-
io.log(JSON.stringify(result, null, 2));
|
|
704
|
-
return;
|
|
705
|
-
}
|
|
706
|
-
io.log(result.content);
|
|
707
|
-
}
|
|
708
|
-
function parseInstructionTarget(value) {
|
|
709
|
-
return parseRuntimeTarget(value);
|
|
710
|
-
}
|
|
711
405
|
export async function collaborationFlowsCommand(options, io) {
|
|
712
406
|
const flows = listCollaborationFlows();
|
|
713
407
|
if (options.json) {
|
|
@@ -788,283 +482,6 @@ export async function workflowTemplateRenderCommand(options, io) {
|
|
|
788
482
|
}
|
|
789
483
|
io.log(rendered.content);
|
|
790
484
|
}
|
|
791
|
-
export async function commandsManifestCommand(options, io) {
|
|
792
|
-
const manifest = listCommandManifest();
|
|
793
|
-
if (options.json) {
|
|
794
|
-
io.log(JSON.stringify(manifest, null, 2));
|
|
795
|
-
return;
|
|
796
|
-
}
|
|
797
|
-
for (const command of manifest) {
|
|
798
|
-
io.log(command.command + " - " + command.summary);
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
|
-
export async function runtimeAdaptersCommand(options, io) {
|
|
802
|
-
const adapters = listRuntimeAdapters();
|
|
803
|
-
if (options.json) {
|
|
804
|
-
io.log(JSON.stringify(adapters, null, 2));
|
|
805
|
-
return;
|
|
806
|
-
}
|
|
807
|
-
for (const adapter of adapters) {
|
|
808
|
-
io.log(adapter.target +
|
|
809
|
-
" - " +
|
|
810
|
-
adapter.label +
|
|
811
|
-
" (" +
|
|
812
|
-
adapter.defaultInstructionFiles.join(", ") +
|
|
813
|
-
")");
|
|
814
|
-
}
|
|
815
|
-
}
|
|
816
|
-
export async function runtimeBootstrapCommand(options, io) {
|
|
817
|
-
const target = parseSkillRenderTarget(stringOption(options.target) ?? "generic");
|
|
818
|
-
const bootstrap = renderRuntimeBootstrap(target);
|
|
819
|
-
const filePath = stringOption(options.file);
|
|
820
|
-
if (filePath) {
|
|
821
|
-
const resolvedFilePath = resolveWorkspaceWritePath(process.cwd(), path.normalize(filePath));
|
|
822
|
-
const existing = await readFile(resolvedFilePath, "utf8").catch(() => "");
|
|
823
|
-
const result = upsertRuntimeBootstrapBlock(existing, bootstrap, {
|
|
824
|
-
force: Boolean(options.force),
|
|
825
|
-
});
|
|
826
|
-
if (!options.check && !options["dry-run"] && !result.drift) {
|
|
827
|
-
await writeFile(resolvedFilePath, result.content);
|
|
828
|
-
}
|
|
829
|
-
if (options.json) {
|
|
830
|
-
io.log(JSON.stringify(result, null, 2));
|
|
831
|
-
return;
|
|
832
|
-
}
|
|
833
|
-
io.log(result.changed
|
|
834
|
-
? "Runtime bootstrap changed"
|
|
835
|
-
: "Runtime bootstrap unchanged");
|
|
836
|
-
return;
|
|
837
|
-
}
|
|
838
|
-
if (options.json) {
|
|
839
|
-
io.log(JSON.stringify(bootstrap, null, 2));
|
|
840
|
-
return;
|
|
841
|
-
}
|
|
842
|
-
io.log(bootstrap.content);
|
|
843
|
-
}
|
|
844
|
-
export async function protocolRenderCommand(options, io) {
|
|
845
|
-
const protocol = await renderSubagentProtocol(removeUndefined({
|
|
846
|
-
target: parseSkillRenderTarget(stringOption(options.target) ?? "generic"),
|
|
847
|
-
taskId: stringOption(options.task),
|
|
848
|
-
}));
|
|
849
|
-
if (options.json) {
|
|
850
|
-
io.log(JSON.stringify(protocol, null, 2));
|
|
851
|
-
return;
|
|
852
|
-
}
|
|
853
|
-
io.log(protocol.content);
|
|
854
|
-
}
|
|
855
|
-
export async function protocolBlockCommand(options, io) {
|
|
856
|
-
const filePath = requireArg(options, "file");
|
|
857
|
-
const protocol = await renderSubagentProtocol(removeUndefined({
|
|
858
|
-
target: parseSkillRenderTarget(stringOption(options.target) ?? "generic"),
|
|
859
|
-
taskId: stringOption(options.task),
|
|
860
|
-
}));
|
|
861
|
-
const existing = await readFile(filePath, "utf8").catch(() => "");
|
|
862
|
-
const result = upsertSubagentProtocolBlock(existing, protocol, {
|
|
863
|
-
force: Boolean(options.force),
|
|
864
|
-
});
|
|
865
|
-
const shouldWrite = !options.check && !options["dry-run"] && !result.drift && result.changed;
|
|
866
|
-
if (shouldWrite) {
|
|
867
|
-
await writeFile(filePath, result.content);
|
|
868
|
-
}
|
|
869
|
-
if (options.json) {
|
|
870
|
-
io.log(JSON.stringify(result, null, 2));
|
|
871
|
-
return;
|
|
872
|
-
}
|
|
873
|
-
if (result.drift) {
|
|
874
|
-
io.log("Drift detected for subagent protocol block");
|
|
875
|
-
return;
|
|
876
|
-
}
|
|
877
|
-
io.log(result.changed
|
|
878
|
-
? "Subagent protocol block changed"
|
|
879
|
-
: "Subagent protocol block unchanged");
|
|
880
|
-
}
|
|
881
|
-
export async function diagramsLintCommand(options, io) {
|
|
882
|
-
const result = await lintMermaidDiagram({
|
|
883
|
-
filePath: requireArg(options, "file"),
|
|
884
|
-
});
|
|
885
|
-
const evidence = stringOption(options.task)
|
|
886
|
-
? await recordDiagramLintEvidence({
|
|
887
|
-
taskId: stringOption(options.task) ?? "",
|
|
888
|
-
result,
|
|
889
|
-
})
|
|
890
|
-
: undefined;
|
|
891
|
-
const output = removeUndefined({ result, evidence });
|
|
892
|
-
if (options.json) {
|
|
893
|
-
io.log(JSON.stringify(output, null, 2));
|
|
894
|
-
}
|
|
895
|
-
else {
|
|
896
|
-
io.log(result.valid ? "Mermaid diagram valid" : "Mermaid diagram invalid");
|
|
897
|
-
if (result.installHint) {
|
|
898
|
-
io.log(result.installHint);
|
|
899
|
-
}
|
|
900
|
-
if (evidence) {
|
|
901
|
-
io.log("Created " + evidence.artifact);
|
|
902
|
-
}
|
|
903
|
-
}
|
|
904
|
-
if (!result.valid) {
|
|
905
|
-
throw new Error("diagram lint failed");
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
export async function mcpOAuthProxyEvaluateCommand(options, io) {
|
|
909
|
-
const evaluation = evaluateMcpOAuthProxy(removeUndefined({
|
|
910
|
-
enabled: Boolean(options.enable),
|
|
911
|
-
mode: parseMcpProxyMode(stringOption(options.mode) ?? "stdio-proxy"),
|
|
912
|
-
serverUrl: requireArg(options, "server-url"),
|
|
913
|
-
tokenStorage: parseMcpSecretStorage(stringOption(options["token-storage"]) ?? "keychain"),
|
|
914
|
-
tokenPath: stringOption(options["token-path"]),
|
|
915
|
-
refreshWindowSeconds: Number(stringOption(options["refresh-window"]) ?? 300),
|
|
916
|
-
approvedBy: options.approve
|
|
917
|
-
? (stringOption(options.approver) ?? "local-user")
|
|
918
|
-
: undefined,
|
|
919
|
-
}));
|
|
920
|
-
if (options.json) {
|
|
921
|
-
io.log(JSON.stringify(evaluation, null, 2));
|
|
922
|
-
return;
|
|
923
|
-
}
|
|
924
|
-
io.log(evaluation.approved
|
|
925
|
-
? "MCP proxy plan approved"
|
|
926
|
-
: "MCP proxy plan has risks");
|
|
927
|
-
for (const risk of evaluation.risks) {
|
|
928
|
-
io.log("RISK: " + risk);
|
|
929
|
-
}
|
|
930
|
-
}
|
|
931
|
-
function parseMcpProxyMode(value) {
|
|
932
|
-
if (["stdio-proxy", "direct-http", "tool-native-oauth"].includes(value)) {
|
|
933
|
-
return value;
|
|
934
|
-
}
|
|
935
|
-
throw new Error("unknown MCP proxy mode: " + value);
|
|
936
|
-
}
|
|
937
|
-
function parseMcpSecretStorage(value) {
|
|
938
|
-
if (["keychain", "libsecret", "windows-credential", "secure-file"].includes(value)) {
|
|
939
|
-
return value;
|
|
940
|
-
}
|
|
941
|
-
throw new Error("unknown MCP secret storage: " + value);
|
|
942
|
-
}
|
|
943
|
-
export async function skillsValidateCommand(options, io) {
|
|
944
|
-
const report = await validateSkills();
|
|
945
|
-
if (options.json) {
|
|
946
|
-
io.log(JSON.stringify(report, null, 2));
|
|
947
|
-
}
|
|
948
|
-
else {
|
|
949
|
-
io.log(report.valid ? "Skills valid" : "Skills invalid");
|
|
950
|
-
for (const error of report.errors) {
|
|
951
|
-
io.log(`ERROR: ${error}`);
|
|
952
|
-
}
|
|
953
|
-
for (const warning of report.warnings) {
|
|
954
|
-
io.log(`WARN: ${warning}`);
|
|
955
|
-
}
|
|
956
|
-
}
|
|
957
|
-
if (!report.valid) {
|
|
958
|
-
throw new Error("skills validation failed");
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
|
-
export async function sourcesListCommand(options, io) {
|
|
962
|
-
const sources = await readSourceOfTruth();
|
|
963
|
-
if (options.json) {
|
|
964
|
-
io.log(JSON.stringify(sources, null, 2));
|
|
965
|
-
return;
|
|
966
|
-
}
|
|
967
|
-
for (const source of sources) {
|
|
968
|
-
io.log(`${source.id ?? "unknown"} - ${source.name ?? "Unnamed source"}`);
|
|
969
|
-
io.log(` ${(source.locations ?? []).join(", ")}`);
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
export async function lessonsListCommand(options, io) {
|
|
973
|
-
const lessons = await listAgentLessons();
|
|
974
|
-
if (options.json) {
|
|
975
|
-
io.log(JSON.stringify(lessons, null, 2));
|
|
976
|
-
return;
|
|
977
|
-
}
|
|
978
|
-
if (lessons.length === 0) {
|
|
979
|
-
io.log("No lessons");
|
|
980
|
-
return;
|
|
981
|
-
}
|
|
982
|
-
for (const lesson of lessons) {
|
|
983
|
-
io.log(`${lesson.timestamp} ${lesson.operation}: ${lesson.errorSignature}`);
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
export async function lessonsAddCommand(options, io) {
|
|
987
|
-
const lesson = await addAgentLesson(removeUndefined({
|
|
988
|
-
taskId: stringOption(options.task),
|
|
989
|
-
actor: stringOption(options.actor) ?? "parent",
|
|
990
|
-
operation: requireArg(options, "operation"),
|
|
991
|
-
failedAction: requireArg(options, "failed-action"),
|
|
992
|
-
errorSignature: requireArg(options, "error-signature"),
|
|
993
|
-
rootCause: requireArg(options, "root-cause"),
|
|
994
|
-
fix: requireArg(options, "fix"),
|
|
995
|
-
prevention: requireArg(options, "prevention"),
|
|
996
|
-
appliesTo: parseCsv(options["applies-to"]),
|
|
997
|
-
verifiedBy: parseCsv(options["verified-by"]),
|
|
998
|
-
}));
|
|
999
|
-
if (options.json) {
|
|
1000
|
-
io.log(JSON.stringify(lesson, null, 2));
|
|
1001
|
-
return;
|
|
1002
|
-
}
|
|
1003
|
-
io.log(`Recorded lesson ${lesson.errorSignature}`);
|
|
1004
|
-
}
|
|
1005
|
-
export async function lessonsPromoteCommand(options, io) {
|
|
1006
|
-
const result = await promoteAgentLessons(removeUndefined({
|
|
1007
|
-
to: parsePromotionTarget(stringOption(options.to) ?? "doc"),
|
|
1008
|
-
filter: stringOption(options.filter),
|
|
1009
|
-
}));
|
|
1010
|
-
if (options.json) {
|
|
1011
|
-
io.log(JSON.stringify(result, null, 2));
|
|
1012
|
-
return;
|
|
1013
|
-
}
|
|
1014
|
-
io.log(`Created ${result.artifact}`);
|
|
1015
|
-
io.log(`Promoted lessons: ${result.lessons.length}`);
|
|
1016
|
-
}
|
|
1017
|
-
function parsePromotionTarget(value) {
|
|
1018
|
-
if (["skill", "rule", "doc"].includes(value)) {
|
|
1019
|
-
return value;
|
|
1020
|
-
}
|
|
1021
|
-
throw new Error(`unknown promotion target: ${value}`);
|
|
1022
|
-
}
|
|
1023
|
-
export async function skillsListCommand(options, io) {
|
|
1024
|
-
const skills = listSkills();
|
|
1025
|
-
if (options.json) {
|
|
1026
|
-
io.log(JSON.stringify(skills, null, 2));
|
|
1027
|
-
return;
|
|
1028
|
-
}
|
|
1029
|
-
for (const skill of skills) {
|
|
1030
|
-
io.log(`${skill.id} - ${skill.name} (${skill.loadBudget})`);
|
|
1031
|
-
io.log(` ${skill.summary}`);
|
|
1032
|
-
io.log(` sources: ${skill.sourceGroups.join(", ")}`);
|
|
1033
|
-
}
|
|
1034
|
-
}
|
|
1035
|
-
export async function skillsPlanCommand(options, io) {
|
|
1036
|
-
const plan = await planSkillsForTask(requireArg(options, "task"));
|
|
1037
|
-
await recordSkillPlan(plan);
|
|
1038
|
-
if (options.json) {
|
|
1039
|
-
io.log(JSON.stringify(plan, null, 2));
|
|
1040
|
-
return;
|
|
1041
|
-
}
|
|
1042
|
-
io.log(`Skills for ${plan.taskId}:`);
|
|
1043
|
-
for (const item of plan.selected) {
|
|
1044
|
-
io.log(` ${item.skill.id} (score ${item.score})`);
|
|
1045
|
-
for (const reason of item.rationale) {
|
|
1046
|
-
io.log(` - ${reason}`);
|
|
1047
|
-
}
|
|
1048
|
-
}
|
|
1049
|
-
io.log(`Source groups: ${plan.sourceGroups.join(", ")}`);
|
|
1050
|
-
}
|
|
1051
|
-
export async function skillsRenderCommand(options, io) {
|
|
1052
|
-
const target = parseSkillRenderTarget(stringOption(options.target) ?? "generic");
|
|
1053
|
-
const rendered = await renderSkills({
|
|
1054
|
-
target,
|
|
1055
|
-
taskId: stringOption(options.task),
|
|
1056
|
-
skillIds: parseCsv(options.skills),
|
|
1057
|
-
});
|
|
1058
|
-
await recordSkillRender(rendered);
|
|
1059
|
-
if (options.json) {
|
|
1060
|
-
io.log(JSON.stringify(rendered, null, 2));
|
|
1061
|
-
return;
|
|
1062
|
-
}
|
|
1063
|
-
io.log(rendered.content);
|
|
1064
|
-
}
|
|
1065
|
-
function parseSkillRenderTarget(value) {
|
|
1066
|
-
return parseRuntimeTarget(value);
|
|
1067
|
-
}
|
|
1068
485
|
// --- Autonomous workflow commands ---
|
|
1069
486
|
const GATE_MODES = ["none", "phase", "all"];
|
|
1070
487
|
export async function workflowRunCommand(options, io) {
|
|
@@ -1374,225 +791,6 @@ async function workflowDryRun(options, io, taskId, gates, maxIterations) {
|
|
|
1374
791
|
}, null, 2));
|
|
1375
792
|
}
|
|
1376
793
|
}
|
|
1377
|
-
// --- Estimate & Benchmark commands ---
|
|
1378
|
-
const CONFIDENCE_LEVELS = ["low", "medium", "high"];
|
|
1379
|
-
export async function estimateCommand(options, io) {
|
|
1380
|
-
const cwd = process.cwd();
|
|
1381
|
-
const taskId = requireArg(options, "task");
|
|
1382
|
-
const sizingRaw = requireArg(options, "sizing");
|
|
1383
|
-
const soloDays = numberOption(options["solo-days"], 0);
|
|
1384
|
-
const aiDays = numberOption(options["ai-unguided-days"], 0);
|
|
1385
|
-
const confidence = (stringOption(options.confidence) ??
|
|
1386
|
-
"medium");
|
|
1387
|
-
const declaredBy = stringOption(options["declared-by"]) ?? "pm";
|
|
1388
|
-
if (!SIZING_LABELS.includes(sizingRaw)) {
|
|
1389
|
-
throw new Error(`--sizing must be one of: ${SIZING_LABELS.join(", ")}`);
|
|
1390
|
-
}
|
|
1391
|
-
if (!CONFIDENCE_LEVELS.includes(confidence)) {
|
|
1392
|
-
throw new Error(`--confidence must be one of: ${CONFIDENCE_LEVELS.join(", ")}`);
|
|
1393
|
-
}
|
|
1394
|
-
if (soloDays <= 0)
|
|
1395
|
-
throw new Error(`--solo-days must be > 0`);
|
|
1396
|
-
if (aiDays <= 0)
|
|
1397
|
-
throw new Error(`--ai-unguided-days must be > 0`);
|
|
1398
|
-
const record = await recordEstimate(cwd, {
|
|
1399
|
-
taskId,
|
|
1400
|
-
sizingLabel: sizingRaw,
|
|
1401
|
-
soloEstimateDays: soloDays,
|
|
1402
|
-
aiUnguidedEstimateDays: aiDays,
|
|
1403
|
-
confidence,
|
|
1404
|
-
declaredBy,
|
|
1405
|
-
});
|
|
1406
|
-
if (options.json) {
|
|
1407
|
-
io.log(JSON.stringify(record, null, 2));
|
|
1408
|
-
return;
|
|
1409
|
-
}
|
|
1410
|
-
io.log(`Estimate recorded for ${taskId} [${record.id}]`);
|
|
1411
|
-
io.log(` Sizing: ${record.sizingLabel}`);
|
|
1412
|
-
io.log(` Solo: ${record.soloEstimateDays}d`);
|
|
1413
|
-
io.log(` AI-unguided: ${record.aiUnguidedEstimateDays}d`);
|
|
1414
|
-
io.log(` Confidence: ${record.confidence}`);
|
|
1415
|
-
io.log(` Declared by: ${record.declaredBy}`);
|
|
1416
|
-
}
|
|
1417
|
-
export async function benchmarkCommand(options, io) {
|
|
1418
|
-
const cwd = process.cwd();
|
|
1419
|
-
if (options.summary) {
|
|
1420
|
-
const summary = await summarizeBenchmark(cwd);
|
|
1421
|
-
if (options.json) {
|
|
1422
|
-
io.log(JSON.stringify(summary, null, 2));
|
|
1423
|
-
return;
|
|
1424
|
-
}
|
|
1425
|
-
if (summary.stories.length === 0) {
|
|
1426
|
-
io.log("No estimates recorded yet. Use: orchestra estimate --task <id> ...");
|
|
1427
|
-
return;
|
|
1428
|
-
}
|
|
1429
|
-
const header = `${"Story".padEnd(14)} ${"Size".padEnd(4)} ${"Solo".padEnd(6)} ${"AI".padEnd(6)} ${"Actual".padEnd(8)} ${"vs Solo".padEnd(8)} ${"vs AI".padEnd(8)} ${"QA".padEnd(4)} ${"Rev".padEnd(4)} ${"Blk".padEnd(4)} ${"Ev".padEnd(4)} ${"Les"}`;
|
|
1430
|
-
io.log(header);
|
|
1431
|
-
io.log("─".repeat(header.length));
|
|
1432
|
-
for (const s of summary.stories) {
|
|
1433
|
-
const actual = s.actualDays !== null ? `${s.actualDays}d` : "pending";
|
|
1434
|
-
const vsSolo = s.vsSoloPct !== null
|
|
1435
|
-
? `${s.vsSoloPct > 0 ? "+" : ""}${s.vsSoloPct}%`
|
|
1436
|
-
: "—";
|
|
1437
|
-
const vsAi = s.vsAiUnguidedPct !== null
|
|
1438
|
-
? `${s.vsAiUnguidedPct > 0 ? "+" : ""}${s.vsAiUnguidedPct}%`
|
|
1439
|
-
: "—";
|
|
1440
|
-
io.log(`${s.taskId.padEnd(14)} ${s.sizingLabel.padEnd(4)} ${`${s.soloEstimateDays}d`.padEnd(6)} ${`${s.aiUnguidedEstimateDays}d`.padEnd(6)} ${actual.padEnd(8)} ${vsSolo.padEnd(8)} ${vsAi.padEnd(8)} ${String(s.qaIterations).padEnd(4)} ${String(s.quality.reviewCount).padEnd(4)} ${String(s.quality.blockingReviews).padEnd(4)} ${String(s.quality.evidenceCount).padEnd(4)} ${s.quality.lessonCount}`);
|
|
1441
|
-
}
|
|
1442
|
-
if (summary.totalWithActuals > 0) {
|
|
1443
|
-
io.log("");
|
|
1444
|
-
io.log(`Avg savings vs solo: ${summary.avgVsSoloPct}%`);
|
|
1445
|
-
io.log(`Avg savings vs AI-unguided: ${summary.avgVsAiUnguidedPct}%`);
|
|
1446
|
-
io.log(`Stories with actuals: ${summary.totalWithActuals}/${summary.stories.length}`);
|
|
1447
|
-
}
|
|
1448
|
-
return;
|
|
1449
|
-
}
|
|
1450
|
-
const taskId = requireArg(options, "task");
|
|
1451
|
-
const result = await computeBenchmark(cwd, taskId);
|
|
1452
|
-
if (options.json) {
|
|
1453
|
-
io.log(JSON.stringify(result, null, 2));
|
|
1454
|
-
return;
|
|
1455
|
-
}
|
|
1456
|
-
io.log(`Benchmark: ${taskId} [${result.status}]`);
|
|
1457
|
-
io.log(` Sizing: ${result.sizingLabel}`);
|
|
1458
|
-
io.log(` Solo: ${result.soloEstimateDays}d (declared)`);
|
|
1459
|
-
io.log(` AI-unguided: ${result.aiUnguidedEstimateDays}d (declared)`);
|
|
1460
|
-
io.log(` Actual: ${result.actualDays !== null ? `${result.actualDays}d` : "pending — run not complete"}`);
|
|
1461
|
-
if (result.vsSoloPct !== null) {
|
|
1462
|
-
const sign = result.vsSoloPct > 0 ? "+" : "";
|
|
1463
|
-
io.log(` vs Solo: ${sign}${result.vsSoloPct}%`);
|
|
1464
|
-
io.log(` vs AI: ${result.vsAiUnguidedPct !== null ? `${result.vsAiUnguidedPct > 0 ? "+" : ""}${result.vsAiUnguidedPct}%` : "—"}`);
|
|
1465
|
-
}
|
|
1466
|
-
io.log(` QA loops: ${result.qaIterations}`);
|
|
1467
|
-
io.log(` Reviews: ${result.quality.reviewCount} (${result.quality.blockingReviews} blocking)`);
|
|
1468
|
-
io.log(` Evidence: ${result.quality.evidenceCount} artifacts`);
|
|
1469
|
-
io.log(` Gate blocks: ${result.quality.gateBlockCount}`);
|
|
1470
|
-
io.log(` Lessons: ${result.quality.lessonCount}`);
|
|
1471
|
-
if (result.quality.totalInputTokens > 0 ||
|
|
1472
|
-
result.quality.totalOutputTokens > 0) {
|
|
1473
|
-
io.log(` Tokens: ${result.quality.totalInputTokens}in / ${result.quality.totalOutputTokens}out`);
|
|
1474
|
-
io.log(` Cost: $${result.quality.estimatedCostUsd}`);
|
|
1475
|
-
}
|
|
1476
|
-
}
|
|
1477
|
-
// --- Velocity command ---
|
|
1478
|
-
export async function velocityCommand(options, io) {
|
|
1479
|
-
const cwd = process.cwd();
|
|
1480
|
-
if (typeof options.sprints === "string") {
|
|
1481
|
-
const limit = Number(options.sprints);
|
|
1482
|
-
if (!Number.isInteger(limit) || limit <= 0) {
|
|
1483
|
-
throw new Error("--sprints must be a positive integer");
|
|
1484
|
-
}
|
|
1485
|
-
const report = await velocityTrend(cwd, limit);
|
|
1486
|
-
if (options.json) {
|
|
1487
|
-
io.log(JSON.stringify(report, null, 2));
|
|
1488
|
-
return;
|
|
1489
|
-
}
|
|
1490
|
-
io.log(`Sprint Velocity Report`);
|
|
1491
|
-
io.log(` Trend: ${report.trend}`);
|
|
1492
|
-
for (const sprint of report.sprints) {
|
|
1493
|
-
io.log(` ${sprint.sprintId} ${sprint.storiesCompleted} stories ${sprint.pointsCompleted} pts`);
|
|
1494
|
-
}
|
|
1495
|
-
return;
|
|
1496
|
-
}
|
|
1497
|
-
const report = await computeVelocity(cwd);
|
|
1498
|
-
if (options.json) {
|
|
1499
|
-
io.log(JSON.stringify(report, null, 2));
|
|
1500
|
-
return;
|
|
1501
|
-
}
|
|
1502
|
-
io.log(`Velocity Report`);
|
|
1503
|
-
io.log(` Stories completed: ${report.totalStoriesCompleted}`);
|
|
1504
|
-
io.log(` Points completed: ${report.totalPointsCompleted}`);
|
|
1505
|
-
io.log(` Avg actual days: ${report.avgActualDaysPerStory !== null ? report.avgActualDaysPerStory + "d" : "n/a"}`);
|
|
1506
|
-
io.log(` vs Solo estimate: ${report.avgVsSoloPct !== null ? report.avgVsSoloPct + "%" : "n/a"}`);
|
|
1507
|
-
io.log(` vs AI estimate: ${report.avgVsAiUnguidedPct !== null ? report.avgVsAiUnguidedPct + "%" : "n/a"}`);
|
|
1508
|
-
io.log(` Trend: ${report.trend}`);
|
|
1509
|
-
if (report.weeks.length > 0) {
|
|
1510
|
-
io.log(`\nWeekly breakdown:`);
|
|
1511
|
-
for (const week of report.weeks) {
|
|
1512
|
-
io.log(` ${week.week} ${week.storiesCompleted} stories ${week.pointsCompleted} pts`);
|
|
1513
|
-
}
|
|
1514
|
-
}
|
|
1515
|
-
}
|
|
1516
|
-
// --- Sprint command ---
|
|
1517
|
-
export async function sprintCommand(subcommand, options, io) {
|
|
1518
|
-
const cwd = process.cwd();
|
|
1519
|
-
if (subcommand === "start") {
|
|
1520
|
-
const id = requireArg(options, "id");
|
|
1521
|
-
const taskIds = requireArg(options, "tasks")
|
|
1522
|
-
.split(",")
|
|
1523
|
-
.map((taskId) => taskId.trim())
|
|
1524
|
-
.filter(Boolean);
|
|
1525
|
-
const sprint = await startSprint(cwd, id, taskIds);
|
|
1526
|
-
if (options.json) {
|
|
1527
|
-
io.log(JSON.stringify(sprint, null, 2));
|
|
1528
|
-
return;
|
|
1529
|
-
}
|
|
1530
|
-
io.log(`Sprint started: ${sprint.id} (${sprint.taskIds.length} tasks)`);
|
|
1531
|
-
return;
|
|
1532
|
-
}
|
|
1533
|
-
if (subcommand === "close") {
|
|
1534
|
-
const id = requireArg(options, "id");
|
|
1535
|
-
const sprint = await closeSprint(cwd, id);
|
|
1536
|
-
if (options.json) {
|
|
1537
|
-
io.log(JSON.stringify(sprint, null, 2));
|
|
1538
|
-
return;
|
|
1539
|
-
}
|
|
1540
|
-
io.log(`Sprint closed: ${sprint.id}`);
|
|
1541
|
-
return;
|
|
1542
|
-
}
|
|
1543
|
-
throw new Error(`unknown sprint command: ${subcommand ?? ""}`.trim());
|
|
1544
|
-
}
|
|
1545
|
-
// --- Calibration command ---
|
|
1546
|
-
export async function calibrationCommand(options, io) {
|
|
1547
|
-
const report = await calibrationReport(process.cwd());
|
|
1548
|
-
const roleFilter = typeof options.role === "string" ? options.role : null;
|
|
1549
|
-
const filtered = roleFilter
|
|
1550
|
-
? { roles: report.roles.filter((role) => role.role === roleFilter) }
|
|
1551
|
-
: report;
|
|
1552
|
-
if (options.json) {
|
|
1553
|
-
io.log(JSON.stringify(filtered, null, 2));
|
|
1554
|
-
return;
|
|
1555
|
-
}
|
|
1556
|
-
io.log(`Calibration Report`);
|
|
1557
|
-
for (const role of filtered.roles) {
|
|
1558
|
-
io.log(` ${role.role} stories=${role.stories} declared=${role.avgDeclaredDays}d actual=${role.avgActualDays}d error=${role.avgErrorPct}% bias=${role.bias}`);
|
|
1559
|
-
}
|
|
1560
|
-
}
|
|
1561
|
-
// --- Burndown command ---
|
|
1562
|
-
export async function burndownCommand(options, io) {
|
|
1563
|
-
const cwd = process.cwd();
|
|
1564
|
-
const sprintCsv = requireArg(options, "sprint");
|
|
1565
|
-
const sprintTaskIds = sprintCsv
|
|
1566
|
-
.split(",")
|
|
1567
|
-
.map((s) => s.trim())
|
|
1568
|
-
.filter(Boolean);
|
|
1569
|
-
if (sprintTaskIds.length === 0)
|
|
1570
|
-
throw new Error(`--sprint requires at least one task id`);
|
|
1571
|
-
const series = await computeSprintBurndown(cwd, sprintTaskIds);
|
|
1572
|
-
if (options.json) {
|
|
1573
|
-
io.log(JSON.stringify(series, null, 2));
|
|
1574
|
-
return;
|
|
1575
|
-
}
|
|
1576
|
-
for (const w of series.warnings)
|
|
1577
|
-
io.log(`⚠ ${w}`);
|
|
1578
|
-
if (series.totalPoints === 0) {
|
|
1579
|
-
io.log("No points to chart — record estimates first with: orchestra estimate --task <id> ...");
|
|
1580
|
-
return;
|
|
1581
|
-
}
|
|
1582
|
-
io.log(`Sprint burndown total=${series.totalPoints} pts tasks=${series.sprintTaskIds.length}`);
|
|
1583
|
-
io.log("");
|
|
1584
|
-
io.log(renderBurndownAscii(series));
|
|
1585
|
-
io.log("");
|
|
1586
|
-
io.log("Task breakdown:");
|
|
1587
|
-
for (const t of series.taskBreakdown) {
|
|
1588
|
-
const arch = t.architectPoints !== null ? `arch=${t.architectPoints}` : "arch=—";
|
|
1589
|
-
const dev = t.developerPoints !== null ? `dev=${t.developerPoints}` : "dev=—";
|
|
1590
|
-
const done = t.completedAt
|
|
1591
|
-
? `done ${t.completedAt.slice(0, 10)}`
|
|
1592
|
-
: "pending";
|
|
1593
|
-
io.log(` ${t.taskId.padEnd(14)} ${arch.padEnd(10)} ${dev.padEnd(10)} resolved=${t.resolvedPoints} ${done}`);
|
|
1594
|
-
}
|
|
1595
|
-
}
|
|
1596
794
|
function parseRuntimeTargetOptions(options) {
|
|
1597
795
|
const targetValues = [
|
|
1598
796
|
...parseCsv(options.target),
|
|
@@ -1600,6 +798,9 @@ function parseRuntimeTargetOptions(options) {
|
|
|
1600
798
|
];
|
|
1601
799
|
return [...new Set(targetValues)].map((target) => parseRuntimeTarget(target));
|
|
1602
800
|
}
|
|
801
|
+
function parseSkillRenderTarget(value) {
|
|
802
|
+
return parseRuntimeTarget(value);
|
|
803
|
+
}
|
|
1603
804
|
function parseCsv(value) {
|
|
1604
805
|
if (typeof value !== "string" || value.trim() === "") {
|
|
1605
806
|
return [];
|
|
@@ -1648,18 +849,6 @@ function parseRiskAcceptance(options) {
|
|
|
1648
849
|
});
|
|
1649
850
|
return Object.keys(acceptance).length > 0 ? acceptance : undefined;
|
|
1650
851
|
}
|
|
1651
|
-
function parseProviderRouting(options) {
|
|
1652
|
-
return {
|
|
1653
|
-
provider: requireArg(options, "provider"),
|
|
1654
|
-
model: requireArg(options, "model"),
|
|
1655
|
-
fallbacks: parseCsv(options.fallbacks),
|
|
1656
|
-
maxTokens: numberOption(options["max-tokens"], 0),
|
|
1657
|
-
maxCostUsd: numberOption(options["max-cost-usd"], 0),
|
|
1658
|
-
timeoutMs: numberOption(options["timeout-ms"], 30000),
|
|
1659
|
-
retries: numberOption(options.retries, 0),
|
|
1660
|
-
requiredCapabilities: parseCsv(options.capabilities),
|
|
1661
|
-
};
|
|
1662
|
-
}
|
|
1663
852
|
function parseBudgetEscalationDecision(options) {
|
|
1664
853
|
if (options["approve-budget-fallback"]) {
|
|
1665
854
|
return removeUndefined({
|
|
@@ -1677,13 +866,6 @@ function parseBudgetEscalationDecision(options) {
|
|
|
1677
866
|
}
|
|
1678
867
|
return undefined;
|
|
1679
868
|
}
|
|
1680
|
-
function parseApprovalDecision(options) {
|
|
1681
|
-
return {
|
|
1682
|
-
id: requireArg(options, "id"),
|
|
1683
|
-
approver: requireArg(options, "approver"),
|
|
1684
|
-
rationale: requireArg(options, "rationale"),
|
|
1685
|
-
};
|
|
1686
|
-
}
|
|
1687
869
|
function numberOption(value, fallback) {
|
|
1688
870
|
if (typeof value !== "string" || value.trim() === "") {
|
|
1689
871
|
return fallback;
|
|
@@ -1820,43 +1002,6 @@ function renderSummaryMarkdown(summary) {
|
|
|
1820
1002
|
"",
|
|
1821
1003
|
].join("\n");
|
|
1822
1004
|
}
|
|
1823
|
-
function renderUsageReport(report) {
|
|
1824
|
-
return [
|
|
1825
|
-
`Usage${report.taskId ? ` for ${report.taskId}` : ""}`,
|
|
1826
|
-
`- Requests: ${report.totals.requests}`,
|
|
1827
|
-
`- Input tokens: ${report.totals.inputTokens}`,
|
|
1828
|
-
`- Output tokens: ${report.totals.outputTokens}`,
|
|
1829
|
-
`- Total tokens: ${report.totals.totalTokens}`,
|
|
1830
|
-
`- Estimated cost USD: ${report.totals.estimatedCostUsd}`,
|
|
1831
|
-
"",
|
|
1832
|
-
"By role:",
|
|
1833
|
-
...usageLines(report.byRole),
|
|
1834
|
-
"",
|
|
1835
|
-
"By provider:",
|
|
1836
|
-
...usageLines(report.byProvider),
|
|
1837
|
-
].join("\n");
|
|
1838
|
-
}
|
|
1839
|
-
function renderBudgetCheck(result) {
|
|
1840
|
-
return [
|
|
1841
|
-
`Budget check${result.taskId ? ` for ${result.taskId}` : ""}: ${result.passed ? "passed" : "failed"}`,
|
|
1842
|
-
`- Applied budgets: ${result.appliedBudgets.length > 0
|
|
1843
|
-
? result.appliedBudgets.join(", ")
|
|
1844
|
-
: "none"}`,
|
|
1845
|
-
`- Requests: ${result.usage.totals.requests}`,
|
|
1846
|
-
`- Total tokens: ${result.usage.totals.totalTokens}`,
|
|
1847
|
-
`- Estimated cost USD: ${result.usage.totals.estimatedCostUsd}`,
|
|
1848
|
-
"",
|
|
1849
|
-
"Violations:",
|
|
1850
|
-
...(result.violations.length === 0
|
|
1851
|
-
? ["- none"]
|
|
1852
|
-
: result.violations.map((violation) => `- ${violation.scope} ${violation.metric}: ${violation.actual} > ${violation.limit}`)),
|
|
1853
|
-
].join("\n");
|
|
1854
|
-
}
|
|
1855
|
-
function usageLines(items) {
|
|
1856
|
-
return items.length === 0
|
|
1857
|
-
? ["- none"]
|
|
1858
|
-
: items.map((item) => `- ${item.key}: ${item.requests} requests, ${item.totalTokens} tokens, $${item.estimatedCostUsd}`);
|
|
1859
|
-
}
|
|
1860
1005
|
function renderPullRequestSummaryMarkdown(summary) {
|
|
1861
1006
|
return [
|
|
1862
1007
|
`# PR Summary: ${summary.task.id}`,
|