@ngockhoale/ukit 2.0.4 → 2.0.6
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 +12 -0
- package/package.json +1 -1
- package/src/core/runtimeConfig.js +6 -6
- package/templates/.claude/agents/handoff-planner.md +1 -1
- package/templates/.claude/hooks/context-window-guard.sh +42 -8
- package/templates/.codex/settings.json +1 -1
- package/templates/ukit/storage/config.json +11 -11
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to UKit are documented here.
|
|
4
4
|
|
|
5
|
+
## 2.0.6 - 2026-08-12
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- **`context-window-guard.sh` now issues an actionable directive instead of a passive notice.** At 80%+ of `compact.hardCapTokens` it previously only printed an FYI warning that nothing acted on, so it kept re-firing every prompt with no remedy. It now instructs the agent, in the same turn: persist progress to `docs/STATUS.md` (update-status skill), split remaining multi-phase work (e.g. a `handoff-fullstack` run) into bounded `docs/AI_HANDOFF` tasks instead of continuing in one long thread, or tell the user plainly to `/compact`/start a fresh session. The full directive is debounced (3 min at hard phase, 8 min at soft) so it does not repeat in full every prompt — a short reminder line stands in until the phase changes or the cooldown lapses. `/compact` itself still cannot be invoked from a hook (client-only command), so this closes the gap by making the advisory self-actionable rather than attempting to fake a call the hook has no access to.
|
|
10
|
+
|
|
11
|
+
## 2.0.5 - 2026-08-11
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- **Model IDs refreshed to the Claude 5 family**: `claude-sonnet-4-6` → `claude-sonnet-5`, `claude-opus-4-6` → `claude-opus-5`, across the `code`/`smart` tiers, `orchestration.modelTiers.vision.fallbackModel`, `handoff.defaultModel`/`advisorModel`/`orchestratorModel`, the Codex adapter settings, the `handoff-planner` agent example, and the config's own Vietnamese documentation strings. `claude-haiku-4-5` is unchanged — Haiku 4.5 is still current, so the `lite` tier was already correct. 54 references in live config, source and tests; historical records (`docs/AI_HANDOFF/archive/`, `docs/plans/`, `docs/WORKLOG.md`, `.ukit/storage/backups/`) are deliberately left alone, since rewriting what a past cycle actually ran on would be falsifying the record.
|
|
16
|
+
|
|
5
17
|
## 2.0.4 - 2026-08-11
|
|
6
18
|
|
|
7
19
|
### Added
|
package/package.json
CHANGED
|
@@ -117,14 +117,14 @@ export function buildDefaultRuntimeConfig(overrides = {}) {
|
|
|
117
117
|
},
|
|
118
118
|
router: {
|
|
119
119
|
enabled: true,
|
|
120
|
-
defaultModel: 'claude-sonnet-
|
|
121
|
-
advisorModel: 'claude-opus-
|
|
120
|
+
defaultModel: 'claude-sonnet-5',
|
|
121
|
+
advisorModel: 'claude-opus-5',
|
|
122
122
|
advisorEnabled: true,
|
|
123
123
|
maxAdvisorCalls: 3,
|
|
124
124
|
},
|
|
125
125
|
orchestration: {
|
|
126
126
|
enabled: true,
|
|
127
|
-
orchestratorModel: 'claude-sonnet-
|
|
127
|
+
orchestratorModel: 'claude-sonnet-5',
|
|
128
128
|
advisorEnabled: true,
|
|
129
129
|
contracts: {
|
|
130
130
|
'tiny-fix': {
|
|
@@ -176,12 +176,12 @@ export function buildDefaultRuntimeConfig(overrides = {}) {
|
|
|
176
176
|
},
|
|
177
177
|
modelTiers: {
|
|
178
178
|
lite: { claudeModel: 'claude-haiku-4-5', genericModel: 'unic-lite' },
|
|
179
|
-
code: { claudeModel: 'claude-sonnet-
|
|
180
|
-
smart: { claudeModel: 'claude-opus-
|
|
179
|
+
code: { claudeModel: 'claude-sonnet-5', genericModel: 'unic-code' },
|
|
180
|
+
smart: { claudeModel: 'claude-opus-5', genericModel: 'unic-smart' },
|
|
181
181
|
vision: {
|
|
182
182
|
claudeModel: 'unic-vision',
|
|
183
183
|
genericModel: 'unic-vision',
|
|
184
|
-
fallbackModel: 'claude-sonnet-
|
|
184
|
+
fallbackModel: 'claude-sonnet-5',
|
|
185
185
|
capabilityTier: true,
|
|
186
186
|
note: 'Capability tier, not a cost tier. Orthogonal to lite/code/smart — never insert into escalation.tierOrder. fallbackModel is used when unicMode is off.',
|
|
187
187
|
},
|
|
@@ -52,7 +52,7 @@ If zero testable behavior → write `N/A` + explicit justification in each task'
|
|
|
52
52
|
Append this footer to `PLAN.md` — mandatory, checked by a hook before the write is allowed:
|
|
53
53
|
```
|
|
54
54
|
## Planner Report
|
|
55
|
-
PLANNER_MODEL: <your exact model ID — e.g. claude-opus-
|
|
55
|
+
PLANNER_MODEL: <your exact model ID — e.g. claude-opus-5>
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
## Phase 2 — Split into TASK-xxx.md
|
|
@@ -134,21 +134,55 @@ const ratio = estimatedTokens / hardCap;
|
|
|
134
134
|
if (ratio < 0.8) process.exit(0);
|
|
135
135
|
|
|
136
136
|
const pct = Math.round(ratio * 100);
|
|
137
|
+
const phase = ratio >= 1 ? 'hard' : 'soft';
|
|
138
|
+
|
|
139
|
+
// Debounce the directive block so it does not re-print in full every single prompt
|
|
140
|
+
// while the phase is unchanged — that would just be more tokens added to the same
|
|
141
|
+
// oversized context it is warning about. Re-arms on phase change (soft -> hard) or
|
|
142
|
+
// after the cooldown, and resets naturally once a real compaction/new session drops
|
|
143
|
+
// the live transcript back under 0.8, since this whole branch exits early above.
|
|
144
|
+
const GUARD_STATE_PATH = path.join(projectRoot, '.ukit', 'storage', 'cache', 'context-guard-state.json');
|
|
145
|
+
const COOLDOWN_MS = phase === 'hard' ? 3 * 60 * 1000 : 8 * 60 * 1000;
|
|
146
|
+
|
|
147
|
+
function readGuardState() {
|
|
148
|
+
try {
|
|
149
|
+
return JSON.parse(fs.readFileSync(GUARD_STATE_PATH, 'utf8'));
|
|
150
|
+
} catch {
|
|
151
|
+
return { lastPhase: null, lastActionAt: 0 };
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function writeGuardState(state) {
|
|
156
|
+
try {
|
|
157
|
+
fs.mkdirSync(path.dirname(GUARD_STATE_PATH), { recursive: true });
|
|
158
|
+
fs.writeFileSync(GUARD_STATE_PATH, `${JSON.stringify(state, null, 2)}\n`, 'utf8');
|
|
159
|
+
} catch { /* best-effort only; never block the prompt over this */ }
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const guardState = readGuardState();
|
|
163
|
+
const now = Date.now();
|
|
164
|
+
const withinCooldown = guardState.lastPhase === phase
|
|
165
|
+
&& (now - Number(guardState.lastActionAt || 0)) < COOLDOWN_MS;
|
|
166
|
+
|
|
137
167
|
const lines_out = [];
|
|
138
168
|
if (ratio >= 1) {
|
|
139
169
|
lines_out.push(`UKIT CONTEXT ALERT — live context ~${estimatedTokens.toLocaleString()} tokens, at/over the ${hardCap.toLocaleString()} cap (${pct}%).`);
|
|
140
170
|
lines_out.push('The next few turns risk "Your input exceeds the context window of this model".');
|
|
141
|
-
lines_out.push('Act now: /compact, or finish this thread and start a fresh session.');
|
|
142
|
-
lines_out.push('If /compact itself already failed, the context is too large to summarise —');
|
|
143
|
-
lines_out.push('a new session is the only way out. Work committed to disk is not lost.');
|
|
144
171
|
} else {
|
|
145
172
|
lines_out.push(`UKIT CONTEXT WARNING — live context ~${estimatedTokens.toLocaleString()} tokens (${pct}% of the ${hardCap.toLocaleString()} cap).`);
|
|
146
|
-
lines_out.push('Wrap up or /compact soon, while compacting still works.');
|
|
147
173
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
lines_out.push('
|
|
151
|
-
|
|
174
|
+
|
|
175
|
+
if (withinCooldown) {
|
|
176
|
+
lines_out.push('(Directive already issued this phase — act on it now if not already done; this is just a reminder.)');
|
|
177
|
+
} else {
|
|
178
|
+
lines_out.push('ACTION THIS TURN, before starting new investigation/subagents/pipeline phases:');
|
|
179
|
+
lines_out.push('1) Persist current progress now (update docs/STATUS.md, e.g. via the update-status skill) so nothing is lost.');
|
|
180
|
+
lines_out.push('2) If the remaining work still has multiple steps or pipeline phases left (e.g. a handoff-fullstack run with implement/review/deploy still ahead), split what remains into bounded docs/AI_HANDOFF tasks instead of continuing in this one thread — smaller phases keep each turn under the cap.');
|
|
181
|
+
lines_out.push('3) Otherwise, tell the user plainly: run /compact now, or wrap up and start a fresh session — work already committed/persisted to disk is not lost.');
|
|
182
|
+
if (sidechainEntries > 0) {
|
|
183
|
+
lines_out.push(`Note: ${sidechainEntries} subagent entries in this stretch — each teammate carries its own context window, and every finished report is injected back here, so running many at once is the fastest way to overflow this session. Avoid spawning more until context drops back under the cap.`);
|
|
184
|
+
}
|
|
185
|
+
writeGuardState({ lastPhase: phase, lastActionAt: now });
|
|
152
186
|
}
|
|
153
187
|
|
|
154
188
|
process.stdout.write(`${lines_out.join('\n')}\n`);
|
|
@@ -264,7 +264,7 @@
|
|
|
264
264
|
"configPath": ".ukit/storage/config.json",
|
|
265
265
|
"modelField": "orchestration.orchestratorModel",
|
|
266
266
|
"advisorField": "orchestration.advisorEnabled",
|
|
267
|
-
"defaultModel": "claude-sonnet-
|
|
267
|
+
"defaultModel": "claude-sonnet-5",
|
|
268
268
|
"internalOnly": true,
|
|
269
269
|
"qualityFirst": true,
|
|
270
270
|
"safeUpwardBias": true,
|
|
@@ -73,14 +73,14 @@
|
|
|
73
73
|
},
|
|
74
74
|
"router": {
|
|
75
75
|
"enabled": true,
|
|
76
|
-
"defaultModel": "claude-sonnet-
|
|
77
|
-
"advisorModel": "claude-opus-
|
|
76
|
+
"defaultModel": "claude-sonnet-5",
|
|
77
|
+
"advisorModel": "claude-opus-5",
|
|
78
78
|
"advisorEnabled": true,
|
|
79
79
|
"maxAdvisorCalls": 3
|
|
80
80
|
},
|
|
81
81
|
"orchestration": {
|
|
82
82
|
"enabled": true,
|
|
83
|
-
"orchestratorModel": "claude-sonnet-
|
|
83
|
+
"orchestratorModel": "claude-sonnet-5",
|
|
84
84
|
"advisorEnabled": true,
|
|
85
85
|
"contracts": {
|
|
86
86
|
"tiny-fix": {
|
|
@@ -139,12 +139,12 @@
|
|
|
139
139
|
},
|
|
140
140
|
"modelTiers": {
|
|
141
141
|
"lite": { "claudeModel": "claude-haiku-4-5", "genericModel": "unic-lite" },
|
|
142
|
-
"code": { "claudeModel": "claude-sonnet-
|
|
143
|
-
"smart": { "claudeModel": "claude-opus-
|
|
142
|
+
"code": { "claudeModel": "claude-sonnet-5", "genericModel": "unic-code" },
|
|
143
|
+
"smart": { "claudeModel": "claude-opus-5", "genericModel": "unic-smart" },
|
|
144
144
|
"vision": {
|
|
145
145
|
"claudeModel": "unic-vision",
|
|
146
146
|
"genericModel": "unic-vision",
|
|
147
|
-
"fallbackModel": "claude-sonnet-
|
|
147
|
+
"fallbackModel": "claude-sonnet-5",
|
|
148
148
|
"capabilityTier": true,
|
|
149
149
|
"note": "Capability tier, not a cost tier. Orthogonal to lite/code/smart — never insert into escalation.tierOrder. fallbackModel is used when unicMode is off."
|
|
150
150
|
}
|
|
@@ -192,7 +192,7 @@
|
|
|
192
192
|
"minTestsHappyPath": 1,
|
|
193
193
|
"minTestsEdgeCase": 1,
|
|
194
194
|
"regressionTestRequiredForBugfix": true,
|
|
195
|
-
"smartModelHint": "claude-opus-
|
|
195
|
+
"smartModelHint": "claude-opus-5"
|
|
196
196
|
},
|
|
197
197
|
"executor": {
|
|
198
198
|
"testFirstRequired": true,
|
|
@@ -338,8 +338,8 @@
|
|
|
338
338
|
"doi_reviewer_model": {
|
|
339
339
|
"field": "handoff.reviewer.model",
|
|
340
340
|
"mac_dinh": "unic-smart",
|
|
341
|
-
"y_nghia": "Model dùng cho reviewer agent ở Phase 3. BẮT BUỘC khác model executor để bắt được lỗi mà executor miss. Có thể dùng claude-opus-
|
|
342
|
-
"vi_du": "Nếu executor là unic-code (Kilo Code), set reviewer.model=unic-smart hoặc claude-opus-
|
|
341
|
+
"y_nghia": "Model dùng cho reviewer agent ở Phase 3. BẮT BUỘC khác model executor để bắt được lỗi mà executor miss. Có thể dùng claude-opus-5, unic-smart, hoặc bất kỳ model reasoning mạnh nào.",
|
|
342
|
+
"vi_du": "Nếu executor là unic-code (Kilo Code), set reviewer.model=unic-smart hoặc claude-opus-5. Nếu executor là claude-sonnet, set reviewer thành claude-opus."
|
|
343
343
|
},
|
|
344
344
|
"tat_reviewer_phase": {
|
|
345
345
|
"field": "handoff.reviewer.enabled",
|
|
@@ -485,7 +485,7 @@
|
|
|
485
485
|
"minTestsHappyPath": "Tối thiểu test cho happy path.",
|
|
486
486
|
"minTestsEdgeCase": "Tối thiểu test cho edge case (null/empty/boundary/concurrent…).",
|
|
487
487
|
"regressionTestRequiredForBugfix": "Bug fix phải có regression test fail-trước-fix.",
|
|
488
|
-
"smartModelHint": "Gợi ý model mạnh nhất cho phase plan (ví dụ claude-opus-
|
|
488
|
+
"smartModelHint": "Gợi ý model mạnh nhất cho phase plan (ví dụ claude-opus-5). UKit không tự ép, chỉ ghi hint vào task."
|
|
489
489
|
},
|
|
490
490
|
"executor": {
|
|
491
491
|
"testFirstRequired": "Executor phải viết test trước khi implement (RED → GREEN).",
|
|
@@ -496,7 +496,7 @@
|
|
|
496
496
|
},
|
|
497
497
|
"reviewer": {
|
|
498
498
|
"enabled": "Bật Phase 3 review độc lập. Tắt = bỏ lưới an toàn cuối cùng, không khuyến nghị.",
|
|
499
|
-
"model": "Model reviewer. BẮT BUỘC khác executor model. Mặc định unic-smart; có thể dùng claude-opus-
|
|
499
|
+
"model": "Model reviewer. BẮT BUỘC khác executor model. Mặc định unic-smart; có thể dùng claude-opus-5 hoặc bất kỳ model reasoning mạnh nào.",
|
|
500
500
|
"agent": "Tên reviewer agent (xem .claude/agents/code-reviewer.md).",
|
|
501
501
|
"mustDifferFromExecutor": "Nếu true, reviewer tự refuse khi phát hiện cùng model với executor.",
|
|
502
502
|
"blockOnCritical": "CRITICAL → block handoff cứng. Set false chỉ khi muốn warning mềm.",
|