@ngockhoale/ukit 1.6.0 → 1.6.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 CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  All notable changes to UKit are documented here.
4
4
 
5
+ ## 1.6.2 - 2026-07-26
6
+
7
+ ### Added
8
+
9
+ - `ukit update` — new command that upgrades the globally installed UKit CLI to the latest published version (equivalent to `npm install -g @ngockhoale/ukit`).
10
+
11
+ ### Changed
12
+
13
+ - Downgraded `find-cause` and `map-impact` orchestration contracts from `modelTier: smart` (opus) to `modelTier: code` (sonnet); `review-release` stays on `smart`. Reduces unnecessary Opus usage for routine debugging/impact-mapping work.
14
+
15
+ ### Fixed
16
+
17
+ - Auto-compact context-pressure state is now surfaced to the model as a warning (`[ukit-skill-router] Context pressure: soft/hard ...`) once token usage crosses the soft/hard threshold, instead of being silently tracked and only reinjected after Claude Code's native compaction already began. Users previously had to compact manually because nothing ever prompted proactive `/compact` suggestions.
18
+
5
19
  ## 1.5.24 - 2026-06-10
6
20
 
7
21
  ### Fixed
package/README.md CHANGED
@@ -162,6 +162,7 @@ These commands are still available, but they are **advanced workflows**, not def
162
162
  - `ukit uninstall` — remove UKit-managed assets
163
163
  - `ukit status` — inspect shared UKit runtime state
164
164
  - `ukit memory ...` — inspect/export/forget shared memory items
165
+ - `ukit update` — upgrade the global UKit CLI to the latest published version (same as `npm install -g @ngockhoale/ukit`)
165
166
  - `ukit index ...` — run repo indexing/query/triage tools directly
166
167
  - `ukit build index` — alias for `ukit index build`
167
168
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ngockhoale/ukit",
3
- "version": "1.6.0",
3
+ "version": "1.6.2",
4
4
  "description": "Install/update an index-first AI workspace for Claude Code, Antigravity, OpenAI Codex, and OpenCode.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -0,0 +1,27 @@
1
+ import { updateUkit, UKIT_PACKAGE_NAME } from '../../core/update.js';
2
+
3
+ const KNOWN_UPDATE_FLAGS = new Set(['--help', '-h']);
4
+
5
+ export async function runUpdate({ packageVersion, argv = [] }) {
6
+ if (argv.includes('--help') || argv.includes('-h')) {
7
+ console.log('Usage: ukit update');
8
+ console.log('');
9
+ console.log('Upgrade the globally installed UKit CLI to the latest published version.');
10
+ console.log(`Equivalent to: npm install -g ${UKIT_PACKAGE_NAME}`);
11
+ return;
12
+ }
13
+
14
+ const unknownFlags = argv.filter((a) => a.startsWith('-') && !KNOWN_UPDATE_FLAGS.has(a));
15
+ if (unknownFlags.length > 0) {
16
+ throw new Error(
17
+ `Unknown option(s): ${unknownFlags.join(', ')}. Run \`ukit update --help\` for usage.`,
18
+ );
19
+ }
20
+
21
+ console.log(`[UKit] Current version: ${packageVersion}`);
22
+ console.log(`[UKit] Running: npm install -g ${UKIT_PACKAGE_NAME}`);
23
+
24
+ updateUkit();
25
+
26
+ console.log('[UKit] Update complete. Run `ukit --version` to confirm the new version.');
27
+ }
package/src/cli/index.js CHANGED
@@ -5,6 +5,7 @@ import { runUninstall } from './commands/uninstall.js';
5
5
  import { runIndexTools } from './commands/indexTools.js';
6
6
  import { runStatus } from './commands/status.js';
7
7
  import { runMemory } from './commands/memory.js';
8
+ import { runUpdate } from './commands/update.js';
8
9
 
9
10
  const GLOBAL_FLAGS = new Set(['--help', '-h', '--version', '-v']);
10
11
 
@@ -58,6 +59,11 @@ export async function runCli({ argv, packageRoot, projectRoot, packageVersion })
58
59
  return;
59
60
  }
60
61
 
