@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.
Files changed (178) hide show
  1. package/.opencode/README.md +47 -0
  2. package/.opencode/install-manifest.json +41 -0
  3. package/.opencode/lib/artifact-scaffolder.js +111 -0
  4. package/.opencode/lib/contract-consistency.js +218 -0
  5. package/.opencode/lib/parallel-execution-rules.js +261 -0
  6. package/.opencode/lib/runtime-paths.js +95 -0
  7. package/.opencode/lib/runtime-summary.js +82 -0
  8. package/.opencode/lib/state-guard.js +99 -0
  9. package/.opencode/lib/task-board-rules.js +375 -0
  10. package/.opencode/lib/work-item-store.js +280 -0
  11. package/.opencode/lib/workflow-state-controller.js +1739 -0
  12. package/.opencode/lib/workflow-state-rules.js +331 -0
  13. package/.opencode/opencode.json +93 -0
  14. package/.opencode/package.json +3 -0
  15. package/.opencode/tests/artifact-scaffolder.test.js +733 -0
  16. package/.opencode/tests/multi-work-item-runtime.test.js +369 -0
  17. package/.opencode/tests/parallel-execution-runtime.test.js +259 -0
  18. package/.opencode/tests/session-start-hook.test.js +357 -0
  19. package/.opencode/tests/state-guard.test.js +124 -0
  20. package/.opencode/tests/task-board-rules.test.js +204 -0
  21. package/.opencode/tests/work-item-store.test.js +380 -0
  22. package/.opencode/tests/workflow-behavior.test.js +149 -0
  23. package/.opencode/tests/workflow-contract-consistency.test.js +387 -0
  24. package/.opencode/tests/workflow-state-cli.test.js +1275 -0
  25. package/.opencode/tests/workflow-state-controller.test.js +1038 -0
  26. package/.opencode/work-items/feature-001/state.json +70 -0
  27. package/.opencode/work-items/index.json +13 -0
  28. package/.opencode/workflow-state.js +489 -0
  29. package/.opencode/workflow-state.json +70 -0
  30. package/AGENTS.md +265 -0
  31. package/README.md +401 -0
  32. package/agents/architect-agent.md +63 -0
  33. package/agents/ba-agent.md +56 -0
  34. package/agents/code-reviewer.md +77 -0
  35. package/agents/fullstack-agent.md +115 -0
  36. package/agents/master-orchestrator.md +60 -0
  37. package/agents/pm-agent.md +56 -0
  38. package/agents/qa-agent.md +124 -0
  39. package/agents/tech-lead-agent.md +60 -0
  40. package/assets/install-bundle/README.md +7 -0
  41. package/assets/install-bundle/opencode/README.md +11 -0
  42. package/assets/install-bundle/opencode/agents/ArchitectAgent.md +63 -0
  43. package/assets/install-bundle/opencode/agents/BAAgent.md +56 -0
  44. package/assets/install-bundle/opencode/agents/CodeReviewer.md +77 -0
  45. package/assets/install-bundle/opencode/agents/FullstackAgent.md +115 -0
  46. package/assets/install-bundle/opencode/agents/MasterOrchestrator.md +60 -0
  47. package/assets/install-bundle/opencode/agents/PMAgent.md +56 -0
  48. package/assets/install-bundle/opencode/agents/QAAgent.md +124 -0
  49. package/assets/install-bundle/opencode/agents/TechLeadAgent.md +60 -0
  50. package/assets/install-bundle/opencode/commands/brainstorm.md +44 -0
  51. package/assets/install-bundle/opencode/commands/delivery.md +45 -0
  52. package/assets/install-bundle/opencode/commands/execute-plan.md +44 -0
  53. package/assets/install-bundle/opencode/commands/migrate.md +61 -0
  54. package/assets/install-bundle/opencode/commands/quick-task.md +45 -0
  55. package/assets/install-bundle/opencode/commands/task.md +46 -0
  56. package/assets/install-bundle/opencode/commands/write-plan.md +50 -0
  57. package/assets/install-bundle/opencode/context/core/lane-selection.md +54 -0
  58. package/assets/install-bundle/opencode/skills/brainstorming/SKILL.md +51 -0
  59. package/assets/install-bundle/opencode/skills/code-review/SKILL.md +48 -0
  60. package/assets/install-bundle/opencode/skills/subagent-driven-development/SKILL.md +79 -0
  61. package/assets/install-bundle/opencode/skills/systematic-debugging/SKILL.md +61 -0
  62. package/assets/install-bundle/opencode/skills/test-driven-development/SKILL.md +48 -0
  63. package/assets/install-bundle/opencode/skills/using-skills/SKILL.md +39 -0
  64. package/assets/install-bundle/opencode/skills/verification-before-completion/SKILL.md +137 -0
  65. package/assets/install-bundle/opencode/skills/writing-plans/SKILL.md +68 -0
  66. package/assets/install-bundle/opencode/skills/writing-specs/SKILL.md +47 -0
  67. package/assets/opencode.json.template +11 -0
  68. package/assets/openkit-install.json.template +19 -0
  69. package/bin/openkit.js +9 -0
  70. package/commands/brainstorm.md +44 -0
  71. package/commands/delivery.md +45 -0
  72. package/commands/execute-plan.md +44 -0
  73. package/commands/migrate.md +61 -0
  74. package/commands/quick-task.md +45 -0
  75. package/commands/task.md +46 -0
  76. package/commands/write-plan.md +50 -0
  77. package/context/core/approval-gates.md +146 -0
  78. package/context/core/code-quality.md +42 -0
  79. package/context/core/issue-routing.md +85 -0
  80. package/context/core/lane-selection.md +54 -0
  81. package/context/core/project-config.md +143 -0
  82. package/context/core/session-resume.md +85 -0
  83. package/context/core/workflow-state-schema.md +224 -0
  84. package/context/core/workflow.md +442 -0
  85. package/context/navigation.md +94 -0
  86. package/docs/adr/README.md +6 -0
  87. package/docs/architecture/2026-03-20-task-intake-dashboard.md +54 -0
  88. package/docs/architecture/README.md +7 -0
  89. package/docs/briefs/2026-03-20-task-intake-dashboard.md +48 -0
  90. package/docs/briefs/README.md +7 -0
  91. package/docs/governance/README.md +25 -0
  92. package/docs/governance/adr-policy.md +27 -0
  93. package/docs/governance/definition-of-done.md +17 -0
  94. package/docs/governance/naming-conventions.md +21 -0
  95. package/docs/governance/severity-levels.md +12 -0
  96. package/docs/maintainer/README.md +51 -0
  97. package/docs/operations/README.md +79 -0
  98. package/docs/operations/internal-records/2026-03-24-release-checklist.md +79 -0
  99. package/docs/operations/internal-records/2026-03-24-simplified-install-ux.md +36 -0
  100. package/docs/operations/internal-records/README.md +18 -0
  101. package/docs/operations/runbooks/README.md +23 -0
  102. package/docs/operations/runbooks/openkit-daily-usage.md +288 -0
  103. package/docs/operations/runbooks/workflow-state-smoke-tests.md +302 -0
  104. package/docs/operator/README.md +50 -0
  105. package/docs/plans/2026-03-20-task-intake-dashboard.md +49 -0
  106. package/docs/plans/2026-03-21-openkit-full-delivery-multi-task-runtime.md +521 -0
  107. package/docs/plans/2026-03-23-openkit-global-install-runtime.md +157 -0
  108. package/docs/plans/README.md +7 -0
  109. package/docs/qa/2026-03-20-task-intake-dashboard.md +41 -0
  110. package/docs/qa/README.md +7 -0
  111. package/docs/specs/2026-03-20-task-intake-dashboard.md +50 -0
  112. package/docs/specs/2026-03-21-openkit-full-delivery-multi-task-runtime.md +462 -0
  113. package/docs/specs/README.md +7 -0
  114. package/docs/templates/README.md +36 -0
  115. package/docs/templates/adr-template.md +18 -0
  116. package/docs/templates/architecture-template.md +31 -0
  117. package/docs/templates/implementation-plan-template.md +32 -0
  118. package/docs/templates/migration-baseline-checklist.md +48 -0
  119. package/docs/templates/migration-plan-template.md +52 -0
  120. package/docs/templates/migration-report-template.md +74 -0
  121. package/docs/templates/migration-verify-checklist.md +39 -0
  122. package/docs/templates/product-brief-template.md +32 -0
  123. package/docs/templates/qa-report-template.md +37 -0
  124. package/docs/templates/quick-task-template.md +36 -0
  125. package/docs/templates/spec-template.md +31 -0
  126. package/hooks/hooks.json +16 -0
  127. package/hooks/session-start +162 -0
  128. package/package.json +24 -0
  129. package/registry.json +328 -0
  130. package/skills/brainstorming/SKILL.md +51 -0
  131. package/skills/code-review/SKILL.md +48 -0
  132. package/skills/subagent-driven-development/SKILL.md +79 -0
  133. package/skills/systematic-debugging/SKILL.md +61 -0
  134. package/skills/test-driven-development/SKILL.md +48 -0
  135. package/skills/using-skills/SKILL.md +39 -0
  136. package/skills/verification-before-completion/SKILL.md +137 -0
  137. package/skills/writing-plans/SKILL.md +68 -0
  138. package/skills/writing-specs/SKILL.md +47 -0
  139. package/src/audit/vietnamese-detection.js +259 -0
  140. package/src/cli/commands/detect-vietnamese.js +24 -0
  141. package/src/cli/commands/doctor.js +33 -0
  142. package/src/cli/commands/help.js +33 -0
  143. package/src/cli/commands/init.js +25 -0
  144. package/src/cli/commands/install-global.js +26 -0
  145. package/src/cli/commands/install.js +25 -0
  146. package/src/cli/commands/run.js +63 -0
  147. package/src/cli/commands/uninstall.js +32 -0
  148. package/src/cli/commands/upgrade.js +25 -0
  149. package/src/cli/conflict-output.js +19 -0
  150. package/src/cli/index.js +56 -0
  151. package/src/global/doctor.js +101 -0
  152. package/src/global/ensure-install.js +32 -0
  153. package/src/global/install-state.js +73 -0
  154. package/src/global/launcher.js +51 -0
  155. package/src/global/materialize.js +123 -0
  156. package/src/global/paths.js +85 -0
  157. package/src/global/uninstall.js +25 -0
  158. package/src/global/workspace-state.js +63 -0
  159. package/src/install/asset-manifest.js +284 -0
  160. package/src/install/conflicts.js +43 -0
  161. package/src/install/discovery.js +138 -0
  162. package/src/install/install-state.js +136 -0
  163. package/src/install/materialize.js +158 -0
  164. package/src/install/merge-policy.js +145 -0
  165. package/src/runtime/doctor.js +281 -0
  166. package/src/runtime/launcher.js +49 -0
  167. package/src/runtime/opencode-layering.js +135 -0
  168. package/src/runtime/openkit-managed-summary.js +27 -0
  169. package/tests/cli/openkit-cli.test.js +417 -0
  170. package/tests/global/doctor.test.js +130 -0
  171. package/tests/global/ensure-install.test.js +105 -0
  172. package/tests/install/discovery.test.js +124 -0
  173. package/tests/install/install-state.test.js +346 -0
  174. package/tests/install/materialize.test.js +244 -0
  175. package/tests/install/merge-policy.test.js +177 -0
  176. package/tests/runtime/doctor.test.js +430 -0
  177. package/tests/runtime/launcher.test.js +230 -0
  178. package/tests/runtime/module-boundary.test.js +16 -0
