Skip to content

Commit d0f286a

Browse files
committed
Release v2.3.0: kit portability hardening
- De-brand shipped agent-harness surface (remove Flowser/CloakBrowser/OpenClaw product literals + dangling process/context refs from skills/agents/hooks prose) - Config loader reads .vc.json first with legacy .ck.json fallback (byte-mirrored across .claude and .codex hooks) - Add standing validate-kit-portability.mjs gate (survivor-allowlist, not disk existence) wired into vc-audit-vc; widen vc-publish Step 8 leak detection
1 parent d4a8ff9 commit d0f286a

75 files changed

Lines changed: 640 additions & 225 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/agents/vc-code-reviewer.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
name: code-reviewer
33
tools: Glob, Grep, Read, Bash, WebFetch, WebSearch, TaskCreate, TaskGet, TaskUpdate, TaskList
4+
model: sonnet
45
permissionMode: default
56
description: "Comprehensive code review with scout-based edge case detection. Use after implementing features, before PRs, for quality assessment, security audits, or performance optimization."
67
---

.claude/agents/vc-execute-agent.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name: execute-agent
33
description: EXECUTE MODE - Implementing EXACTLY what was planned. Full tool access. Can only be invoked after explicit user confirmation. Use after plan is approved.
44
tools: Read, Write, Edit, Grep, Glob, Bash, Delete
5-
model: sonnet
5+
model: opus
66
permissionMode: acceptEdits
77
---
88

.claude/agents/vc-fast-mode-agent.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name: fast-mode-agent
33
description: FAST MODE - Execute compressed RIPER-5 workflow (RESEARCH + INNOVATE + PLAN) in one session, then pause for EXECUTE confirmation. Use when you want quick end-to-end solution.
44
tools: Read, Write, Edit, Grep, Glob, Bash, Delete
5-
model: sonnet
5+
model: opus
66
permissionMode: acceptEdits
77
---
88

.claude/agents/vc-ui-ux-designer.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
name: ui-ux-designer
33
description: 'Use this agent when the user needs UI/UX execution support including interface implementation, design-system polish, responsive layouts, animations, accessibility review, or design documentation. Examples:\n\n<example>\nContext: User wants to implement a new landing page from an approved direction\nuser: "I need a modern landing page for our SaaS product with a hero section, features, and pricing"\nassistant: "I''ll use the ui-ux-designer agent to translate that approved direction into a polished implementation plan and UI output."\n<commentary>The user is requesting UI/UX execution work, so delegate to the ui-ux-designer agent to handle the design-aware implementation and polish.</commentary>\n</example>\n\n<example>\nContext: User has implemented a new feature and wants design review\nuser: "I''ve added a new dashboard widget, can you review the design?"\nassistant: "Let me first capture the current UI and then use the ui-ux-designer agent to analyze and provide design recommendations."\n<commentary>Use screenshot tools to capture current state, then delegate to ui-ux-designer for expert design analysis and suggestions.</commentary>\n</example>\n\n<example>\nContext: User mentions design inconsistencies\nuser: "The buttons across different pages look inconsistent"\nassistant: "I''ll use the ui-ux-designer agent to audit the design system and propose a more consistent implementation."\n<commentary>Design-system work requires the ui-ux-designer agent to analyze, document, and improve consistent design patterns.</commentary>\n</example>\n\n<example>\nContext: Proactive design optimization opportunity\nuser: "Here''s the new signup form I just built"\nassistant: "Let me use the ui-ux-designer agent to review the form design for accessibility, user experience, and mobile responsiveness."\n<commentary>Even without an explicit design brief, ui-ux-designer can help ensure design quality and best practices during execute-phase polish.</commentary>\n</example>'
44
permissionMode: acceptEdits
5+
model: sonnet
56
tools: Glob, Grep, Read, Edit, MultiEdit, Write, NotebookEdit, Bash, WebFetch, WebSearch, TaskCreate, TaskGet, TaskUpdate, TaskList, Task(research-agent)
67
---
78

89
[MODE: EXECUTE]
910

1011
This agent is callable from RIPER-5 EXECUTE phase for UI/UX implementation, design review, and accessibility polish tasks.
1112

12-
**Read `process/context/all-context.md` first for context routing, then read `process/context/uxui/uiux.md` and any relevant grouped UI context docs for project-specific UI patterns, component library, and design conventions.** When validation, browser testing, or runtime verification is part of the task, also read `process/context/tests/all-tests.md` before deeper test docs.
13+
**Read `process/context/all-context.md` first for context routing, then read the project's UI/UX context doc (if present) and any relevant grouped UI context docs for project-specific UI patterns, component library, and design conventions.** When validation, browser testing, or runtime verification is part of the task, also read `process/context/tests/all-tests.md` before deeper test docs.
1314