62
+ if (command === 'update') {
63
+ await runUpdate({ packageVersion, argv: commandArgv });
64
+ return;
65
+ }
66
+
61
67
  if (command === 'build' && (commandArgv[0] ?? '').toLowerCase() === 'index') {
62
68
  await runIndexTools({ projectRoot, argv: ['build', ...commandArgv.slice(1)] });
63
69
  return;
@@ -85,6 +91,7 @@ export async function runCli({ argv, packageRoot, projectRoot, packageVersion })
85
91
  console.log(' index Codebase index tools (build/query/triage)');
86
92
  console.log(' status Show UKit runtime status');
87
93
  console.log(' memory Inspect shared UKit memory');
94
+ console.log(' update Upgrade the global UKit CLI to the latest version');
88
95
  console.log(' version Show UKit version');
89
96
  console.log('');
90
97
  console.log('Options (install / diff):');
@@ -0,0 +1,19 @@
1
+ import { spawnSync as defaultSpawnSync } from 'node:child_process';
2
+
3
+ export const UKIT_PACKAGE_NAME = '@ngockhoale/ukit';
4
+
5
+ export function updateUkit({ spawnSync = defaultSpawnSync } = {}) {
6
+ const result = spawnSync('npm', ['install', '-g', UKIT_PACKAGE_NAME], {
7
+ stdio: 'inherit',
8
+ });
9
+
10
+ if (result.error) {
11
+ throw new Error(`Failed to run npm install -g ${UKIT_PACKAGE_NAME}: ${result.error.message}`);
12
+ }
13
+
14
+ if (result.status !== 0) {
15
+ throw new Error(`npm install -g ${UKIT_PACKAGE_NAME} exited with code ${result.status}`);
16
+ }
17
+
18
+ return result;
19
+ }
@@ -2601,7 +2601,7 @@ const { pathToFileURL } = require('url');
2601
2601
  NODE
2602
2602
 
2603
2603
  if [ -f "$THRESHOLD_SCRIPT" ]; then
2604
- printf '%s' "$INPUT" | CLAUDE_PROJECT_DIR="$PROJECT_ROOT" node "$THRESHOLD_SCRIPT" prompt >/dev/null 2>&1 || true
2604
+ printf '%s' "$INPUT" | CLAUDE_PROJECT_DIR="$PROJECT_ROOT" node "$THRESHOLD_SCRIPT" prompt 2>/dev/null || true
2605
2605
  fi
2606
2606
 
2607
2607
  exit 0
@@ -433,6 +433,9 @@ function printRouteState(state) {
433
433
  console.log(`recent-output: ${recentOutputDisplay}`);
434
434
  }
435
435
  console.log(`summary: ${compactSummary}`);
436
+ if (state.routeSummary?.executionContract?.modelTier) {
437
+ console.log(`modelTier: ${state.routeSummary.executionContract.modelTier}`);
438
+ }
436
439
  if (nextDisplay) {
437
440
  console.log(`next: ${nextDisplay}`);
438
441
  }
@@ -1655,6 +1658,7 @@ function buildExecutionContract(executionMode = null) {
1655
1658
 
1656
1659
  const contracts = {
1657
1660
  'tiny-fix': {
1661
+ modelTier: 'lite',
1658
1662
  maxReadPasses: 0,
1659
1663
  maxContextPulls: 0,
1660
1664
  verificationPolicy: 'minimal-or-targeted',
@@ -1663,6 +1667,7 @@ function buildExecutionContract(executionMode = null) {
1663
1667
  completionEvidence: ['write-evidence'],
1664
1668
  },
1665
1669
  'local-fix': {
1670
+ modelTier: 'code',
1666
1671
  maxReadPasses: 1,
1667
1672
  maxContextPulls: 1,
1668
1673
  verificationPolicy: 'targeted-if-covered',
@@ -1671,6 +1676,7 @@ function buildExecutionContract(executionMode = null) {
1671
1676
  completionEvidence: ['write-evidence'],
1672
1677
  },
1673
1678
  'local-build': {
1679
+ modelTier: 'code',
1674
1680
  maxReadPasses: 2,
1675
1681
  maxContextPulls: 1,
1676
1682
  verificationPolicy: 'targeted-if-covered',
@@ -1679,6 +1685,7 @@ function buildExecutionContract(executionMode = null) {
1679
1685
  completionEvidence: ['write-evidence'],
1680
1686
  },
1681
1687
  'find-cause': {
1688
+ modelTier: 'code',
1682
1689
  maxReadPassesBeforeReassess: 3,
1683
1690
  verificationPolicy: 'root-cause-then-targeted',
1684
1691
  completionRule: 'never-claim-fixed-without-write-and-verification',
@@ -1686,6 +1693,7 @@ function buildExecutionContract(executionMode = null) {
1686
1693
  completionEvidence: ['write-evidence', 'verification-evidence'],
1687
1694
  },
1688
1695
  'shared-edit': {
1696
+ modelTier: 'code',
1689
1697
  maxReadPasses: 2,
1690
1698
  maxContextPulls: 2,
1691
1699
  verificationPolicy: 'targeted-then-widen-on-risk',
@@ -1695,6 +1703,7 @@ function buildExecutionContract(executionMode = null) {
1695
1703
  mirrorConsistencyRequired: true,
1696
1704
  },
1697
1705
  'map-impact': {
1706
+ modelTier: 'code',
1698
1707
  maxReadPasses: 3,
1699
1708
  maxContextPulls: 3,
1700
1709
  verificationPolicy: 'impact-first-then-targeted-then-widen-on-risk',
@@ -1704,6 +1713,7 @@ function buildExecutionContract(executionMode = null) {
1704
1713
  mirrorConsistencyRequired: true,
1705
1714
  },
1706
1715
  'review-release': {
1716
+ modelTier: 'smart',
1707
1717
  verificationPolicy: 'evidence-first',
1708
1718
  completionRule: 'report-findings-not-implementation',
1709
1719
  delegationPolicy: 'allow-review-sidecar',
@@ -1019,12 +1019,18 @@ async function runCli() {
1019
1019
  return;
1020
1020
  }
1021
1021
 
1022
- await updateCompactPressureFromPrompt(projectRoot, {
1022
+ const nextState = await updateCompactPressureFromPrompt(projectRoot, {
1023
1023
  promptText,
1024
1024
  routingContext: routeState?.routingContext ?? {},
1025
1025
  previousContext: routeState?.previousContext ?? null,
1026
1026
  routeSummary: routeState?.routeSummary ?? null,
1027
1027
  }, config);
1028
+
1029
+ if (nextState.phase === 'soft' || nextState.phase === 'hard') {
1030
+ process.stdout.write(
1031
+ `[ukit-skill-router] Context pressure: ${nextState.phase} (est ${nextState.estimatedTotalTokens} / soft ${nextState.softThreshold} / hard ${nextState.hardThreshold}). Suggest running /compact soon, or I will self-summarize before continuing.\n`,
1032
+ );
1033
+ }
1028
1034
  }
1029
1035
  }
1030
1036
 
@@ -136,6 +136,32 @@ Khi Handoff mode: đọc `docs/AI_HANDOFF/RULES.md` để biết 4 phase (Idea+P
136
136
  - `autonomy.level` in `.ukit/storage/config.json` controls how much UKit acts without asking first: `conservative` (ask more), `balanced` (default), `free-run` (auto-run more).
137
137
  - End users should not need to change this; maintainers may tune it per-project.
138
138
 
139
+ ## 3-Tier Model Routing
140
+
141
+ **Internal orchestration only — end users still just use natural language. No new commands.**
142
+
143
+ UKit routes tasks to one of three model tiers based on task complexity:
144
+
145
+ | Tier | Generic alias | Claude model | Typical tasks |
146
+ |------|--------------|--------------|---------------|
147
+ | lite | `unic-lite` | claude-haiku | Reads, git queries, bash summaries, small doc edits |
148
+ | code | `unic-code` | claude-sonnet | Normal coding, local fixes, shared edits, builds, debugging, impact mapping |
149
+ | smart | `unic-smart` | claude-opus | Release review/audit, and escalated deep reasoning after repeated failure |
150
+
151
+ ### Contract-to-tier mapping
152
+
153
+ | Contract | Tier |
154
+ |----------|------|
155
+ | `tiny-fix` | lite |
156
+ | `local-fix`, `local-build`, `shared-edit`, `find-cause`, `map-impact` | code |
157
+ | `review-release` | smart |
158
+
159
+ ### Escalation rule
160
+
161
+ When the same file or symbol fails `debugLoopThreshold` (default: 2) times in one session, UKit routes the next attempt one tier higher (capped at `smart`). Config: `orchestration.escalation` in `.ukit/storage/config.json`.
162
+
163
+ This is internal orchestration — end users do not need to know about tiers, thresholds, or escalation. The AI handles routing transparently.
164
+
139
165
  ## Project Snapshot
140
166
 
141
167
  - Project: {{project.name}} | Root: {{project.root}}