@@ -0,0 +1,137 @@
1
+ ---
2
+ name: verification-before-completion
3
+ description: "Use before claiming work is complete, fixed, or passing. Requires fresh verification evidence before any success claim."
4
+ ---
5
+
6
+ # Skill: Verification Before Completion
7
+
8
+ ## Context
9
+
10
+ Use this skill immediately before the agent:
11
+
12
+ - says the work is done
13
+ - claims tests pass / the fix is done / the workflow is complete
14
+ - creates a commit, PR, or merge
15
+ - moves the task to the next step as if it were already complete
16
+
17
+ OpenKit prioritizes **evidence before assertion**. Without fresh verification evidence, you must not speak as if the work is already sound.
18
+
19
+ ## Iron Law
20
+
21
+ ```
22
+ DO NOT CLAIM COMPLETION WITHOUT FRESH VERIFICATION EVIDENCE
23
+ ```
24
+
25
+ If you have not run the command that proves the claim in the current working session, the agent must report the real status as "not yet verified" instead of guessing.
26
+
27
+ ## Gate Function
28
+
29
+ Before making any statement that implies success:
30
+
31
+ 1. IDENTIFY which command proves the claim
32
+ 2. RUN the full command
33
+ 3. READ the real output without inventing meaning
34
+ 4. CHECK the exit code, error count, and pass/fail counts
35
+ 5. ONLY THEN speak as if the outcome succeeded
36
+
37
+ If the command fails, or if no verification path exists yet, report that exact reality.
38
+
39
+ ## What Counts as Valid Evidence
40
+
41
+ ### Tests
42
+
43
+ Valid example:
44
+
45
+ - `node --test ".opencode/tests/*.test.js"` with real passing output
46
+
47
+ Not valid:
48
+
49
+ - "it passed earlier"
50
+ - "the code looks right"
51
+ - "part of the suite passed so the rest is probably fine"
52
+
53
+ ### Runtime behavior
54
+
55
+ Valid examples:
56
+
57
+ - run `node .opencode/workflow-state.js status`
58
+ - run `node .opencode/workflow-state.js doctor`
59
+ - run a manual smoke test with clearly described observed input and output
60
+
61
+ Not valid:
62
+
63
+ - "this hook probably prints the right output because the unit test passed" when the claim is about integrated runtime behavior that has not been checked appropriately
64
+
65
+ ### Requirements / plan completion
66
+
67
+ Valid example:
68
+
69
+ - compare every item in the brief, spec, or plan against the diff and verification output
70
+
71
+ Not valid:
72
+
73
+ - "tests passed, so the requirements must all be done"
74
+
75
+ ## Current OpenKit Reality
76
+
77
+ OpenKit does not currently define repo-wide build, lint, or test commands for general application code.
78
+
79
+ So this skill must stay honest to the actual repo state:
80
+
81
+ - if the repo has workflow-runtime tests, use them
82
+ - if it only has runtime CLI checks or manual checks, say clearly that those are the real verification paths
83
+ - if no suitable validation path exists, report that gap instead of inventing a command
84
+
85
+ ## Common Failure Patterns
86
+
87
+ | Claim | Required evidence | Not enough |
88
+ |------|-------------------|------------|
89
+ | "Tests pass" | latest test-command output | old run, memory, assumption |
90
+ | "Bug fixed" | symptom reproduction + passing verification | code changes alone |
91
+ | "Ready to commit" | passing verification for the relevant scope | only looking at the diff |
92
+ | "Requirements met" | checklist against spec/plan + verification | partial test success |
93
+ | "Agent task done" | inspect changes + verify behavior | trusting a subagent report |
94
+
95
+ ## Red Flags
96
+
97
+ If you catch yourself thinking these phrases, stop:
98
+
99
+ - “should work now”
100
+ - “looks correct”
101
+ - “probably fine”
102
+ - “just this once”
103
+ - “the old test already passed”
104
+ - “I'm pretty sure”
105
+
106
+ Those are signs the agent is shifting from engineering into guessing.
107
+
108
+ ## Required Output Style When Verification Fails or Is Missing
109
+
110
+ If verification fails:
111
+
112
+ - state the command you ran
113
+ - state the real failure status
114
+ - include the important output or summary
115
+ - do not use fuzzy wording like "almost done"
116
+
117
+ If no verification path exists:
118
+
119
+ - say clearly that the repo does not yet have an appropriate command
120
+ - describe any manual check you did perform
121
+ - explain the remaining limitation
122
+
123
+ ## Before Commit / PR / Merge
124
+
125
+ Immediately before commit, PR, or merge, the agent must check:
126
+
127
+ - which claim is about to be made
128
+ - which command proves it
129
+ - whether fresh output actually exists
130
+
131
+ Do not use commit or merge as a way to "close the task and move on" when verification is still missing.
132
+
133
+ ## Bottom Line
134
+
135
+ **Evidence before claims. Always.**
136
+
137
+ OpenKit may still lack tooling in many areas, but it must never lack honesty about verification status.
@@ -0,0 +1,68 @@
1
+ ---
2
+ name: writing-plans
3
+ description: "Converts approved architecture and scope into bite-sized implementation plans with validation matched to the workflow mode."
4
+ ---
5
+
6
+ # Skill: Writing Implementation Plans
7
+
8
+ ## Context
9
+
10
+ This skill is used by the Tech Lead Agent. It turns design documents (spec and architecture) into concrete coding steps that the Fullstack Agent can execute.
11
+
12
+ Each plan should be detailed enough that the Fullstack Agent can execute it without guesswork.
13
+
14
+ ## Core Rules of a Good Plan
15
+
16
+ 1. **Bite-sized tasks**: each task should take roughly 2-5 minutes. If a task looks like more than 10 minutes, split it smaller.
17
+ 2. **Atomic steps**: each step should be a complete, testable unit. Do not leave half-finished code behind.
18
+ 3. **Exact file paths**: specify the exact absolute path or repository-relative path for every file to create or edit.
19
+ 4. **Validation flow**: plan validation must match the active workflow mode. Full-delivery logic work should be TDD-first when the repository has suitable test tooling. Migration work should prioritize preserved invariants, blocker-decoupling steps, compatibility checks, staged verification, and targeted tests only where they are truly reliable and helpful. If the repo does not define a standard command yet, the plan must state the missing validation path instead of inventing one.
20
+
21
+ ## Execution Process
22
+
23
+ ### Step 1: Context Gathering
24
+ Make sure you have read:
25
+ - `docs/specs/YYYY-MM-DD-<feature>.md`
26
+ - `docs/architecture/YYYY-MM-DD-<feature>.md`
27
+ - `context/core/code-quality.md`
28
+
29
+ ### Step 2: Write the Plan Document
30
+
31
+ Create `docs/plans/YYYY-MM-DD-<feature>.md` using this structure:
32
+
33
+ ```markdown
34
+ # Implementation Plan: [Feature Name]
35
+
36
+ ## Dependencies
37
+ - Are any additional packages required? (`npm install X`, `pip install Y`)
38
+ - Are any environment variables required?
39
+
40
+ ## Implementation Steps
41
+
42
+ For each task, follow a validation-aware structure:
43
+
44
+ ### [ ] Task 1: [Specific action name, e.g. Init Database Schema]
45
+ - **File**: `path/to/file.ext`
46
+ - **Goal**: [Brief description]
47
+ - **Validation Command**: `[test/build/typecheck/smoke/manual verification command for this step, or an explicit note that no repo-native validation command exists yet]`
48
+ - **Details**:
49
+ - State the baseline or expected change for this step
50
+ - State the implementation or upgrade action
51
+ - State how the result will be verified honestly
52
+
53
+ ### [ ] Task 2: [Next task]
54
+ ...
55
+ ```
56
+
57
+ ### Step 3: Review and Refine
58
+ - Are the tasks small enough?
59
+ - Does any task require changing more than 3 files at once? -> If yes, split it.
60
+ - In full mode, does any logic task skip the "write test first" step without justification? -> Add the test requirement.
61
+ - In migration mode, does the plan mix rewrite work into the migration instead of isolating blockers and proving parity? -> Rewrite the sequence.
62
+ - In migration mode, does the plan rely on fake TDD instead of baseline, compatibility, and regression evidence? -> Rewrite the validation guidance.
63
+ - Does the plan cover all acceptance criteria from the spec?
64
+
65
+ ## Anti-Patterns
66
+ - "Task 1: Build the frontend, Task 2: Build the backend." (Far too large.)
67
+ - No test guidance or test command, and no explicit note that the repo lacks a standard command.
68
+ - A plan that does not specify which files need to be edited.
@@ -0,0 +1,47 @@
1
+ ---
2
+ name: writing-specs
3
+ description: "Converts requirements into structured spec documents with concrete acceptance criteria."
4
+ ---
5
+
6
+ # Skill: Writing Specs
7
+
8
+ ## Context
9
+
10
+ This skill is used by the BA Agent to turn a high-level Product Brief into a detailed low-level spec that is ready for the Architect and the development team.
11
+
12
+ ## Execution Process
13
+
14
+ ### 1. Verification (Input Check)
15
+ - Make sure you already have a Product Brief.
16
+ - If the Product Brief is still vague (for example: "make it faster"), go back to the PM Agent or user and get measurable detail.
17
+
18
+ ### 2. User Stories Breakdown
19
+ Break the feature into user flows (user stories).
20
+ **Required format:** `As a [User Type], I want [Action], so that [Benefit/Value].`
21
+
22
+ ### 3. BDD Acceptance Criteria
23
+ This is the hardest and most important section. Each user story must include Given-When-Then acceptance criteria.
24
+
25
+ **Bad example (too vague):**
26
+ > The submit button should be disabled when the data is invalid.
27
+
28
+ **Good example (Given-When-Then):**
29
+ > **Given** the user is on the "Create New" form
30
+ > **And** the "Email" field is blank or invalid
31
+ > **When** they try to click the "Submit" button
32
+ > **Then** the "Submit" button must be disabled
33
+ > **And** an empty/invalid-format error message appears under the "Email" field
34
+
35
+ ### 4. Edge Cases
36
+ You must include a dedicated section for failure conditions and awkward scenarios:
37
+ - What happens if the network drops mid-request?
38
+ - What happens if the user double-clicks the button?
39
+ - What happens with input that is too long, too short, or contains special characters?
40
+ - Race conditions?
41
+
42
+ ### 5. Document Output
43
+ Create the markdown file at `docs/specs/YYYY-MM-DD-<feature-name>.md`.
44
+
45
+ ## Anti-Patterns to Avoid
46
+ - **Tech leaking**: putting technical implementation decisions in the spec (for example: "Use React `useState` to store the form"). A spec should describe behavior and requirements, not code.
47
+ - **Unmeasurable goals**: "beautiful UI", "fast performance". Replace them with measurable requirements like "responsive on mobile" or "response time < 200ms".
@@ -0,0 +1,259 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { spawnSync } from 'node:child_process';
4
+
5
+ import { OPENKIT_ASSET_MANIFEST } from '../install/asset-manifest.js';
6
+
7
+ const TEXT_EXTENSIONS = new Set(['.md', '.txt']);
8
+ const MACHINE_EXTENSIONS = new Set(['.json', '.js']);
9
+ const VIETNAMESE_DIACRITIC_REGEX = /[\u00C0-\u1EF9]/u;
10
+ const EXCLUDED_TOP_LEVEL_NAMES = new Set(['.git', '.worktrees', 'node_modules']);
11
+ const EXCLUDED_RELATIVE_PREFIXES = ['.git/', '.worktrees/', 'node_modules/'];
12
+
13
+ const HIGH_PRIORITY_PREFIXES = ['skills/', 'agents/', 'commands/', '.opencode/README.md'];
14
+ const MEDIUM_PRIORITY_PREFIXES = ['docs/', 'assets/install-bundle/opencode/'];
15
+
16
+ function walkFiles(rootPath, relativePath = '') {
17
+ const targetPath = relativePath ? path.join(rootPath, relativePath) : rootPath;
18
+ if (!fs.existsSync(targetPath)) {
19
+ return [];
20
+ }
21
+
22
+ const stat = fs.statSync(targetPath);
23
+ if (stat.isFile()) {
24
+ return [relativePath || path.basename(targetPath)];
25
+ }
26
+
27
+ const files = [];
28
+ for (const entry of fs.readdirSync(targetPath, { withFileTypes: true })) {
29
+ const childRelativePath = relativePath ? path.join(relativePath, entry.name) : entry.name;
30
+ if (entry.isDirectory() && shouldExcludePath(childRelativePath)) {
31
+ continue;
32
+ }
33
+ if (entry.isDirectory()) {
34
+ files.push(...walkFiles(rootPath, childRelativePath));
35
+ continue;
36
+ }
37
+ if (shouldExcludePath(childRelativePath)) {
38
+ continue;
39
+ }
40
+ files.push(childRelativePath);
41
+ }
42
+
43
+ return files;
44
+ }
45
+
46
+ function listTrackedFiles(projectRoot) {
47
+ const result = spawnSync('git', ['ls-files', '--cached', '--others', '--exclude-standard'], {
48
+ cwd: projectRoot,
49
+ encoding: 'utf8',
50
+ });
51
+
52
+ if (result.status !== 0) {
53
+ return null;
54
+ }
55
+
56
+ const trackedFiles = new Set();
57
+
58
+ for (const line of result.stdout.split('\n')) {
59
+ const normalizedPath = line.trim();
60
+ if (!normalizedPath) {
61
+ continue;
62
+ }
63
+
64
+ const absolutePath = path.join(projectRoot, normalizedPath);
65
+ if (!fs.existsSync(absolutePath)) {
66
+ continue;
67
+ }
68
+
69
+ const stat = fs.statSync(absolutePath);
70
+ if (!stat.isFile()) {
71
+ continue;
72
+ }
73
+
74
+ trackedFiles.add(normalizedPath);
75
+ }
76
+
77
+ return trackedFiles;
78
+ }
79
+
80
+ function listCheckedInFiles(projectRoot) {
81
+ const gitTrackedFiles = spawnSync('git', ['ls-files', '--cached'], {
82
+ cwd: projectRoot,
83
+ encoding: 'utf8',
84
+ });
85
+
86
+ if (gitTrackedFiles.status === 0) {
87
+ const files = new Set();
88
+
89
+ for (const line of gitTrackedFiles.stdout.split('\n')) {
90
+ const normalizedPath = line.trim();
91
+ if (!normalizedPath) {
92
+ continue;
93
+ }
94
+
95
+ const absolutePath = path.join(projectRoot, normalizedPath);
96
+ if (!fs.existsSync(absolutePath)) {
97
+ continue;
98
+ }
99
+
100
+ const stat = fs.statSync(absolutePath);
101
+ if (!stat.isFile()) {
102
+ continue;
103
+ }
104
+
105
+ files.add(normalizedPath);
106
+ }
107
+
108
+ return files;
109
+ }
110
+
111
+ return new Set(walkFiles(projectRoot));
112
+ }
113
+
114
+ function shouldExcludePath(filePath) {
115
+ const normalizedPath = filePath.split(path.sep).join('/');
116
+ if (EXCLUDED_TOP_LEVEL_NAMES.has(normalizedPath)) {
117
+ return true;
118
+ }
119
+
120
+ return EXCLUDED_RELATIVE_PREFIXES.some(
121
+ (prefix) => normalizedPath === prefix.slice(0, -1) || normalizedPath.startsWith(prefix)
122
+ );
123
+ }
124
+
125
+ function isTextCandidate(filePath) {
126
+ const extension = path.extname(filePath).toLowerCase();
127
+ return TEXT_EXTENSIONS.has(extension) || MACHINE_EXTENSIONS.has(extension);
128
+ }
129
+
130
+ function isMachineFacing(filePath) {
131
+ return MACHINE_EXTENSIONS.has(path.extname(filePath).toLowerCase());
132
+ }
133
+
134
+ function readUtf8(projectRoot, relativePath) {
135
+ return fs.readFileSync(path.join(projectRoot, relativePath), 'utf8');
136
+ }
137
+
138
+ function classifyPriority(filePath) {
139
+ if (HIGH_PRIORITY_PREFIXES.some((prefix) => filePath === prefix || filePath.startsWith(prefix))) {
140
+ return 'high';
141
+ }
142
+
143
+ if (MEDIUM_PRIORITY_PREFIXES.some((prefix) => filePath === prefix || filePath.startsWith(prefix))) {
144
+ return 'medium';
145
+ }
146
+
147
+ return 'low';
148
+ }
149
+
150
+ function buildPairingMap() {
151
+ const derivedPairs = OPENKIT_ASSET_MANIFEST.bundle.assets
152
+ .filter((asset) => asset.sourcePath !== asset.bundledPath)
153
+ .map((asset) => ({
154
+ sourcePath: asset.sourcePath,
155
+ derivedPath: asset.bundledPath,
156
+ assetId: asset.id,
157
+ derived: true,
158
+ }));
159
+
160
+ derivedPairs.push({
161
+ sourcePath: '.opencode/README.md',
162
+ derivedPath: 'assets/install-bundle/opencode/README.md',
163
+ assetId: 'opencode.bundle.runtime-readme',
164
+ derived: true,
165
+ });
166
+
167
+ return derivedPairs.sort((left, right) => left.sourcePath.localeCompare(right.sourcePath));
168
+ }
169
+
170
+ export function detectVietnameseInventory(projectRoot) {
171
+ const filesToScan = listCheckedInFiles(projectRoot);
172
+
173
+ const textFiles = [...filesToScan].filter(isTextCandidate).sort((left, right) => left.localeCompare(right));
174
+ const humanFacingMatches = [];
175
+ const machineFacingMatches = [];
176
+
177
+ for (const filePath of textFiles) {
178
+ const contents = readUtf8(projectRoot, filePath);
179
+ if (!VIETNAMESE_DIACRITIC_REGEX.test(contents)) {
180
+ continue;
181
+ }
182
+
183
+ const match = {
184
+ path: filePath,
185
+ priority: classifyPriority(filePath),
186
+ machineFacing: isMachineFacing(filePath),
187
+ };
188
+
189
+ if (match.machineFacing) {
190
+ machineFacingMatches.push(match);
191
+ continue;
192
+ }
193
+
194
+ humanFacingMatches.push(match);
195
+ }
196
+
197
+ const pairingMap = buildPairingMap();
198
+ const matchedPaths = new Set(humanFacingMatches.map((match) => match.path));
199
+ const pairingSummary = pairingMap.map((pair) => ({
200
+ ...pair,
201
+ sourceHasVietnamese: matchedPaths.has(pair.sourcePath),
202
+ derivedHasVietnamese: matchedPaths.has(pair.derivedPath),
203
+ }));
204
+
205
+ const priorityCounts = {
206
+ high: humanFacingMatches.filter((match) => match.priority === 'high').length,
207
+ medium: humanFacingMatches.filter((match) => match.priority === 'medium').length,
208
+ low: humanFacingMatches.filter((match) => match.priority === 'low').length,
209
+ };
210
+
211
+ return {
212
+ detectionMode: 'heuristic',
213
+ detectionScope: 'repo-wide checked-in files',
214
+ explicitExclusions: [...EXCLUDED_TOP_LEVEL_NAMES],
215
+ scannedFileCount: textFiles.length,
216
+ vietnameseBearingFiles: humanFacingMatches,
217
+ machineFacingMatches,
218
+ machineFacingOutOfScope: machineFacingMatches.length === 0,
219
+ priorityCounts,
220
+ pairingMap: pairingSummary,
221
+ };
222
+ }
223
+
224
+ export function renderVietnameseInventoryReport(inventory) {
225
+ const lines = [];
226
+ lines.push(`Inventory status: ${inventory.vietnameseBearingFiles.length > 0 ? 'matches-found' : 'clear'}`);
227
+ lines.push(`Detection scope: ${inventory.detectionScope}`);
228
+ lines.push(`Detection mode: ${inventory.detectionMode}`);
229
+ lines.push('Heuristic review: required for false positives and false negatives');
230
+ lines.push(`Scanned files: ${inventory.scannedFileCount}`);
231
+ lines.push(
232
+ `Priority counts: high=${inventory.priorityCounts.high}, medium=${inventory.priorityCounts.medium}, low=${inventory.priorityCounts.low}`
233
+ );
234
+ lines.push(`Explicit exclusions: ${inventory.explicitExclusions.join(', ')}`);
235
+ lines.push(
236
+ `Machine-facing literals: ${inventory.machineFacingOutOfScope ? 'out-of-scope confirmed' : 'review needed'}`
237
+ );
238
+
239
+ const completePairingCoverage = inventory.pairingMap.every(
240
+ (pair) => pair.sourceHasVietnamese === pair.derivedHasVietnamese
241
+ );
242
+ lines.push(`Pairing map coverage: ${completePairingCoverage ? 'complete' : 'mismatch-detected'}`);
243
+ lines.push('');
244
+ lines.push('Vietnamese-bearing checked-in files:');
245
+
246
+ for (const match of inventory.vietnameseBearingFiles) {
247
+ lines.push(`- [${match.priority}] ${match.path}`);
248
+ }
249
+
250
+ lines.push('');
251
+ lines.push('Source-versus-derived pairing map:');
252
+ for (const pair of inventory.pairingMap) {
253
+ lines.push(
254
+ `- ${pair.sourcePath} -> ${pair.derivedPath} [source=${pair.sourceHasVietnamese ? 'vi' : 'clear'}, derived=${pair.derivedHasVietnamese ? 'vi' : 'clear'}]`
255
+ );
256
+ }
257
+
258
+ return `${lines.join('\n')}\n`;
259
+ }
@@ -0,0 +1,24 @@
1
+ import { detectVietnameseInventory, renderVietnameseInventoryReport } from '../../audit/vietnamese-detection.js';
2
+
3
+ function detectVietnameseHelp() {
4
+ return [
5
+ 'Usage: openkit internal-audit-vietnamese',
6
+ '',
7
+ 'Run the maintainer audit helper for heuristic Vietnamese detection across repo-wide checked-in files.',
8
+ 'This helper uses heuristics and still requires review for false positives and false negatives.',
9
+ ].join('\n');
10
+ }
11
+
12
+ export const detectVietnameseCommand = {
13
+ name: 'internal-audit-vietnamese',
14
+ async run(args = [], io) {
15
+ if (args.includes('--help') || args.includes('-h')) {
16
+ io.stdout.write(`${detectVietnameseHelp()}\n`);
17
+ return 0;
18
+ }
19
+
20
+ const inventory = detectVietnameseInventory(process.cwd());
21
+ io.stdout.write(renderVietnameseInventoryReport(inventory));
22
+ return 0;
23
+ },
24
+ };
@@ -0,0 +1,33 @@
1
+ import { inspectGlobalDoctor, renderGlobalDoctorSummary } from '../../global/doctor.js';
2
+
3
+ function doctorHelp() {
4
+ return [
5
+ 'Usage: openkit doctor',
6
+ '',
7
+ 'Check whether the global OpenKit install and the current workspace are ready.',
8
+ ].join('\n');
9
+ }
10
+
11
+ export const doctorCommand = {
12
+ name: 'doctor',
13
+ async run(args = [], io) {
14
+ if (args.includes('--help') || args.includes('-h')) {
15
+ io.stdout.write(`${doctorHelp()}\n`);
16
+ return 0;
17
+ }
18
+
19
+ const result = inspectGlobalDoctor({
20
+ projectRoot: process.cwd(),
21
+ env: process.env,
22
+ });
23
+ const output = renderGlobalDoctorSummary(result);
24
+
25
+ if (result.canRunCleanly) {
26
+ io.stdout.write(output);
27
+ return 0;
28
+ }
29
+
30
+ io.stdout.write(output);
31
+ return 1;
32
+ },
33
+ };
@@ -0,0 +1,33 @@
1
+ function topLevelHelp() {
2
+ return [
3
+ 'Usage: openkit <command> [options]',
4
+ '',
5
+ 'Quickstart:',
6
+ ' npm install -g openkit',
7
+ ' openkit run',
8
+ '',
9
+ 'Commands:',
10
+ ' help Show CLI help',
11
+ ' install-global Manual global setup command',
12
+ ' init Compatibility alias for install-global',
13
+ ' install Compatibility alias for install-global',
14
+ ' run Launch OpenCode and perform first-time setup if needed',
15
+ ' upgrade Refresh the global OpenKit install',
16
+ ' uninstall Remove the global OpenKit install',
17
+ ' doctor Inspect global OpenKit and workspace readiness',
18
+ ].join('\n');
19
+ }
20
+
21
+ export const helpCommand = {
22
+ name: 'help',
23
+ async run(args = [], io, context = {}) {
24
+ const [target] = args;
25
+
26
+ if (target && context.commands?.[target]) {
27
+ return context.commands[target].run(['--help'], io, context);
28
+ }
29
+
30
+ io.stdout.write(`${topLevelHelp()}\n`);
31
+ return 0;
32
+ },
33
+ };
@@ -0,0 +1,25 @@
1
+ import { materializeGlobalInstall } from '../../global/materialize.js';
2
+
3
+ function initHelp() {
4
+ return [
5
+ 'Usage: openkit init',
6
+ '',
7
+ 'Compatibility alias for manual global setup.',
8
+ 'Most users should run `openkit run`.',
9
+ ].join('\n');
10
+ }
11
+
12
+ export const initCommand = {
13
+ name: 'init',
14
+ async run(args = [], io) {
15
+ if (args.includes('--help') || args.includes('-h')) {
16
+ io.stdout.write(`${initHelp()}\n`);
17
+ return 0;
18
+ }
19
+
20
+ const result = materializeGlobalInstall({ env: process.env });
21
+ io.stdout.write('Installed OpenKit globally.\n');
22
+ io.stdout.write(`Kit root: ${result.kitRoot}\n`);
23
+ return 0;
24
+ },
25
+ };
@@ -0,0 +1,26 @@
1
+ import { materializeGlobalInstall } from '../../global/materialize.js';
2
+
3
+ function installGlobalHelp() {
4
+ return [
5
+ 'Usage: openkit install-global',
6
+ '',
7
+ 'Manually install OpenKit globally into the OpenCode home directory.',
8
+ 'Most users should run `openkit run`, which performs first-time setup automatically.',
9
+ ].join('\n');
10
+ }
11
+
12
+ export const installGlobalCommand = {
13
+ name: 'install-global',
14
+ async run(args = [], io) {
15
+ if (args.includes('--help') || args.includes('-h')) {
16
+ io.stdout.write(`${installGlobalHelp()}\n`);
17
+ return 0;
18
+ }
19
+
20
+ const result = materializeGlobalInstall({ env: process.env });
21
+ io.stdout.write(`Installed OpenKit globally.\n`);
22
+ io.stdout.write(`Kit root: ${result.kitRoot}\n`);
23
+ io.stdout.write(`Profile root: ${result.profilesRoot}\n`);
24
+ return 0;
25
+ },
26
+ };
@@ -0,0 +1,25 @@
1
+ import { materializeGlobalInstall } from '../../global/materialize.js';
2
+
3
+ function installHelp() {
4
+ return [
5
+ 'Usage: openkit install',
6
+ '',
7
+ 'Compatibility alias for manual global setup.',
8
+ 'Most users should run `openkit run`.',
9
+ ].join('\n');
10
+ }
11
+
12
+ export const installCommand = {
13
+ name: 'install',
14
+ async run(args = [], io) {
15
+ if (args.includes('--help') || args.includes('-h')) {
16
+ io.stdout.write(`${installHelp()}\n`);
17
+ return 0;
18
+ }
19
+
20
+ const result = materializeGlobalInstall({ env: process.env });
21
+ io.stdout.write('Installed OpenKit globally.\n');
22
+ io.stdout.write(`Kit root: ${result.kitRoot}\n`);
23
+ return 0;
24
+ },
25
+ };