@duypham93/openkit 0.2.1 → 0.2.2
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 +1 -1
- package/.opencode/opencode.json +5 -91
- package/AGENTS.md +5 -5
- package/README.md +5 -5
- package/context/core/project-config.md +2 -2
- package/docs/maintainer/README.md +1 -1
- package/docs/operator/README.md +1 -1
- package/docs/plans/2026-03-23-openkit-global-install-runtime.md +2 -2
- package/package.json +1 -1
- package/src/global/launcher.js +2 -2
- package/src/global/materialize.js +7 -17
- package/src/global/paths.js +1 -0
- package/src/runtime/opencode-layering.js +6 -15
- package/tests/cli/openkit-cli.test.js +5 -4
- package/tests/runtime/launcher.test.js +31 -55
- package/.opencode/package.json +0 -3
package/.opencode/README.md
CHANGED
|
@@ -8,7 +8,7 @@ For phase-1 navigation, treat this file as a local runtime boundary note, not as
|
|
|
8
8
|
|
|
9
9
|
What lives here:
|
|
10
10
|
|
|
11
|
-
- `.opencode/opencode.json`: the current repository-local
|
|
11
|
+
- `.opencode/opencode.json`: the current repository-local OpenCode project config
|
|
12
12
|
- `.opencode/workflow-state.json`: the active compatibility mirror
|
|
13
13
|
- `.opencode/work-items/`: per-item backing store
|
|
14
14
|
- `.opencode/workflow-state.js`: lower-level runtime utility CLI
|
package/.opencode/opencode.json
CHANGED
|
@@ -1,93 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
"name": "OpenKit AI Software Factory",
|
|
8
|
-
"version": "0.1.0",
|
|
9
|
-
"entryAgent": "MasterOrchestrator",
|
|
10
|
-
"productSurface": {
|
|
11
|
-
"current": "repository-local-openkit-runtime",
|
|
12
|
-
"emerging": "global-openkit-install",
|
|
13
|
-
"installReadiness": "emerging",
|
|
14
|
-
"migrationState": "staged-not-complete",
|
|
15
|
-
"targetWrapperEntrypoint": "opencode.json",
|
|
16
|
-
"repositoryInternal": [
|
|
17
|
-
".opencode/opencode.json",
|
|
18
|
-
".opencode/workflow-state.json",
|
|
19
|
-
".opencode/work-items/",
|
|
20
|
-
".opencode/workflow-state.js",
|
|
21
|
-
"hooks/",
|
|
22
|
-
"agents/",
|
|
23
|
-
"skills/",
|
|
24
|
-
"commands/",
|
|
25
|
-
"context/",
|
|
26
|
-
"docs/"
|
|
27
|
-
],
|
|
28
|
-
"wrapperFacingMetadata": [
|
|
29
|
-
"registry.json",
|
|
30
|
-
".opencode/install-manifest.json"
|
|
31
|
-
],
|
|
32
|
-
"notes": "This file remains the live checked-in runtime manifest for the repository authoring and compatibility surface while the preferred end-user install path stays global."
|
|
33
|
-
},
|
|
34
|
-
"registry": {
|
|
35
|
-
"path": "registry.json",
|
|
36
|
-
"schema": "openkit/component-registry@1"
|
|
37
|
-
},
|
|
38
|
-
"installManifest": {
|
|
39
|
-
"path": ".opencode/install-manifest.json",
|
|
40
|
-
"schema": "openkit/install-manifest@1"
|
|
41
|
-
},
|
|
42
|
-
"activeProfile": "openkit-core",
|
|
43
|
-
"installationMode": "additive-non-destructive",
|
|
44
|
-
"runtimeSurface": "repository-internal",
|
|
45
|
-
"wrapperMetadataSurface": "staged-additive"
|
|
46
|
-
},
|
|
47
|
-
"hooks": {
|
|
48
|
-
"config": "hooks/hooks.json"
|
|
49
|
-
},
|
|
50
|
-
"state": {
|
|
51
|
-
"file": ".opencode/workflow-state.json"
|
|
52
|
-
},
|
|
53
|
-
"agents": {
|
|
54
|
-
"root": "agents",
|
|
55
|
-
"primary": "agents/master-orchestrator.md",
|
|
56
|
-
"teamRoles": [
|
|
57
|
-
"agents/master-orchestrator.md",
|
|
58
|
-
"agents/pm-agent.md",
|
|
59
|
-
"agents/ba-agent.md",
|
|
60
|
-
"agents/architect-agent.md",
|
|
61
|
-
"agents/tech-lead-agent.md",
|
|
62
|
-
"agents/fullstack-agent.md",
|
|
63
|
-
"agents/qa-agent.md"
|
|
64
|
-
],
|
|
65
|
-
"helpers": [
|
|
66
|
-
"agents/code-reviewer.md"
|
|
67
|
-
]
|
|
68
|
-
},
|
|
69
|
-
"skills": {
|
|
70
|
-
"root": "skills"
|
|
71
|
-
},
|
|
72
|
-
"commands": {
|
|
73
|
-
"root": "commands",
|
|
74
|
-
"available": [
|
|
75
|
-
"commands/task.md",
|
|
76
|
-
"commands/quick-task.md",
|
|
77
|
-
"commands/migrate.md",
|
|
78
|
-
"commands/delivery.md",
|
|
79
|
-
"commands/brainstorm.md",
|
|
80
|
-
"commands/write-plan.md",
|
|
81
|
-
"commands/execute-plan.md"
|
|
82
|
-
]
|
|
83
|
-
},
|
|
84
|
-
"artifacts": {
|
|
85
|
-
"tasks": "docs/tasks",
|
|
86
|
-
"briefs": "docs/briefs",
|
|
87
|
-
"specs": "docs/specs",
|
|
88
|
-
"architecture": "docs/architecture",
|
|
89
|
-
"plans": "docs/plans",
|
|
90
|
-
"qa": "docs/qa",
|
|
91
|
-
"adr": "docs/adr"
|
|
92
|
-
}
|
|
2
|
+
"$schema": "https://opencode.ai/config.json",
|
|
3
|
+
"instructions": [
|
|
4
|
+
"AGENTS.md",
|
|
5
|
+
"context/navigation.md"
|
|
6
|
+
]
|
|
93
7
|
}
|
package/AGENTS.md
CHANGED
|
@@ -41,7 +41,7 @@ Current repository facts:
|
|
|
41
41
|
- `context/core/workflow.md` is the canonical workflow-semantics document for lane behavior, stages, escalation, approvals, and quick-lane artifact expectations
|
|
42
42
|
- Historical planning and example docs have been intentionally pruned from the working tree; prefer current runtime docs and git history when older rationale is needed
|
|
43
43
|
- `npm install -g @duypham93/openkit`, `openkit run`, `openkit doctor`, `openkit upgrade`, and `openkit uninstall` now define the preferred operator path for the global OpenKit kit
|
|
44
|
-
- `.opencode/opencode.json` is present as the
|
|
44
|
+
- `.opencode/opencode.json` is present as the repository-local OpenCode config for this kit
|
|
45
45
|
- `.opencode/workflow-state.json` is present as the active external compatibility mirror for the active work item
|
|
46
46
|
- `.opencode/work-items/` is present as the internal per-item workflow backing store for managed runtime state
|
|
47
47
|
- `.opencode/workflow-state.js` now supports the live mode-aware workflow state contract
|
|
@@ -71,7 +71,7 @@ Approved follow-on direction from FEATURE-002 also includes:
|
|
|
71
71
|
The next product-layer direction is the global OpenKit kit layered over OpenCode while preserving the checked-in authoring and compatibility runtime. In this repository today:
|
|
72
72
|
|
|
73
73
|
- the global install path is implemented for the `openkit` CLI and stores the managed kit inside the OpenCode home directory, materializing it automatically on first `openkit run`
|
|
74
|
-
- `.opencode/opencode.json` remains the checked-in
|
|
74
|
+
- `.opencode/opencode.json` remains the checked-in repository-local OpenCode config for the authoring surface
|
|
75
75
|
- `registry.json` remains checked-in local metadata describing repository surfaces and profiles
|
|
76
76
|
- `.opencode/install-manifest.json` remains additive local install metadata for this repository
|
|
77
77
|
- project artifacts stay local to the target repository, while kit installation and workspace state are managed through the global OpenKit path
|
|
@@ -130,7 +130,7 @@ Current state:
|
|
|
130
130
|
- No single canonical package manager or language toolchain has been established for future generated applications
|
|
131
131
|
- Node.js is a documented runtime dependency for the workflow-state utility only, not for future application code by default
|
|
132
132
|
- The workflow-state CLI exists and is aligned with the live stage and approval model documented in this repository
|
|
133
|
-
- The repository-local
|
|
133
|
+
- The repository-local OpenCode config still lives at `.opencode/opencode.json`; do not claim that a root `opencode.json` entrypoint already exists unless the file is added
|
|
134
134
|
|
|
135
135
|
Rules for agents:
|
|
136
136
|
|
|
@@ -153,8 +153,8 @@ These are illustrative patterns, not current repository commands.
|
|
|
153
153
|
|
|
154
154
|
The operating system layer is file-backed and should stay explicit.
|
|
155
155
|
|
|
156
|
-
-
|
|
157
|
-
-
|
|
156
|
+
- Repository-local OpenCode config: `.opencode/opencode.json`
|
|
157
|
+
- Repository-local OpenCode config for the checked-in authoring surface: `.opencode/opencode.json`
|
|
158
158
|
- Active compatibility mirror: `.opencode/workflow-state.json`
|
|
159
159
|
- Per-item backing store: `.opencode/work-items/`
|
|
160
160
|
- Workflow-state CLI: `node .opencode/workflow-state.js ...`
|
package/README.md
CHANGED
|
@@ -80,7 +80,7 @@ The preferred product path is now the globally installed OpenKit kit. This repos
|
|
|
80
80
|
Preferred global path:
|
|
81
81
|
|
|
82
82
|
1. Run `npm install -g @duypham93/openkit` to install the CLI once on the machine.
|
|
83
|
-
2. Run `openkit run <args>` to launch
|
|
83
|
+
2. Run `openkit run <args>` to launch OpenCode with the OpenKit-managed kit directory injected as the active config for the current project; on first run, OpenKit materializes the global kit into the OpenCode home directory automatically.
|
|
84
84
|
3. Run `openkit doctor` to confirm the global install and current workspace are healthy.
|
|
85
85
|
4. Run `openkit upgrade` to refresh the installed global kit when a newer package version is available.
|
|
86
86
|
5. Run `openkit uninstall [--remove-workspaces]` when you need to remove the global kit and optionally clear workspace state.
|
|
@@ -100,7 +100,7 @@ On first run, `openkit run` materializes the managed global kit into the OpenCod
|
|
|
100
100
|
|
|
101
101
|
Current boundary:
|
|
102
102
|
|
|
103
|
-
- `.opencode/opencode.json` is
|
|
103
|
+
- `.opencode/opencode.json` is the repository-local OpenCode config for this checked-in authoring surface.
|
|
104
104
|
- `.opencode/workflow-state.json`, `.opencode/work-items/`, `.opencode/workflow-state.js`, `hooks/`, `agents/`, `skills/`, `commands/`, `context/`, and `docs/` remain repository-internal runtime or support surfaces.
|
|
105
105
|
- `registry.json` is local metadata describing repository surfaces and the global-kit compatibility contract.
|
|
106
106
|
- `.opencode/install-manifest.json` records the local installed profile for this repository and remains additive metadata rather than a destructive installer.
|
|
@@ -196,7 +196,7 @@ node .opencode/workflow-state.js show
|
|
|
196
196
|
node --test ".opencode/tests/*.test.js"
|
|
197
197
|
```
|
|
198
198
|
|
|
199
|
-
The
|
|
199
|
+
The repository-local OpenCode config stays intentionally minimal and should not be treated as proof that the kit only supports one model or one launcher shape.
|
|
200
200
|
|
|
201
201
|
## Registry Metadata
|
|
202
202
|
|
|
@@ -204,7 +204,7 @@ OpenKit includes a small checked-in metadata layer for local inspection and for
|
|
|
204
204
|
|
|
205
205
|
- `registry.json` describes the component categories that exist in this repository today, including agents, skills, commands, artifact directories, runtime files, hooks, and anchor docs, while also declaring which metadata participates in the global-kit compatibility contract.
|
|
206
206
|
- `.opencode/install-manifest.json` records which local profile is active for this repository, points back to `registry.json`, and documents the current install stance as additive and non-destructive.
|
|
207
|
-
- `.opencode/opencode.json` remains the
|
|
207
|
+
- `.opencode/opencode.json` remains the repository-local OpenCode config, while `registry.json` and `.opencode/install-manifest.json` carry the additive OpenKit metadata for this repository.
|
|
208
208
|
|
|
209
209
|
This metadata is local repository state, not a remote installer. It does not fetch, download, replace, or update components from elsewhere.
|
|
210
210
|
|
|
@@ -225,7 +225,7 @@ The install manifest is intended to make future runtime commands and diagnostics
|
|
|
225
225
|
The current workflow for profile metadata is local and inspectable:
|
|
226
226
|
|
|
227
227
|
1. `registry.json` defines the available component categories, checked-in components, and named profiles.
|
|
228
|
-
2. `.opencode/opencode.json`
|
|
228
|
+
2. `.opencode/opencode.json` remains the repository-local OpenCode config for this worktree.
|
|
229
229
|
3. `.opencode/install-manifest.json` records which profile is installed for this working tree, which broad component categories are present, and that installation remains additive rather than destructive.
|
|
230
230
|
4. `node .opencode/workflow-state.js profiles` lists the named profiles from the registry.
|
|
231
231
|
5. `node .opencode/workflow-state.js show-profile <name>` shows whether a profile is the repository default and which component categories it includes.
|
|
@@ -23,7 +23,7 @@ For the canonical workflow contract, including lane semantics, stage order, esca
|
|
|
23
23
|
- Session hook configuration lives in `hooks/hooks.json`.
|
|
24
24
|
- The session-start hook script lives in `hooks/session-start`.
|
|
25
25
|
- The global OpenKit CLI entrypoint lives at `bin/openkit.js`.
|
|
26
|
-
- The OpenCode
|
|
26
|
+
- The repository-local OpenCode project config lives in `.opencode/opencode.json`.
|
|
27
27
|
- The global install writes its own profile manifest under the OpenCode home directory.
|
|
28
28
|
- The active compatibility mirror lives in `.opencode/workflow-state.json`.
|
|
29
29
|
- The managed work-item backing store lives in `.opencode/work-items/`.
|
|
@@ -82,7 +82,7 @@ Current workflow-state behavior:
|
|
|
82
82
|
- `openkit run` materializes the globally managed kit into the OpenCode home directory on first use when needed.
|
|
83
83
|
- `openkit doctor` checks the global install and the current workspace bootstrap.
|
|
84
84
|
- `openkit install-global` remains available as a manual or compatibility setup path.
|
|
85
|
-
- `openkit run` launches OpenCode with the
|
|
85
|
+
- `openkit run` launches OpenCode with the OpenKit-managed config directory and workspace-specific environment.
|
|
86
86
|
- `openkit upgrade` refreshes the global managed kit bundle in place.
|
|
87
87
|
- `openkit uninstall` removes the global managed kit and profile, with optional workspace cleanup.
|
|
88
88
|
- `status`, `doctor`, `version`, `profiles`, `show-profile`, and `sync-install-manifest` are part of the current runtime inspection surface.
|
|
@@ -31,7 +31,7 @@ Use it to find canonical repository docs and upkeep surfaces quickly. Do not tre
|
|
|
31
31
|
|
|
32
32
|
## Repository Internals To Keep Honest
|
|
33
33
|
|
|
34
|
-
- `.opencode/opencode.json` remains the checked-in
|
|
34
|
+
- `.opencode/opencode.json` remains the checked-in repository-local OpenCode config even though the preferred end-user install path is now global
|
|
35
35
|
- `.opencode/workflow-state.json` remains the active compatibility mirror for the active work item
|
|
36
36
|
- `.opencode/work-items/` remains the per-item backing store for managed runtime state
|
|
37
37
|
- `registry.json` and `.opencode/install-manifest.json` remain additive local metadata, not destructive install machinery
|
package/docs/operator/README.md
CHANGED
|
@@ -46,5 +46,5 @@ Use it to find the right live docs quickly. Do not treat it as a canonical repla
|
|
|
46
46
|
|
|
47
47
|
- The preferred user path is the global OpenKit install in the OpenCode home directory
|
|
48
48
|
- `openkit install-global` remains available as a manual or compatibility setup command, but it is no longer the preferred onboarding step
|
|
49
|
-
- `.opencode/opencode.json` remains the checked-in
|
|
49
|
+
- `.opencode/opencode.json` remains the checked-in repository-local OpenCode config in this repository
|
|
50
50
|
- `Quick Task+` remains the current semantics of the `quick` lane, not a third live mode
|
|
@@ -35,7 +35,7 @@ approval_gate: tech_lead_to_fullstack
|
|
|
35
35
|
- `npx @duypham93/openkit@latest install-global`
|
|
36
36
|
- `npx @duypham93/openkit@latest doctor`
|
|
37
37
|
- Day-to-day usage in any repo:
|
|
38
|
-
- `
|
|
38
|
+
- `openkit run`
|
|
39
39
|
- Existing repo should not need checked-in `agents/`, `skills/`, `commands/`, or `.opencode/` surfaces just to use the kit.
|
|
40
40
|
|
|
41
41
|
## Proposed Runtime Shape
|
|
@@ -105,7 +105,7 @@ approval_gate: tech_lead_to_fullstack
|
|
|
105
105
|
|
|
106
106
|
### [ ] Task 7: Register and validate the OpenCode profile integration
|
|
107
107
|
- Files: global profile config templates, launcher wiring, doctor/profile checks
|
|
108
|
-
- Goal: make `
|
|
108
|
+
- Goal: make `openkit run` the supported path after global installation, with OpenCode launched through managed config injection rather than a profile flag.
|
|
109
109
|
- Validation: profile registration can be inspected; doctor confirms registration; run-path smoke tests succeed.
|
|
110
110
|
- Notes:
|
|
111
111
|
- do not assume OpenCode plugin APIs that are not proven; verify the real profile/config surface during implementation
|
package/package.json
CHANGED
package/src/global/launcher.js
CHANGED
|
@@ -19,10 +19,10 @@ export function launchGlobalOpenKit(args = [], { projectRoot = process.cwd(), en
|
|
|
19
19
|
OPENKIT_WORKFLOW_STATE: paths.workflowStatePath,
|
|
20
20
|
OPENKIT_KIT_ROOT: paths.kitRoot,
|
|
21
21
|
OPENKIT_HOME: paths.openCodeHome,
|
|
22
|
-
OPENCODE_CONFIG_DIR: paths.
|
|
22
|
+
OPENCODE_CONFIG_DIR: paths.kitRoot,
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
-
const result = spawn('opencode', [
|
|
25
|
+
const result = spawn('opencode', [paths.projectRoot, ...args], {
|
|
26
26
|
cwd: paths.projectRoot,
|
|
27
27
|
env: launcherEnv,
|
|
28
28
|
encoding: 'utf8',
|
|
@@ -58,23 +58,10 @@ function listManagedFiles(kitRoot) {
|
|
|
58
58
|
return files.sort();
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
function
|
|
62
|
-
const kitManifestPath = path.join(kitRoot, '.opencode', 'opencode.json');
|
|
63
|
-
const kitManifest = JSON.parse(fs.readFileSync(kitManifestPath, 'utf8'));
|
|
64
|
-
|
|
61
|
+
function createOpenCodeConfig() {
|
|
65
62
|
return {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
skills_dir: path.join(kitRoot, 'skills'),
|
|
69
|
-
commands_dir: path.join(kitRoot, 'commands'),
|
|
70
|
-
hooks: {
|
|
71
|
-
config: profileHooksPath,
|
|
72
|
-
},
|
|
73
|
-
openkit: {
|
|
74
|
-
profile: 'openkit',
|
|
75
|
-
kit_root: kitRoot,
|
|
76
|
-
manifest: kitManifestPath,
|
|
77
|
-
},
|
|
63
|
+
$schema: 'https://opencode.ai/config.json',
|
|
64
|
+
default_agent: 'master-orchestrator',
|
|
78
65
|
};
|
|
79
66
|
}
|
|
80
67
|
|
|
@@ -92,8 +79,11 @@ export function materializeGlobalInstall({ env = process.env, kitVersion = '0.1.
|
|
|
92
79
|
}
|
|
93
80
|
|
|
94
81
|
const installState = createGlobalInstallState({ kitVersion, profile: 'openkit' });
|
|
82
|
+
const openCodeConfig = createOpenCodeConfig();
|
|
83
|
+
|
|
84
|
+
writeJson(paths.kitConfigPath, openCodeConfig);
|
|
95
85
|
writeJson(paths.installStatePath, installState);
|
|
96
|
-
writeJson(paths.profileManifestPath,
|
|
86
|
+
writeJson(paths.profileManifestPath, openCodeConfig);
|
|
97
87
|
writeJson(paths.profileHooksPath, {
|
|
98
88
|
hooks: {
|
|
99
89
|
SessionStart: [
|
package/src/global/paths.js
CHANGED
|
@@ -52,6 +52,7 @@ export function getGlobalPaths(options = {}) {
|
|
|
52
52
|
return {
|
|
53
53
|
openCodeHome,
|
|
54
54
|
kitRoot,
|
|
55
|
+
kitConfigPath: path.join(kitRoot, 'opencode.json'),
|
|
55
56
|
installStatePath: path.join(kitRoot, 'install-state.json'),
|
|
56
57
|
managedFilesPath: path.join(kitRoot, 'managed-files.json'),
|
|
57
58
|
profilesRoot,
|
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
|
|
4
|
-
export const CONFIG_DIR_RELATIVE_PATHS = [
|
|
5
|
-
'agents_dir',
|
|
6
|
-
'commands_dir',
|
|
7
|
-
'skills_dir',
|
|
8
|
-
'hooks.config',
|
|
9
|
-
];
|
|
10
|
-
|
|
11
4
|
function isPlainObject(value) {
|
|
12
5
|
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
13
6
|
}
|
|
@@ -51,11 +44,6 @@ function parseJsonContent(content, sourceLabel) {
|
|
|
51
44
|
}
|
|
52
45
|
}
|
|
53
46
|
|
|
54
|
-
function shouldResolveRelativeToConfigDir(keyPath) {
|
|
55
|
-
const joinedPath = keyPath.filter((segment) => typeof segment === 'string').join('.');
|
|
56
|
-
return CONFIG_DIR_RELATIVE_PATHS.includes(joinedPath);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
47
|
function normalizeConfigPaths(value, configDir, keyPath = []) {
|
|
60
48
|
if (Array.isArray(value)) {
|
|
61
49
|
return value.map((entry, index) => normalizeConfigPaths(entry, configDir, [...keyPath, index]));
|
|
@@ -74,11 +62,14 @@ function normalizeConfigPaths(value, configDir, keyPath = []) {
|
|
|
74
62
|
return value;
|
|
75
63
|
}
|
|
76
64
|
|
|
77
|
-
|
|
78
|
-
|
|
65
|
+
const parentKey = keyPath.at(-2);
|
|
66
|
+
const currentKey = keyPath.at(-1);
|
|
67
|
+
|
|
68
|
+
if (currentKey === 'instructions' || parentKey === 'instructions') {
|
|
69
|
+
return path.resolve(configDir, value);
|
|
79
70
|
}
|
|
80
71
|
|
|
81
|
-
return
|
|
72
|
+
return value;
|
|
82
73
|
}
|
|
83
74
|
|
|
84
75
|
export function buildOpenCodeLayering({ projectRoot, env = process.env }) {
|
|
@@ -90,7 +90,8 @@ test('openkit install-global materializes global kit and profile files', () => {
|
|
|
90
90
|
assert.equal(fs.existsSync(path.join(kitRoot, '.opencode', 'workflow-state.js')), true);
|
|
91
91
|
assert.equal(fs.existsSync(path.join(kitRoot, 'commands', 'migrate.md')), true);
|
|
92
92
|
assert.equal(fs.existsSync(path.join(profileRoot, 'opencode.json')), true);
|
|
93
|
-
assert.equal(readJson(path.join(profileRoot, 'opencode.json')).
|
|
93
|
+
assert.equal(readJson(path.join(profileRoot, 'opencode.json')).default_agent, 'master-orchestrator');
|
|
94
|
+
assert.equal(fs.existsSync(path.join(kitRoot, 'opencode.json')), true);
|
|
94
95
|
});
|
|
95
96
|
|
|
96
97
|
test('openkit init and install remain compatibility aliases for install-global', () => {
|
|
@@ -215,10 +216,10 @@ process.stdout.write('mock opencode launched\\n');
|
|
|
215
216
|
assert.match(result.stdout, /mock opencode launched/);
|
|
216
217
|
|
|
217
218
|
const invocation = readJson(logPath);
|
|
218
|
-
assert.deepEqual(invocation.argv, [
|
|
219
|
+
assert.deepEqual(invocation.argv, [projectRoot, '--mode', 'quick']);
|
|
219
220
|
assert.equal(fs.realpathSync(invocation.cwd), fs.realpathSync(projectRoot));
|
|
220
221
|
assert.equal(fs.realpathSync(invocation.projectRoot), fs.realpathSync(projectRoot));
|
|
221
|
-
assert.equal(invocation.configDir, path.join(tempHome, '
|
|
222
|
+
assert.equal(invocation.configDir, path.join(tempHome, 'kits', 'openkit'));
|
|
222
223
|
assert.match(invocation.workflowState, /workspaces\/.*\/openkit\/\.opencode\/workflow-state\.json$/);
|
|
223
224
|
assert.equal(invocation.kitRoot, path.join(tempHome, 'kits', 'openkit'));
|
|
224
225
|
});
|
|
@@ -291,7 +292,7 @@ process.stdout.write('mock opencode launched after auto-install\\n');
|
|
|
291
292
|
assert.equal(fs.existsSync(path.join(tempHome, 'kits', 'openkit', '.opencode', 'workflow-state.js')), true);
|
|
292
293
|
|
|
293
294
|
const invocation = readJson(logPath);
|
|
294
|
-
assert.deepEqual(invocation.argv, [
|
|
295
|
+
assert.deepEqual(invocation.argv, [projectRoot]);
|
|
295
296
|
assert.equal(invocation.kitRoot, path.join(tempHome, 'kits', 'openkit'));
|
|
296
297
|
});
|
|
297
298
|
|
|
@@ -5,7 +5,6 @@ import os from 'node:os';
|
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
|
|
7
7
|
import {
|
|
8
|
-
CONFIG_DIR_RELATIVE_PATHS,
|
|
9
8
|
buildOpenCodeLayering,
|
|
10
9
|
} from '../../src/runtime/opencode-layering.js';
|
|
11
10
|
import { launchManagedOpenCode } from '../../src/runtime/launcher.js';
|
|
@@ -23,8 +22,8 @@ test('buildOpenCodeLayering uses the managed config dir when no baseline config
|
|
|
23
22
|
const projectRoot = makeTempDir();
|
|
24
23
|
|
|
25
24
|
writeJson(path.join(projectRoot, '.opencode', 'opencode.json'), {
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
$schema: 'https://opencode.ai/config.json',
|
|
26
|
+
default_agent: 'master-orchestrator',
|
|
28
27
|
});
|
|
29
28
|
|
|
30
29
|
const result = buildOpenCodeLayering({ projectRoot, env: {} });
|
|
@@ -41,19 +40,15 @@ test('buildOpenCodeLayering preserves baseline config while layering managed con
|
|
|
41
40
|
const baselineConfigDir = path.join(projectRoot, 'user-config');
|
|
42
41
|
|
|
43
42
|
writeJson(path.join(baselineConfigDir, 'opencode.json'), {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
},
|
|
43
|
+
model: 'baseline-model',
|
|
44
|
+
instructions: ['./docs/global-instructions.md'],
|
|
45
|
+
plugin: ['existing-plugin'],
|
|
48
46
|
});
|
|
49
47
|
|
|
50
48
|
writeJson(path.join(projectRoot, '.opencode', 'opencode.json'), {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
hooks: {
|
|
55
|
-
config: 'hooks/hooks.json',
|
|
56
|
-
},
|
|
49
|
+
$schema: 'https://opencode.ai/config.json',
|
|
50
|
+
default_agent: 'master-orchestrator',
|
|
51
|
+
instructions: ['AGENTS.md', 'context/navigation.md'],
|
|
57
52
|
});
|
|
58
53
|
|
|
59
54
|
const result = buildOpenCodeLayering({
|
|
@@ -61,12 +56,8 @@ test('buildOpenCodeLayering preserves baseline config while layering managed con
|
|
|
61
56
|
env: {
|
|
62
57
|
OPENCODE_CONFIG_DIR: baselineConfigDir,
|
|
63
58
|
OPENCODE_CONFIG_CONTENT: JSON.stringify({
|
|
64
|
-
model: 'baseline-model',
|
|
65
59
|
customSetting: true,
|
|
66
|
-
|
|
67
|
-
hooks: {
|
|
68
|
-
enabled: true,
|
|
69
|
-
},
|
|
60
|
+
share: 'manual',
|
|
70
61
|
}),
|
|
71
62
|
},
|
|
72
63
|
});
|
|
@@ -75,29 +66,24 @@ test('buildOpenCodeLayering preserves baseline config while layering managed con
|
|
|
75
66
|
|
|
76
67
|
const layeredContent = JSON.parse(result.env.OPENCODE_CONFIG_CONTENT);
|
|
77
68
|
assert.equal(layeredContent.customSetting, true);
|
|
78
|
-
assert.equal(layeredContent.
|
|
79
|
-
assert.equal(layeredContent.
|
|
80
|
-
assert.equal(layeredContent.
|
|
81
|
-
assert.
|
|
82
|
-
assert.deepEqual(layeredContent.
|
|
83
|
-
enabled: true,
|
|
84
|
-
config: 'hooks/hooks.json',
|
|
85
|
-
});
|
|
69
|
+
assert.equal(layeredContent.share, 'manual');
|
|
70
|
+
assert.equal(layeredContent.model, 'baseline-model');
|
|
71
|
+
assert.equal(layeredContent.default_agent, 'master-orchestrator');
|
|
72
|
+
assert.deepEqual(layeredContent.plugin, ['existing-plugin']);
|
|
73
|
+
assert.deepEqual(layeredContent.instructions, ['AGENTS.md', 'context/navigation.md']);
|
|
86
74
|
assert.equal(result.baseline.configDir, baselineConfigDir);
|
|
87
|
-
assert.equal(result.baseline.config.commands_dir, path.join(baselineConfigDir, 'user-commands'));
|
|
88
|
-
assert.equal(
|
|
89
|
-
result.baseline.config.hooks.config,
|
|
90
|
-
path.join(baselineConfigDir, 'user-hooks', 'hooks.json')
|
|
91
|
-
);
|
|
92
75
|
assert.equal(result.baseline.config.model, 'baseline-model');
|
|
76
|
+
assert.deepEqual(result.baseline.config.instructions, [
|
|
77
|
+
path.join(baselineConfigDir, 'docs/global-instructions.md'),
|
|
78
|
+
]);
|
|
93
79
|
});
|
|
94
80
|
|
|
95
|
-
test('buildOpenCodeLayering only
|
|
81
|
+
test('buildOpenCodeLayering only resolves instruction paths relative to the config dir', () => {
|
|
96
82
|
const projectRoot = makeTempDir();
|
|
97
83
|
const baselineConfigDir = path.join(projectRoot, 'user-config');
|
|
98
84
|
|
|
99
85
|
writeJson(path.join(projectRoot, '.opencode', 'opencode.json'), {
|
|
100
|
-
|
|
86
|
+
$schema: 'https://opencode.ai/config.json',
|
|
101
87
|
});
|
|
102
88
|
|
|
103
89
|
const result = buildOpenCodeLayering({
|
|
@@ -105,23 +91,13 @@ test('buildOpenCodeLayering only normalizes the documented config-dir-relative k
|
|
|
105
91
|
env: {
|
|
106
92
|
OPENCODE_CONFIG_DIR: baselineConfigDir,
|
|
107
93
|
OPENCODE_CONFIG_CONTENT: JSON.stringify({
|
|
108
|
-
|
|
109
|
-
agents_dir: 'agents',
|
|
110
|
-
skills_dir: 'skills',
|
|
111
|
-
commands_dir: 'commands',
|
|
112
|
-
hooks: {
|
|
113
|
-
config: 'hooks/hooks.json',
|
|
114
|
-
},
|
|
94
|
+
instructions: ['docs/local.md'],
|
|
115
95
|
otherRelativePath: 'notes/local.md',
|
|
116
96
|
}),
|
|
117
97
|
},
|
|
118
98
|
});
|
|
119
99
|
|
|
120
|
-
assert.deepEqual(
|
|
121
|
-
assert.equal(result.baseline.config.agents_dir, path.join(baselineConfigDir, 'agents'));
|
|
122
|
-
assert.equal(result.baseline.config.skills_dir, path.join(baselineConfigDir, 'skills'));
|
|
123
|
-
assert.equal(result.baseline.config.commands_dir, path.join(baselineConfigDir, 'commands'));
|
|
124
|
-
assert.equal(result.baseline.config.hooks.config, path.join(baselineConfigDir, 'hooks', 'hooks.json'));
|
|
100
|
+
assert.deepEqual(result.baseline.config.instructions, [path.join(baselineConfigDir, 'docs/local.md')]);
|
|
125
101
|
assert.equal(result.baseline.config.otherRelativePath, 'notes/local.md');
|
|
126
102
|
});
|
|
127
103
|
|
|
@@ -129,7 +105,7 @@ test('launchManagedOpenCode reports a clear error when opencode is unavailable',
|
|
|
129
105
|
const projectRoot = makeTempDir();
|
|
130
106
|
|
|
131
107
|
writeJson(path.join(projectRoot, '.opencode', 'opencode.json'), {
|
|
132
|
-
|
|
108
|
+
$schema: 'https://opencode.ai/config.json',
|
|
133
109
|
});
|
|
134
110
|
|
|
135
111
|
const result = launchManagedOpenCode([], {
|
|
@@ -153,7 +129,7 @@ test('launchManagedOpenCode uses interactive stdio by default for the real launc
|
|
|
153
129
|
let spawnCall = null;
|
|
154
130
|
|
|
155
131
|
writeJson(path.join(projectRoot, '.opencode', 'opencode.json'), {
|
|
156
|
-
|
|
132
|
+
$schema: 'https://opencode.ai/config.json',
|
|
157
133
|
});
|
|
158
134
|
|
|
159
135
|
const result = launchManagedOpenCode(['status'], {
|
|
@@ -178,13 +154,14 @@ test('launchManagedOpenCode forwards layered config to opencode on the supported
|
|
|
178
154
|
const baselineConfigDir = path.join(projectRoot, 'user-config');
|
|
179
155
|
|
|
180
156
|
writeJson(path.join(baselineConfigDir, 'opencode.json'), {
|
|
181
|
-
|
|
157
|
+
model: 'baseline-model',
|
|
158
|
+
instructions: ['./docs/global-instructions.md'],
|
|
182
159
|
});
|
|
183
160
|
|
|
184
161
|
writeJson(path.join(projectRoot, '.opencode', 'opencode.json'), {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
162
|
+
$schema: 'https://opencode.ai/config.json',
|
|
163
|
+
default_agent: 'master-orchestrator',
|
|
164
|
+
instructions: ['AGENTS.md', 'context/navigation.md'],
|
|
188
165
|
});
|
|
189
166
|
|
|
190
167
|
fs.mkdirSync(fakeBinDir, { recursive: true });
|
|
@@ -223,8 +200,7 @@ test('launchManagedOpenCode forwards layered config to opencode on the supported
|
|
|
223
200
|
|
|
224
201
|
const layeredContent = JSON.parse(payload.configContent);
|
|
225
202
|
assert.equal(layeredContent.customSetting, true);
|
|
226
|
-
assert.equal(layeredContent.model, '
|
|
227
|
-
assert.equal(layeredContent.
|
|
228
|
-
assert.
|
|
229
|
-
assert.equal(layeredContent.skills_dir, path.join(baselineConfigDir, 'baseline-skills'));
|
|
203
|
+
assert.equal(layeredContent.model, 'baseline-model');
|
|
204
|
+
assert.equal(layeredContent.default_agent, 'master-orchestrator');
|
|
205
|
+
assert.deepEqual(layeredContent.instructions, ['AGENTS.md', 'context/navigation.md']);
|
|
230
206
|
});
|
package/.opencode/package.json
DELETED