ultra-builder-pro-cli 5.0.1 → 6.0.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/CHANGELOG.md +103 -3
- package/README.md +67 -478
- package/README.zh-CN.md +49 -422
- package/adapters/_shared/frontmatter.cjs +1 -18
- package/adapters/_shared/plugin-core.cjs +17 -83
- package/adapters/_shared/runtime-assets.cjs +6 -120
- package/adapters/claude.js +8 -24
- package/adapters/codex.js +13 -32
- package/bin/install.js +35 -57
- package/docs/PLUGIN-ISOLATION-CONTRACT.md +13 -101
- package/docs/examples/drive/claude-reviewer.sh +53 -0
- package/docs/examples/drive/claude-writer.sh +43 -0
- package/engine/FORMATS.md +1051 -0
- package/engine/checks.cjs +139 -0
- package/engine/cli.cjs +148 -0
- package/engine/completion.cjs +48 -0
- package/engine/context.cjs +94 -0
- package/engine/drive.cjs +220 -0
- package/engine/expect-worker.cjs +5 -0
- package/engine/expect.cjs +33 -0
- package/engine/formats.cjs +189 -0
- package/engine/git-state.cjs +112 -0
- package/engine/ledger.cjs +205 -0
- package/engine/loading.cjs +28 -0
- package/engine/merge.cjs +273 -0
- package/engine/milestone.cjs +89 -0
- package/engine/plan.cjs +232 -0
- package/engine/project.cjs +5 -0
- package/engine/signals.cjs +3 -0
- package/engine/states.cjs +175 -0
- package/hooks/session-start.cjs +54 -0
- package/package.json +17 -52
- package/skills/ultra/SKILL.md +395 -0
- package/.ultra-template/changes/abandoned/.gitkeep +0 -0
- package/.ultra-template/changes/active/.gitkeep +0 -1
- package/.ultra-template/changes/archive/.gitkeep +0 -1
- package/.ultra-template/contexts/TEMPLATE.md +0 -135
- package/.ultra-template/decisions/.gitkeep +0 -1
- package/.ultra-template/evidence/.gitkeep +0 -1
- package/.ultra-template/north-star.md +0 -52
- package/.ultra-template/project-brief.md +0 -28
- package/.ultra-template/research/.gitkeep +0 -1
- package/.ultra-template/specs/architecture.md +0 -81
- package/.ultra-template/specs/discovery.md +0 -74
- package/.ultra-template/specs/product.md +0 -80
- package/.ultra-template/specs/research-distillate.md +0 -57
- package/.ultra-template/tasks.json +0 -4
- package/.ultra-template/test-report.json +0 -44
- package/adapters/_shared/host-profile.cjs +0 -5
- package/adapters/grok.js +0 -242
- package/adapters/kimi.js +0 -232
- package/adapters/opencode.js +0 -408
- package/adapters/zcode.js +0 -375
- package/bin/delegate-worker.cjs +0 -5
- package/bin/delegate.cjs +0 -5
- package/docs/ARCHITECTURE.md +0 -274
- package/docs/ARTIFACT-AUTHORITY.md +0 -305
- package/docs/DECISIONS.md +0 -229
- package/docs/PHILOSOPHY.md +0 -261
- package/docs/RUNTIME-COMPAT-MATRIX.md +0 -316
- package/docs/SKILL-AUTHORING.md +0 -113
- package/docs/WORKFLOW-LIFECYCLE.md +0 -350
- package/docs/evals/adversarial-review-2026-08-14.md +0 -84
- package/docs/evals/ultra-5-0-journey-results.md +0 -62
- package/docs/evals/ultra-5-0-live-acp-conformance.md +0 -93
- package/docs/evals/ultra-5-0-route-journeys.md +0 -145
- package/docs/evals/zcode-automation-2026-08-14.md +0 -103
- package/hooks/README.md +0 -52
- package/hooks/_common.py +0 -1779
- package/hooks/adapters/codex.py +0 -295
- package/hooks/adapters/grok.py +0 -134
- package/hooks/adapters/kimi.py +0 -156
- package/hooks/adapters/zcode.py +0 -227
- package/hooks/block_dangerous_commands.py +0 -201
- package/hooks/compact_context.py +0 -224
- package/hooks/mid_workflow_recall.py +0 -47
- package/hooks/post_edit_guard.py +0 -215
- package/hooks/session_context.py +0 -741
- package/skills/ultra-change/SKILL.md +0 -165
- package/skills/ultra-change/references/change-contract.md +0 -199
- package/skills/ultra-change/references/execution-grant.md +0 -109
- package/skills/ultra-change/references/primary-transfer.md +0 -273
- package/skills/ultra-change/scripts/validate_primary_transfer.cjs +0 -1928
- package/skills/ultra-delegate/SKILL.md +0 -195
- package/skills/ultra-delegate/patches/zcode-acp-0.1.0-zcode-0.16.5.patch +0 -184
- package/skills/ultra-delegate/references/delegation-contract.md +0 -138
- package/skills/ultra-delegate/scripts/acp-conformance.cjs +0 -287
- package/skills/ultra-delegate/scripts/acp-driver.cjs +0 -762
- package/skills/ultra-delegate/scripts/agent-execution-driver.cjs +0 -320
- package/skills/ultra-delegate/scripts/cli-driver.cjs +0 -61
- package/skills/ultra-delegate/scripts/delegate-profiles/kimi-read-only.md +0 -15
- package/skills/ultra-delegate/scripts/delegate-profiles/kimi-write.md +0 -17
- package/skills/ultra-delegate/scripts/delegate-worker.cjs +0 -328
- package/skills/ultra-delegate/scripts/delegate.cjs +0 -690
- package/skills/ultra-delegate/scripts/delegate_wait.py +0 -86
- package/skills/ultra-delegate/scripts/host-profile.cjs +0 -267
- package/skills/ultra-deliver/SKILL.md +0 -194
- package/skills/ultra-deliver/references/baseline-reconciliation.md +0 -41
- package/skills/ultra-dev/SKILL.md +0 -265
- package/skills/ultra-dev/references/debugging.md +0 -22
- package/skills/ultra-domain-modeling/SKILL.md +0 -79
- package/skills/ultra-grilling/SKILL.md +0 -121
- package/skills/ultra-grilling/references/reframing.md +0 -76
- package/skills/ultra-init/SKILL.md +0 -143
- package/skills/ultra-init/references/brownfield-adoption.md +0 -32
- package/skills/ultra-init/scripts/init_project.cjs +0 -1031
- package/skills/ultra-plan/SKILL.md +0 -160
- package/skills/ultra-plan/references/task-evidence-v2.md +0 -300
- package/skills/ultra-plan/scripts/validate_task_evidence.cjs +0 -859
- package/skills/ultra-research/SKILL.md +0 -167
- package/skills/ultra-research/references/00-problem-validation.md +0 -36
- package/skills/ultra-research/references/01-opportunity-discovery.md +0 -33
- package/skills/ultra-research/references/02-market-assessment.md +0 -31
- package/skills/ultra-research/references/03-alternatives.md +0 -31
- package/skills/ultra-research/references/04-product-strategy.md +0 -41
- package/skills/ultra-research/references/05-assumptions-validation.md +0 -31
- package/skills/ultra-research/references/10-user-personas.md +0 -30
- package/skills/ultra-research/references/11-user-scenarios.md +0 -28
- package/skills/ultra-research/references/20-user-stories.md +0 -31
- package/skills/ultra-research/references/21-features-scope.md +0 -38
- package/skills/ultra-research/references/22-success-metrics.md +0 -33
- package/skills/ultra-research/references/30-architecture-context.md +0 -30
- package/skills/ultra-research/references/31-solution-strategy.md +0 -28
- package/skills/ultra-research/references/32-building-blocks.md +0 -28
- package/skills/ultra-research/references/40-deployment.md +0 -29
- package/skills/ultra-research/references/41-quality-risks.md +0 -28
- package/skills/ultra-research/references/99-synthesis.md +0 -59
- package/skills/ultra-research/references/north-star-v2.md +0 -168
- package/skills/ultra-research/references/wayfinding.md +0 -50
- package/skills/ultra-research/scripts/validate_north_star.cjs +0 -1174
- package/skills/ultra-review/SKILL.md +0 -275
- package/skills/ultra-review/references/adversarial-evaluation.md +0 -31
- package/skills/ultra-review/references/code.md +0 -17
- package/skills/ultra-review/references/comments.md +0 -12
- package/skills/ultra-review/references/design.md +0 -12
- package/skills/ultra-review/references/errors.md +0 -13
- package/skills/ultra-review/references/review-modes.md +0 -29
- package/skills/ultra-review/references/spec.md +0 -18
- package/skills/ultra-review/references/tests.md +0 -12
- package/skills/ultra-review/references/unified-schema.md +0 -284
- package/skills/ultra-review/references/worker-packet.md +0 -183
- package/skills/ultra-review/scripts/review_wait.py +0 -2943
- package/skills/ultra-status/SKILL.md +0 -209
- package/skills/ultra-status/references/route-contract.md +0 -100
- package/skills/ultra-tdd/SKILL.md +0 -91
- package/skills/ultra-tdd/references/templates/README.md +0 -20
- package/skills/ultra-tdd/references/templates/feature-flag-default-audit.sh +0 -79
- package/skills/ultra-tdd/references/templates/persistence-real.ts +0 -78
- package/skills/ultra-tdd/references/templates/testcontainer-postgres.py +0 -78
- package/skills/ultra-tdd/references/templates/testcontainer-postgres.ts +0 -73
- package/skills/ultra-tdd/references/templates/vertical-slice.ts +0 -66
- package/skills/ultra-tdd/references/test-execution.md +0 -23
- package/skills/ultra-test/SKILL.md +0 -244
- package/skills/ultra-test/references/export-syntax.md +0 -18
- package/skills/ultra-test/scripts/validate_review_transport.cjs +0 -549
- package/skills/ultra-test/scripts/worktree_digest.cjs +0 -576
- package/skills/ultra-think/SKILL.md +0 -56
- package/skills/ultra-think/references/autonomy-boundary.md +0 -48
- package/skills/ultra-think/references/interaction-boundary.md +0 -42
|
@@ -21,17 +21,6 @@ const {
|
|
|
21
21
|
} = require('./runtime-assets.cjs');
|
|
22
22
|
|
|
23
23
|
const PROVENANCE_FILE = 'provenance.json';
|
|
24
|
-
const DELEGATION_RUNNER_FILES = Object.freeze([
|
|
25
|
-
'delegate.cjs',
|
|
26
|
-
'delegate-worker.cjs',
|
|
27
|
-
'host-profile.cjs',
|
|
28
|
-
'agent-execution-driver.cjs',
|
|
29
|
-
'acp-driver.cjs',
|
|
30
|
-
'cli-driver.cjs',
|
|
31
|
-
path.join('delegate-profiles', 'kimi-read-only.md'),
|
|
32
|
-
path.join('delegate-profiles', 'kimi-write.md'),
|
|
33
|
-
]);
|
|
34
|
-
|
|
35
24
|
function titleCase(name) {
|
|
36
25
|
return name.split('-').map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(' ');
|
|
37
26
|
}
|
|
@@ -39,24 +28,20 @@ function titleCase(name) {
|
|
|
39
28
|
function skillFrontmatter(runtime, name, fm) {
|
|
40
29
|
const base = { name, description: String(fm.description || '') };
|
|
41
30
|
const policy = skillPolicy(name);
|
|
42
|
-
if (runtime === 'claude'
|
|
31
|
+
if (runtime === 'claude') {
|
|
43
32
|
return {
|
|
44
33
|
...base,
|
|
45
34
|
'user-invocable': policy.userInvocable,
|
|
46
35
|
...(!policy.allowImplicitInvocation ? { 'disable-model-invocation': true } : {}),
|
|
47
36
|
};
|
|
48
37
|
}
|
|
49
|
-
if (runtime === 'kimi') {
|
|
50
|
-
return {
|
|
51
|
-
...base,
|
|
52
|
-
...(!policy.allowImplicitInvocation ? { disableModelInvocation: true } : {}),
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
38
|
return base;
|
|
56
39
|
}
|
|
57
40
|
|
|
58
41
|
function codexMetadata(name, description) {
|
|
59
|
-
const
|
|
42
|
+
const full = String(description).replace(/\s+/g, ' ').trim();
|
|
43
|
+
const limit = full.length > 64 ? full.lastIndexOf(' ', 64) : full.length;
|
|
44
|
+
const short = full.slice(0, limit > 0 ? limit : 64).replace(/[\s.,;:]+$/, '');
|
|
60
45
|
return [
|
|
61
46
|
'interface:',
|
|
62
47
|
` display_name: ${JSON.stringify(titleCase(name))}`,
|
|
@@ -68,7 +53,11 @@ function codexMetadata(name, description) {
|
|
|
68
53
|
].join('\n');
|
|
69
54
|
}
|
|
70
55
|
|
|
71
|
-
function copySkills({ runtime, repoRoot, skillRoot }) {
|
|
56
|
+
function copySkills({ runtime, repoRoot, skillRoot, publishedRoot }) {
|
|
57
|
+
copyTree(path.join(repoRoot, 'engine'), path.join(skillRoot, '..', 'engine'));
|
|
58
|
+
const cli = path.join(publishedRoot, 'engine', 'cli.cjs');
|
|
59
|
+
const formats = path.join(publishedRoot, 'engine', 'FORMATS.md');
|
|
60
|
+
const quotedCli = "'" + cli.replaceAll("'", "'\\''") + "'";
|
|
72
61
|
const installed = [];
|
|
73
62
|
for (const name of skillsForRuntime(runtime)) {
|
|
74
63
|
const source = path.join(repoRoot, 'skills', name);
|
|
@@ -81,14 +70,13 @@ function copySkills({ runtime, repoRoot, skillRoot }) {
|
|
|
81
70
|
if (relative !== 'SKILL.md') return buffer;
|
|
82
71
|
const { fm, body } = parse(buffer.toString('utf8'));
|
|
83
72
|
if (!fm) throw new Error(`missing frontmatter in ${name}`);
|
|
84
|
-
return Buffer.from(serialize(
|
|
73
|
+
return Buffer.from(serialize(
|
|
74
|
+
skillFrontmatter(runtime, name, fm), body
|
|
75
|
+
.replaceAll('__UBP_ENGINE_CLI__', quotedCli)
|
|
76
|
+
.replaceAll('__UBP_ENGINE_FORMATS__', formats),
|
|
77
|
+
));
|
|
85
78
|
},
|
|
86
79
|
});
|
|
87
|
-
if (name === 'ultra-init') {
|
|
88
|
-
const template = path.join(repoRoot, '.ultra-template');
|
|
89
|
-
if (!fs.existsSync(template)) throw new Error('missing canonical .ultra-template');
|
|
90
|
-
copyTree(template, path.join(target, 'assets', 'project-template'));
|
|
91
|
-
}
|
|
92
80
|
if (runtime === 'codex') {
|
|
93
81
|
const { fm } = parse(fs.readFileSync(path.join(source, 'SKILL.md'), 'utf8'));
|
|
94
82
|
writeAtomic(
|
|
@@ -101,20 +89,13 @@ function copySkills({ runtime, repoRoot, skillRoot }) {
|
|
|
101
89
|
return installed;
|
|
102
90
|
}
|
|
103
91
|
|
|
104
|
-
function copyHooks({
|
|
92
|
+
function copyHooks({ repoRoot, hookRoot, hooksManifest }) {
|
|
105
93
|
ensureDir(hookRoot);
|
|
106
|
-
for (const name of
|
|
94
|
+
for (const name of WORKFLOW_HOOK_FILES) {
|
|
107
95
|
const source = path.join(repoRoot, 'hooks', name);
|
|
108
96
|
if (!fs.existsSync(source)) throw new Error(`missing allowlisted hook: ${name}`);
|
|
109
97
|
fs.copyFileSync(source, path.join(hookRoot, name));
|
|
110
98
|
}
|
|
111
|
-
if (['codex', 'kimi', 'grok', 'zcode'].includes(runtime)) {
|
|
112
|
-
ensureDir(path.join(hookRoot, 'adapters'));
|
|
113
|
-
fs.copyFileSync(
|
|
114
|
-
path.join(repoRoot, 'hooks', 'adapters', `${runtime}.py`),
|
|
115
|
-
path.join(hookRoot, 'adapters', `${runtime}.py`),
|
|
116
|
-
);
|
|
117
|
-
}
|
|
118
99
|
writeAtomic(path.join(hookRoot, 'hooks.json'), `${JSON.stringify(hooksManifest, null, 2)}\n`);
|
|
119
100
|
return [...WORKFLOW_HOOK_FILES];
|
|
120
101
|
}
|
|
@@ -175,19 +156,7 @@ function inspectPlugin({ adapter, repoRoot, pluginRoot, skillRoot, hookRoot, man
|
|
|
175
156
|
issue('SKILL_MISSING', { skill: name });
|
|
176
157
|
}
|
|
177
158
|
}
|
|
178
|
-
const
|
|
179
|
-
const missingDelegationRunnerFiles = DELEGATION_RUNNER_FILES.filter((relative) => {
|
|
180
|
-
const candidate = path.join(delegationRunnerRoot, relative);
|
|
181
|
-
return !fs.existsSync(candidate) || !fs.statSync(candidate).isFile();
|
|
182
|
-
});
|
|
183
|
-
if (missingDelegationRunnerFiles.length > 0) {
|
|
184
|
-
issue('DELEGATION_RUNNER_MISSING', {
|
|
185
|
-
paths: missingDelegationRunnerFiles.map((relative) => (
|
|
186
|
-
path.join(delegationRunnerRoot, relative)
|
|
187
|
-
)),
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
for (const name of [...WORKFLOW_HOOK_FILES, '_common.py']) {
|
|
159
|
+
for (const name of WORKFLOW_HOOK_FILES) {
|
|
191
160
|
if (!fs.existsSync(path.join(hookRoot, name))) issue('HOOK_MISSING', { hook: name });
|
|
192
161
|
}
|
|
193
162
|
for (const retired of ['commands', 'agents', 'runtime', '.mcp.json']) {
|
|
@@ -202,41 +171,6 @@ function inspectPlugin({ adapter, repoRoot, pluginRoot, skillRoot, hookRoot, man
|
|
|
202
171
|
report.checks.plugin_manifest = {
|
|
203
172
|
status: fs.existsSync(manifestFile) ? 'pass' : 'fail',
|
|
204
173
|
};
|
|
205
|
-
report.checks.delegation_runner = {
|
|
206
|
-
status: missingDelegationRunnerFiles.length === 0 ? 'pass' : 'fail',
|
|
207
|
-
entrypoint: path.join(delegationRunnerRoot, 'delegate.cjs'),
|
|
208
|
-
};
|
|
209
|
-
try {
|
|
210
|
-
const installedProfiles = require(path.join(delegationRunnerRoot, 'host-profile.cjs'));
|
|
211
|
-
const installedDrivers = require(path.join(delegationRunnerRoot, 'agent-execution-driver.cjs'));
|
|
212
|
-
const profile = installedProfiles.hostProfile(adapter);
|
|
213
|
-
const selection = installedDrivers.selectExecutionDriver({
|
|
214
|
-
host: adapter,
|
|
215
|
-
profile,
|
|
216
|
-
cliCommand: profile.binary,
|
|
217
|
-
env: process.env,
|
|
218
|
-
});
|
|
219
|
-
report.checks.acp_capability = {
|
|
220
|
-
status: 'pass',
|
|
221
|
-
...selection.acpCapability,
|
|
222
|
-
};
|
|
223
|
-
report.checks.agent_execution_driver = {
|
|
224
|
-
status: 'pass',
|
|
225
|
-
selected: selection.driver,
|
|
226
|
-
fallback_reason: selection.fallbackReason,
|
|
227
|
-
};
|
|
228
|
-
if (adapter === 'zcode') {
|
|
229
|
-
report.checks.zcode_transport_maturity = {
|
|
230
|
-
status: profile.transportMaturity,
|
|
231
|
-
installed_runtime_only: profile.installedRuntimeOnly === true,
|
|
232
|
-
surface: profile.acp?.surface || null,
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
} catch (error) {
|
|
236
|
-
issue('EXECUTION_DRIVER_INSPECTION_FAILED', { message: error.message });
|
|
237
|
-
report.checks.acp_capability = { status: 'fail' };
|
|
238
|
-
report.checks.agent_execution_driver = { status: 'fail' };
|
|
239
|
-
}
|
|
240
174
|
report.status = report.issues.length === 0 ? 'healthy' : 'degraded';
|
|
241
175
|
return report;
|
|
242
176
|
}
|
|
@@ -1,132 +1,18 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
*
|
|
6
|
-
* Skills carry semantic workflow. Hooks are optional acceleration and safety.
|
|
7
|
-
* There is no prompt projection, worker registry, MCP kernel, or runtime daemon.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
const USER_INVOKED_SKILLS = Object.freeze([
|
|
11
|
-
'ultra-init',
|
|
12
|
-
'ultra-research',
|
|
13
|
-
'ultra-change',
|
|
14
|
-
'ultra-plan',
|
|
15
|
-
'ultra-dev',
|
|
16
|
-
'ultra-test',
|
|
17
|
-
'ultra-deliver',
|
|
18
|
-
'ultra-delegate',
|
|
19
|
-
]);
|
|
20
|
-
|
|
21
|
-
const MODEL_INVOKED_SKILLS = Object.freeze([
|
|
22
|
-
'ultra-grilling',
|
|
23
|
-
'ultra-domain-modeling',
|
|
24
|
-
'ultra-tdd',
|
|
25
|
-
'ultra-review',
|
|
26
|
-
'ultra-think',
|
|
27
|
-
]);
|
|
28
|
-
|
|
29
|
-
const ROUTER_SKILLS = Object.freeze(['ultra-status']);
|
|
30
|
-
const PUBLIC_SKILL_INVOCATION_MODES = Object.freeze({
|
|
31
|
-
'ultra-init': Object.freeze({
|
|
32
|
-
create: 'explicit-entry',
|
|
33
|
-
recover: 'explicit-entry',
|
|
34
|
-
}),
|
|
35
|
-
'ultra-research': Object.freeze({
|
|
36
|
-
baseline: 'explicit-entry',
|
|
37
|
-
'change-scoped': 'grant-continuable',
|
|
38
|
-
}),
|
|
39
|
-
'ultra-change': Object.freeze({
|
|
40
|
-
intake: 'explicit-entry',
|
|
41
|
-
'evidence-needed': 'explicit-entry',
|
|
42
|
-
reconcile: 'grant-continuable',
|
|
43
|
-
accepted: 'explicit-entry',
|
|
44
|
-
}),
|
|
45
|
-
'ultra-plan': Object.freeze({
|
|
46
|
-
decompose: 'grant-continuable',
|
|
47
|
-
recover: 'grant-continuable',
|
|
48
|
-
}),
|
|
49
|
-
'ultra-dev': Object.freeze({
|
|
50
|
-
execute: 'grant-continuable',
|
|
51
|
-
resume: 'grant-continuable',
|
|
52
|
-
reopen: 'grant-continuable',
|
|
53
|
-
}),
|
|
54
|
-
'ultra-test': Object.freeze({
|
|
55
|
-
audit: 'grant-continuable',
|
|
56
|
-
reaudit: 'grant-continuable',
|
|
57
|
-
}),
|
|
58
|
-
'ultra-deliver': Object.freeze({
|
|
59
|
-
reconcile: 'grant-continuable',
|
|
60
|
-
finalize: 'explicit-entry',
|
|
61
|
-
}),
|
|
62
|
-
'ultra-delegate': Object.freeze({
|
|
63
|
-
task: 'explicit-entry',
|
|
64
|
-
research: 'explicit-entry',
|
|
65
|
-
aggregate: 'explicit-entry',
|
|
66
|
-
}),
|
|
67
|
-
'ultra-status': Object.freeze({
|
|
68
|
-
route: 'router',
|
|
69
|
-
history: 'router',
|
|
70
|
-
installation: 'router',
|
|
71
|
-
delegation: 'router',
|
|
72
|
-
recovery: 'router',
|
|
73
|
-
}),
|
|
74
|
-
});
|
|
75
|
-
const GRANT_CONTINUABLE_SKILLS = Object.freeze(USER_INVOKED_SKILLS.filter((name) => (
|
|
76
|
-
Object.values(PUBLIC_SKILL_INVOCATION_MODES[name]).includes('grant-continuable')
|
|
77
|
-
)));
|
|
78
|
-
const SUPPORTED_RUNTIMES = Object.freeze(['claude', 'opencode', 'codex', 'kimi', 'grok', 'zcode']);
|
|
79
|
-
|
|
80
|
-
const WORKFLOW_HOOK_FILES = Object.freeze([
|
|
81
|
-
'session_context.py',
|
|
82
|
-
'mid_workflow_recall.py',
|
|
83
|
-
'compact_context.py',
|
|
84
|
-
'post_edit_guard.py',
|
|
85
|
-
'block_dangerous_commands.py',
|
|
86
|
-
]);
|
|
3
|
+
const SUPPORTED_RUNTIMES = Object.freeze(['claude', 'codex']);
|
|
4
|
+
const WORKFLOW_HOOK_FILES = Object.freeze(['session-start.cjs']);
|
|
87
5
|
|
|
88
6
|
function skillsForRuntime(runtime) {
|
|
89
7
|
if (!SUPPORTED_RUNTIMES.includes(runtime)) {
|
|
90
8
|
throw new Error(`unsupported Ultra runtime: ${runtime}`);
|
|
91
9
|
}
|
|
92
|
-
return [
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function isSupportedRuntime(runtime) {
|
|
96
|
-
return SUPPORTED_RUNTIMES.includes(runtime);
|
|
10
|
+
return ['ultra'];
|
|
97
11
|
}
|
|
98
12
|
|
|
99
13
|
function skillPolicy(name) {
|
|
100
|
-
if (
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
if (MODEL_INVOKED_SKILLS.includes(name)) {
|
|
104
|
-
return {
|
|
105
|
-
userInvocable: false,
|
|
106
|
-
allowImplicitInvocation: true,
|
|
107
|
-
invocationClasses: ['model-discipline'],
|
|
108
|
-
modes: {},
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
const modes = PUBLIC_SKILL_INVOCATION_MODES[name];
|
|
112
|
-
const invocationClasses = [...new Set(Object.values(modes))];
|
|
113
|
-
return {
|
|
114
|
-
userInvocable: true,
|
|
115
|
-
allowImplicitInvocation: invocationClasses.includes('grant-continuable'),
|
|
116
|
-
invocationClasses,
|
|
117
|
-
modes,
|
|
118
|
-
};
|
|
14
|
+
if (name !== 'ultra') throw new Error(`unknown packaged Ultra skill: ${name}`);
|
|
15
|
+
return { userInvocable: true, allowImplicitInvocation: true };
|
|
119
16
|
}
|
|
120
17
|
|
|
121
|
-
module.exports = {
|
|
122
|
-
GRANT_CONTINUABLE_SKILLS,
|
|
123
|
-
USER_INVOKED_SKILLS,
|
|
124
|
-
MODEL_INVOKED_SKILLS,
|
|
125
|
-
PUBLIC_SKILL_INVOCATION_MODES,
|
|
126
|
-
ROUTER_SKILLS,
|
|
127
|
-
SUPPORTED_RUNTIMES,
|
|
128
|
-
WORKFLOW_HOOK_FILES,
|
|
129
|
-
isSupportedRuntime,
|
|
130
|
-
skillPolicy,
|
|
131
|
-
skillsForRuntime,
|
|
132
|
-
};
|
|
18
|
+
module.exports = { SUPPORTED_RUNTIMES, WORKFLOW_HOOK_FILES, skillsForRuntime, skillPolicy };
|
package/adapters/claude.js
CHANGED
|
@@ -41,30 +41,14 @@ function resolveRepoRoot(ctx = {}) {
|
|
|
41
41
|
return ctx.repoRoot || path.resolve(__dirname, '..');
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
function hookCommand(name) {
|
|
45
|
-
return {
|
|
46
|
-
type: 'command',
|
|
47
|
-
command: `python3 "\${CLAUDE_PLUGIN_ROOT}/hooks/${name}"`,
|
|
48
|
-
timeout: 10,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
44
|
function buildHooksManifest() {
|
|
53
45
|
return {
|
|
54
|
-
description: 'Ultra file-first context sensors and narrow effect protection.',
|
|
55
46
|
hooks: {
|
|
56
|
-
SessionStart: [
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
{ matcher: 'Write|Edit|Grep', hooks: [hookCommand('mid_workflow_recall.py')] },
|
|
62
|
-
{ matcher: 'Bash', hooks: [hookCommand('block_dangerous_commands.py')] },
|
|
63
|
-
],
|
|
64
|
-
PostToolUse: [
|
|
65
|
-
{ matcher: 'Write|Edit', hooks: [hookCommand('post_edit_guard.py')] },
|
|
66
|
-
],
|
|
67
|
-
PreCompact: [{ hooks: [hookCommand('compact_context.py')] }],
|
|
47
|
+
SessionStart: [{ hooks: [{
|
|
48
|
+
type: 'command',
|
|
49
|
+
command: `node "\${CLAUDE_PLUGIN_ROOT}/hooks/session-start.cjs"`,
|
|
50
|
+
timeout: 10,
|
|
51
|
+
}] }],
|
|
68
52
|
},
|
|
69
53
|
};
|
|
70
54
|
}
|
|
@@ -73,13 +57,13 @@ function buildStaging(repoRoot, staging, publishedRoot) {
|
|
|
73
57
|
const skillRoot = path.join(staging, 'skills');
|
|
74
58
|
const hookRoot = path.join(staging, 'hooks');
|
|
75
59
|
const hooks = buildHooksManifest();
|
|
76
|
-
const skills = copySkills({ runtime: 'claude', repoRoot, skillRoot });
|
|
77
|
-
copyHooks({
|
|
60
|
+
const skills = copySkills({ runtime: 'claude', repoRoot, skillRoot, publishedRoot });
|
|
61
|
+
copyHooks({ repoRoot, hookRoot, hooksManifest: hooks });
|
|
78
62
|
const pkg = JSON.parse(fs.readFileSync(path.join(repoRoot, 'package.json'), 'utf8'));
|
|
79
63
|
writeAtomic(path.join(staging, '.claude-plugin', 'plugin.json'), `${JSON.stringify({
|
|
80
64
|
name: PLUGIN_NAME,
|
|
81
65
|
version: pkg.version,
|
|
82
|
-
description: '
|
|
66
|
+
description: 'UBP v6 method, engine and session status line for Claude Code.',
|
|
83
67
|
author: { name: pkg.author },
|
|
84
68
|
repository: pkg.homepage,
|
|
85
69
|
license: pkg.license,
|
package/adapters/codex.js
CHANGED
|
@@ -77,6 +77,7 @@ function installCleanupRoots(ctx, pluginRoot) {
|
|
|
77
77
|
add(resolveTarget(ctx), [
|
|
78
78
|
'.', 'config.toml', 'plugins', path.join('plugins', 'cache'),
|
|
79
79
|
path.join('plugins', 'cache', 'personal'), 'tmp', path.join('tmp', 'arg0'),
|
|
80
|
+
path.join('tmp', 'arg0-macos'),
|
|
80
81
|
]);
|
|
81
82
|
return [...groups].map(([root, candidates]) => ({
|
|
82
83
|
root,
|
|
@@ -101,31 +102,14 @@ function shellQuote(value) {
|
|
|
101
102
|
return `'${String(value).replaceAll("'", "'\"'\"'")}'`;
|
|
102
103
|
}
|
|
103
104
|
|
|
104
|
-
function
|
|
105
|
-
const adapter = path.join(pluginRoot, 'hooks', 'adapters', 'codex.py');
|
|
106
|
-
return {
|
|
107
|
-
type: 'command',
|
|
108
|
-
command: `python3 ${shellQuote(adapter)} ${shellQuote(name)}`,
|
|
109
|
-
timeout: 10,
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function buildHooksManifest(pluginRoot = '${CODEX_PLUGIN_ROOT}') {
|
|
105
|
+
function buildHooksManifest(pluginRoot) {
|
|
114
106
|
return {
|
|
115
107
|
hooks: {
|
|
116
|
-
SessionStart: [
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
{ matcher: 'Write|Edit|Grep|apply_patch', hooks: [hookCommand(pluginRoot, 'mid_workflow_recall.py')] },
|
|
122
|
-
{ matcher: 'Bash', hooks: [hookCommand(pluginRoot, 'block_dangerous_commands.py')] },
|
|
123
|
-
],
|
|
124
|
-
PostToolUse: [
|
|
125
|
-
{ matcher: 'Write|Edit|apply_patch', hooks: [hookCommand(pluginRoot, 'post_edit_guard.py')] },
|
|
126
|
-
],
|
|
127
|
-
PreCompact: [{ matcher: 'manual|auto', hooks: [hookCommand(pluginRoot, 'compact_context.py')] }],
|
|
128
|
-
PostCompact: [{ hooks: [hookCommand(pluginRoot, 'compact_context.py')] }],
|
|
108
|
+
SessionStart: [{ hooks: [{
|
|
109
|
+
type: 'command',
|
|
110
|
+
command: `node ${shellQuote(path.join(pluginRoot, 'hooks', 'session-start.cjs'))}`,
|
|
111
|
+
timeout: 10,
|
|
112
|
+
}] }],
|
|
129
113
|
},
|
|
130
114
|
};
|
|
131
115
|
}
|
|
@@ -142,9 +126,9 @@ function contentHash(root, version) {
|
|
|
142
126
|
function buildStaging(repoRoot, staging, publishedRoot) {
|
|
143
127
|
const skillRoot = path.join(staging, 'skills');
|
|
144
128
|
const hookRoot = path.join(staging, 'hooks');
|
|
145
|
-
const skills = copySkills({ runtime: 'codex', repoRoot, skillRoot });
|
|
129
|
+
const skills = copySkills({ runtime: 'codex', repoRoot, skillRoot, publishedRoot });
|
|
146
130
|
copyHooks({
|
|
147
|
-
|
|
131
|
+
repoRoot, hookRoot,
|
|
148
132
|
hooksManifest: buildHooksManifest(publishedRoot),
|
|
149
133
|
});
|
|
150
134
|
if (fs.existsSync(path.join(repoRoot, 'LICENSE'))) {
|
|
@@ -155,7 +139,7 @@ function buildStaging(repoRoot, staging, publishedRoot) {
|
|
|
155
139
|
writeAtomic(path.join(staging, '.codex-plugin', 'plugin.json'), `${JSON.stringify({
|
|
156
140
|
name: PLUGIN_NAME,
|
|
157
141
|
version,
|
|
158
|
-
description: '
|
|
142
|
+
description: 'UBP v6 method, engine and session status line for Codex.',
|
|
159
143
|
author: { name: pkg.author },
|
|
160
144
|
homepage: pkg.homepage,
|
|
161
145
|
repository: pkg.repository?.url || pkg.repository,
|
|
@@ -164,16 +148,14 @@ function buildStaging(repoRoot, staging, publishedRoot) {
|
|
|
164
148
|
skills: './skills/',
|
|
165
149
|
interface: {
|
|
166
150
|
displayName: 'Ultra Builder Pro',
|
|
167
|
-
shortDescription: '
|
|
168
|
-
longDescription: '
|
|
151
|
+
shortDescription: 'UBP v6 method, engine and session status line.',
|
|
152
|
+
longDescription: 'UBP v6 method, engine and session status line for Codex.',
|
|
169
153
|
developerName: pkg.author,
|
|
170
154
|
category: 'Developer Tools',
|
|
171
155
|
capabilities: ['Interactive', 'Write'],
|
|
172
156
|
websiteURL: pkg.homepage,
|
|
173
157
|
defaultPrompt: [
|
|
174
|
-
'
|
|
175
|
-
'Reconcile this change with $ultra-builder-pro:ultra-change.',
|
|
176
|
-
'Show workflow status with $ultra-builder-pro:ultra-status.',
|
|
158
|
+
'Drive this project with $ultra-builder-pro:ultra.',
|
|
177
159
|
],
|
|
178
160
|
},
|
|
179
161
|
}, null, 2)}\n`);
|
|
@@ -183,7 +165,6 @@ function buildStaging(repoRoot, staging, publishedRoot) {
|
|
|
183
165
|
contracts: {
|
|
184
166
|
plugin_manifest: { root: 'plugin', path: '.codex-plugin/plugin.json' },
|
|
185
167
|
hooks_manifest: { root: 'plugin', path: 'hooks/hooks.json' },
|
|
186
|
-
hook_adapter: { root: 'plugin', path: 'hooks/adapters/codex.py' },
|
|
187
168
|
},
|
|
188
169
|
});
|
|
189
170
|
return { skills, version };
|
package/bin/install.js
CHANGED
|
@@ -1,25 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
* ultra-builder-pro-cli — multi-runtime installer.
|
|
5
|
-
*
|
|
6
|
-
* Distributes fourteen Skills and five hooks to Claude Code, OpenCode, Codex CLI,
|
|
7
|
-
* Kimi Code, Grok Build, and ZCode through runtime-specific adapters under adapters/.
|
|
8
|
-
* Install is idempotent and atomic; uninstall removes only managed assets.
|
|
9
|
-
*
|
|
10
|
-
* Usage:
|
|
11
|
-
* npx ultra-builder-pro-cli [options]
|
|
12
|
-
*
|
|
13
|
-
* --claude / --opencode / --codex / --kimi / --grok / --zcode select runtime(s)
|
|
14
|
-
* --all install to all supported runtimes
|
|
15
|
-
* -g, --global install to runtime's global config dir
|
|
16
|
-
* -l, --local project scope where the host supports it
|
|
17
|
-
* -u, --uninstall remove installed assets
|
|
18
|
-
* -d, --doctor inspect installation provenance without mutation
|
|
19
|
-
* --json emit machine-readable doctor output
|
|
20
|
-
* -c, --config-dir <path> override config directory
|
|
21
|
-
* -h, --help show help
|
|
22
|
-
*/
|
|
3
|
+
// UBP v6 installer for Claude Code and Codex; engine commands dispatch below.
|
|
23
4
|
|
|
24
5
|
'use strict';
|
|
25
6
|
|
|
@@ -57,7 +38,7 @@ function printBanner() {
|
|
|
57
38
|
paint('cyan', ' ╚═════╝ ╚═════╝ ╚═╝ ╚═════╝╚══════╝╚═╝'),
|
|
58
39
|
'',
|
|
59
40
|
` ${paint('bold', 'Ultra Builder Pro CLI')} ${paint('dim', 'v' + pkg.version)}`,
|
|
60
|
-
` ${paint('dim', '
|
|
41
|
+
` ${paint('dim', 'Project engine and method for Claude Code and Codex')}`,
|
|
61
42
|
'',
|
|
62
43
|
];
|
|
63
44
|
console.log(banner.join('\n'));
|
|
@@ -66,23 +47,32 @@ function printBanner() {
|
|
|
66
47
|
function printHelp() {
|
|
67
48
|
console.log(` ${paint('yellow', 'Usage:')} npx ultra-builder-pro-cli [options]
|
|
68
49
|
|
|
50
|
+
${paint('yellow', 'Progress:')}
|
|
51
|
+
${paint('cyan', 'status')} show progress computed from project files
|
|
52
|
+
${paint('cyan', 'gate')} validate the plan and record its snapshot
|
|
53
|
+
${paint('cyan', 'check')} run registered checks and record evidence
|
|
54
|
+
${paint('cyan', 'node done <id>')} complete a ready node with green requirements
|
|
55
|
+
${paint('cyan', 'milestone close <id>')} close a milestone after its journey and review
|
|
56
|
+
${paint('cyan', 'context <id>')} compile the brief for a node
|
|
57
|
+
${paint('cyan', 'approve <items>')} record the Owner's approval of reductions
|
|
58
|
+
${paint('cyan', 'drive')} run unattended until the next Owner touch
|
|
59
|
+
${paint('cyan', 'retro')} list failure classes since the latest closure
|
|
60
|
+
${paint('cyan', 'merge <branch>')} merge after verifying the expected HEAD and checks
|
|
61
|
+
|
|
69
62
|
${paint('yellow', 'Runtime selection (pick ≥1, or --all):')}
|
|
70
63
|
${paint('cyan', '--claude')} Claude Code
|
|
71
|
-
${paint('cyan', '--opencode')} OpenCode
|
|
72
64
|
${paint('cyan', '--codex')} Codex CLI (OpenAI)
|
|
73
|
-
${paint('cyan', '--kimi')} Kimi Code (Moonshot AI)
|
|
74
|
-
${paint('cyan', '--grok')} Grok Build (xAI)
|
|
75
|
-
${paint('cyan', '--zcode')} ZCode (Z.AI)
|
|
76
65
|
${paint('cyan', '--all')} all supported runtimes
|
|
77
66
|
|
|
78
67
|
${paint('yellow', 'Scope:')}
|
|
79
68
|
${paint('cyan', '-g, --global')} install to runtime's global config directory
|
|
80
|
-
${paint('cyan', '-l, --local')} project scope (Claude
|
|
69
|
+
${paint('cyan', '-l, --local')} project scope (Claude Code only)
|
|
81
70
|
|
|
82
71
|
${paint('yellow', 'Other:')}
|
|
83
72
|
${paint('cyan', '-u, --uninstall')} remove installed assets
|
|
84
73
|
${paint('cyan', '-d, --doctor')} verify installed version, provenance, managed assets, and live entry points
|
|
85
|
-
${paint('cyan', '--json')} emit machine-readable
|
|
74
|
+
${paint('cyan', '--json')} emit machine-readable output (doctor and engine commands)
|
|
75
|
+
${paint('cyan', '--root <dir>')} engine commands: the project root (default: current directory)
|
|
86
76
|
${paint('cyan', '-c, --config-dir')} override one runtime's config directory; multi-runtime installs use <path>/<runtime>
|
|
87
77
|
${paint('cyan', '-h, --help')} show this help
|
|
88
78
|
${paint('cyan', '-v, --version')} show CLI version
|
|
@@ -91,21 +81,9 @@ function printHelp() {
|
|
|
91
81
|
${paint('dim', '# Install to Claude Code globally')}
|
|
92
82
|
npx ultra-builder-pro-cli --claude --global
|
|
93
83
|
|
|
94
|
-
${paint('dim', '# Install
|
|
84
|
+
${paint('dim', '# Install both plugins in their user scopes')}
|
|
95
85
|
npx ultra-builder-pro-cli --all --global
|
|
96
86
|
|
|
97
|
-
${paint('dim', '# Uninstall from OpenCode')}
|
|
98
|
-
npx ultra-builder-pro-cli --opencode --global --uninstall
|
|
99
|
-
|
|
100
|
-
${paint('dim', '# Install to Kimi Code globally')}
|
|
101
|
-
npx ultra-builder-pro-cli --kimi --global
|
|
102
|
-
|
|
103
|
-
${paint('dim', '# Install to Grok Build globally')}
|
|
104
|
-
npx ultra-builder-pro-cli --grok --global
|
|
105
|
-
|
|
106
|
-
${paint('dim', '# Install to ZCode globally')}
|
|
107
|
-
npx ultra-builder-pro-cli --zcode --global
|
|
108
|
-
|
|
109
87
|
${paint('dim', '# Verify all host installations without changing them')}
|
|
110
88
|
npx ultra-builder-pro-cli --all --global --doctor
|
|
111
89
|
`);
|
|
@@ -129,11 +107,7 @@ function parseArgs(argv) {
|
|
|
129
107
|
const a = args[i];
|
|
130
108
|
switch (a) {
|
|
131
109
|
case '--claude': runtimes.add('claude'); break;
|
|
132
|
-
case '--opencode': runtimes.add('opencode'); break;
|
|
133
110
|
case '--codex': runtimes.add('codex'); break;
|
|
134
|
-
case '--kimi': runtimes.add('kimi'); break;
|
|
135
|
-
case '--grok': runtimes.add('grok'); break;
|
|
136
|
-
case '--zcode': runtimes.add('zcode'); break;
|
|
137
111
|
case '--all':
|
|
138
112
|
SUPPORTED_RUNTIMES.forEach(r => runtimes.add(r));
|
|
139
113
|
break;
|
|
@@ -189,16 +163,18 @@ function loadAdapter(runtime) {
|
|
|
189
163
|
return require(adapterPath);
|
|
190
164
|
}
|
|
191
165
|
|
|
192
|
-
function resolveScope(flags) {
|
|
166
|
+
function resolveScope(flags, runtime) {
|
|
193
167
|
if (flags.global && flags.local) bail('cannot use --global and --local together');
|
|
194
|
-
if (!flags.global && !flags.local) return 'local';
|
|
168
|
+
if (!flags.global && !flags.local) return runtime === 'codex' ? 'global' : 'local';
|
|
195
169
|
return flags.global ? 'global' : 'local';
|
|
196
170
|
}
|
|
197
171
|
|
|
198
172
|
async function main() {
|
|
199
|
-
if (
|
|
200
|
-
|
|
201
|
-
|
|
173
|
+
if (['status', 'gate', 'check', 'node', 'milestone', 'context', 'approve', 'retro', 'merge',
|
|
174
|
+
'drive']
|
|
175
|
+
.includes(process.argv[2])) {
|
|
176
|
+
const { handle } = require('../engine/cli.cjs');
|
|
177
|
+
process.exitCode = await handle(process.argv.slice(2));
|
|
202
178
|
return;
|
|
203
179
|
}
|
|
204
180
|
const { runtimes, flags } = parseArgs(process.argv);
|
|
@@ -218,22 +194,24 @@ async function main() {
|
|
|
218
194
|
if (flags.json && !flags.doctor) bail('--json is available only with --doctor');
|
|
219
195
|
|
|
220
196
|
if (runtimes.length === 0) {
|
|
221
|
-
bail('no runtime selected; use --claude / --
|
|
197
|
+
bail('no runtime selected; use --claude / --codex / --all');
|
|
222
198
|
}
|
|
223
199
|
|
|
224
|
-
const
|
|
200
|
+
const scopes = Object.fromEntries(runtimes.map((r) => [r, resolveScope(flags, r)]));
|
|
201
|
+
if (runtimes.includes('codex') && flags.local && !flags.configDir) {
|
|
202
|
+
bail('Codex is user-scope only; --local requires an isolated --config-dir');
|
|
203
|
+
}
|
|
225
204
|
const repoRoot = path.resolve(__dirname, '..');
|
|
226
205
|
const configDir = flags.configDir ? expandTilde(flags.configDir) : null;
|
|
227
|
-
const userScopedOnly = runtimes.filter((runtime) => ['kimi', 'grok', 'zcode'].includes(runtime));
|
|
228
|
-
if (scope === 'local' && !configDir && userScopedOnly.length) {
|
|
229
|
-
bail(`${userScopedOnly.join(', ')} plugins are user-scoped by their hosts; use --global or an isolated --config-dir`);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
206
|
if (!flags.json) printBanner();
|
|
233
207
|
|
|
234
208
|
const mode = flags.doctor ? 'doctor' : flags.uninstall ? 'uninstall' : 'install';
|
|
235
209
|
if (!flags.json) {
|
|
236
210
|
console.log(` ${paint('bold', 'Mode:')} ${mode}`);
|
|
211
|
+
const scope = runtimes.map((r) => {
|
|
212
|
+
const label = scopes[r] === 'global' ? 'global (user)' : 'local';
|
|
213
|
+
return `${r}=${label}`;
|
|
214
|
+
}).join(', ');
|
|
237
215
|
console.log(` ${paint('bold', 'Scope:')} ${scope}`);
|
|
238
216
|
console.log(` ${paint('bold', 'Runtimes:')} ${runtimes.join(', ')}`);
|
|
239
217
|
if (configDir) {
|
|
@@ -253,7 +231,7 @@ async function main() {
|
|
|
253
231
|
: configDir;
|
|
254
232
|
return {
|
|
255
233
|
repoRoot,
|
|
256
|
-
scope,
|
|
234
|
+
scope: scopes[runtime],
|
|
257
235
|
configDir: runtimeConfigDir,
|
|
258
236
|
homeDir: runtimeConfigDir || os.homedir(),
|
|
259
237
|
};
|