@duypham93/openkit 0.2.0
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/.opencode/README.md +47 -0
- package/.opencode/install-manifest.json +41 -0
- package/.opencode/lib/artifact-scaffolder.js +111 -0
- package/.opencode/lib/contract-consistency.js +218 -0
- package/.opencode/lib/parallel-execution-rules.js +261 -0
- package/.opencode/lib/runtime-paths.js +95 -0
- package/.opencode/lib/runtime-summary.js +82 -0
- package/.opencode/lib/state-guard.js +99 -0
- package/.opencode/lib/task-board-rules.js +375 -0
- package/.opencode/lib/work-item-store.js +280 -0
- package/.opencode/lib/workflow-state-controller.js +1739 -0
- package/.opencode/lib/workflow-state-rules.js +331 -0
- package/.opencode/opencode.json +93 -0
- package/.opencode/package.json +3 -0
- package/.opencode/tests/artifact-scaffolder.test.js +733 -0
- package/.opencode/tests/multi-work-item-runtime.test.js +369 -0
- package/.opencode/tests/parallel-execution-runtime.test.js +259 -0
- package/.opencode/tests/session-start-hook.test.js +357 -0
- package/.opencode/tests/state-guard.test.js +124 -0
- package/.opencode/tests/task-board-rules.test.js +204 -0
- package/.opencode/tests/work-item-store.test.js +380 -0
- package/.opencode/tests/workflow-behavior.test.js +149 -0
- package/.opencode/tests/workflow-contract-consistency.test.js +387 -0
- package/.opencode/tests/workflow-state-cli.test.js +1275 -0
- package/.opencode/tests/workflow-state-controller.test.js +1038 -0
- package/.opencode/work-items/feature-001/state.json +70 -0
- package/.opencode/work-items/index.json +13 -0
- package/.opencode/workflow-state.js +489 -0
- package/.opencode/workflow-state.json +70 -0
- package/AGENTS.md +265 -0
- package/README.md +401 -0
- package/agents/architect-agent.md +63 -0
- package/agents/ba-agent.md +56 -0
- package/agents/code-reviewer.md +77 -0
- package/agents/fullstack-agent.md +115 -0
- package/agents/master-orchestrator.md +60 -0
- package/agents/pm-agent.md +56 -0
- package/agents/qa-agent.md +124 -0
- package/agents/tech-lead-agent.md +60 -0
- package/assets/install-bundle/README.md +7 -0
- package/assets/install-bundle/opencode/README.md +11 -0
- package/assets/install-bundle/opencode/agents/ArchitectAgent.md +63 -0
- package/assets/install-bundle/opencode/agents/BAAgent.md +56 -0
- package/assets/install-bundle/opencode/agents/CodeReviewer.md +77 -0
- package/assets/install-bundle/opencode/agents/FullstackAgent.md +115 -0
- package/assets/install-bundle/opencode/agents/MasterOrchestrator.md +60 -0
- package/assets/install-bundle/opencode/agents/PMAgent.md +56 -0
- package/assets/install-bundle/opencode/agents/QAAgent.md +124 -0
- package/assets/install-bundle/opencode/agents/TechLeadAgent.md +60 -0
- package/assets/install-bundle/opencode/commands/brainstorm.md +44 -0
- package/assets/install-bundle/opencode/commands/delivery.md +45 -0
- package/assets/install-bundle/opencode/commands/execute-plan.md +44 -0
- package/assets/install-bundle/opencode/commands/migrate.md +61 -0
- package/assets/install-bundle/opencode/commands/quick-task.md +45 -0
- package/assets/install-bundle/opencode/commands/task.md +46 -0
- package/assets/install-bundle/opencode/commands/write-plan.md +50 -0
- package/assets/install-bundle/opencode/context/core/lane-selection.md +54 -0
- package/assets/install-bundle/opencode/skills/brainstorming/SKILL.md +51 -0
- package/assets/install-bundle/opencode/skills/code-review/SKILL.md +48 -0
- package/assets/install-bundle/opencode/skills/subagent-driven-development/SKILL.md +79 -0
- package/assets/install-bundle/opencode/skills/systematic-debugging/SKILL.md +61 -0
- package/assets/install-bundle/opencode/skills/test-driven-development/SKILL.md +48 -0
- package/assets/install-bundle/opencode/skills/using-skills/SKILL.md +39 -0
- package/assets/install-bundle/opencode/skills/verification-before-completion/SKILL.md +137 -0
- package/assets/install-bundle/opencode/skills/writing-plans/SKILL.md +68 -0
- package/assets/install-bundle/opencode/skills/writing-specs/SKILL.md +47 -0
- package/assets/opencode.json.template +11 -0
- package/assets/openkit-install.json.template +19 -0
- package/bin/openkit.js +9 -0
- package/commands/brainstorm.md +44 -0
- package/commands/delivery.md +45 -0
- package/commands/execute-plan.md +44 -0
- package/commands/migrate.md +61 -0
- package/commands/quick-task.md +45 -0
- package/commands/task.md +46 -0
- package/commands/write-plan.md +50 -0
- package/context/core/approval-gates.md +146 -0
- package/context/core/code-quality.md +42 -0
- package/context/core/issue-routing.md +85 -0
- package/context/core/lane-selection.md +54 -0
- package/context/core/project-config.md +143 -0
- package/context/core/session-resume.md +85 -0
- package/context/core/workflow-state-schema.md +224 -0
- package/context/core/workflow.md +442 -0
- package/context/navigation.md +94 -0
- package/docs/adr/README.md +6 -0
- package/docs/architecture/2026-03-20-task-intake-dashboard.md +54 -0
- package/docs/architecture/README.md +7 -0
- package/docs/briefs/2026-03-20-task-intake-dashboard.md +48 -0
- package/docs/briefs/README.md +7 -0
- package/docs/governance/README.md +25 -0
- package/docs/governance/adr-policy.md +27 -0
- package/docs/governance/definition-of-done.md +17 -0
- package/docs/governance/naming-conventions.md +21 -0
- package/docs/governance/severity-levels.md +12 -0
- package/docs/maintainer/README.md +51 -0
- package/docs/operations/README.md +79 -0
- package/docs/operations/internal-records/2026-03-24-release-checklist.md +79 -0
- package/docs/operations/internal-records/2026-03-24-simplified-install-ux.md +36 -0
- package/docs/operations/internal-records/README.md +18 -0
- package/docs/operations/runbooks/README.md +23 -0
- package/docs/operations/runbooks/openkit-daily-usage.md +288 -0
- package/docs/operations/runbooks/workflow-state-smoke-tests.md +302 -0
- package/docs/operator/README.md +50 -0
- package/docs/plans/2026-03-20-task-intake-dashboard.md +49 -0
- package/docs/plans/2026-03-21-openkit-full-delivery-multi-task-runtime.md +521 -0
- package/docs/plans/2026-03-23-openkit-global-install-runtime.md +157 -0
- package/docs/plans/README.md +7 -0
- package/docs/qa/2026-03-20-task-intake-dashboard.md +41 -0
- package/docs/qa/README.md +7 -0
- package/docs/specs/2026-03-20-task-intake-dashboard.md +50 -0
- package/docs/specs/2026-03-21-openkit-full-delivery-multi-task-runtime.md +462 -0
- package/docs/specs/README.md +7 -0
- package/docs/templates/README.md +36 -0
- package/docs/templates/adr-template.md +18 -0
- package/docs/templates/architecture-template.md +31 -0
- package/docs/templates/implementation-plan-template.md +32 -0
- package/docs/templates/migration-baseline-checklist.md +48 -0
- package/docs/templates/migration-plan-template.md +52 -0
- package/docs/templates/migration-report-template.md +74 -0
- package/docs/templates/migration-verify-checklist.md +39 -0
- package/docs/templates/product-brief-template.md +32 -0
- package/docs/templates/qa-report-template.md +37 -0
- package/docs/templates/quick-task-template.md +36 -0
- package/docs/templates/spec-template.md +31 -0
- package/hooks/hooks.json +16 -0
- package/hooks/session-start +162 -0
- package/package.json +24 -0
- package/registry.json +328 -0
- package/skills/brainstorming/SKILL.md +51 -0
- package/skills/code-review/SKILL.md +48 -0
- package/skills/subagent-driven-development/SKILL.md +79 -0
- package/skills/systematic-debugging/SKILL.md +61 -0
- package/skills/test-driven-development/SKILL.md +48 -0
- package/skills/using-skills/SKILL.md +39 -0
- package/skills/verification-before-completion/SKILL.md +137 -0
- package/skills/writing-plans/SKILL.md +68 -0
- package/skills/writing-specs/SKILL.md +47 -0
- package/src/audit/vietnamese-detection.js +259 -0
- package/src/cli/commands/detect-vietnamese.js +24 -0
- package/src/cli/commands/doctor.js +33 -0
- package/src/cli/commands/help.js +33 -0
- package/src/cli/commands/init.js +25 -0
- package/src/cli/commands/install-global.js +26 -0
- package/src/cli/commands/install.js +25 -0
- package/src/cli/commands/run.js +63 -0
- package/src/cli/commands/uninstall.js +32 -0
- package/src/cli/commands/upgrade.js +25 -0
- package/src/cli/conflict-output.js +19 -0
- package/src/cli/index.js +56 -0
- package/src/global/doctor.js +101 -0
- package/src/global/ensure-install.js +32 -0
- package/src/global/install-state.js +73 -0
- package/src/global/launcher.js +51 -0
- package/src/global/materialize.js +123 -0
- package/src/global/paths.js +85 -0
- package/src/global/uninstall.js +25 -0
- package/src/global/workspace-state.js +63 -0
- package/src/install/asset-manifest.js +284 -0
- package/src/install/conflicts.js +43 -0
- package/src/install/discovery.js +138 -0
- package/src/install/install-state.js +136 -0
- package/src/install/materialize.js +158 -0
- package/src/install/merge-policy.js +145 -0
- package/src/runtime/doctor.js +281 -0
- package/src/runtime/launcher.js +49 -0
- package/src/runtime/opencode-layering.js +135 -0
- package/src/runtime/openkit-managed-summary.js +27 -0
- package/tests/cli/openkit-cli.test.js +417 -0
- package/tests/global/doctor.test.js +130 -0
- package/tests/global/ensure-install.test.js +105 -0
- package/tests/install/discovery.test.js +124 -0
- package/tests/install/install-state.test.js +346 -0
- package/tests/install/materialize.test.js +244 -0
- package/tests/install/merge-policy.test.js +177 -0
- package/tests/runtime/doctor.test.js +430 -0
- package/tests/runtime/launcher.test.js +230 -0
- package/tests/runtime/module-boundary.test.js +16 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"feature_id": "FEATURE-001",
|
|
3
|
+
"feature_slug": "task-intake-dashboard",
|
|
4
|
+
"mode": "full",
|
|
5
|
+
"mode_reason": "Feature-sized workflow example with full artifact chain and approvals",
|
|
6
|
+
"routing_profile": {
|
|
7
|
+
"work_intent": "feature",
|
|
8
|
+
"behavior_delta": "extend",
|
|
9
|
+
"dominant_uncertainty": "product",
|
|
10
|
+
"scope_shape": "cross_boundary",
|
|
11
|
+
"selection_reason": "Feature-sized workflow example with full artifact chain and approvals"
|
|
12
|
+
},
|
|
13
|
+
"current_stage": "full_done",
|
|
14
|
+
"status": "done",
|
|
15
|
+
"current_owner": "MasterOrchestrator",
|
|
16
|
+
"artifacts": {
|
|
17
|
+
"task_card": null,
|
|
18
|
+
"brief": "docs/briefs/2026-03-20-task-intake-dashboard.md",
|
|
19
|
+
"spec": "docs/specs/2026-03-20-task-intake-dashboard.md",
|
|
20
|
+
"architecture": "docs/architecture/2026-03-20-task-intake-dashboard.md",
|
|
21
|
+
"plan": "docs/plans/2026-03-20-task-intake-dashboard.md",
|
|
22
|
+
"migration_report": null,
|
|
23
|
+
"qa_report": "docs/qa/2026-03-20-task-intake-dashboard.md",
|
|
24
|
+
"adr": []
|
|
25
|
+
},
|
|
26
|
+
"approvals": {
|
|
27
|
+
"pm_to_ba": {
|
|
28
|
+
"status": "approved",
|
|
29
|
+
"approved_by": "user",
|
|
30
|
+
"approved_at": "2026-03-20",
|
|
31
|
+
"notes": "Golden path brief approved"
|
|
32
|
+
},
|
|
33
|
+
"ba_to_architect": {
|
|
34
|
+
"status": "approved",
|
|
35
|
+
"approved_by": "user",
|
|
36
|
+
"approved_at": "2026-03-20",
|
|
37
|
+
"notes": "Golden path spec approved"
|
|
38
|
+
},
|
|
39
|
+
"architect_to_tech_lead": {
|
|
40
|
+
"status": "approved",
|
|
41
|
+
"approved_by": "user",
|
|
42
|
+
"approved_at": "2026-03-20",
|
|
43
|
+
"notes": "Golden path architecture approved"
|
|
44
|
+
},
|
|
45
|
+
"tech_lead_to_fullstack": {
|
|
46
|
+
"status": "approved",
|
|
47
|
+
"approved_by": "user",
|
|
48
|
+
"approved_at": "2026-03-20",
|
|
49
|
+
"notes": "Golden path plan approved"
|
|
50
|
+
},
|
|
51
|
+
"fullstack_to_qa": {
|
|
52
|
+
"status": "approved",
|
|
53
|
+
"approved_by": "system",
|
|
54
|
+
"approved_at": "2026-03-20",
|
|
55
|
+
"notes": "Documentation-only golden path prepared for QA"
|
|
56
|
+
},
|
|
57
|
+
"qa_to_done": {
|
|
58
|
+
"status": "approved",
|
|
59
|
+
"approved_by": "user",
|
|
60
|
+
"approved_at": "2026-03-20",
|
|
61
|
+
"notes": "Golden path QA report passed"
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"issues": [],
|
|
65
|
+
"retry_count": 0,
|
|
66
|
+
"escalated_from": null,
|
|
67
|
+
"escalation_reason": null,
|
|
68
|
+
"updated_at": "2026-03-20",
|
|
69
|
+
"work_item_id": "feature-001"
|
|
70
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"active_work_item_id": "feature-001",
|
|
3
|
+
"work_items": [
|
|
4
|
+
{
|
|
5
|
+
"work_item_id": "feature-001",
|
|
6
|
+
"feature_id": "FEATURE-001",
|
|
7
|
+
"feature_slug": "task-intake-dashboard",
|
|
8
|
+
"mode": "full",
|
|
9
|
+
"status": "done",
|
|
10
|
+
"state_path": ".opencode/work-items/feature-001/state.json"
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
}
|
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("fs")
|
|
4
|
+
const path = require("path")
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
ESCALATION_RETRY_THRESHOLD,
|
|
8
|
+
advanceStage,
|
|
9
|
+
clearIssues,
|
|
10
|
+
claimTask,
|
|
11
|
+
createTask,
|
|
12
|
+
createWorkItem,
|
|
13
|
+
getProfile,
|
|
14
|
+
getRuntimeStatus,
|
|
15
|
+
getVersionInfo,
|
|
16
|
+
linkArtifact,
|
|
17
|
+
listTasks,
|
|
18
|
+
listWorkItems,
|
|
19
|
+
listProfiles,
|
|
20
|
+
reassignTask,
|
|
21
|
+
recordIssue,
|
|
22
|
+
releaseTask,
|
|
23
|
+
resolveStatePath,
|
|
24
|
+
routeRework,
|
|
25
|
+
runDoctor,
|
|
26
|
+
scaffoldAndLinkArtifact,
|
|
27
|
+
selectActiveWorkItem,
|
|
28
|
+
assignQaOwner,
|
|
29
|
+
setRoutingProfile,
|
|
30
|
+
setTaskStatus,
|
|
31
|
+
setApproval,
|
|
32
|
+
showState,
|
|
33
|
+
showWorkItemState,
|
|
34
|
+
syncInstallManifest,
|
|
35
|
+
startFeature,
|
|
36
|
+
startTask,
|
|
37
|
+
validateWorkItemBoard,
|
|
38
|
+
validateState,
|
|
39
|
+
} = require("./lib/workflow-state-controller")
|
|
40
|
+
const { resolveWorkItemPaths, validateActiveMirror } = require("./lib/work-item-store")
|
|
41
|
+
const { getRuntimeContext } = require("./lib/runtime-summary")
|
|
42
|
+
|
|
43
|
+
function printUsage() {
|
|
44
|
+
console.log(`Usage:
|
|
45
|
+
node .opencode/workflow-state.js [--state <path>] show
|
|
46
|
+
node .opencode/workflow-state.js [--state <path>] status
|
|
47
|
+
node .opencode/workflow-state.js [--state <path>] doctor
|
|
48
|
+
node .opencode/workflow-state.js [--state <path>] version
|
|
49
|
+
node .opencode/workflow-state.js [--state <path>] profiles
|
|
50
|
+
node .opencode/workflow-state.js [--state <path>] show-profile <name>
|
|
51
|
+
node .opencode/workflow-state.js [--state <path>] sync-install-manifest <name>
|
|
52
|
+
node .opencode/workflow-state.js [--state <path>] validate
|
|
53
|
+
node .opencode/workflow-state.js [--state <path>] start-feature <feature_id> <feature_slug>
|
|
54
|
+
node .opencode/workflow-state.js [--state <path>] start-task <mode> <feature_id> <feature_slug> <mode_reason>
|
|
55
|
+
node .opencode/workflow-state.js [--state <path>] create-work-item <mode> <feature_id> <feature_slug> <mode_reason>
|
|
56
|
+
node .opencode/workflow-state.js [--state <path>] list-work-items
|
|
57
|
+
node .opencode/workflow-state.js [--state <path>] show-work-item <work_item_id>
|
|
58
|
+
node .opencode/workflow-state.js [--state <path>] activate-work-item <work_item_id>
|
|
59
|
+
node .opencode/workflow-state.js [--state <path>] advance-stage <stage>
|
|
60
|
+
node .opencode/workflow-state.js [--state <path>] set-approval <gate> <status> [approved_by] [approved_at] [notes]
|
|
61
|
+
node .opencode/workflow-state.js [--state <path>] link-artifact <kind> <path>
|
|
62
|
+
node .opencode/workflow-state.js [--state <path>] scaffold-artifact <task_card|plan|migration_report> <slug>
|
|
63
|
+
node .opencode/workflow-state.js [--state <path>] set-routing-profile <work_intent> <behavior_delta> <dominant_uncertainty> <scope_shape> <selection_reason>
|
|
64
|
+
node .opencode/workflow-state.js [--state <path>] list-tasks <work_item_id>
|
|
65
|
+
node .opencode/workflow-state.js [--state <path>] create-task <work_item_id> <task_id> <title> <kind> [branch] [worktree_path]
|
|
66
|
+
node .opencode/workflow-state.js [--state <path>] claim-task <work_item_id> <task_id> <owner> <requested_by>
|
|
67
|
+
node .opencode/workflow-state.js [--state <path>] release-task <work_item_id> <task_id> <requested_by>
|
|
68
|
+
node .opencode/workflow-state.js [--state <path>] reassign-task <work_item_id> <task_id> <owner> <requested_by>
|
|
69
|
+
node .opencode/workflow-state.js [--state <path>] assign-qa-owner <work_item_id> <task_id> <qa_owner> <requested_by>
|
|
70
|
+
node .opencode/workflow-state.js [--state <path>] set-task-status <work_item_id> <task_id> <status>
|
|
71
|
+
node .opencode/workflow-state.js [--state <path>] validate-work-item-board <work_item_id>
|
|
72
|
+
node .opencode/workflow-state.js [--state <path>] record-issue <issue_id> <title> <type> <severity> <rooted_in> <recommended_owner> <evidence> <artifact_refs>
|
|
73
|
+
node .opencode/workflow-state.js [--state <path>] clear-issues
|
|
74
|
+
node .opencode/workflow-state.js [--state <path>] route-rework <issue_type> [repeat_failed_fix=true|false]`)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function parseGlobalFlags(argv) {
|
|
78
|
+
const args = [...argv]
|
|
79
|
+
let statePath = null
|
|
80
|
+
|
|
81
|
+
while (args[0] === "--state") {
|
|
82
|
+
args.shift()
|
|
83
|
+
if (!args[0]) {
|
|
84
|
+
throw new Error("Missing value for --state")
|
|
85
|
+
}
|
|
86
|
+
statePath = args.shift()
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return { args, statePath }
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function printState(prefix, result) {
|
|
93
|
+
console.log(prefix)
|
|
94
|
+
console.log(`State file: ${result.statePath}`)
|
|
95
|
+
printRuntimeTaskContext(result.runtimeContext)
|
|
96
|
+
console.log(JSON.stringify(result.state, null, 2))
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function printRuntimeTaskContext(context) {
|
|
100
|
+
if (!context) {
|
|
101
|
+
return
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (context.activeWorkItemId) {
|
|
105
|
+
console.log(`active work item id: ${context.activeWorkItemId}`)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (typeof context.workItemCount === "number") {
|
|
109
|
+
console.log(`work items tracked: ${context.workItemCount}`)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (context.taskBoardSummary) {
|
|
113
|
+
console.log(
|
|
114
|
+
`task board: ${context.taskBoardSummary.total} tasks | ready ${context.taskBoardSummary.ready} | active ${context.taskBoardSummary.active}`,
|
|
115
|
+
)
|
|
116
|
+
if (context.taskBoardSummary.activeTasks.length > 0) {
|
|
117
|
+
console.log(`active tasks: ${context.taskBoardSummary.activeTasks.join("; ")}`)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function printRuntimeStatus(runtime) {
|
|
123
|
+
console.log("OpenKit runtime status:")
|
|
124
|
+
console.log(`project root: ${runtime.projectRoot}`)
|
|
125
|
+
console.log(`kit: ${runtime.kitName} v${runtime.kitVersion}`)
|
|
126
|
+
console.log(`entry agent: ${runtime.entryAgent}`)
|
|
127
|
+
console.log(`active profile: ${runtime.activeProfile}`)
|
|
128
|
+
console.log(`registry: ${runtime.registryPath}`)
|
|
129
|
+
console.log(`install manifest: ${runtime.installManifestPath}`)
|
|
130
|
+
console.log(`state file: ${runtime.statePath}`)
|
|
131
|
+
console.log(`mode: ${runtime.state.mode}`)
|
|
132
|
+
console.log(`stage: ${runtime.state.current_stage}`)
|
|
133
|
+
console.log(`status: ${runtime.state.status}`)
|
|
134
|
+
console.log(`owner: ${runtime.state.current_owner}`)
|
|
135
|
+
if (runtime.state.feature_id && runtime.state.feature_slug) {
|
|
136
|
+
console.log(`work item: ${runtime.state.feature_id} (${runtime.state.feature_slug})`)
|
|
137
|
+
}
|
|
138
|
+
printRuntimeTaskContext(runtime.runtimeContext)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function printDoctorReport(report) {
|
|
142
|
+
console.log("OpenKit doctor:")
|
|
143
|
+
console.log(`active profile: ${report.runtime.activeProfile}`)
|
|
144
|
+
console.log(`registry: ${report.runtime.registryPath}`)
|
|
145
|
+
console.log(`install manifest: ${report.runtime.installManifestPath}`)
|
|
146
|
+
printRuntimeTaskContext(report.runtime.runtimeContext)
|
|
147
|
+
for (const check of report.checks) {
|
|
148
|
+
console.log(`[${check.ok ? "ok" : "error"}] ${check.label}`)
|
|
149
|
+
}
|
|
150
|
+
console.log(
|
|
151
|
+
`Summary: ${report.summary.ok} ok, ${report.summary.warn} warn, ${report.summary.error} error`,
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function printProfiles(profiles) {
|
|
156
|
+
console.log("OpenKit profiles:")
|
|
157
|
+
for (const profile of profiles) {
|
|
158
|
+
const marker = profile.defaultForRepository ? "*" : " "
|
|
159
|
+
console.log(`${marker} ${profile.name} - ${profile.description}`)
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function printProfile(profile) {
|
|
164
|
+
console.log(`Profile: ${profile.name}`)
|
|
165
|
+
console.log(`default: ${profile.defaultForRepository ? "yes" : "no"}`)
|
|
166
|
+
console.log(`components: ${profile.componentRefs.join(", ")}`)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function printVersion(info) {
|
|
170
|
+
console.log(`OpenKit version: ${info.kitVersion}`)
|
|
171
|
+
console.log(`active profile: ${info.activeProfile}`)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function printWorkItems(result) {
|
|
175
|
+
console.log(`Active work item: ${result.index.active_work_item_id ?? "none"}`)
|
|
176
|
+
for (const item of result.workItems) {
|
|
177
|
+
const marker = item.work_item_id === result.index.active_work_item_id ? "*" : " "
|
|
178
|
+
console.log(`${marker} ${item.work_item_id} | ${item.feature_id} | ${item.mode} | ${item.status}`)
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function printWorkItem(result) {
|
|
183
|
+
console.log(`Work item: ${result.state.work_item_id}`)
|
|
184
|
+
console.log(`feature: ${result.state.feature_id} (${result.state.feature_slug})`)
|
|
185
|
+
console.log(`mode: ${result.state.mode}`)
|
|
186
|
+
console.log(`stage: ${result.state.current_stage}`)
|
|
187
|
+
console.log(`status: ${result.state.status}`)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function printTasks(result) {
|
|
191
|
+
console.log(`Tasks for ${result.workItemId}:`)
|
|
192
|
+
for (const task of result.tasks) {
|
|
193
|
+
console.log(`${task.task_id} | ${task.status} | ${task.kind} | ${task.title}`)
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function toBoolean(value) {
|
|
198
|
+
return value === "true"
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function requireArgument(value, placeholder, command) {
|
|
202
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
203
|
+
throw new Error(`${command} requires ${placeholder}`)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return value
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function enrichStateResult(result, statePath) {
|
|
210
|
+
const runtimeRoot = path.dirname(path.dirname(statePath ?? result.statePath))
|
|
211
|
+
return {
|
|
212
|
+
...result,
|
|
213
|
+
runtimeContext: getRuntimeContext(runtimeRoot, result.state),
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function extendDoctorReport(report, statePath) {
|
|
218
|
+
const runtimeRoot = path.dirname(path.dirname(statePath))
|
|
219
|
+
const checks = [...report.checks]
|
|
220
|
+
const runtimeContext = getRuntimeContext(runtimeRoot, report.runtime.state)
|
|
221
|
+
const activeWorkItemId = runtimeContext.activeWorkItemId
|
|
222
|
+
const indexPath = path.join(runtimeRoot, ".opencode", "work-items", "index.json")
|
|
223
|
+
const index = fs.existsSync(indexPath) ? JSON.parse(fs.readFileSync(indexPath, "utf8")) : null
|
|
224
|
+
const activeWorkItem = index?.work_items?.find((entry) => entry.work_item_id === activeWorkItemId) ?? null
|
|
225
|
+
let activePointerOk = !index || !activeWorkItemId
|
|
226
|
+
let mirrorOk = !index || !activeWorkItemId
|
|
227
|
+
let boardOk = true
|
|
228
|
+
|
|
229
|
+
if (index && activeWorkItemId) {
|
|
230
|
+
const activeStatePath = resolveWorkItemPaths(runtimeRoot, activeWorkItemId).statePath
|
|
231
|
+
activePointerOk = fs.existsSync(activeStatePath)
|
|
232
|
+
|
|
233
|
+
try {
|
|
234
|
+
validateActiveMirror(runtimeRoot)
|
|
235
|
+
mirrorOk = true
|
|
236
|
+
} catch (_error) {
|
|
237
|
+
mirrorOk = false
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (report.runtime.state?.mode === "full" && report.runtime.state?.work_item_id) {
|
|
242
|
+
boardOk = report.runtime.state.current_stage === "full_implementation" || report.runtime.state.current_stage === "full_qa"
|
|
243
|
+
? runtimeContext.taskBoardPresent
|
|
244
|
+
: true
|
|
245
|
+
} else if (!report.runtime.state && activeWorkItem?.mode === "full") {
|
|
246
|
+
try {
|
|
247
|
+
validateWorkItemBoard(activeWorkItemId, statePath)
|
|
248
|
+
boardOk = true
|
|
249
|
+
} catch (_error) {
|
|
250
|
+
boardOk = false
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
checks.push(
|
|
255
|
+
{ label: "active work item pointer resolves to stored state", ok: activePointerOk },
|
|
256
|
+
{ label: "compatibility mirror matches active work item state", ok: mirrorOk },
|
|
257
|
+
{ label: "active work item task board is valid", ok: boardOk },
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
const summary = checks.reduce(
|
|
261
|
+
(counts, check) => {
|
|
262
|
+
if (check.ok) {
|
|
263
|
+
counts.ok += 1
|
|
264
|
+
} else {
|
|
265
|
+
counts.error += 1
|
|
266
|
+
}
|
|
267
|
+
return counts
|
|
268
|
+
},
|
|
269
|
+
{ ok: 0, warn: 0, error: 0 },
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
return {
|
|
273
|
+
...report,
|
|
274
|
+
runtime: {
|
|
275
|
+
...report.runtime,
|
|
276
|
+
runtimeContext,
|
|
277
|
+
},
|
|
278
|
+
checks,
|
|
279
|
+
summary,
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
async function main() {
|
|
284
|
+
const { args, statePath } = parseGlobalFlags(process.argv.slice(2))
|
|
285
|
+
const [command, ...rest] = args
|
|
286
|
+
|
|
287
|
+
if (!command) {
|
|
288
|
+
printUsage()
|
|
289
|
+
process.exit(1)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
let result
|
|
293
|
+
switch (command) {
|
|
294
|
+
case "show":
|
|
295
|
+
result = enrichStateResult(showState(statePath), statePath)
|
|
296
|
+
printState("Workflow state:", result)
|
|
297
|
+
return
|
|
298
|
+
case "status":
|
|
299
|
+
result = getRuntimeStatus(statePath)
|
|
300
|
+
result.runtimeContext = getRuntimeContext(result.runtimeRoot, result.state)
|
|
301
|
+
printRuntimeStatus(result)
|
|
302
|
+
return
|
|
303
|
+
case "doctor":
|
|
304
|
+
result = extendDoctorReport(runDoctor(statePath), resolveStatePath(statePath))
|
|
305
|
+
printDoctorReport(result)
|
|
306
|
+
process.exit(result.summary.error > 0 ? 1 : 0)
|
|
307
|
+
return
|
|
308
|
+
case "version":
|
|
309
|
+
result = getVersionInfo(statePath)
|
|
310
|
+
printVersion(result)
|
|
311
|
+
return
|
|
312
|
+
case "profiles":
|
|
313
|
+
result = listProfiles(statePath)
|
|
314
|
+
printProfiles(result)
|
|
315
|
+
return
|
|
316
|
+
case "show-profile":
|
|
317
|
+
result = getProfile(rest[0], statePath)
|
|
318
|
+
printProfile(result)
|
|
319
|
+
return
|
|
320
|
+
case "sync-install-manifest":
|
|
321
|
+
result = syncInstallManifest(rest[0], statePath)
|
|
322
|
+
console.log(`Updated install manifest profile to '${result.profile.name}'`)
|
|
323
|
+
console.log(`Install manifest: ${result.installManifestPath}`)
|
|
324
|
+
return
|
|
325
|
+
case "validate":
|
|
326
|
+
result = validateState(statePath)
|
|
327
|
+
console.log(`Workflow state is valid: ${result.statePath}`)
|
|
328
|
+
return
|
|
329
|
+
case "start-feature":
|
|
330
|
+
result = startFeature(rest[0], rest[1], statePath)
|
|
331
|
+
console.log(`Started feature ${rest[0]} (${rest[1]})`)
|
|
332
|
+
console.log(`State file: ${result.statePath}`)
|
|
333
|
+
return
|
|
334
|
+
case "start-task":
|
|
335
|
+
result = startTask(rest[0], rest[1], rest[2], rest.slice(3).join(" "), statePath)
|
|
336
|
+
console.log(`Started ${result.state.mode} task ${rest[1]} (${rest[2]})`)
|
|
337
|
+
console.log(`State file: ${result.statePath}`)
|
|
338
|
+
return
|
|
339
|
+
case "create-work-item":
|
|
340
|
+
result = createWorkItem(rest[0], rest[1], rest[2], rest.slice(3).join(" "), statePath)
|
|
341
|
+
console.log(`Created ${result.state.mode} work item ${rest[1]} (${rest[2]})`)
|
|
342
|
+
console.log(`State file: ${result.statePath}`)
|
|
343
|
+
return
|
|
344
|
+
case "list-work-items":
|
|
345
|
+
result = listWorkItems(statePath)
|
|
346
|
+
printWorkItems(result)
|
|
347
|
+
return
|
|
348
|
+
case "show-work-item":
|
|
349
|
+
result = showWorkItemState(rest[0], statePath)
|
|
350
|
+
printWorkItem(result)
|
|
351
|
+
return
|
|
352
|
+
case "activate-work-item":
|
|
353
|
+
result = selectActiveWorkItem(rest[0], statePath)
|
|
354
|
+
console.log(`Activated work item '${result.state.work_item_id}'`)
|
|
355
|
+
console.log(`State file: ${result.statePath}`)
|
|
356
|
+
return
|
|
357
|
+
case "advance-stage":
|
|
358
|
+
result = advanceStage(rest[0], statePath)
|
|
359
|
+
console.log(`Advanced workflow to stage '${result.state.current_stage}'`)
|
|
360
|
+
console.log(`State file: ${result.statePath}`)
|
|
361
|
+
return
|
|
362
|
+
case "set-approval":
|
|
363
|
+
result = setApproval(rest[0], rest[1], rest[2], rest[3], rest[4], statePath)
|
|
364
|
+
console.log(`Updated approval gate '${rest[0]}' to '${rest[1]}'`)
|
|
365
|
+
console.log(`State file: ${result.statePath}`)
|
|
366
|
+
return
|
|
367
|
+
case "link-artifact":
|
|
368
|
+
result = linkArtifact(rest[0], rest[1], statePath)
|
|
369
|
+
console.log(`Linked artifact '${rest[0]}' -> '${rest[1]}'`)
|
|
370
|
+
console.log(`State file: ${result.statePath}`)
|
|
371
|
+
return
|
|
372
|
+
case "scaffold-artifact":
|
|
373
|
+
result = scaffoldAndLinkArtifact(rest[0], rest[1], statePath)
|
|
374
|
+
console.log(`Created artifact '${rest[0]}' at '${result.artifactPath}'`)
|
|
375
|
+
console.log(`State file: ${result.statePath}`)
|
|
376
|
+
return
|
|
377
|
+
case "set-routing-profile":
|
|
378
|
+
result = setRoutingProfile(rest[0], rest[1], rest[2], rest[3], rest.slice(4).join(" "), statePath)
|
|
379
|
+
console.log(`Updated routing profile for mode '${result.state.mode}'`)
|
|
380
|
+
console.log(`State file: ${result.statePath}`)
|
|
381
|
+
return
|
|
382
|
+
case "list-tasks":
|
|
383
|
+
result = listTasks(rest[0], statePath)
|
|
384
|
+
printTasks(result)
|
|
385
|
+
return
|
|
386
|
+
case "create-task":
|
|
387
|
+
result = createTask(
|
|
388
|
+
rest[0],
|
|
389
|
+
{
|
|
390
|
+
task_id: rest[1],
|
|
391
|
+
title: rest[2],
|
|
392
|
+
kind: rest[3],
|
|
393
|
+
...(rest[4] && rest[5]
|
|
394
|
+
? {
|
|
395
|
+
worktree_metadata: {
|
|
396
|
+
task_id: rest[1],
|
|
397
|
+
branch: rest[4],
|
|
398
|
+
worktree_path: rest[5],
|
|
399
|
+
},
|
|
400
|
+
}
|
|
401
|
+
: {}),
|
|
402
|
+
},
|
|
403
|
+
statePath,
|
|
404
|
+
)
|
|
405
|
+
console.log(`Created task '${rest[1]}' on work item '${rest[0]}'`)
|
|
406
|
+
console.log(`State file: ${result.statePath}`)
|
|
407
|
+
return
|
|
408
|
+
case "claim-task":
|
|
409
|
+
result = claimTask(rest[0], rest[1], rest[2], statePath, {
|
|
410
|
+
requestedBy: requireArgument(rest[3], "<requested_by>", "claim-task"),
|
|
411
|
+
})
|
|
412
|
+
console.log(`Claimed task '${rest[1]}' for '${rest[2]}'`)
|
|
413
|
+
console.log(`State file: ${result.statePath}`)
|
|
414
|
+
return
|
|
415
|
+
case "release-task":
|
|
416
|
+
result = releaseTask(rest[0], rest[1], statePath, {
|
|
417
|
+
requestedBy: requireArgument(rest[2], "<requested_by>", "release-task"),
|
|
418
|
+
})
|
|
419
|
+
console.log(`Released task '${rest[1]}'`)
|
|
420
|
+
console.log(`State file: ${result.statePath}`)
|
|
421
|
+
return
|
|
422
|
+
case "reassign-task":
|
|
423
|
+
result = reassignTask(rest[0], rest[1], rest[2], statePath, {
|
|
424
|
+
requestedBy: requireArgument(rest[3], "<requested_by>", "reassign-task"),
|
|
425
|
+
})
|
|
426
|
+
console.log(`Reassigned task '${rest[1]}' to '${rest[2]}'`)
|
|
427
|
+
console.log(`State file: ${result.statePath}`)
|
|
428
|
+
return
|
|
429
|
+
case "assign-qa-owner":
|
|
430
|
+
result = assignQaOwner(rest[0], rest[1], rest[2], statePath, {
|
|
431
|
+
requestedBy: requireArgument(rest[3], "<requested_by>", "assign-qa-owner"),
|
|
432
|
+
})
|
|
433
|
+
console.log(`Assigned QA owner '${rest[2]}' to task '${rest[1]}'`)
|
|
434
|
+
console.log(`State file: ${result.statePath}`)
|
|
435
|
+
return
|
|
436
|
+
case "set-task-status":
|
|
437
|
+
result = setTaskStatus(rest[0], rest[1], rest[2], statePath)
|
|
438
|
+
console.log(`Updated task '${rest[1]}' to '${rest[2]}'`)
|
|
439
|
+
console.log(`State file: ${result.statePath}`)
|
|
440
|
+
return
|
|
441
|
+
case "validate-work-item-board":
|
|
442
|
+
result = validateWorkItemBoard(rest[0], statePath)
|
|
443
|
+
console.log(`Task board is valid for work item '${result.workItemId}'`)
|
|
444
|
+
console.log(`State file: ${result.statePath}`)
|
|
445
|
+
return
|
|
446
|
+
case "record-issue":
|
|
447
|
+
result = recordIssue(
|
|
448
|
+
{
|
|
449
|
+
issue_id: rest[0],
|
|
450
|
+
title: rest[1],
|
|
451
|
+
type: rest[2],
|
|
452
|
+
severity: rest[3],
|
|
453
|
+
rooted_in: rest[4],
|
|
454
|
+
recommended_owner: rest[5],
|
|
455
|
+
evidence: rest[6],
|
|
456
|
+
artifact_refs: rest[7],
|
|
457
|
+
},
|
|
458
|
+
statePath,
|
|
459
|
+
)
|
|
460
|
+
console.log(`Recorded issue '${rest[0]}'`)
|
|
461
|
+
console.log(`State file: ${result.statePath}`)
|
|
462
|
+
return
|
|
463
|
+
case "clear-issues":
|
|
464
|
+
result = clearIssues(statePath)
|
|
465
|
+
console.log("Cleared workflow issues")
|
|
466
|
+
console.log(`State file: ${result.statePath}`)
|
|
467
|
+
return
|
|
468
|
+
case "route-rework":
|
|
469
|
+
result = routeRework(rest[0], toBoolean(rest[1] ?? "false"), statePath)
|
|
470
|
+
console.log(`Routed rework for '${rest[0]}' to stage '${result.state.current_stage}'`)
|
|
471
|
+
if (result.state.retry_count >= ESCALATION_RETRY_THRESHOLD) {
|
|
472
|
+
console.log(
|
|
473
|
+
`Escalation threshold reached: retry_count is at or above ${ESCALATION_RETRY_THRESHOLD}`,
|
|
474
|
+
)
|
|
475
|
+
}
|
|
476
|
+
console.log(`State file: ${result.statePath}`)
|
|
477
|
+
return
|
|
478
|
+
case "help":
|
|
479
|
+
printUsage()
|
|
480
|
+
return
|
|
481
|
+
default:
|
|
482
|
+
throw new Error(`Unknown command '${command}'`)
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
main().catch((error) => {
|
|
487
|
+
console.error(error.message)
|
|
488
|
+
process.exit(1)
|
|
489
|
+
})
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"feature_id": "FEATURE-001",
|
|
3
|
+
"feature_slug": "task-intake-dashboard",
|
|
4
|
+
"mode": "full",
|
|
5
|
+
"mode_reason": "Feature-sized workflow example with full artifact chain and approvals",
|
|
6
|
+
"routing_profile": {
|
|
7
|
+
"work_intent": "feature",
|
|
8
|
+
"behavior_delta": "extend",
|
|
9
|
+
"dominant_uncertainty": "product",
|
|
10
|
+
"scope_shape": "cross_boundary",
|
|
11
|
+
"selection_reason": "Feature-sized workflow example with full artifact chain and approvals"
|
|
12
|
+
},
|
|
13
|
+
"current_stage": "full_done",
|
|
14
|
+
"status": "done",
|
|
15
|
+
"current_owner": "MasterOrchestrator",
|
|
16
|
+
"artifacts": {
|
|
17
|
+
"task_card": null,
|
|
18
|
+
"brief": "docs/briefs/2026-03-20-task-intake-dashboard.md",
|
|
19
|
+
"spec": "docs/specs/2026-03-20-task-intake-dashboard.md",
|
|
20
|
+
"architecture": "docs/architecture/2026-03-20-task-intake-dashboard.md",
|
|
21
|
+
"plan": "docs/plans/2026-03-20-task-intake-dashboard.md",
|
|
22
|
+
"migration_report": null,
|
|
23
|
+
"qa_report": "docs/qa/2026-03-20-task-intake-dashboard.md",
|
|
24
|
+
"adr": []
|
|
25
|
+
},
|
|
26
|
+
"approvals": {
|
|
27
|
+
"pm_to_ba": {
|
|
28
|
+
"status": "approved",
|
|
29
|
+
"approved_by": "user",
|
|
30
|
+
"approved_at": "2026-03-20",
|
|
31
|
+
"notes": "Golden path brief approved"
|
|
32
|
+
},
|
|
33
|
+
"ba_to_architect": {
|
|
34
|
+
"status": "approved",
|
|
35
|
+
"approved_by": "user",
|
|
36
|
+
"approved_at": "2026-03-20",
|
|
37
|
+
"notes": "Golden path spec approved"
|
|
38
|
+
},
|
|
39
|
+
"architect_to_tech_lead": {
|
|
40
|
+
"status": "approved",
|
|
41
|
+
"approved_by": "user",
|
|
42
|
+
"approved_at": "2026-03-20",
|
|
43
|
+
"notes": "Golden path architecture approved"
|
|
44
|
+
},
|
|
45
|
+
"tech_lead_to_fullstack": {
|
|
46
|
+
"status": "approved",
|
|
47
|
+
"approved_by": "user",
|
|
48
|
+
"approved_at": "2026-03-20",
|
|
49
|
+
"notes": "Golden path plan approved"
|
|
50
|
+
},
|
|
51
|
+
"fullstack_to_qa": {
|
|
52
|
+
"status": "approved",
|
|
53
|
+
"approved_by": "system",
|
|
54
|
+
"approved_at": "2026-03-20",
|
|
55
|
+
"notes": "Documentation-only golden path prepared for QA"
|
|
56
|
+
},
|
|
57
|
+
"qa_to_done": {
|
|
58
|
+
"status": "approved",
|
|
59
|
+
"approved_by": "user",
|
|
60
|
+
"approved_at": "2026-03-20",
|
|
61
|
+
"notes": "Golden path QA report passed"
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"issues": [],
|
|
65
|
+
"retry_count": 0,
|
|
66
|
+
"escalated_from": null,
|
|
67
|
+
"escalation_reason": null,
|
|
68
|
+
"updated_at": "2026-03-20",
|
|
69
|
+
"work_item_id": "feature-001"
|
|
70
|
+
}
|