1415
When the orchestrator passes `Work context`, `Feature`, `Reports`, `Plans`, or one exact selected plan file path, treat those as authoritative scope hints. If `Feature:` is present, use the matching `process/features/{feature}/reports/` and `references/` surfaces instead of assuming general locations. Treat direct `*_PLAN_*.md`, legacy `PLAN.md`, legacy `plan.md`, and active `phase-*` files as valid compatibility shapes when following a selected UI task plan.
1516

.claude/agents/vc-update-process-agent.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,11 @@ Location: [Where in file - section name or append location]
106106
- "No context updates needed" is only allowed if you name the reviewed files and give a concrete reason for each unchanged file/group.
107107
- Route changes to the correct file:
108108
- Context routing/grouping changes → `process/context/all-context.md`
109-
- Container/Docker/service changes → `flowser-container.md`
109+
- Container/Docker/service changes → the relevant container/runtime context doc
110110
- Test patterns/commands/frameworks → `process/context/tests/all-tests.md` or deeper `process/context/tests/*.md`
111111
- Architecture/API/conventions/env vars → `all-context.md`
112112
- UI/UX patterns/components → `uiux.md`
113-
- Skill runtime/app changes → `skill-apps.md` or `flowser-skills.md`
113+
- Skill runtime/app changes → the relevant skill-app or skill-system context doc
114114
- Workflow package changes → `cf-workflows.md`
115115
- Known bugs/tech debt → `process/general-plans/backlog/backlog.md` or `process/features/{feature}/backlog/`
116116
- New context file needed → create it in the owning group when one exists, otherwise root; update `process/context/all-context.md` and the owning `all-{group}.md`
@@ -265,13 +265,13 @@ For each approved improvement:
265265
|---|---|
266266
| `all-context.md` | Root context entrypoint, architecture, API surface, conventions, env vars, monorepo layout |
267267
| `tests/all-tests.md` | Testing quick-start, runner selection, commands, debugging procedures, and routing |
268-
| `flowser-container.md` | Docker container lifecycle, plugin deployment, local dev commands, service ports |
268+
| container context doc | Docker container lifecycle, plugin deployment, local dev commands, service ports |
269269
| `cf-workflows.md` | Cloudflare Workers workflow context and patterns |
270270
| `uiux.md` | UI/UX design patterns, component conventions, styling guidelines |
271271
| `example-simple-prd.md` | Reference template for simple plan structure |
272272
| `example-complex-prd.md` | Reference template for complex plan depth |
273273
| `tests/browser-automation.md` | Browser automation test patterns, `chrome-debug` workflows, and browser debugging |
274-
| `flowser-skills.md` | Flowser skill system context, skill.json format, deployment |
274+
| skill-system context doc | skill system context, skill.json format, deployment |
275275
| `infra.md` | Infrastructure context: VPS, Docker, deployment, networking |
276276
| `skill-apps.md` | Vite skill apps infrastructure, gateway proxy, supervisord lifecycle |
277277

