@haposoft/cafekit 0.16.6 → 0.18.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/README.md +14 -22
- package/bin/__tests__/codex-hooks-ownership.test.js +2 -2
- package/bin/__tests__/codex-hooks.test.js +0 -36
- package/bin/__tests__/codex-native.test.js +46 -88
- package/bin/__tests__/develop-contract.test.js +26 -57
- package/bin/__tests__/docs-sync-on-demand.test.js +93 -0
- package/bin/__tests__/grok-envelope.test.js +0 -56
- package/bin/__tests__/hook-payload.test.js +4 -6
- package/bin/__tests__/legacy-authority-decoupled.test.js +159 -0
- package/bin/__tests__/legacy-hooks-retired.test.js +221 -0
- package/bin/__tests__/omp-bridge.test.js +20 -17
- package/bin/__tests__/omp-hooks.test.js +0 -19
- package/bin/__tests__/optional-skill-inventory.test.js +112 -4
- package/bin/__tests__/orca-session.test.js +0 -2
- package/bin/__tests__/package-inventory.test.js +100 -541
- package/bin/__tests__/runtime-dir.test.js +0 -3
- package/bin/__tests__/runtime-schema.test.js +3 -2
- package/bin/__tests__/skill-routing-source.test.js +27 -15
- package/bin/__tests__/spec-narrowing.test.js +0 -27
- package/bin/__tests__/specs-v2-execution-closeout.test.js +4 -69
- package/bin/__tests__/ui-ux-skill.test.js +101 -0
- package/bin/__tests__/usage-hook-retired.test.js +114 -0
- package/bin/__tests__/validator-grounding.test.js +9 -28
- package/bin/phases/codex-runtime.js +24 -0
- package/bin/phases/omp-runtime.js +22 -0
- package/package.json +1 -1
- package/src/claude/CLAUDE.md +3 -10
- package/src/claude/agents/brainstormer.md +7 -3
- package/src/claude/agents/code-auditor.md +35 -50
- package/src/claude/agents/debugger.md +5 -79
- package/src/claude/agents/deployer.md +3 -5
- package/src/claude/agents/docs-keeper.md +2 -7
- package/src/claude/agents/implementer.md +6 -9
- package/src/claude/agents/inspector.md +2 -3
- package/src/claude/agents/project-manager.md +7 -15
- package/src/claude/agents/researcher.md +9 -3
- package/src/claude/agents/spec-maker.md +11 -11
- package/src/claude/hooks/__tests__/fixtures/statusline-default.golden +1 -1
- package/src/claude/hooks/__tests__/spec-gate.test.js +112 -3
- package/src/claude/hooks/__tests__/spec-state-touched.test.js +134 -0
- package/src/claude/hooks/__tests__/state.test.js +68 -0
- package/src/claude/hooks/__tests__/statusline.test.js +140 -11
- package/src/claude/hooks/agent.cjs +2 -1
- package/src/claude/hooks/lib/context.cjs +0 -89
- package/src/claude/hooks/lib/hook-payload.cjs +2 -2
- package/src/claude/hooks/rules.cjs +2 -1
- package/src/claude/hooks/session.cjs +0 -1
- package/src/claude/hooks/spec-gate.cjs +18 -28
- package/src/claude/hooks/spec-state.cjs +95 -1
- package/src/claude/hooks/state.cjs +21 -2
- package/src/claude/migration-manifest.json +30 -15
- package/src/claude/rules/ai-dev-rules.md +1 -1
- package/src/claude/rules/hook-protocols.md +8 -15
- package/src/claude/rules/manage-docs.md +9 -23
- package/src/claude/rules/orchestrator.md +3 -4
- package/src/claude/rules/review-audit-self-decision.md +3 -3
- package/src/claude/rules/skill-domain-routing.md +1 -3
- package/src/claude/rules/skill-workflow-routing.md +4 -5
- package/src/claude/rules/state-sync.md +3 -12
- package/src/claude/rules/workflow.md +10 -18
- package/src/claude/runtime.schema.json +5 -3
- package/src/claude/scripts/generate-skill-catalog.cjs +7 -6
- package/src/claude/scripts/provenance.cjs +23 -5
- package/src/claude/scripts/spec-receipt.cjs +52 -6
- package/src/claude/scripts/spec-resolver.cjs +1 -2
- package/src/claude/scripts/validate-spec-output.cjs +5 -32
- package/src/claude/scripts/workflow-policy.cjs +22 -10
- package/src/claude/settings/settings.json +1 -32
- package/src/claude/skills/{question → ask}/SKILL.md +9 -75
- package/src/claude/skills/brainstorm/SKILL.md +43 -131
- package/src/claude/skills/code-review/SKILL.md +48 -17
- package/src/claude/skills/code-review/references/spec-compliance-review.md +2 -3
- package/src/claude/skills/code-review/references/verification-gate.md +22 -27
- package/src/claude/skills/debug/SKILL.md +29 -149
- package/src/claude/skills/develop/SKILL.md +27 -36
- package/src/claude/skills/develop/references/parallel-waves.md +0 -8
- package/src/claude/skills/develop/references/quality-gate.md +15 -13
- package/src/claude/skills/docs/SKILL.md +2 -2
- package/src/claude/skills/docs/references/update-workflow.md +1 -1
- package/src/claude/skills/fix/SKILL.md +153 -0
- package/src/claude/skills/{hotfix → fix}/references/diagnosis-protocol.md +2 -2
- package/src/claude/skills/{hotfix → fix}/references/parallel-patterns.md +2 -2
- package/src/claude/skills/{hotfix → fix}/references/prevention-gate.md +3 -3
- package/src/claude/skills/{hotfix → fix}/references/review-cycle.md +1 -1
- package/src/claude/skills/git/SKILL.md +48 -9
- package/src/claude/skills/git/references/commit-protocols.md +35 -16
- package/src/claude/skills/git/references/worktree-blueprint.md +42 -6
- package/src/claude/skills/orca/SKILL.md +9 -8
- package/src/claude/skills/research/SKILL.md +2 -0
- package/src/claude/skills/scout/SKILL.md +61 -0
- package/src/claude/skills/{inspect → scout}/references/internal-inspection.md +26 -10
- package/src/claude/skills/specs/SKILL.md +22 -29
- package/src/claude/skills/specs/references/review.md +8 -6
- package/src/claude/skills/specs/references/templates.md +38 -44
- package/src/claude/skills/sync/SKILL.md +8 -15
- package/src/claude/skills/sync/references/rebind-and-audit.md +59 -0
- package/src/claude/skills/sync/references/sync-protocols.md +4 -13
- package/src/claude/skills/test/SKILL.md +22 -3
- package/src/claude/skills/test/references/execution-strategy.md +83 -0
- package/src/claude/skills/test/references/failure-triage.md +1 -1
- package/src/claude/skills/ui-ux/LICENSE +21 -0
- package/src/claude/skills/ui-ux/SKILL.md +497 -0
- package/src/claude/skills/ui-ux/references/brand-tokens.md +90 -0
- package/src/claude/skills/ui-ux/references/budgets.md +113 -0
- package/src/claude/skills/ui-ux/references/checklist.md +271 -0
- package/src/claude/skills/ui-ux/references/components/accordion.md +246 -0
- package/src/claude/skills/ui-ux/references/components/avatar.md +153 -0
- package/src/claude/skills/ui-ux/references/components/banner.md +43 -0
- package/src/claude/skills/ui-ux/references/components/breadcrumb.md +201 -0
- package/src/claude/skills/ui-ux/references/components/button.md +142 -0
- package/src/claude/skills/ui-ux/references/components/card.md +113 -0
- package/src/claude/skills/ui-ux/references/components/charts.md +376 -0
- package/src/claude/skills/ui-ux/references/components/chat.md +132 -0
- package/src/claude/skills/ui-ux/references/components/choice-controls.md +369 -0
- package/src/claude/skills/ui-ux/references/components/comment-thread.md +17 -0
- package/src/claude/skills/ui-ux/references/components/description-list.md +116 -0
- package/src/claude/skills/ui-ux/references/components/empty-state.md +98 -0
- package/src/claude/skills/ui-ux/references/components/file-upload.md +107 -0
- package/src/claude/skills/ui-ux/references/components/inline-edit.md +128 -0
- package/src/claude/skills/ui-ux/references/components/input.md +161 -0
- package/src/claude/skills/ui-ux/references/components/list-row.md +56 -0
- package/src/claude/skills/ui-ux/references/components/loading.md +198 -0
- package/src/claude/skills/ui-ux/references/components/logo.md +147 -0
- package/src/claude/skills/ui-ux/references/components/otp-input.md +43 -0
- package/src/claude/skills/ui-ux/references/components/quantity-input.md +100 -0
- package/src/claude/skills/ui-ux/references/components/range-slider.md +16 -0
- package/src/claude/skills/ui-ux/references/components/small-controls.md +340 -0
- package/src/claude/skills/ui-ux/references/components/sortable-header.md +86 -0
- package/src/claude/skills/ui-ux/references/components/tag-input.md +14 -0
- package/src/claude/skills/ui-ux/references/components/timeline.md +38 -0
- package/src/claude/skills/ui-ux/references/components/tree.md +30 -0
- package/src/claude/skills/ui-ux/references/design-process.md +650 -0
- package/src/claude/skills/ui-ux/references/layouts/app-kanban.html +303 -0
- package/src/claude/skills/ui-ux/references/layouts/app.md +1369 -0
- package/src/claude/skills/ui-ux/references/layouts/form.md +430 -0
- package/src/claude/skills/ui-ux/references/layouts/overlay.md +552 -0
- package/src/claude/skills/ui-ux/references/layouts/pricing.md +204 -0
- package/src/claude/skills/ui-ux/references/locked-rules.md +35 -0
- package/src/claude/skills/ui-ux/references/principles.md +408 -0
- package/src/claude/skills/ui-ux/references/refactor.md +245 -0
- package/src/claude/skills/ui-ux/references/responsive.md +195 -0
- package/src/claude/skills/ui-ux/references/review.md +528 -0
- package/src/claude/skills/ui-ux/references/rules-color.md +623 -0
- package/src/claude/skills/ui-ux/references/rules-form.md +235 -0
- package/src/claude/skills/ui-ux/references/rules-state.md +680 -0
- package/src/claude/skills/ui-ux/references/rules-type.md +369 -0
- package/src/claude/skills/ui-ux/references/styles.md +311 -0
- package/src/claude/skills/ui-ux/references/system.md +219 -0
- package/src/claude/skills/ui-ux/references/tailwind-v4-traps.md +237 -0
- package/src/claude/skills/ui-ux/references/tokens.css +362 -0
- package/src/claude/skills/ui-ux/scripts/lint-skill.mjs +216 -0
- package/src/claude/skills/ui-ux/scripts/package.json +9 -0
- package/src/claude/skills/ui-ux/scripts/probe.mjs +4447 -0
- package/src/claude/skills/ui-ux-pro-max/SKILL.md +1 -1
- package/src/claude/status.cjs +149 -144
- package/src/codex/AGENTS.md +8 -13
- package/src/codex/hooks/agent.cjs +2 -1
- package/src/codex/hooks/lib/spec-receipt.cjs +5 -0
- package/src/codex/hooks/lib/spec-utils.cjs +0 -7
- package/src/codex/hooks/rules.cjs +2 -1
- package/src/codex/hooks/session.cjs +0 -2
- package/src/codex/hooks/spec-gate.cjs +8 -18
- package/src/codex/hooks.json +0 -20
- package/src/codex/rules/state-sync.md +3 -12
- package/src/common/AGENTS.md +2 -2
- package/src/omp/extensions/cafekit-bridge.mjs +6 -6
- package/src/claude/hooks/__tests__/completion-authority.test.js +0 -990
- package/src/claude/hooks/__tests__/semantic-review-authority.test.js +0 -259
- package/src/claude/hooks/completion-authority-check.cjs +0 -56
- package/src/claude/hooks/completion-authority-state.cjs +0 -527
- package/src/claude/hooks/completion-authority.cjs +0 -163
- package/src/claude/hooks/semantic-review-authority.cjs +0 -154
- package/src/claude/hooks/task-scaffold-guard.cjs +0 -114
- package/src/claude/hooks/usage.cjs +0 -197
- package/src/claude/skills/delegate/SKILL.md +0 -124
- package/src/claude/skills/delegate/references/codex-delegation.md +0 -71
- package/src/claude/skills/delegate/references/grok-delegation.md +0 -84
- package/src/claude/skills/hotfix/SKILL.md +0 -289
- package/src/claude/skills/inspect/SKILL.md +0 -142
- package/src/claude/skills/loop/SKILL.md +0 -114
- package/src/claude/skills/loop/references/bounded-loop-protocol.md +0 -104
- package/src/claude/skills/loop/references/metric-and-guard-contract.md +0 -76
- package/src/claude/skills/route/SKILL.md +0 -94
- package/src/claude/skills/route/references/agent-timing.md +0 -46
- package/src/claude/skills/route/references/chaining-patterns.md +0 -53
- package/src/claude/skills/route/references/task-taxonomy.md +0 -48
- package/src/codex/hooks/completion-authority-check.cjs +0 -67
- package/src/codex/hooks/completion-authority-state.cjs +0 -527
- package/src/codex/hooks/completion-authority.cjs +0 -109
- package/src/codex/hooks/semantic-review-authority.cjs +0 -130
- package/src/codex/hooks/task-scaffold-guard.cjs +0 -63
- /package/src/claude/skills/{question → ask}/templates/question.md +0 -0
- /package/src/claude/skills/{hotfix → fix}/references/escalation-tactics.md +0 -0
- /package/src/claude/skills/{hotfix → fix}/references/workflow-specialized.md +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: cf:ui-ux-pro-max
|
|
3
3
|
description: "UI/UX design intelligence for web and mobile. Includes 50+ styles, 161 color palettes, 57 font pairings, 161 product types, 99 UX guidelines, and 25 chart types across 10 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind, shadcn/ui, and HTML/CSS). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, and check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, and mobile app. Elements: button, modal, navbar, sidebar, card, table, form, and chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, and flat design. Topics: color systems, accessibility, animation, layout, typography, font pairing, spacing, interaction states, shadow, and gradient. Integrations: shadcn/ui MCP for component search and examples."
|
|
4
4
|
user-invocable: true
|
|
5
|
-
when_to_use: "Invoke to
|
|
5
|
+
when_to_use: "Invoke to look up color palettes, font pairings, product-type styles, or UX guidelines; to build or review a screen use cf:ui-ux."
|
|
6
6
|
category: frontend
|
|
7
7
|
keywords: [ui, ux, design-system, layout]
|
|
8
8
|
metadata:
|
package/src/claude/status.cjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Custom Claude Code statusline for Node.js -
|
|
5
|
+
* Custom Claude Code statusline for Node.js - one-line default
|
|
6
6
|
* Cross-platform support: Windows, macOS, Linux
|
|
7
7
|
* Features: ANSI colors, tool/agent/todo tracking, context window, session timer
|
|
8
8
|
* No external dependencies - uses only Node.js built-in modules
|
|
@@ -26,10 +26,6 @@ const { getGitInfo } = require('./hooks/lib/git.cjs');
|
|
|
26
26
|
// ratio so 1M-context models are not treated as if they were 200k.
|
|
27
27
|
const AUTOCOMPACT_BUFFER_RATIO = 0.225;
|
|
28
28
|
|
|
29
|
-
// Usage cache freshness gate: a cache older than this hides the quota area
|
|
30
|
-
// instead of rendering stale numbers.
|
|
31
|
-
const USAGE_CACHE_TTL_MS = 300000;
|
|
32
|
-
|
|
33
29
|
/**
|
|
34
30
|
* Expand home directory to ~
|
|
35
31
|
*/
|
|
@@ -104,7 +100,7 @@ async function readStdin() {
|
|
|
104
100
|
* @returns {string|null} Formatted usage string or null if unavailable
|
|
105
101
|
*/
|
|
106
102
|
function buildUsageString(ctx) {
|
|
107
|
-
if (!ctx.sessionText
|
|
103
|
+
if (!ctx.sessionText) return null;
|
|
108
104
|
let str = ctx.sessionText.replace(' until reset', ' left');
|
|
109
105
|
if (ctx.usagePercent != null) str += ` (${Math.round(ctx.usagePercent)}%)`;
|
|
110
106
|
return str;
|
|
@@ -130,77 +126,115 @@ function buildBranchPart(ctx) {
|
|
|
130
126
|
return branchPart;
|
|
131
127
|
}
|
|
132
128
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
129
|
+
// Default session line: one row of single-width symbols, each value labelled by
|
|
130
|
+
// its glyph so the line stays short and every number says what it measures.
|
|
131
|
+
// ◆ model (effort) ϟfast ✱thinking ◔ context% ⧗ 5h-quota% reset ◷ weekly% ⎇ branch ●changed ↑ahead ↓behind ± +added/-removed ⏱ session ↻ cache-hit%
|
|
132
|
+
|
|
133
|
+
/** Quarter-circle glyph that fills with the percentage. */
|
|
134
|
+
function fillGlyph(percent) {
|
|
135
|
+
if (percent >= 88) return '●';
|
|
136
|
+
if (percent >= 63) return '◕';
|
|
137
|
+
if (percent >= 38) return '◑';
|
|
138
|
+
if (percent >= 13) return '◔';
|
|
139
|
+
return '○';
|
|
140
|
+
}
|
|
137
141
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
142
|
+
/** Same thresholds as the context bar; plain text when colours are off. */
|
|
143
|
+
function tintPercent(percent, text) {
|
|
144
|
+
if (percent >= 85) return red(text);
|
|
145
|
+
if (percent >= 70) return yellow(text);
|
|
146
|
+
return green(text);
|
|
147
|
+
}
|
|
141
148
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const
|
|
149
|
+
/** "2h 48m until reset" → "2h48m"; anything else → null. */
|
|
150
|
+
function shortReset(sessionText) {
|
|
151
|
+
const match = /^(\d+)h (\d+)m/.exec(sessionText || '');
|
|
152
|
+
return match ? `${match[1]}h${match[2]}m` : null;
|
|
153
|
+
}
|
|
145
154
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
155
|
+
/** 28147114 → "7h49m"; under an hour → "12m". */
|
|
156
|
+
function formatDuration(ms) {
|
|
157
|
+
const minutes = Math.floor(ms / 60000);
|
|
158
|
+
const hours = Math.floor(minutes / 60);
|
|
159
|
+
return hours > 0 ? `${hours}h${String(minutes % 60).padStart(2, '0')}m` : `${minutes}m`;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** "#80✓" approved, "#80✗" changes requested, "#80" pending, dim "#80" draft; "!80" for a GitLab MR. */
|
|
163
|
+
function formatPr(pr) {
|
|
164
|
+
const label = `${pr.kind === 'mr' ? '!' : '#'}${pr.number}`;
|
|
165
|
+
if (pr.review_state === 'approved') return `${label}${green('✓')}`;
|
|
166
|
+
if (pr.review_state === 'changes_requested') return `${label}${red('✗')}`;
|
|
167
|
+
if (pr.review_state === 'draft') return dim(label);
|
|
168
|
+
return label;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Parts of the default line in display order. `drop` ranks what goes first
|
|
173
|
+
* when the terminal is too narrow (higher drops earlier); 0 never drops.
|
|
174
|
+
*/
|
|
175
|
+
function buildLineParts(ctx, { minimal = false } = {}) {
|
|
176
|
+
let model = `◆ ${ctx.modelName}`;
|
|
177
|
+
if (ctx.effortLevel) model += ` ${dim(`(${ctx.effortLevel})`)}`;
|
|
178
|
+
const flags = `${ctx.fastMode ? 'ϟ' : ''}${ctx.thinking ? '✱' : ''}`;
|
|
179
|
+
if (flags) model += ` ${flags}`;
|
|
180
|
+
const parts = [{ text: model, drop: 0 }];
|
|
149
181
|
|
|
150
|
-
// Build session part: 🤖 model contextBar% ⌛ time left (usage%)
|
|
151
|
-
let sessionPart = `🤖 ${ctx.modelName}`;
|
|
152
182
|
if (ctx.contextPercent > 0) {
|
|
153
|
-
|
|
183
|
+
parts.push({ text: tintPercent(ctx.contextPercent, `${fillGlyph(ctx.contextPercent)} ${ctx.contextPercent}%`), drop: 0 });
|
|
154
184
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
185
|
+
|
|
186
|
+
if (!minimal && ctx.usagePercent != null) {
|
|
187
|
+
const pct = Math.round(ctx.usagePercent);
|
|
188
|
+
const reset = shortReset(ctx.sessionText);
|
|
189
|
+
parts.push({ text: `⧗ ${tintPercent(pct, `${pct}%`)}${reset ? ` ${dim(reset)}` : ''}`, drop: 2 });
|
|
160
190
|
}
|
|
161
191
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
// if (ctx.costText) statsItems.push(`💵 ${ctx.costText.replace(/(\.\d{2})\d+/, '$1')}`);
|
|
165
|
-
if (ctx.linesAdded > 0 || ctx.linesRemoved > 0) {
|
|
166
|
-
statsItems.push(`📝 ${green(`+${ctx.linesAdded}`)} ${red(`-${ctx.linesRemoved}`)}`);
|
|
192
|
+
if (!minimal && ctx.weeklyPercent != null) {
|
|
193
|
+
parts.push({ text: `◷ ${tintPercent(ctx.weeklyPercent, `${ctx.weeklyPercent}%`)}`, drop: 3 });
|
|
167
194
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
const sessionStats = `${sessionPart} ${statsPart}`;
|
|
181
|
-
|
|
182
|
-
if (visibleLength(allOneLine) <= threshold && statsLen > 0) {
|
|
183
|
-
// Ultra-wide: everything on one line (session first)
|
|
184
|
-
lines.push(allOneLine);
|
|
185
|
-
} else if (visibleLength(sessionLocation) <= threshold) {
|
|
186
|
-
// Wide: session+location on line 1 | stats on line 2
|
|
187
|
-
lines.push(sessionLocation);
|
|
188
|
-
if (statsLen > 0) lines.push(statsPart);
|
|
189
|
-
} else if (sessionLen <= threshold) {
|
|
190
|
-
// Medium: session on line 1 | location on line 2 | stats on line 3
|
|
191
|
-
lines.push(sessionPart);
|
|
192
|
-
lines.push(locationPart);
|
|
193
|
-
if (statsLen > 0) lines.push(statsPart);
|
|
194
|
-
} else {
|
|
195
|
-
// Narrow: session | dir | branch | stats (each on own line)
|
|
196
|
-
lines.push(sessionPart);
|
|
197
|
-
lines.push(dirPart);
|
|
198
|
-
if (branchPart) lines.push(branchPart);
|
|
199
|
-
if (planPart) lines.push(planPart);
|
|
200
|
-
if (statsLen > 0) lines.push(statsPart);
|
|
195
|
+
|
|
196
|
+
if (ctx.gitBranch) {
|
|
197
|
+
let git = `⎇ ${ctx.gitBranch}`;
|
|
198
|
+
if (!minimal) {
|
|
199
|
+
const changed = ctx.gitUnstaged + ctx.gitStaged;
|
|
200
|
+
if (changed > 0) git += ` ${yellow(`●${changed}`)}`;
|
|
201
|
+
if (ctx.gitAhead > 0) git += ` ↑${ctx.gitAhead}`;
|
|
202
|
+
if (ctx.gitBehind > 0) git += ` ↓${ctx.gitBehind}`;
|
|
203
|
+
if (ctx.pr) git += ` ${formatPr(ctx.pr)}`;
|
|
204
|
+
if (ctx.inWorktree) git += ' ⊟';
|
|
205
|
+
}
|
|
206
|
+
parts.push({ text: git, drop: 1 });
|
|
201
207
|
}
|
|
202
208
|
|
|
203
|
-
|
|
209
|
+
if (!minimal && (ctx.linesAdded > 0 || ctx.linesRemoved > 0)) {
|
|
210
|
+
parts.push({ text: `± ${green(`+${ctx.linesAdded}`)}/${red(`-${ctx.linesRemoved}`)}`, drop: 4 });
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (!minimal && ctx.durationMs >= 60000) {
|
|
214
|
+
parts.push({ text: `⏱ ${formatDuration(ctx.durationMs)}`, drop: 5 });
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (!minimal && ctx.cacheHitRatio != null) {
|
|
218
|
+
const pct = Math.round(ctx.cacheHitRatio * 100);
|
|
219
|
+
const tinted = pct < 50 ? red(`${pct}%`) : pct < 80 ? yellow(`${pct}%`) : green(`${pct}%`);
|
|
220
|
+
parts.push({ text: `↻ ${tinted}`, drop: 6 });
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return parts;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/** Join parts, dropping the highest-ranked ones until the line fits the terminal. */
|
|
227
|
+
function fitLine(parts) {
|
|
228
|
+
const width = getTerminalWidth() - 2;
|
|
229
|
+
const kept = [...parts];
|
|
230
|
+
const join = () => kept.map((part) => part.text).join(' ');
|
|
231
|
+
while (visibleLength(join()) > width) {
|
|
232
|
+
const candidates = kept.filter((part) => part.drop > 0);
|
|
233
|
+
if (candidates.length === 0) break;
|
|
234
|
+
const victim = candidates.reduce((a, b) => (b.drop > a.drop ? b : a));
|
|
235
|
+
kept.splice(kept.indexOf(victim), 1);
|
|
236
|
+
}
|
|
237
|
+
return join();
|
|
204
238
|
}
|
|
205
239
|
|
|
206
240
|
/**
|
|
@@ -309,52 +343,21 @@ function renderTodosLine(transcript) {
|
|
|
309
343
|
return `${yellow('▸')} ${display} ${dim(`(${completedCount} done, ${pendingCount} pending)`)}`;
|
|
310
344
|
}
|
|
311
345
|
|
|
312
|
-
/**
|
|
313
|
-
* Render minimal mode - single line with emojis, no progress bar
|
|
314
|
-
* Format: "🤖 opus 4.5 🔋 50% ⏰ 2h 16m (38%) 🌿 branch 📁 ~/path"
|
|
315
|
-
*/
|
|
346
|
+
/** minimal mode: model, context and branch only. */
|
|
316
347
|
function renderMinimal(ctx) {
|
|
317
|
-
|
|
318
|
-
if (ctx.contextPercent > 0) {
|
|
319
|
-
const batteryIcon = ctx.contextPercent > 70 ? red('🔋') : '🔋';
|
|
320
|
-
parts.push(`${batteryIcon} ${ctx.contextPercent}%`);
|
|
321
|
-
}
|
|
322
|
-
const usageStr = buildUsageString(ctx);
|
|
323
|
-
if (usageStr) parts.push(`⏰ ${usageStr}${ctx.weeklyText ? ` ${ctx.weeklyText}` : ''}`);
|
|
324
|
-
if (ctx.gitBranch) parts.push(`🌿 ${ctx.gitBranch}`);
|
|
325
|
-
parts.push(`📁 ${ctx.currentDir}`);
|
|
326
|
-
console.log(parts.join(' '));
|
|
348
|
+
writeStyledLines([fitLine(buildLineParts(ctx, { minimal: true }))]);
|
|
327
349
|
}
|
|
328
350
|
|
|
329
|
-
/**
|
|
330
|
-
* Render compact mode - 2 lines: session info + location (branch + dir)
|
|
331
|
-
*/
|
|
351
|
+
/** compact mode: the default line without the agent and todo lines. */
|
|
332
352
|
function renderCompact(ctx) {
|
|
333
|
-
|
|
334
|
-
let line1 = `🤖 ${ctx.modelName}`;
|
|
335
|
-
if (ctx.contextPercent > 0) {
|
|
336
|
-
line1 += ` ${coloredBar(ctx.contextPercent, 12)} ${ctx.contextPercent}%`;
|
|
337
|
-
}
|
|
338
|
-
const usageStr = buildUsageString(ctx);
|
|
339
|
-
if (usageStr) line1 += ` ⌛ ${usageStr}${ctx.weeklyText ? ` ${ctx.weeklyText}` : ''}`;
|
|
340
|
-
console.log(line1.replace(/ /g, '\u00A0'));
|
|
341
|
-
|
|
342
|
-
// Line 2: Location (branch + directory)
|
|
343
|
-
let line2 = `📁 ${ctx.currentDir}`;
|
|
344
|
-
if (ctx.gitBranch) line2 += ` 🌿 ${ctx.gitBranch}`;
|
|
345
|
-
console.log(line2.replace(/ /g, '\u00A0'));
|
|
353
|
+
render(ctx, true);
|
|
346
354
|
}
|
|
347
355
|
|
|
348
356
|
/**
|
|
349
|
-
*
|
|
350
|
-
* Falls back to single line if multi-line fails
|
|
357
|
+
* full mode: the default line, then agent and todo lines only while they exist.
|
|
351
358
|
*/
|
|
352
359
|
function render(ctx, singleLineMode = false) {
|
|
353
|
-
const lines = [];
|
|
354
|
-
|
|
355
|
-
// Session lines (cleaner multi-line layout)
|
|
356
|
-
const sessionLines = renderSessionLines(ctx);
|
|
357
|
-
lines.push(...sessionLines);
|
|
360
|
+
const lines = [fitLine(buildLineParts(ctx))];
|
|
358
361
|
|
|
359
362
|
if (!singleLineMode) {
|
|
360
363
|
// Agents lines (one per agent for clarity)
|
|
@@ -463,6 +466,8 @@ async function main() {
|
|
|
463
466
|
currentDir = expandHome(currentDir);
|
|
464
467
|
|
|
465
468
|
const modelName = data.model?.display_name || 'Claude';
|
|
469
|
+
// Live /effort value; absent when the model has no effort parameter.
|
|
470
|
+
const effortLevel = typeof data.effort?.level === 'string' ? data.effort.level : '';
|
|
466
471
|
|
|
467
472
|
// Git detection using batched cache
|
|
468
473
|
const rawDir = data.workspace?.current_dir || data.cwd || process.cwd();
|
|
@@ -522,55 +527,39 @@ async function main() {
|
|
|
522
527
|
} catch {}
|
|
523
528
|
}
|
|
524
529
|
|
|
525
|
-
//
|
|
530
|
+
// Quota text, filled from the payload's rate_limits below
|
|
526
531
|
let sessionText = '';
|
|
527
532
|
let weeklyText = '';
|
|
533
|
+
let weeklyPercent = null;
|
|
528
534
|
const transcriptPath = data.transcript_path;
|
|
529
535
|
|
|
530
536
|
// Parse transcript for tools/agents/todos
|
|
531
537
|
const transcript = transcriptPath ? await parseTranscript(transcriptPath) : { tools: [], agents: [], todos: [], sessionStart: null };
|
|
532
538
|
|
|
533
|
-
//
|
|
539
|
+
// Quota windows come only from Claude Code's own rate_limits, sent for Pro/Max after
|
|
540
|
+
// the session's first API response; without it the quota segments stay hidden.
|
|
534
541
|
let usagePercent = null;
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
const
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
const fresh = typeof cache.timestamp === 'number'
|
|
542
|
-
&& Date.now() - cache.timestamp < USAGE_CACHE_TTL_MS;
|
|
543
|
-
if (cache.status === 'unavailable') {
|
|
544
|
-
sessionText = 'N/A';
|
|
545
|
-
} else if (cache.status === 'available' && fresh) {
|
|
546
|
-
const fiveHour = cache.data?.five_hour;
|
|
547
|
-
usagePercent = fiveHour?.utilization ?? null;
|
|
548
|
-
const resetAt = fiveHour?.resets_at;
|
|
549
|
-
if (resetAt) {
|
|
550
|
-
const resetTime = new Date(resetAt);
|
|
551
|
-
const remaining = Math.floor(resetTime.getTime() / 1000) - Math.floor(Date.now() / 1000);
|
|
552
|
-
if (remaining > 0 && remaining < 18000) {
|
|
553
|
-
const rh = Math.floor(remaining / 3600);
|
|
554
|
-
const rm = Math.floor((remaining % 3600) / 60);
|
|
555
|
-
sessionText = `${rh}h ${rm}m until reset`;
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
const sevenDay = cache.data?.seven_day;
|
|
559
|
-
if (sevenDay?.utilization != null) {
|
|
560
|
-
weeklyText = `wk ${Math.round(sevenDay.utilization)}%`;
|
|
561
|
-
const wkResetAt = sevenDay.resets_at;
|
|
562
|
-
if (wkResetAt) {
|
|
563
|
-
const wkRemaining = Math.floor(new Date(wkResetAt).getTime() / 1000) - Math.floor(Date.now() / 1000);
|
|
564
|
-
if (wkRemaining > 0) {
|
|
565
|
-
const wd = Math.floor(wkRemaining / 86400);
|
|
566
|
-
const wh = Math.floor((wkRemaining % 86400) / 3600);
|
|
567
|
-
weeklyText += ` (${wd}d ${wh}h)`;
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
}
|
|
542
|
+
const applyWindows = (fiveHour, sevenDay) => {
|
|
543
|
+
if (fiveHour?.percent != null) {
|
|
544
|
+
usagePercent = fiveHour.percent;
|
|
545
|
+
const remaining = Math.floor(fiveHour.resetsAtMs / 1000) - Math.floor(Date.now() / 1000);
|
|
546
|
+
if (remaining > 0 && remaining < 18000) {
|
|
547
|
+
sessionText = `${Math.floor(remaining / 3600)}h ${Math.floor((remaining % 3600) / 60)}m until reset`;
|
|
571
548
|
}
|
|
572
549
|
}
|
|
573
|
-
|
|
550
|
+
if (sevenDay?.percent != null) {
|
|
551
|
+
weeklyPercent = Math.round(sevenDay.percent);
|
|
552
|
+
weeklyText = `wk ${weeklyPercent}%`;
|
|
553
|
+
const wkRemaining = Math.floor(sevenDay.resetsAtMs / 1000) - Math.floor(Date.now() / 1000);
|
|
554
|
+
if (wkRemaining > 0) {
|
|
555
|
+
weeklyText += ` (${Math.floor(wkRemaining / 86400)}d ${Math.floor((wkRemaining % 86400) / 3600)}h)`;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
const fromPayload = (window) => (window && typeof window.used_percentage === 'number'
|
|
560
|
+
? { percent: window.used_percentage, resetsAtMs: Number(window.resets_at) * 1000 }
|
|
561
|
+
: null);
|
|
562
|
+
applyWindows(fromPayload(data.rate_limits?.five_hour), fromPayload(data.rate_limits?.seven_day));
|
|
574
563
|
|
|
575
564
|
// Cost and lines changed
|
|
576
565
|
const billingMode = env.CLAUDE_BILLING_MODE || 'api';
|
|
@@ -580,6 +569,14 @@ async function main() {
|
|
|
580
569
|
: null;
|
|
581
570
|
const linesAdded = data.cost?.total_lines_added || 0;
|
|
582
571
|
const linesRemoved = data.cost?.total_lines_removed || 0;
|
|
572
|
+
const durationMs = Number(data.cost?.total_duration_ms) || 0;
|
|
573
|
+
const cacheHitRatio = data.prompt_cache?.requests > 0 && typeof data.prompt_cache.hit_ratio === 'number'
|
|
574
|
+
? data.prompt_cache.hit_ratio
|
|
575
|
+
: null;
|
|
576
|
+
const fastMode = data.fast_mode === true;
|
|
577
|
+
const thinking = data.thinking?.enabled === true;
|
|
578
|
+
const pr = typeof data.pr?.number === 'number' ? data.pr : null;
|
|
579
|
+
const inWorktree = Boolean(data.worktree?.name || data.workspace?.git_worktree);
|
|
583
580
|
|
|
584
581
|
// Config counts
|
|
585
582
|
const configs = countConfigs(rawDir);
|
|
@@ -587,6 +584,7 @@ async function main() {
|
|
|
587
584
|
// Build render context
|
|
588
585
|
const ctx = {
|
|
589
586
|
modelName,
|
|
587
|
+
effortLevel,
|
|
590
588
|
currentDir,
|
|
591
589
|
gitBranch,
|
|
592
590
|
gitUnstaged,
|
|
@@ -597,10 +595,17 @@ async function main() {
|
|
|
597
595
|
contextPercent,
|
|
598
596
|
sessionText,
|
|
599
597
|
weeklyText,
|
|
598
|
+
weeklyPercent,
|
|
600
599
|
usagePercent,
|
|
601
600
|
costText,
|
|
602
601
|
linesAdded,
|
|
603
602
|
linesRemoved,
|
|
603
|
+
durationMs,
|
|
604
|
+
cacheHitRatio,
|
|
605
|
+
fastMode,
|
|
606
|
+
thinking,
|
|
607
|
+
pr,
|
|
608
|
+
inWorktree,
|
|
604
609
|
configs,
|
|
605
610
|
transcript
|
|
606
611
|
};
|
|
@@ -636,11 +641,11 @@ async function main() {
|
|
|
636
641
|
|
|
637
642
|
} catch (err) {
|
|
638
643
|
// Fallback: output minimal single line on any error
|
|
639
|
-
console.log(
|
|
644
|
+
console.log(`◆ ${expandHome(process.cwd() || 'unknown')}`);
|
|
640
645
|
}
|
|
641
646
|
}
|
|
642
647
|
|
|
643
648
|
main().catch(() => {
|
|
644
|
-
console.log('
|
|
649
|
+
console.log('◆ statusline error');
|
|
645
650
|
process.exit(1);
|
|
646
651
|
});
|
package/src/codex/AGENTS.md
CHANGED
|
@@ -10,17 +10,19 @@
|
|
|
10
10
|
- For skill selection, read `.codex/rules/skill-workflow-routing.md` and
|
|
11
11
|
`.codex/rules/skill-domain-routing.md`. When capability presence is uncertain,
|
|
12
12
|
run `node .codex/scripts/generate-skill-catalog.cjs --skills`; its Codex-bound
|
|
13
|
-
root is `.agents/skills`.
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
root is `.agents/skills`. Explicit, obvious, and factual intents stay
|
|
14
|
+
direct; compose a short chain only for ambiguous, multi-step, multi-domain, or
|
|
15
|
+
risk-elevated work.
|
|
16
16
|
- Consult `.codex/rules/review-audit-self-decision.md` before applying audit
|
|
17
17
|
feedback, reversing a verified or user decision, or cutting scope, and
|
|
18
18
|
`.codex/rules/process-management.md` whenever a task starts, reuses, or ends
|
|
19
19
|
long-running processes.
|
|
20
|
+
- Read `.codex/rules/state-sync.md` before changing a task `Status:` or Receipt,
|
|
21
|
+
and `.codex/rules/hook-protocols.md` when a hook blocks or asks.
|
|
20
22
|
- Project hooks live in `.codex/hooks.json`; review trusted hooks with `/hooks`.
|
|
21
|
-
- New Specs work uses the process-first flow. `$cf-specs` opens
|
|
23
|
+
- New Specs work uses the process-first flow. `$cf-specs` opens GATE-SCOPE, writes
|
|
22
24
|
`specs/<feature>/plan.md` with flat `task-NN-*.md` files beside it, then opens
|
|
23
|
-
|
|
25
|
+
GATE-REVIEW after adversarial review. It never starts implementation.
|
|
24
26
|
- Start implementation only through a new explicit `$cf-develop` invocation.
|
|
25
27
|
Execute one unblocked task at a time; each task has exactly one `Status:`
|
|
26
28
|
field and the controller is its sole state-and-proof writer.
|
|
@@ -28,16 +30,9 @@
|
|
|
28
30
|
requires a canonical final inline `## Receipt` with the exact command,
|
|
29
31
|
`Exit: 0`, `Verification: PASS`, runtime-derived Base and Head values, and
|
|
30
32
|
non-empty fenced current output.
|
|
31
|
-
- At
|
|
33
|
+
- At GATE-DONE, show current receipts and unresolved limitations. The user decides
|
|
32
34
|
completion; no command, review, or host state may invent approval or proof.
|
|
33
35
|
|
|
34
|
-
### Legacy Specs compatibility
|
|
35
|
-
|
|
36
|
-
Existing packets containing `spec.json`, nested tasks, or legacy kernel
|
|
37
|
-
artifacts keep their installed adapter, `task_registry`, `semantic_model`,
|
|
38
|
-
`planning_depth`, lane, `execution_tier`, machine authority, separate receipts,
|
|
39
|
-
and closeout contract. Do not migrate them during unrelated process-first work.
|
|
40
|
-
|
|
41
36
|
## Codex caveats
|
|
42
37
|
|
|
43
38
|
- Custom agents use snake_case names and `fork_turns: "none"` for explicit delegation.
|
|
@@ -26,6 +26,7 @@ try {
|
|
|
26
26
|
const thinkLang = runtime.locale?.thinkingLanguage || (respondLang ? 'en' : '');
|
|
27
27
|
const plansPath = resolveProjectPath(projectRoot, runtime.paths?.plans, 'plans');
|
|
28
28
|
const docsPath = resolveProjectPath(projectRoot, runtime.paths?.docs, 'docs');
|
|
29
|
+
const specsPath = resolveProjectPath(projectRoot, runtime.paths?.specs, 'specs');
|
|
29
30
|
const venv = resolveVenv(projectRoot);
|
|
30
31
|
const lines = [
|
|
31
32
|
`## Subagent: ${payload.agent_type || 'unknown'}`,
|
|
@@ -44,7 +45,7 @@ try {
|
|
|
44
45
|
|
|
45
46
|
lines.push(
|
|
46
47
|
'## Rules',
|
|
47
|
-
`- Plans → ${plansPath}/ | Docs → ${docsPath}/`,
|
|
48
|
+
`- Specs → ${specsPath}/ | Plans → ${plansPath}/ | Docs → ${docsPath}/`,
|
|
48
49
|
'- YAGNI · KISS · DRY',
|
|
49
50
|
'- Be concise. List unresolved questions at end.'
|
|
50
51
|
);
|
|
@@ -99,6 +99,10 @@ function checkFeatureReceipt(featureDir, runtimeContext) {
|
|
|
99
99
|
if (!policy) return { failures: ['shared_validator'], status: 'missing' };
|
|
100
100
|
return receiptHelper().checkFeatureReceipt(featureDir, runtimeContext, policy);
|
|
101
101
|
}
|
|
102
|
+
function receiptFixHint(failures, body) {
|
|
103
|
+
const helper = receiptHelper();
|
|
104
|
+
return typeof helper.receiptFixHint === 'function' ? helper.receiptFixHint(failures, body) : null;
|
|
105
|
+
}
|
|
102
106
|
function readTaskProof(featureDir, taskPath) {
|
|
103
107
|
return receiptHelper().readTaskProof(featureDir, taskPath, getSharedPolicy() || {});
|
|
104
108
|
}
|
|
@@ -115,6 +119,7 @@ module.exports = {
|
|
|
115
119
|
loadSharedPolicy,
|
|
116
120
|
loadSharedReceipt,
|
|
117
121
|
readTaskProof,
|
|
122
|
+
receiptFixHint,
|
|
118
123
|
safeTaskFile,
|
|
119
124
|
validateCanonicalReceipt,
|
|
120
125
|
};
|
|
@@ -152,17 +152,10 @@ function readActiveFeatureTarget(options) {
|
|
|
152
152
|
return resolver.readActiveFeatureTarget(options);
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
-
function resolvePersistedSpec(options) {
|
|
156
|
-
const resolver = sharedResolver();
|
|
157
|
-
if (typeof resolver.resolvePersistedSpec !== 'function') return null;
|
|
158
|
-
return resolver.resolvePersistedSpec(options);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
155
|
module.exports = {
|
|
162
156
|
findActiveSpec,
|
|
163
157
|
extractExplicitTarget,
|
|
164
158
|
readActiveFeatureTarget,
|
|
165
|
-
resolvePersistedSpec,
|
|
166
159
|
findAllActiveSpecs,
|
|
167
160
|
findAllSpecCandidates,
|
|
168
161
|
resolveActiveSpec,
|
|
@@ -79,6 +79,7 @@ try {
|
|
|
79
79
|
const thinkLang = runtime.locale?.thinkingLanguage || (respondLang ? 'en' : '');
|
|
80
80
|
const plansPath = resolveProjectPath(projectRoot, runtime.paths?.plans, 'plans');
|
|
81
81
|
const docsPath = resolveProjectPath(projectRoot, runtime.paths?.docs, 'docs');
|
|
82
|
+
const specsPath = resolveProjectPath(projectRoot, runtime.paths?.specs, 'specs');
|
|
82
83
|
const lines = [];
|
|
83
84
|
|
|
84
85
|
if ((thinkLang && thinkLang !== respondLang) || respondLang) {
|
|
@@ -92,7 +93,7 @@ try {
|
|
|
92
93
|
|
|
93
94
|
lines.push(
|
|
94
95
|
'## Rules',
|
|
95
|
-
`- Markdown: Plans → "${plansPath}/" | Docs → "${docsPath}/"`,
|
|
96
|
+
`- Markdown: Specs → "${specsPath}/" | Plans → "${plansPath}/" | Docs → "${docsPath}/"`,
|
|
96
97
|
'- Do not create markdown outside those directories unless explicitly asked.',
|
|
97
98
|
`- docs.maxLoc: ${runtime.docs?.maxLoc || 800} lines per doc file`
|
|
98
99
|
);
|
|
@@ -10,7 +10,6 @@ const {
|
|
|
10
10
|
readPayload
|
|
11
11
|
} = require('./lib/hook-context.cjs');
|
|
12
12
|
const { clearState } = require('./lib/privacy-state.cjs');
|
|
13
|
-
const { clearState: clearCompletionState } = require('./completion-authority-state.cjs');
|
|
14
13
|
|
|
15
14
|
function readPackage(projectRoot) {
|
|
16
15
|
try {
|
|
@@ -89,7 +88,6 @@ try {
|
|
|
89
88
|
|
|
90
89
|
// Approval tokens never survive a session boundary or compaction.
|
|
91
90
|
clearState(projectRoot);
|
|
92
|
-
clearCompletionState(projectRoot, payload.session_id);
|
|
93
91
|
|
|
94
92
|
// Orca (onorca.dev) sets ORCA_PANE_KEY in every pane; it is a presence marker, not a
|
|
95
93
|
// secret. ORCA_AGENT_HOOK_TOKEN and ORCA_AGENT_LAUNCH_TOKEN live in the same
|
|
@@ -16,9 +16,9 @@ const {
|
|
|
16
16
|
checkWorkflowReceiptDetails,
|
|
17
17
|
checkWorkflowReceiptSet,
|
|
18
18
|
loadSharedPolicy,
|
|
19
|
+
receiptFixHint,
|
|
19
20
|
} = require('./lib/spec-receipt.cjs');
|
|
20
21
|
const { taskStatusMap } = require('./lib/spec-utils.cjs');
|
|
21
|
-
const FINAL_STATE = require('./completion-authority-check.cjs');
|
|
22
22
|
|
|
23
23
|
function emitBlock(reason) {
|
|
24
24
|
process.stdout.write(`${JSON.stringify({ decision: 'block', reason })}\n`);
|
|
@@ -53,9 +53,7 @@ try {
|
|
|
53
53
|
// the payload leaves, which is what made the block unescapable on this runtime too.
|
|
54
54
|
const target = resolver.extractExplicitTarget(payload)
|
|
55
55
|
|| resolver.readActiveFeatureTarget({ projectRoot, runtime });
|
|
56
|
-
let resolved =
|
|
57
|
-
? resolver.resolveWorkflowCandidate({ projectRoot, runtime, target, includeCompleted: true })
|
|
58
|
-
: FINAL_STATE.resolveCandidate({ resolver, projectRoot, runtime, payload });
|
|
56
|
+
let resolved = resolver.resolveWorkflowCandidate({ projectRoot, runtime, target, includeCompleted: true });
|
|
59
57
|
if (typeof resolver.refineWorkflowGateResolution === 'function') {
|
|
60
58
|
resolved = resolver.refineWorkflowGateResolution(resolved);
|
|
61
59
|
}
|
|
@@ -75,7 +73,7 @@ try {
|
|
|
75
73
|
const lines = [`Completion gate: ${checked.failures.length} done task(s) lack a verification receipt.`];
|
|
76
74
|
for (const failure of checked.failures) {
|
|
77
75
|
lines.push(`- \`${failure.featureName}/${failure.taskPath}\`: failed check(s) ${failure.failures.join(', ')}`);
|
|
78
|
-
lines.push(`
|
|
76
|
+
lines.push(` In \`specs/${failure.featureName}/${failure.taskPath}\`: ${receiptFixHint(failure.failures, failure.body) || 'write a runtime-bound `## Receipt` with the planned command'}.`);
|
|
79
77
|
}
|
|
80
78
|
emitBlock(lines.slice(0, 8).join('\n'));
|
|
81
79
|
process.exit(0);
|
|
@@ -108,18 +106,10 @@ try {
|
|
|
108
106
|
const lifecyclePhase = activeSpec.current_phase || activeSpec.phase;
|
|
109
107
|
const explicitCloseout = ['done', 'completed', 'complete'].includes(activeSpec.status)
|
|
110
108
|
|| ['closeout', 'completion', 'completed', 'complete'].includes(lifecyclePhase);
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
runtime,
|
|
116
|
-
payload: { ...payload, session_id: sessionIdentity(payload) },
|
|
117
|
-
});
|
|
118
|
-
if (!finalState.ok) {
|
|
119
|
-
emitBlock(`Completion gate: ${finalState.reason}`);
|
|
120
|
-
process.exit(0);
|
|
121
|
-
}
|
|
122
|
-
if (finalState.active) process.exit(0);
|
|
109
|
+
// Legacy 2.1 closeout is retired; a 2.1 packet mid-execution keeps the ordinary receipt checks.
|
|
110
|
+
if (!processWorkflow && activeSpec.schema_version === '2.1' && explicitCloseout) {
|
|
111
|
+
emitBlock('Completion gate: Legacy spec.json closeout is no longer supported; move the packet to plan.md with flat task files');
|
|
112
|
+
process.exit(0);
|
|
123
113
|
}
|
|
124
114
|
const runtimeContext = POLICY.deriveRuntimeContext({
|
|
125
115
|
projectRoot,
|
|
@@ -228,7 +218,7 @@ try {
|
|
|
228
218
|
lines.push(result.taskPath === 'feature-receipt.md'
|
|
229
219
|
? ` Run final integration proof, then write \`specs/${active.featureName}/feature-receipt.md\`.`
|
|
230
220
|
: processWorkflow
|
|
231
|
-
? `
|
|
221
|
+
? ` In \`specs/${active.featureName}/${path.posix.basename(result.taskPath)}\`: ${receiptFixHint(result.failures, result.body) || 'write a runtime-bound `## Receipt` with command output'}.`
|
|
232
222
|
: ` Write canonical proof to \`specs/${active.featureName}/receipts/${path.posix.basename(result.taskPath)}\`; legacy \`## Evidence\` remains read-compatible.`);
|
|
233
223
|
}
|
|
234
224
|
if (completionBlocked) {
|