@ngockhoale/ukit 2.7.1 → 2.7.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/CHANGELOG.md +21 -0
- package/README.md +1 -3
- package/manifests/hostCapabilities.yaml +0 -10
- package/manifests/instructionRules.yaml +0 -16
- package/manifests/platform.full.yaml +2 -16
- package/package.json +3 -5
- package/scripts/perf/audit-perf.mjs +4 -4
- package/scripts/perf/perf-findings.json +420 -0
- package/src/cli/adapters.js +10 -13
- package/src/cli/commands/doctor.js +15 -7
- package/src/cli/index.js +2 -2
- package/src/core/opencodeSteer.js +37 -0
- package/src/core/projectImportant.js +14 -8
- package/src/core/runInstallPipeline.js +10 -0
- package/src/core/runtimeConfig.js +36 -4
- package/src/core/status.js +6 -4
- package/src/manifest/selectItems.js +0 -1
- package/templates/.claude/agents/bug-debugger.md +1 -1
- package/templates/.claude/agents/feature-implementer.md +1 -1
- package/templates/.claude/agents/ukit-small-task-maintainer.md +2 -2
- package/templates/.claude/commands/ukit/handoff-create.md +4 -4
- package/templates/.claude/commands/ukit/handoff-fullstack.md +4 -4
- package/templates/.claude/commands/ukit/handoff-implement.md +2 -2
- package/templates/.claude/commands/ukit/handoff-review.md +2 -2
- package/templates/.claude/skills/update-status/SKILL.md +1 -1
- package/templates/.claude/ukit/index/route-task.mjs +7 -2
- package/templates/.codex/README.md +1 -1
- package/templates/.codex/settings.json +0 -1
- package/templates/.omp/agents/bug-debugger.md +1 -1
- package/templates/.omp/agents/feature-implementer.md +1 -1
- package/templates/.omp/agents/ukit-small-task-maintainer.md +2 -2
- package/templates/AGENTS.md +4 -13
- package/templates/CLAUDE.md +1 -3
- package/templates/adapter-presets/claude/settings.local.json +0 -1
- package/templates/docs/AI_HANDOFF/INDEX.md +1 -1
- package/templates/docs/AI_HANDOFF/RULES.md +2 -2
- package/templates/docs/PROJECT.md +1 -1
- package/templates/docs/UKIT_INTERNALS.md +1 -1
- package/templates/instructions/core.md +1 -3
- package/templates/instructions/layout.yaml +2 -4
- package/templates/instructions/overlays/agents.md +3 -10
- package/templates/ukit/storage/config.json +0 -10
- package/templates/adapter-presets/opencode/opencode.template.json +0 -1
package/src/cli/adapters.js
CHANGED
|
@@ -19,16 +19,6 @@ export const OPTIONAL_ADAPTERS = [
|
|
|
19
19
|
'.codex/agents',
|
|
20
20
|
],
|
|
21
21
|
},
|
|
22
|
-
{
|
|
23
|
-
key: 'opencode',
|
|
24
|
-
label: 'OpenCode',
|
|
25
|
-
itemIds: [
|
|
26
|
-
'multi-opencode-config',
|
|
27
|
-
],
|
|
28
|
-
managedPaths: [
|
|
29
|
-
'opencode.json',
|
|
30
|
-
],
|
|
31
|
-
},
|
|
32
22
|
{
|
|
33
23
|
key: 'omp',
|
|
34
24
|
label: 'Oh My Pi (omp)',
|
|
@@ -75,13 +65,11 @@ export const TOOL_ALIASES = new Map([
|
|
|
75
65
|
['claude-code', 'claude'],
|
|
76
66
|
['codex', 'codex'],
|
|
77
67
|
['openai-codex', 'codex'],
|
|
78
|
-
['opencode', 'opencode'],
|
|
79
|
-
['open-code', 'opencode'],
|
|
80
68
|
['omp', 'omp'],
|
|
81
69
|
['oh-my-pi', 'omp'],
|
|
82
70
|
]);
|
|
83
71
|
|
|
84
|
-
export const TOOLS_FLAG_HELP = 'all|none|claude,codex,
|
|
72
|
+
export const TOOLS_FLAG_HELP = 'all|none|claude,codex,omp';
|
|
85
73
|
|
|
86
74
|
export function parseToolsArg(argv = []) {
|
|
87
75
|
let toolsArg = null;
|
|
@@ -137,6 +125,15 @@ export function resolveOptionalToolKeys(toolsArg) {
|
|
|
137
125
|
);
|
|
138
126
|
}
|
|
139
127
|
|
|
128
|
+
// legacy: 'opencode'/'open-code' were adapters until the OpenCode lane was removed.
|
|
129
|
+
// Warn + ignore so `--tools=opencode` still exits 0 instead of hard-failing.
|
|
130
|
+
if (normalizedToken === 'opencode' || normalizedToken === 'open-code') {
|
|
131
|
+
console.warn(
|
|
132
|
+
`[UKit] '${token}' was removed as a UKit adapter — ignoring. Allowed: ${TOOLS_FLAG_HELP}`,
|
|
133
|
+
);
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
|
|
140
137
|
const normalizedTool = TOOL_ALIASES.get(normalizedToken) ?? null;
|
|
141
138
|
if (!normalizedTool) {
|
|
142
139
|
throw new Error(`Unknown tool '${token}'. Allowed: ${TOOLS_FLAG_HELP}`);
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
} from '../../core/projectImportant.js';
|
|
25
25
|
import { runDocContractChecks } from '../../core/docContracts.js';
|
|
26
26
|
import { inspectUnattendedMode } from '../../core/unattendedDoctor.js';
|
|
27
|
+
import { findOpencodeArtifacts, opencodeSteerMessage } from '../../core/opencodeSteer.js';
|
|
27
28
|
|
|
28
29
|
export const DOCTOR_HELP_FLAGS = new Set(['--help', '-h']);
|
|
29
30
|
const KNOWN_FLAGS = new Set([...DOCTOR_HELP_FLAGS, '--skills', '--gateway', '--docs']);
|
|
@@ -203,13 +204,16 @@ export async function runDoctor({ packageRoot, projectRoot, argv = [], homeDir =
|
|
|
203
204
|
remedy: INSTALL_REPAIR,
|
|
204
205
|
});
|
|
205
206
|
}
|
|
206
|
-
|
|
207
|
+
// SPEC FR-007 — a leftover opencode.json is a WARN row: advisory only, never a
|
|
208
|
+
// FAIL, never auto-fixed. Removal is the user's manual action.
|
|
209
|
+
const opencodeArtifacts = findOpencodeArtifacts(projectRoot);
|
|
210
|
+
if (opencodeArtifacts.length > 0) {
|
|
207
211
|
projectChecks.push({
|
|
208
|
-
label:
|
|
209
|
-
passed:
|
|
210
|
-
|
|
211
|
-
remediationClass: '
|
|
212
|
-
remedy:
|
|
212
|
+
label: opencodeSteerMessage(opencodeArtifacts),
|
|
213
|
+
passed: true,
|
|
214
|
+
severity: 'warning',
|
|
215
|
+
remediationClass: 'advisory',
|
|
216
|
+
remedy: 'Remove it manually: rm opencode.json',
|
|
213
217
|
});
|
|
214
218
|
}
|
|
215
219
|
|
|
@@ -252,7 +256,11 @@ export async function runDoctor({ packageRoot, projectRoot, argv = [], homeDir =
|
|
|
252
256
|
console.log('[UKit] Project rules checks:');
|
|
253
257
|
for (const check of projectChecks) {
|
|
254
258
|
if (check.applicable === false) continue;
|
|
255
|
-
|
|
259
|
+
const severity = check.severity === 'warning' ? ' (warning)' : '';
|
|
260
|
+
console.log(`[UKit] ${ok(check.passed)} ${check.label}${severity}`);
|
|
261
|
+
if (check.remedy && check.severity === 'warning') {
|
|
262
|
+
console.log(`[UKit] remedy: ${check.remedy}`);
|
|
263
|
+
}
|
|
256
264
|
}
|
|
257
265
|
|
|
258
266
|
// TASK-011 / SPEC §8 (FR-007): unattended-mode checks — same remediation-class
|
package/src/cli/index.js
CHANGED
|
@@ -117,8 +117,8 @@ export async function runCli({ argv, packageRoot, projectRoot, packageVersion })
|
|
|
117
117
|
console.log('');
|
|
118
118
|
console.log('Options (install / diff):');
|
|
119
119
|
console.log(' --tools=<list> Comma-separated adapters to enable (default: all)');
|
|
120
|
-
console.log(' Values: claude, codex,
|
|
121
|
-
console.log(' Example: ukit install --tools=claude,codex,
|
|
120
|
+
console.log(' Values: claude, codex, omp');
|
|
121
|
+
console.log(' Example: ukit install --tools=claude,codex,omp');
|
|
122
122
|
console.log(' Use --tools=none to disable all optional adapters');
|
|
123
123
|
console.log(' --with-codegraph Enable CodeGraph MCP integration in CLAUDE.md');
|
|
124
124
|
console.log(' Adds routing rules that prefer codegraph_* tools for');
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// SPEC FR-004 — OpenCode support was removed. Any leftover artifact is a user
|
|
2
|
+
// file: UKit never installs, repairs, merges, or deletes it (only `ukit
|
|
3
|
+
// uninstall` may). This helper is the single source of truth for detection and
|
|
4
|
+
// the canonical steer message shared by projectImportant, status, and doctor.
|
|
5
|
+
|
|
6
|
+
import { existsSync } from 'node:fs';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
|
|
9
|
+
// Extensible list — detection is one existsSync per known filename, no parsing.
|
|
10
|
+
const OPENCODE_ARTIFACT_NAMES = ['opencode.json'];
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @param {string} projectRoot
|
|
14
|
+
* @returns {string[]} absolute paths of detected OpenCode artifacts
|
|
15
|
+
*/
|
|
16
|
+
export function findOpencodeArtifacts(projectRoot) {
|
|
17
|
+
return OPENCODE_ARTIFACT_NAMES
|
|
18
|
+
.map((name) => path.join(projectRoot, name))
|
|
19
|
+
.filter((candidate) => existsSync(candidate));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Canonical steer copy. Callers must print this verbatim so every surface
|
|
24
|
+
* (status line, doctor WARN row, stderr warning) reads identically.
|
|
25
|
+
*
|
|
26
|
+
* @param {string[]} paths detected artifact paths from findOpencodeArtifacts
|
|
27
|
+
* @returns {string}
|
|
28
|
+
*/
|
|
29
|
+
export function opencodeSteerMessage(paths = []) {
|
|
30
|
+
const names = (Array.isArray(paths) ? paths : [])
|
|
31
|
+
.map((entry) => path.basename(String(entry)))
|
|
32
|
+
.filter(Boolean);
|
|
33
|
+
const fileList = names.length > 0 ? names.join(' ') : 'opencode.json';
|
|
34
|
+
return `[ukit] ${fileList} detected — OpenCode is no longer supported. `
|
|
35
|
+
+ `ukit will not install, repair, or merge this file. `
|
|
36
|
+
+ `Remove it manually: rm ${fileList}`;
|
|
37
|
+
}
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
isSensitiveDataGateEnabled,
|
|
26
26
|
loadSensitiveAllowlist,
|
|
27
27
|
} from './sensitiveValueScanner.js';
|
|
28
|
+
import { findOpencodeArtifacts, opencodeSteerMessage } from './opencodeSteer.js';
|
|
28
29
|
|
|
29
30
|
export const PROJECT_IMPORTANT_FILENAME = 'PROJECT_IMPORTANT.md';
|
|
30
31
|
export const PROJECT_IMPORTANT_CODEPOINT_LIMIT = 6000;
|
|
@@ -338,12 +339,14 @@ export async function renderProjectImportantForProject(projectRoot, options = {}
|
|
|
338
339
|
* TASK-044 — adapter wiring facts for status/doctor (spec §13/§14).
|
|
339
340
|
*
|
|
340
341
|
* Returns install + wiring facts only — never file bodies. Claude wiring is
|
|
341
|
-
* always expected; omp/Codex
|
|
342
|
-
* absent adapter is `installed:false`, never a failure.
|
|
342
|
+
* always expected; omp/Codex are checked only when installed, and an
|
|
343
|
+
* absent adapter is `installed:false`, never a failure. A leftover
|
|
344
|
+
* `opencode.json` is no longer an adapter signal — it is detected and
|
|
345
|
+
* reported via `opencodeArtifacts` + a steer warning, never wired.
|
|
343
346
|
*
|
|
344
347
|
* @param {string} projectRoot
|
|
345
348
|
* @param {{ trackedPaths?: string[] }} [options] install.json file list, if known
|
|
346
|
-
* @returns {Promise<{claude: object, omp: object, codex: object,
|
|
349
|
+
* @returns {Promise<{claude: object, omp: object, codex: object, opencodeArtifacts: string[], agentsFallback: boolean}>}
|
|
347
350
|
*/
|
|
348
351
|
export async function inspectProjectImportantWiring(projectRoot, options = {}) {
|
|
349
352
|
const trackedPaths = Array.isArray(options.trackedPaths) ? options.trackedPaths : [];
|
|
@@ -397,7 +400,7 @@ export async function inspectProjectImportantWiring(projectRoot, options = {}) {
|
|
|
397
400
|
wired: runtimeModule && hookInstalled && hookExecutable && settingsWired,
|
|
398
401
|
};
|
|
399
402
|
|
|
400
|
-
// --- AGENTS.md owner-instructions pointer (shared Codex
|
|
403
|
+
// --- AGENTS.md owner-instructions pointer (shared Codex fallback) ---
|
|
401
404
|
let agentsFallback = false;
|
|
402
405
|
try {
|
|
403
406
|
const agents = await readFile(agentsPath, 'utf8');
|
|
@@ -425,9 +428,12 @@ export async function inspectProjectImportantWiring(projectRoot, options = {}) {
|
|
|
425
428
|
const codexInstalled = tracked('.codex/') || await exists(path.join(projectRoot, '.codex', 'settings.json'));
|
|
426
429
|
const codex = { installed: codexInstalled, wired: codexInstalled && agentsFallback };
|
|
427
430
|
|
|
428
|
-
// --- OpenCode
|
|
429
|
-
|
|
430
|
-
const
|
|
431
|
+
// --- OpenCode steer (SPEC FR-005) — a leftover opencode.json is a user file:
|
|
432
|
+
// never wired, never installed/repaired. Detect it and steer toward removal.
|
|
433
|
+
const opencodeArtifacts = findOpencodeArtifacts(projectRoot);
|
|
434
|
+
if (opencodeArtifacts.length > 0) {
|
|
435
|
+
console.warn(opencodeSteerMessage(opencodeArtifacts));
|
|
436
|
+
}
|
|
431
437
|
|
|
432
|
-
return { claude, omp, codex,
|
|
438
|
+
return { claude, omp, codex, opencodeArtifacts, agentsFallback };
|
|
433
439
|
}
|
|
@@ -15,6 +15,7 @@ import { ensureGitignore } from './ensureGitignore.js';
|
|
|
15
15
|
import { repairBrokenHooks } from './repairBrokenHooks.js';
|
|
16
16
|
import { applyGatewayResilienceEnv } from './gatewayResilienceEnv.js';
|
|
17
17
|
import { cleanupEmptyParents, readJsonIfExists, removeFileOrLinkOnly, resolveProjectRelativePath } from './fileOps.js';
|
|
18
|
+
import { findOpencodeArtifacts, opencodeSteerMessage } from './opencodeSteer.js';
|
|
18
19
|
|
|
19
20
|
const AUTO_PRUNE_OBSOLETE_PREFIXES = [
|
|
20
21
|
'.claude/skills/',
|
|
@@ -261,6 +262,15 @@ export async function runInstallPipeline({
|
|
|
261
262
|
const installMetaData = await readJsonIfExists(pathConfig.installMetaPath);
|
|
262
263
|
const isReinstall = Boolean(installMetaData?.tool === 'ukit');
|
|
263
264
|
|
|
265
|
+
// SPEC FR-004/§security — a leftover opencode.json is a user file: detect and
|
|
266
|
+
// steer toward manual removal. Install never writes, merges, repairs, or
|
|
267
|
+
// deletes it (obsolete-path pruning excludes it; only `ukit uninstall` may
|
|
268
|
+
// remove it).
|
|
269
|
+
const opencodeArtifacts = findOpencodeArtifacts(pathConfig.projectRoot);
|
|
270
|
+
if (opencodeArtifacts.length > 0) {
|
|
271
|
+
console.warn(opencodeSteerMessage(opencodeArtifacts));
|
|
272
|
+
}
|
|
273
|
+
|
|
264
274
|
if (isReinstall && !dryRun) {
|
|
265
275
|
await migrateLegacyRuntimeRoot(pathConfig.projectRoot);
|
|
266
276
|
}
|
|
@@ -9,8 +9,10 @@ const require = createRequire(import.meta.url);
|
|
|
9
9
|
const { version: PACKAGE_VERSION } = require('../../package.json');
|
|
10
10
|
|
|
11
11
|
// legacy: 'antigravity' stays valid — Antigravity adapter removed in v2.2.0, but an existing
|
|
12
|
-
// config.json naming it must not become invalid.
|
|
13
|
-
|
|
12
|
+
// config.json naming it must not become invalid. 'opencode' is NOT kept valid here: the
|
|
13
|
+
// OpenCode lane was removed this cycle, so stale 'opencode' values are normalized away
|
|
14
|
+
// (strip + console.warn) in normalizeLegacyOpencodeEntries instead of hard-failing.
|
|
15
|
+
const VALID_AGENTS = new Set(['claude-code', 'codex', 'antigravity', 'omp']);
|
|
14
16
|
|
|
15
17
|
// Reserved permission modes for orchestration.permissionMode (single source of truth).
|
|
16
18
|
// 'unattended' is the only mode implemented this cycle; interactive/safe-auto are reserved.
|
|
@@ -90,7 +92,6 @@ export function buildDefaultRuntimeConfig(overrides = {}) {
|
|
|
90
92
|
mustNotBlockMainTask: true,
|
|
91
93
|
targets: {
|
|
92
94
|
claude: { autoCompact: true, mode: 'precompact-reinject', preserveExistingHooks: true },
|
|
93
|
-
opencode: { autoCompact: true, mode: 'native-auto-prune', preserveExistingCompaction: true },
|
|
94
95
|
// 'precompact-reinject' like claude, NOT codex's 'soft-handoff': omp exposes real
|
|
95
96
|
// pre-compaction hook events, so there is nothing to work around with a state file.
|
|
96
97
|
omp: { autoCompact: true, mode: 'precompact-reinject', preserveExistingHooks: true },
|
|
@@ -653,6 +654,37 @@ export function validateRuntimeConfig(config) {
|
|
|
653
654
|
};
|
|
654
655
|
}
|
|
655
656
|
|
|
657
|
+
// OpenCode was removed as an adapter this cycle. Stale 'opencode' values inside
|
|
658
|
+
// validated agent lists/keys are stripped with a steer warning — never a hard-fail —
|
|
659
|
+
// so an old config.json still loads instead of falling back to defaults.
|
|
660
|
+
function normalizeLegacyOpencodeEntries(config) {
|
|
661
|
+
const warned = { value: false };
|
|
662
|
+
const warnOnce = () => {
|
|
663
|
+
if (!warned.value) {
|
|
664
|
+
console.warn(`[UKit] Removed stale 'opencode' agent entries from UKit runtime config — OpenCode is no longer supported.`);
|
|
665
|
+
warned.value = true;
|
|
666
|
+
}
|
|
667
|
+
};
|
|
668
|
+
|
|
669
|
+
if (isPlainObject(config) && config.agent === 'opencode') {
|
|
670
|
+
warnOnce();
|
|
671
|
+
config.agent = 'claude-code';
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
if (isPlainObject(config) && Array.isArray(config.agents) && config.agents.includes('opencode')) {
|
|
675
|
+
warnOnce();
|
|
676
|
+
config.agents = config.agents.filter((agent) => agent !== 'opencode');
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
const targets = config?.compact?.agentContext?.targets;
|
|
680
|
+
if (isPlainObject(targets) && 'opencode' in targets) {
|
|
681
|
+
warnOnce();
|
|
682
|
+
delete targets.opencode;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
return config;
|
|
686
|
+
}
|
|
687
|
+
|
|
656
688
|
export async function inspectRuntimeConfig(projectRoot) {
|
|
657
689
|
const runtimePaths = buildRuntimePaths(projectRoot);
|
|
658
690
|
let exists = false;
|
|
@@ -670,7 +702,7 @@ export async function inspectRuntimeConfig(projectRoot) {
|
|
|
670
702
|
}
|
|
671
703
|
}
|
|
672
704
|
|
|
673
|
-
const config = buildDefaultRuntimeConfig(rawConfig ?? {});
|
|
705
|
+
const config = normalizeLegacyOpencodeEntries(buildDefaultRuntimeConfig(rawConfig ?? {}));
|
|
674
706
|
const validation = validateRuntimeConfig(config);
|
|
675
707
|
const errors = [
|
|
676
708
|
...(parseError ? [`config.json parse error: ${parseError}`] : []),
|
package/src/core/status.js
CHANGED
|
@@ -8,13 +8,13 @@ import { countMemoryItems } from './memory/store.js';
|
|
|
8
8
|
import { buildCompactPressureState } from './compact/threshold.js';
|
|
9
9
|
import { detectProjectContext } from '../context/detectProjectContext.js';
|
|
10
10
|
import { inspectProjectImportant, inspectProjectImportantWiring } from './projectImportant.js';
|
|
11
|
+
import { opencodeSteerMessage } from './opencodeSteer.js';
|
|
11
12
|
|
|
12
13
|
function formatPrimaryAgent(agentKey) {
|
|
13
14
|
if (agentKey === 'claude-code') return 'Claude Code';
|
|
14
15
|
if (agentKey === 'codex') return 'OpenAI Codex';
|
|
15
16
|
// legacy: Antigravity adapter removed in this release; existing config.json may still name it
|
|
16
17
|
if (agentKey === 'antigravity') return 'Antigravity';
|
|
17
|
-
if (agentKey === 'opencode') return 'OpenCode';
|
|
18
18
|
if (agentKey === 'omp') return 'Oh My Pi (omp)';
|
|
19
19
|
return agentKey || 'Unknown';
|
|
20
20
|
}
|
|
@@ -24,7 +24,6 @@ async function detectAdapterLabels(projectRoot, primaryAgent) {
|
|
|
24
24
|
|
|
25
25
|
const checks = [
|
|
26
26
|
{ label: 'OpenAI Codex', path: '.codex/settings.json' },
|
|
27
|
-
{ label: 'OpenCode', path: 'opencode.json' },
|
|
28
27
|
{ label: 'Oh My Pi (omp)', path: '.omp/config.yml' },
|
|
29
28
|
];
|
|
30
29
|
|
|
@@ -171,8 +170,11 @@ export async function buildStatusReport(projectRoot) {
|
|
|
171
170
|
claude: piWiring.claude.wired,
|
|
172
171
|
omp: piWiring.omp.installed ? piWiring.omp.wired : undefined,
|
|
173
172
|
codex: piWiring.codex.installed ? piWiring.codex.wired : undefined,
|
|
174
|
-
opencode: piWiring.opencode.installed ? piWiring.opencode.wired : undefined,
|
|
175
173
|
},
|
|
174
|
+
// SPEC FR-006 — leftover opencode.json is a user file: steer, never wire.
|
|
175
|
+
opencodeSteer: piWiring.opencodeArtifacts.length > 0
|
|
176
|
+
? opencodeSteerMessage(piWiring.opencodeArtifacts)
|
|
177
|
+
: null,
|
|
176
178
|
};
|
|
177
179
|
|
|
178
180
|
return {
|
|
@@ -226,7 +228,6 @@ function formatProjectImportantWiring(pi) {
|
|
|
226
228
|
const parts = [`Claude runtime ${mark(pi.wiring.claude)}`];
|
|
227
229
|
if (pi.wiring.omp !== undefined) parts.push(`omp runtime ${mark(pi.wiring.omp)}`);
|
|
228
230
|
if (pi.wiring.codex !== undefined) parts.push(`Codex fallback ${mark(pi.wiring.codex)}`);
|
|
229
|
-
if (pi.wiring.opencode !== undefined) parts.push(`OpenCode fallback ${mark(pi.wiring.opencode)}`);
|
|
230
231
|
return parts.join(' / ');
|
|
231
232
|
}
|
|
232
233
|
|
|
@@ -237,6 +238,7 @@ export function formatStatusReport(report) {
|
|
|
237
238
|
`${padLabel('Project')} ${report.projectName}`,
|
|
238
239
|
`${padLabel('Project rules')} ${formatProjectImportantRules(report.projectImportant)}`,
|
|
239
240
|
`${padLabel('Rule wiring')} ${formatProjectImportantWiring(report.projectImportant)}`,
|
|
241
|
+
...(report.projectImportant.opencodeSteer ? [report.projectImportant.opencodeSteer] : []),
|
|
240
242
|
`${padLabel('Adapters')} ${report.adapters.join(', ')}`,
|
|
241
243
|
`${padLabel('Memory items')} ${report.memoryCounts.projectCount} project / ${report.memoryCounts.sessionCount} session / ${report.memoryCounts.userCount} user`,
|
|
242
244
|
`${padLabel('Last compact')} ${report.lastCompact}`,
|
|
@@ -50,7 +50,7 @@ Systematic debugging — understand before fixing.
|
|
|
50
50
|
|
|
51
51
|
```
|
|
52
52
|
STATUS: DONE | BLOCKED | PARTIAL
|
|
53
|
-
EXECUTOR_TOOL: [claude-code | kilo-code | codex |
|
|
53
|
+
EXECUTOR_TOOL: [claude-code | kilo-code | codex | other]
|
|
54
54
|
EXECUTOR_MODEL: [exact model name you are running as. "unknown" if you cannot tell.]
|
|
55
55
|
EXECUTOR_SUBAGENT: [subagent name within your host, if any, else "-"]
|
|
56
56
|
SUMMARY: [1-2 sentences — root cause and fix]
|
|
@@ -72,7 +72,7 @@ and even then, report it, don't ask about it.
|
|
|
72
72
|
|
|
73
73
|
```
|
|
74
74
|
STATUS: DONE | BLOCKED | PARTIAL
|
|
75
|
-
EXECUTOR_TOOL: [claude-code | kilo-code | codex |
|
|
75
|
+
EXECUTOR_TOOL: [claude-code | kilo-code | codex | other]
|
|
76
76
|
EXECUTOR_MODEL: [exact model name you are running as — e.g. unic-code, claude-sonnet-4-5, gpt-5-mini. If you truly cannot tell, write "unknown" — reviewer treats unknown as suspicious and asks the human to confirm.]
|
|
77
77
|
EXECUTOR_SUBAGENT: [name of the subagent you are, if your host has multiple — e.g. "Kilo:code", "Claude:feature-implementer". Otherwise "-".]
|
|
78
78
|
SUMMARY: [1-2 sentences of what was implemented]
|
|
@@ -24,7 +24,7 @@ You are UKit's internal small-task maintainer. You run as a sidecar/parallel/non
|
|
|
24
24
|
- Summarizing `docs/STATUS.md`, `docs/TASKS.md`, `docs/WORKLOG.md`, or memory snippets into compact handoff notes.
|
|
25
25
|
- Deciding fast vs slow lane, safe vs risky lane, whether a skill should be activated, and whether the current prompt has enough steps planned.
|
|
26
26
|
- Choosing compact-now vs compact-later and summarize-vs-keep-detail for UKit context hygiene.
|
|
27
|
-
- Keeping agent context compact without removing existing lanes: Claude PreCompact/reinject stays active
|
|
27
|
+
- Keeping agent context compact without removing existing lanes: Claude PreCompact/reinject stays active and Codex Desktop soft handoffs use `compact.codexContext.compactTarget` (default 150 lines; preferred 120-150; hard max 170) while preserving critical state.
|
|
28
28
|
- Small, reversible UKit runtime maintenance decisions.
|
|
29
29
|
|
|
30
30
|
## Never Use For
|
|
@@ -45,7 +45,7 @@ You are UKit's internal small-task maintainer. You run as a sidecar/parallel/non
|
|
|
45
45
|
5. If safe, make the smallest cleanup/summary/classification/routing decision.
|
|
46
46
|
6. Follow the CoDev priority order: output quality first, then safety, then speed, then token discipline. Spend tokens/steps when they protect correctness.
|
|
47
47
|
7. Use small step budgets: trivial = 1 step, simple = up to 2 steps, non-trivial = up to 4 planned steps before the main model reassesses.
|
|
48
|
-
8. For long sessions, preserve existing Claude
|
|
48
|
+
8. For long sessions, preserve existing Claude auto-compact behavior; for Codex Desktop, target a compact handoff of about 120-150 lines, never above 170 lines for this lane, not a full transcript replay.
|
|
49
49
|
9. Preserve user-owned content; do not delete unclear tasks.
|
|
50
50
|
10. Report exactly what changed or what decision was made.
|
|
51
51
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# /ukit:handoff-create — Phase 1 + 2: Plan
|
|
2
2
|
|
|
3
3
|
**Role: PLANNER**
|
|
4
|
-
**Tool: any** (Claude Code / Codex / omp / Kilo
|
|
4
|
+
**Tool: any** (Claude Code / Codex / omp / Kilo — your choice)
|
|
5
5
|
**Model split:**
|
|
6
6
|
- Read/understand → lite model (haiku · unic-lite · cheapest available)
|
|
7
7
|
- Write plan + tasks → strong model (Opus · unic-smart · strongest available)
|
|
@@ -49,7 +49,7 @@ After the batched call, run Steps 1–2.5 to completion without further question
|
|
|
49
49
|
4. Read `docs/AI_HANDOFF/tasks/_TEMPLATE.md` → task file structure
|
|
50
50
|
5. Return a compact summary. Do NOT write anything yet.
|
|
51
51
|
|
|
52
|
-
> **For the human operator, on a tool with no agent support (Codex
|
|
52
|
+
> **For the human operator, on a tool with no agent support (Codex) — not an instruction to the model:** manually switch to the lite model, run the steps above yourself, keep the summary in context.
|
|
53
53
|
|
|
54
54
|
---
|
|
55
55
|
|
|
@@ -122,7 +122,7 @@ The planner agent does the following (use Step 1 summary — do NOT re-read file
|
|
|
122
122
|
|
|
123
123
|
8. Report: task IDs, dependency graph, any `needs_breakdown` + reason
|
|
124
124
|
|
|
125
|
-
> **For the human operator, on a tool with no agent support (Codex
|
|
125
|
+
> **For the human operator, on a tool with no agent support (Codex) — not an instruction to the model:** manually switch to the strong model, execute steps 1–7 above yourself.
|
|
126
126
|
|
|
127
127
|
---
|
|
128
128
|
|
|
@@ -143,7 +143,7 @@ intact. What it no longer does is hand a stalled plan back and wait.
|
|
|
143
143
|
2. `Issues Found` → route back to Step 2: planner revises `PLAN.md` and the affected `TASK-xxx.md` files to address every finding, then re-submit for another Step 2.5 review (this becomes the next round). Do NOT commit or hand off to executor on `Issues Found`.
|
|
144
144
|
3. `Approved` → append `PLAN_REVIEW: Approved by <reviewer model>` to PLAN.md's `## Planner Report` footer, then proceed.
|
|
145
145
|
|
|
146
|
-
> **For the human operator, on a tool with no agent support (Codex
|
|
146
|
+
> **For the human operator, on a tool with no agent support (Codex) — not an instruction to the model:** manually switch to the strong model in a **separate** chat/session from Step 2, paste PLAN.md, review using the Spec/Plan Review checklist in `.claude/agents/code-reviewer.md`.
|
|
147
147
|
|
|
148
148
|
---
|
|
149
149
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# /ukit:handoff-fullstack — Full Pipeline: Plan → Implement → Review
|
|
2
2
|
|
|
3
3
|
**Role: ORCHESTRATOR**
|
|
4
|
-
**Tool: any** (Claude Code / Codex / omp / Kilo
|
|
4
|
+
**Tool: any** (Claude Code / Codex / omp / Kilo — your choice)
|
|
5
5
|
|
|
6
6
|
## Model Split
|
|
7
7
|
|
|
@@ -186,7 +186,7 @@ counter and starts a new cycle automatically.
|
|
|
186
186
|
|
|
187
187
|
Return a compact summary. Do NOT write any files yet.
|
|
188
188
|
|
|
189
|
-
> **For the human operator, on a tool with no agent support (Codex
|
|
189
|
+
> **For the human operator, on a tool with no agent support (Codex) — not an instruction to the model:** manually switch to the lite model and run P1 yourself.
|
|
190
190
|
|
|
191
191
|
### P2 — Write PLAN.md + task files (strong model)
|
|
192
192
|
|
|
@@ -270,7 +270,7 @@ is written. What it no longer does is hand a stalled plan back to a human who is
|
|
|
270
270
|
2. `Issues Found` → route back to P2: `handoff-planner` revises `PLAN.md` and the affected `TASK-xxx.md` files to address every finding, then re-submit for one more P2.5 review round — subject to the loop cap above.
|
|
271
271
|
3. `Approved` → append `PLAN_REVIEW: Approved by <reviewer model>` to PLAN.md's `## Planner Report` footer, then proceed to P3.
|
|
272
272
|
|
|
273
|
-
> **For the human operator, on a tool with no agent support (Codex
|
|
273
|
+
> **For the human operator, on a tool with no agent support (Codex) — not an instruction to the model:** manually switch to the strong model in a **separate** chat/session from P2, paste PLAN.md, review using the Spec/Plan Review checklist in `.claude/agents/code-reviewer.md`.
|
|
274
274
|
|
|
275
275
|
### P3 — Commit the plan (lite model)
|
|
276
276
|
|
|
@@ -281,7 +281,7 @@ git add docs/AI_HANDOFF/ && git commit -m "handoff: plan — <goal>"
|
|
|
281
281
|
|
|
282
282
|
Replace `<goal>` with the one-sentence goal from ACTIVE.md. This locks the plan in git before any implementation begins.
|
|
283
283
|
|
|
284
|
-
> **For the human operator, on a tool with no agent support (Codex
|
|
284
|
+
> **For the human operator, on a tool with no agent support (Codex) — not an instruction to the model:** manually switch to the lite model for P2/P3.
|
|
285
285
|
|
|
286
286
|
---
|
|
287
287
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# /ukit:handoff-implement — Phase 3: Execute
|
|
2
2
|
|
|
3
3
|
**Role: EXECUTOR (orchestrated)**
|
|
4
|
-
**Tool: any** (Claude Code / Codex / omp / Kilo
|
|
4
|
+
**Tool: any** (Claude Code / Codex / omp / Kilo — your choice)
|
|
5
5
|
**Model: code model** (Sonnet · unic-code · cheap-smart)
|
|
6
6
|
|
|
7
7
|
> **omp model tiers:** the tiers above map to `.omp/config.yml`'s `modelRoles`, referenced from agent frontmatter as `@smol` / `@default` / `@slow`.
|
|
@@ -170,7 +170,7 @@ disk in the task file, which is where the reviewer reads them from. Pasting them
|
|
|
170
170
|
second time is what blows up the orchestrator's context window and kills the run mid-wave.
|
|
171
171
|
```
|
|
172
172
|
|
|
173
|
-
> **For the human operator, on a tool with no agent support (Codex
|
|
173
|
+
> **For the human operator, on a tool with no agent support (Codex) — not an instruction to the model:** open each task in a separate session with the code model.
|
|
174
174
|
|
|
175
175
|
### 3c — Orchestrator: copy changes to main + IMMEDIATELY delete worktree
|
|
176
176
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# /ukit:handoff-review — Phase 4: Review
|
|
2
2
|
|
|
3
3
|
**Role: REVIEWER**
|
|
4
|
-
**Tool: any** (Claude Code / Codex / omp / Kilo
|
|
4
|
+
**Tool: any** (Claude Code / Codex / omp / Kilo — your choice)
|
|
5
5
|
**Model: strong model, MUST differ from executor** (Opus · unic-smart · strongest available)
|
|
6
6
|
|
|
7
7
|
> **omp model tiers:** the tiers above map to `.omp/config.yml`'s `modelRoles`, referenced from agent frontmatter as `@smol` / `@default` / `@slow`.
|
|
@@ -191,4 +191,4 @@ This is the only place this command may ask for a compaction. All state lives in
|
|
|
191
191
|
`INDEX.md` and `RUN.md`, so a compacted or fresh session resumes with nothing lost.
|
|
192
192
|
|
|
193
193
|
> Orchestrator (this session) handles Step 1, 2e, and 3 directly — those are not delegated.
|
|
194
|
-
> **For the human operator, on a tool with no agent support (Codex
|
|
194
|
+
> **For the human operator, on a tool with no agent support (Codex) — not an instruction to the model:** manually switch to the strong model, run 2a–2d per task (one session at a time).
|
|
@@ -48,7 +48,7 @@ When updating meaningful state, update the header:
|
|
|
48
48
|
## Freshness
|
|
49
49
|
|
|
50
50
|
- Last meaningful update: YYYY-MM-DD HH:mm
|
|
51
|
-
- Updated by: Claude / Codex /
|
|
51
|
+
- Updated by: Claude / Codex / human
|
|
52
52
|
- Status confidence: high / medium / low
|
|
53
53
|
- Stale after: 72h
|
|
54
54
|
```
|
|
@@ -816,7 +816,12 @@ async function main() {
|
|
|
816
816
|
const lastPrompt = readFlagValue(args, '--last-prompt')
|
|
817
817
|
?? previousState?.routingContext?.lastExplicitUserPromptText
|
|
818
818
|
?? '';
|
|
819
|
-
const
|
|
819
|
+
const KNOWN_ADAPTERS = new Set(['claude', 'codex', 'antigravity']);
|
|
820
|
+
const rawAdapter = readFlagValue(args, '--adapter') ?? inferAdapterFromInvocation(process.argv[1] || '');
|
|
821
|
+
const adapter = KNOWN_ADAPTERS.has(rawAdapter) ? rawAdapter : 'claude';
|
|
822
|
+
if (rawAdapter !== adapter) {
|
|
823
|
+
console.error(`route-task: unknown --adapter "${rawAdapter}" — falling back to claude`);
|
|
824
|
+
}
|
|
820
825
|
const commandNamespace = adapter === 'codex'
|
|
821
826
|
? '.codex'
|
|
822
827
|
: (adapter === 'antigravity' ? '.antigravity' : '.claude');
|
|
@@ -826,7 +831,7 @@ async function main() {
|
|
|
826
831
|
.trim();
|
|
827
832
|
|
|
828
833
|
if (!promptText && !commandText && !targetFile) {
|
|
829
|
-
console.error('Usage: node .codex/ukit/index/route-task.mjs "<prompt>" [--tool-command <cmd>] [--target <file>] [--type trivial|simple|non-trivial] [--session-id <id>] [--adapter codex|claude|antigravity
|
|
834
|
+
console.error('Usage: node .codex/ukit/index/route-task.mjs "<prompt>" [--tool-command <cmd>] [--target <file>] [--type trivial|simple|non-trivial] [--session-id <id>] [--adapter codex|claude|antigravity]');
|
|
830
835
|
process.exitCode = 1;
|
|
831
836
|
return;
|
|
832
837
|
}
|
|
@@ -8,7 +8,7 @@ Auto-generated by UKit for OpenAI Codex.
|
|
|
8
8
|
## Core UKit Rule
|
|
9
9
|
|
|
10
10
|
- Human-facing workflow should optimize for one remembered command: `ukit install`.
|
|
11
|
-
- After install, normal work should feel natural inside **Claude/Codex/
|
|
11
|
+
- After install, normal work should feel natural inside **Claude/Codex/omp**.
|
|
12
12
|
- **Quality first, then speed, then token discipline**: do not waste reads, logs, or repeated helper output.
|
|
13
13
|
- **Never stop after read-only steps.** For implement/apply/fix requests, continue to actual Edit/Write and verification in the same turn.
|
|
14
14
|
|
|
@@ -49,7 +49,7 @@ Systematic debugging — understand before fixing.
|
|
|
49
49
|
|
|
50
50
|
```
|
|
51
51
|
STATUS: DONE | BLOCKED | PARTIAL
|
|
52
|
-
EXECUTOR_TOOL: [claude-code | kilo-code | codex |
|
|
52
|
+
EXECUTOR_TOOL: [claude-code | kilo-code | codex | other]
|
|
53
53
|
EXECUTOR_MODEL: [exact model name you are running as. "unknown" if you cannot tell.]
|
|
54
54
|
EXECUTOR_SUBAGENT: [subagent name within your host, if any, else "-"]
|
|
55
55
|
SUMMARY: [1-2 sentences — root cause and fix]
|
|
@@ -71,7 +71,7 @@ and even then, report it, don't ask about it.
|
|
|
71
71
|
|
|
72
72
|
```
|
|
73
73
|
STATUS: DONE | BLOCKED | PARTIAL
|
|
74
|
-
EXECUTOR_TOOL: [claude-code | kilo-code | codex |
|
|
74
|
+
EXECUTOR_TOOL: [claude-code | kilo-code | codex | other]
|
|
75
75
|
EXECUTOR_MODEL: [exact model name you are running as — e.g. unic-code, claude-sonnet-4-5, gpt-5-mini. If you truly cannot tell, write "unknown" — reviewer treats unknown as suspicious and asks the human to confirm.]
|
|
76
76
|
EXECUTOR_SUBAGENT: [name of the subagent you are, if your host has multiple — e.g. "Kilo:code", "Claude:feature-implementer". Otherwise "-".]
|
|
77
77
|
SUMMARY: [1-2 sentences of what was implemented]
|
|
@@ -24,7 +24,7 @@ You are UKit's internal small-task maintainer. You run as a sidecar/parallel/non
|
|
|
24
24
|
- Summarizing `docs/STATUS.md`, `docs/TASKS.md`, `docs/WORKLOG.md`, or memory snippets into compact handoff notes.
|
|
25
25
|
- Deciding fast vs slow lane, safe vs risky lane, whether a skill should be activated, and whether the current prompt has enough steps planned.
|
|
26
26
|
- Choosing compact-now vs compact-later and summarize-vs-keep-detail for UKit context hygiene.
|
|
27
|
-
- Keeping agent context compact without removing existing lanes: Claude PreCompact/reinject stays active
|
|
27
|
+
- Keeping agent context compact without removing existing lanes: Claude PreCompact/reinject stays active and Codex Desktop soft handoffs use `compact.codexContext.compactTarget` (default 150 lines; preferred 120-150; hard max 170) while preserving critical state.
|
|
28
28
|
- Small, reversible UKit runtime maintenance decisions.
|
|
29
29
|
|
|
30
30
|
## Never Use For
|
|
@@ -45,7 +45,7 @@ You are UKit's internal small-task maintainer. You run as a sidecar/parallel/non
|
|
|
45
45
|
5. If safe, make the smallest cleanup/summary/classification/routing decision.
|
|
46
46
|
6. Follow the CoDev priority order: output quality first, then safety, then speed, then token discipline. Spend tokens/steps when they protect correctness.
|
|
47
47
|
7. Use small step budgets: trivial = 1 step, simple = up to 2 steps, non-trivial = up to 4 planned steps before the main model reassesses.
|
|
48
|
-
8. For long sessions, preserve existing Claude
|
|
48
|
+
8. For long sessions, preserve existing Claude auto-compact behavior; for Codex Desktop, target a compact handoff of about 120-150 lines, never above 170 lines for this lane, not a full transcript replay.
|
|
49
49
|
9. Preserve user-owned content; do not delete unclear tasks.
|
|
50
50
|
10. Report exactly what changed or what decision was made.
|
|
51
51
|
|
package/templates/AGENTS.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
## Core Rule
|
|
5
5
|
<!-- RULES: CORE-01 CORE-02 -->
|
|
6
6
|
- Human-facing UKit workflow collapses to one remembered command: `ukit install`.
|
|
7
|
-
- After install, default to natural-language work inside **Claude Code / Codex /
|
|
7
|
+
- After install, default to natural-language work inside **Claude Code / Codex / omp**.
|
|
8
8
|
- **Quality first, then speed, then token discipline.**
|
|
9
9
|
- **Never stop after read-only steps** — implement/apply/fix requests continue to Edit/Write + verification in the same turn.
|
|
10
10
|
|
|
@@ -140,25 +140,16 @@ CHỈ kích hoạt khi task đi qua `docs/AI_HANDOFF/` (user nói "execute task
|
|
|
140
140
|
- Contract map: `tiny-fix` → lite · `local-fix`, `local-build`, `shared-edit`, `find-cause`, `map-impact` → code · `review-release` → smart. Escalation: same file/symbol failing `debugLoopThreshold` (default 2) times routes the next attempt one tier higher, capped at `smart`.
|
|
141
141
|
- `unic-vision` is a capability lane, not a cost tier — unverified vision must never guess image contents; route images to `ukit-vision-analyst`. Harness table: `docs/UKIT_INTERNALS.md`.
|
|
142
142
|
|
|
143
|
-
##
|
|
143
|
+
## Project Owner Instructions — Codex
|
|
144
144
|
|
|
145
|
-
|
|
146
|
-
At the start of every OpenCode session, before working on the first task:
|
|
147
|
-
1. Reuse matching route hints from `.claude/ukit/skill-router-state.json`; scan `.claude/skills/` (listing only) and read a SKILL.md only when a task triggers it.
|
|
148
|
-
2. For every non-trivial task, run `/ukit-route <task summary>` for skill + context hints **before** writing code; if it names a skill, read that SKILL.md — do not skip. When `router.enabled: true` in `.ukit/storage/config.json`, prefer router output over guessing; treat it as internal continuation — continue to edit/verify, don't stop.
|
|
149
|
-
|
|
150
|
-
## Project Owner Instructions — Codex and OpenCode
|
|
151
|
-
|
|
152
|
-
When running in Codex or OpenCode, read and follow the root
|
|
145
|
+
When running in Codex, read and follow the root
|
|
153
146
|
`PROJECT_IMPORTANT.md` before doing project work. It is the canonical
|
|
154
147
|
project-owner instruction source. Do not copy its contents into this file.
|
|
155
148
|
If it is missing or unreadable, state that limitation and continue with the
|
|
156
149
|
remaining project instructions.
|
|
157
|
-
<!--
|
|
150
|
+
<!-- RULE: OWN-01 -->
|
|
158
151
|
## Skills
|
|
159
152
|
- Canonical skills live in `.claude/skills/`; adapter mirrors may exist (`.codex/skills/` → symlink). **omp** reads `.claude/skills/` via its `claude` discovery provider.
|
|
160
|
-
- **OpenCode**: reads `AGENTS.md` at session start only — it does NOT auto-load skills; the model must explicitly read the triggered SKILL.md.
|
|
161
|
-
- `ukit-*` commands in `opencode.json` are internal helper entrypoints — never ask end users to run them.
|
|
162
153
|
|
|
163
154
|
## Project Snapshot
|
|
164
155
|
- Project: {{project.name}} | Root: {{project.root}}
|