.claude/hooks/lib/__tests__/statusline-scenarios.test.cjs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ function runStatuslineSync({ payload, cwd = TEST_ROOT, env = {}, inputRaw = null
101101
};
102102
if (!Object.prototype.hasOwnProperty.call(env, 'NO_COLOR')) delete runtimeEnv.NO_COLOR;
103103
scrubAnthropicRuntimeEnv(runtimeEnv, env);
104-
if (!Object.prototype.hasOwnProperty.call(env, 'HOME') && fs.existsSync(path.join(cwd, '.claude', '.ck.json'))) {
104+
if (!Object.prototype.hasOwnProperty.call(env, 'HOME')
105+
&& (fs.existsSync(path.join(cwd, '.claude', '.vc.json')) || fs.existsSync(path.join(cwd, '.claude', '.ck.json')))) {
105106
runtimeEnv.HOME = cwd;
106107
}
107108
const result = spawnSync('node', [STATUSLINE_PATH], {
@@ -133,7 +134,8 @@ function runStatuslineWithDelayedChunks({ chunks, delaysMs, cwd = TEST_ROOT, env
133134
};
134135
if (!Object.prototype.hasOwnProperty.call(env, 'NO_COLOR')) delete runtimeEnv.NO_COLOR;
135136
scrubAnthropicRuntimeEnv(runtimeEnv, env);
136-
if (!Object.prototype.hasOwnProperty.call(env, 'HOME') && fs.existsSync(path.join(cwd, '.claude', '.ck.json'))) {
137+
if (!Object.prototype.hasOwnProperty.call(env, 'HOME')
138+
&& (fs.existsSync(path.join(cwd, '.claude', '.vc.json')) || fs.existsSync(path.join(cwd, '.claude', '.ck.json')))) {
137139
runtimeEnv.HOME = cwd;
138140
}
139141
const child = spawn('node', [STATUSLINE_PATH], {
@@ -179,12 +181,12 @@ function runStatuslineWithDelayedChunks({ chunks, delaysMs, cwd = TEST_ROOT, env
179181
});
180182
}
181183

182-
function createTempConfigProject(mode, extraConfig = {}) {
184+
function createTempConfigProject(mode, extraConfig = {}, { configFileName = '.vc.json' } = {}) {
183185
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), `statusline-mode-${mode}-`));
184186
const ckDir = path.join(tmpDir, '.claude');
185187
fs.mkdirSync(ckDir, { recursive: true });
186188
fs.writeFileSync(
187-
path.join(ckDir, '.ck.json'),
189+
path.join(ckDir, configFileName),
188190
JSON.stringify({ statusline: mode, statuslineQuota: true, ...extraConfig }, null, 2)
189191
);
190192
return tmpDir;
@@ -327,6 +329,28 @@ async function main() {
327329
}
328330
});
329331

332+
await test('Legacy .ck.json-only config still loads via fallback', async () => {
333+
// Project has ONLY the legacy .ck.json (no .vc.json) — central loader fallback
334+
// must still resolve it so existing installs keep working.
335+
const tmpDir = createTempConfigProject('none', {}, { configFileName: '.ck.json' });
336+
try {
337+
const payload = {
338+
model: { display_name: 'Claude' },
339+
workspace: { current_dir: '/tmp' },
340+
context_window: { context_window_size: 200000 }
341+
};
342+
const result = runStatuslineSync({ payload, cwd: tmpDir });
343+
assertSuccessfulRun(result, 'Legacy .ck.json fallback scenario');
344+
const { stdout } = result;
345+
assertTrue(
346+
stdout.trim() === '',
347+
'Legacy .ck.json with mode none should still produce empty output via fallback'
348+
);
349+
} finally {
350+
fs.rmSync(tmpDir, { recursive: true, force: true });
351+
}
352+
});
353+
330354
await test('Mode minimal keeps output to one line', async () => {
331355
const tmpDir = createTempConfigProject('minimal');
332356
try {

.claude/hooks/lib/privacy-checker.cjs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -161,15 +161,17 @@ function extractPaths(toolInput) {
161161
}
162162

163163
/**
164-
* Load .ck.json config to check if privacy block is disabled
165-
* @param {string} [configDir] - Directory containing .ck.json (defaults to .claude in cwd)
164+
* Load .vc.json config to check if privacy block is disabled
165+
* @param {string} [configDir] - Directory containing .vc.json (defaults to .claude in cwd)
166166
* @returns {boolean} true if privacy block should be skipped
167167
*/
168168
function isPrivacyBlockDisabled(configDir) {
169169
try {
170-
const configPath = configDir
171-
? path.join(configDir, '.ck.json')
172-
: path.join(process.cwd(), '.claude', '.ck.json');
170+
const baseDir = configDir || path.join(process.cwd(), '.claude');
171+
// New-first, legacy (.ck.json) fallback for backward compatibility.
172+
const newPath = path.join(baseDir, '.vc.json');
173+
const legacyPath = path.join(baseDir, '.ck.json');
174+
const configPath = fs.existsSync(newPath) ? newPath : legacyPath;
173175
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
174176
return config.privacyBlock === false;
175177
} catch {
@@ -211,7 +213,7 @@ function buildPromptData(filePath) {
211213
* @param {Object} params.toolInput - Tool input with file_path, path, command, etc.
212214
* @param {Object} [params.options]
213215
* @param {boolean} [params.options.disabled] - Skip checks if true
214-
* @param {string} [params.options.configDir] - Directory for .ck.json config
216+
* @param {string} [params.options.configDir] - Directory for .vc.json config
215217
* @param {boolean} [params.options.allowBash] - Allow Bash tool without blocking (default: true)
216218
* @returns {{
217219
* blocked: boolean,

.claude/hooks/lib/scout-checker.cjs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,8 @@ function findGitRoot(startDir) {
145145
}
146146

147147
/**
148-
* Find an optional project-local .ckignore at the git root config directory.
148+
* Find an optional project-local .vcignore at the git root config directory.
149+
* Prefers .vcignore, falls back to legacy .ckignore for backward compatibility.
149150
* This keeps overrides stable regardless of the caller cwd inside the repo.
150151
*
151152
* @param {string} startDir - Directory to start searching from
@@ -156,8 +157,10 @@ function findProjectCkignore(startDir, configDirName) {
156157
if (!configDirName || typeof configDirName !== 'string') return null;
157158
const gitRoot = findGitRoot(startDir);
158159
if (!gitRoot) return null;
159-
const candidate = path.join(gitRoot, configDirName, '.ckignore');
160-
return fs.existsSync(candidate) ? candidate : null;
160+
const candidate = path.join(gitRoot, configDirName, '.vcignore');
161+
if (fs.existsSync(candidate)) return candidate;
162+
const legacyCandidate = path.join(gitRoot, configDirName, '.ckignore');
163+
return fs.existsSync(legacyCandidate) ? legacyCandidate : null;
161164
}
162165

163166
// ═══════════════════════════════════════════════════════════════════════════
@@ -171,10 +174,10 @@ function findProjectCkignore(startDir, configDirName) {
171174
* @param {string} params.toolName - Name of tool (Bash, Glob, Read, etc.)
172175
* @param {Object} params.toolInput - Tool input with file_path, path, pattern, command
173176
* @param {Object} [params.options]
174-
* @param {string} [params.options.ckignorePath] - Path to .ckignore file
175-
* @param {string} [params.options.projectCkignorePath] - Explicit project-local .ckignore path
177+
* @param {string} [params.options.ckignorePath] - Path to .vcignore file
178+
* @param {string} [params.options.projectCkignorePath] - Explicit project-local .vcignore path
176179
* @param {string} [params.options.claudeDir] - Path to .claude or .opencode directory
177-
* @param {string} [params.options.cwd] - Working directory used to discover a project .ckignore
180+
* @param {string} [params.options.cwd] - Working directory used to discover a project .vcignore
178181
* @param {string} [params.options.projectConfigDirName] - Git-root config dir for project-local overrides
179182
* @param {boolean} [params.options.checkBroadPatterns] - Check for overly broad glob patterns (default: true)
180183
* @returns {{
@@ -238,8 +241,14 @@ function checkScoutBlock({ toolName, toolInput, options = {} }) {
238241
}
239242
}
240243

241-
// Resolve .ckignore path
242-
const resolvedCkignorePath = ckignorePath || path.join(claudeDir, '.ckignore');
244+
// Resolve .vcignore path (new-first, legacy .ckignore fallback)
245+
const resolvedCkignorePath = ckignorePath || (
246+
fs.existsSync(path.join(claudeDir, '.vcignore'))
247+
? path.join(claudeDir, '.vcignore')
248+
: (fs.existsSync(path.join(claudeDir, '.ckignore'))
249+
? path.join(claudeDir, '.ckignore')
250+
: path.join(claudeDir, '.vcignore'))
251+
);
243252
const discoveredProjectCkignorePath = projectCkignorePath || findProjectCkignore(cwd, projectConfigDirName);
244253
const resolvedProjectCkignorePath = discoveredProjectCkignorePath
245254
&& path.resolve(discoveredProjectCkignorePath) !== path.resolve(resolvedCkignorePath)

.claude/hooks/lib/statusline-render-modes.cjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* Statusline render mode implementations: full / compact / minimal
55
*
66
* All rendering is config-driven via a resolved layout object (from resolveLayout()).
7-
* When no statuslineLayout is present in .ck.json, output is IDENTICAL to the
7+
* When no statuslineLayout is present in .vc.json, output is IDENTICAL to the
88
* pre-refactor hardcoded renderer — zero regression guarantee.
99
*
1010
* Mode function signatures: (ctx, layout) => void (writes via console.log)

.claude/hooks/lib/statusline-section-registry.cjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ function getSectionRenderer(id) {
128128
* Resolve effective layout from statuslineLayout config, falling back to defaults.
129129
* Supports both new lines[][] format and legacy sections[] format.
130130
* When statuslineLayout is undefined/null, returns defaults — identical pre-refactor behavior.
131-
* @param {Object|undefined} statuslineLayout - From .ck.json config
131+
* @param {Object|undefined} statuslineLayout - From .vc.json config
132132
* @returns {{ sections, theme, responsiveBreakpoint, maxAgentRows, todoTruncation }}
133133
*/
134134
function resolveLayout(statuslineLayout) {

0 commit comments

Comments
 (0)