@whenlabs/when 0.9.2 → 0.9.3
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 +6 -2
- package/dist/chunk-2A2EZZF4.js +19 -0
- package/dist/index.js +30 -32
- package/dist/install-V24JHOA2.js +183 -0
- package/dist/mcp.js +630 -597
- package/package.json +2 -1
- package/templates/statusline.py +311 -0
- package/dist/install-F46OPKIA.js +0 -484
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
A single installable toolkit that brings six WhenLabs developer tools into your Claude Code / AI coding agent workflow. Once installed, all tools are available as MCP tools in every session — Claude uses them automatically when relevant.
|
|
6
6
|
|
|
7
|
+
Five tools (stale, envalid, berth, aware, vow) have CLI scan modes and run on a schedule. Velocity is the sixth tool — it is always-on and embedded (SQLite-backed), so it does not have a CLI scan mode and does not appear in `doctor`/`watch`/`init`/`ci` output.
|
|
8
|
+
|
|
7
9
|
## Install
|
|
8
10
|
|
|
9
11
|
```bash
|
|
@@ -61,6 +63,8 @@ These tools are available to Claude in every session after install:
|
|
|
61
63
|
| `vow_check` | Validate licenses against policy |
|
|
62
64
|
| `vow_hook_install` | Install pre-commit license check hook |
|
|
63
65
|
|
|
66
|
+
> This table shows a highlights subset. Run `when <tool> --help` for all available commands per tool.
|
|
67
|
+
|
|
64
68
|
## Multi-Editor Support
|
|
65
69
|
|
|
66
70
|
Install MCP servers into other editors alongside Claude Code:
|
|
@@ -98,7 +102,7 @@ when ci # Run checks for CI (exits 1 on issues)
|
|
|
98
102
|
|
|
99
103
|
### `when init`
|
|
100
104
|
|
|
101
|
-
One command to onboard any project. Auto-detects your stack, runs all 5 tools in parallel, generates AI context files if missing, and shows a summary with next steps.
|
|
105
|
+
One command to onboard any project. Auto-detects your stack, runs all 5 CLI tools in parallel, generates AI context files if missing, and shows a summary with next steps.
|
|
102
106
|
|
|
103
107
|
### `when doctor`
|
|
104
108
|
|
|
@@ -106,7 +110,7 @@ Runs all 5 CLI tools against the current project and displays a unified health r
|
|
|
106
110
|
|
|
107
111
|
### `when watch`
|
|
108
112
|
|
|
109
|
-
Background daemon that runs all 5 tools on intervals and writes results to `~/.whenlabs/status.json`. Powers the Claude Code status line integration. Use `--once` for a single scan or `--interval <seconds>` to customize the schedule.
|
|
113
|
+
Background daemon that runs all 5 CLI tools on intervals and writes results to `~/.whenlabs/status.json`. Powers the Claude Code status line integration. Use `--once` for a single scan or `--interval <seconds>` to customize the schedule.
|
|
110
114
|
|
|
111
115
|
### `when ci`
|
|
112
116
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/utils/find-bin.ts
|
|
4
|
+
import { resolve, dirname } from "path";
|
|
5
|
+
import { existsSync } from "fs";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
|
+
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
function findBin(name) {
|
|
9
|
+
const pkgRoot = resolve(__dirname, "../..");
|
|
10
|
+
const localBin = resolve(pkgRoot, "node_modules", ".bin", name);
|
|
11
|
+
if (existsSync(localBin)) return localBin;
|
|
12
|
+
const directCli = resolve(pkgRoot, "node_modules", "@whenlabs", name, "dist", "cli.js");
|
|
13
|
+
if (existsSync(directCli)) return directCli;
|
|
14
|
+
return name;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export {
|
|
18
|
+
findBin
|
|
19
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
findBin
|
|
4
|
+
} from "./chunk-2A2EZZF4.js";
|
|
2
5
|
import {
|
|
3
6
|
getStatusPath
|
|
4
7
|
} from "./chunk-4ZVSCJCJ.js";
|
|
@@ -9,16 +12,6 @@ import { Command as Command5 } from "commander";
|
|
|
9
12
|
// src/commands/delegate.ts
|
|
10
13
|
import { Command } from "commander";
|
|
11
14
|
import { spawn } from "child_process";
|
|
12
|
-
import { resolve, dirname } from "path";
|
|
13
|
-
import { existsSync } from "fs";
|
|
14
|
-
import { fileURLToPath } from "url";
|
|
15
|
-
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
16
|
-
function findBin(name) {
|
|
17
|
-
const pkgRoot = resolve(__dirname, "..");
|
|
18
|
-
const localBin = resolve(pkgRoot, "node_modules", ".bin", name);
|
|
19
|
-
if (existsSync(localBin)) return localBin;
|
|
20
|
-
return name;
|
|
21
|
-
}
|
|
22
15
|
function createDelegateCommand(name, description, binName) {
|
|
23
16
|
const cmd = new Command(name);
|
|
24
17
|
cmd.description(description);
|
|
@@ -53,14 +46,14 @@ import { Command as Command2 } from "commander";
|
|
|
53
46
|
|
|
54
47
|
// src/utils/tool-runner.ts
|
|
55
48
|
import { spawn as spawn2 } from "child_process";
|
|
56
|
-
import { resolve
|
|
57
|
-
import { existsSync
|
|
58
|
-
import { fileURLToPath
|
|
59
|
-
var
|
|
49
|
+
import { resolve, dirname } from "path";
|
|
50
|
+
import { existsSync } from "fs";
|
|
51
|
+
import { fileURLToPath } from "url";
|
|
52
|
+
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
60
53
|
function findBin2(name) {
|
|
61
|
-
const pkgRoot =
|
|
62
|
-
const localBin =
|
|
63
|
-
if (
|
|
54
|
+
const pkgRoot = resolve(__dirname, "..", "..");
|
|
55
|
+
const localBin = resolve(pkgRoot, "node_modules", ".bin", name);
|
|
56
|
+
if (existsSync(localBin)) return localBin;
|
|
64
57
|
return name;
|
|
65
58
|
}
|
|
66
59
|
function runTool(bin, args) {
|
|
@@ -303,10 +296,10 @@ function createDoctorCommand() {
|
|
|
303
296
|
// src/commands/init.ts
|
|
304
297
|
import { Command as Command3 } from "commander";
|
|
305
298
|
import { spawn as spawn3 } from "child_process";
|
|
306
|
-
import { resolve as
|
|
307
|
-
import { existsSync as
|
|
308
|
-
import { fileURLToPath as
|
|
309
|
-
var
|
|
299
|
+
import { resolve as resolve2, dirname as dirname2, basename } from "path";
|
|
300
|
+
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
301
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
302
|
+
var __dirname2 = dirname2(fileURLToPath2(import.meta.url));
|
|
310
303
|
var c2 = {
|
|
311
304
|
reset: "\x1B[0m",
|
|
312
305
|
bold: "\x1B[1m",
|
|
@@ -320,15 +313,15 @@ function colorize2(text, ...codes) {
|
|
|
320
313
|
return codes.join("") + text + c2.reset;
|
|
321
314
|
}
|
|
322
315
|
function findBin3(name) {
|
|
323
|
-
const pkgRoot =
|
|
324
|
-
const localBin =
|
|
325
|
-
if (
|
|
316
|
+
const pkgRoot = resolve2(__dirname2, "..");
|
|
317
|
+
const localBin = resolve2(pkgRoot, "node_modules", ".bin", name);
|
|
318
|
+
if (existsSync2(localBin)) return localBin;
|
|
326
319
|
return name;
|
|
327
320
|
}
|
|
328
321
|
function detectProject(cwd) {
|
|
329
322
|
let name = basename(cwd);
|
|
330
|
-
const pkgPath =
|
|
331
|
-
if (
|
|
323
|
+
const pkgPath = resolve2(cwd, "package.json");
|
|
324
|
+
if (existsSync2(pkgPath)) {
|
|
332
325
|
try {
|
|
333
326
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
334
327
|
if (pkg.name) name = pkg.name;
|
|
@@ -349,7 +342,7 @@ function detectProject(cwd) {
|
|
|
349
342
|
];
|
|
350
343
|
const stacks = [];
|
|
351
344
|
for (const [file, stack] of stackFiles) {
|
|
352
|
-
if (
|
|
345
|
+
if (existsSync2(resolve2(cwd, file)) && !stacks.includes(stack)) {
|
|
353
346
|
stacks.push(stack);
|
|
354
347
|
}
|
|
355
348
|
}
|
|
@@ -423,7 +416,7 @@ async function scanVow(cwd) {
|
|
|
423
416
|
}
|
|
424
417
|
}
|
|
425
418
|
async function scanAware(cwd) {
|
|
426
|
-
const hasConfig =
|
|
419
|
+
const hasConfig = existsSync2(resolve2(cwd, ".aware.json"));
|
|
427
420
|
if (!hasConfig) {
|
|
428
421
|
const { exitCode: exitCode2 } = await runTool2(findBin3("aware"), ["init"]);
|
|
429
422
|
if (exitCode2 === 0) return { label: "AI context (aware)", status: "ok", detail: "Generated .aware.json and context files" };
|
|
@@ -488,7 +481,7 @@ function createInitCommand() {
|
|
|
488
481
|
}
|
|
489
482
|
console.log("");
|
|
490
483
|
console.log(colorize2(" Next steps:", c2.bold));
|
|
491
|
-
const mcpInstalled =
|
|
484
|
+
const mcpInstalled = existsSync2(resolve2(process.env.HOME ?? "~", ".claude", "settings.json"));
|
|
492
485
|
if (!mcpInstalled) {
|
|
493
486
|
console.log(` ${colorize2("\u2022", c2.cyan)} Run ${colorize2("when install", c2.bold)} to connect MCP tools to Claude Code`);
|
|
494
487
|
}
|
|
@@ -549,7 +542,7 @@ function sleep(ms) {
|
|
|
549
542
|
}
|
|
550
543
|
function createWatchCommand() {
|
|
551
544
|
const cmd = new Command4("watch");
|
|
552
|
-
cmd.description("Run all 5
|
|
545
|
+
cmd.description("Run all 5 CLI tools on a schedule and write results to ~/.whenlabs/status.json (velocity is embedded and always-on \u2014 it does not participate in scheduled scans)");
|
|
553
546
|
cmd.option("--once", "Run a single scan and exit");
|
|
554
547
|
cmd.option("--interval <seconds>", "Override the default scan interval (seconds)", "60");
|
|
555
548
|
cmd.action(async (options) => {
|
|
@@ -593,10 +586,15 @@ function createWatchCommand() {
|
|
|
593
586
|
}
|
|
594
587
|
|
|
595
588
|
// src/index.ts
|
|
589
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
590
|
+
import { resolve as resolve3, dirname as dirname3 } from "path";
|
|
591
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
592
|
+
var __dirname3 = dirname3(fileURLToPath3(import.meta.url));
|
|
593
|
+
var { version } = JSON.parse(readFileSync2(resolve3(__dirname3, "..", "package.json"), "utf8"));
|
|
596
594
|
var program = new Command5();
|
|
597
|
-
program.name("when").version(
|
|
595
|
+
program.name("when").version(version).description("The WhenLabs developer toolkit \u2014 6 tools, one install");
|
|
598
596
|
program.command("install").description("Install all WhenLabs tools globally (MCP server + CLAUDE.md instructions)").option("--cursor", "Install MCP servers into Cursor (~/.cursor/mcp.json)").option("--vscode", "Install MCP servers into VS Code (settings.json)").option("--windsurf", "Install MCP servers into Windsurf (~/.codeium/windsurf/mcp_config.json)").option("--all", "Install MCP servers into all supported editors").action(async (options) => {
|
|
599
|
-
const { install } = await import("./install-
|
|
597
|
+
const { install } = await import("./install-V24JHOA2.js");
|
|
600
598
|
await install(options);
|
|
601
599
|
});
|
|
602
600
|
program.command("uninstall").description("Remove all WhenLabs tools").option("--cursor", "Remove MCP servers from Cursor").option("--vscode", "Remove MCP servers from VS Code").option("--windsurf", "Remove MCP servers from Windsurf").option("--all", "Remove MCP servers from all supported editors").action(async (options) => {
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
ALL_EDITORS,
|
|
4
|
+
installForEditor,
|
|
5
|
+
registerMcpServer
|
|
6
|
+
} from "./chunk-3PDLNC63.js";
|
|
7
|
+
import {
|
|
8
|
+
injectBlock
|
|
9
|
+
} from "./chunk-NYUYV3UL.js";
|
|
10
|
+
|
|
11
|
+
// src/commands/install.ts
|
|
12
|
+
import { join, resolve, dirname } from "path";
|
|
13
|
+
import { homedir } from "os";
|
|
14
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, chmodSync } from "fs";
|
|
15
|
+
import { execFileSync } from "child_process";
|
|
16
|
+
import { fileURLToPath } from "url";
|
|
17
|
+
|
|
18
|
+
// src/templates/claude-md-content.ts
|
|
19
|
+
var CLAUDE_MD_CONTENT = `# WhenLabs Toolkit
|
|
20
|
+
|
|
21
|
+
## Task Timing (velocity-mcp)
|
|
22
|
+
|
|
23
|
+
Velocity tools are part of the unified \`whenlabs\` MCP server. Follow these rules for EVERY session:
|
|
24
|
+
|
|
25
|
+
1. **Before starting any discrete coding task**, call \`velocity_start_task\` with:
|
|
26
|
+
- Appropriate \`category\` (scaffold, implement, refactor, debug, test, config, docs, deploy)
|
|
27
|
+
- Relevant \`tags\` (e.g. typescript, react, sqlite, api)
|
|
28
|
+
- Clear \`description\` of what you're about to do
|
|
29
|
+
- \`estimated_files\` if you know how many files you'll touch
|
|
30
|
+
- \`project\` set to the current project name (auto-detected from git remote or directory name)
|
|
31
|
+
|
|
32
|
+
2. **After completing each task**, call \`velocity_end_task\` with:
|
|
33
|
+
- The \`task_id\` from the start call
|
|
34
|
+
- \`status\`: completed, failed, or abandoned
|
|
35
|
+
- \`actual_files\`: how many files were actually modified
|
|
36
|
+
- \`notes\`: any useful context about what happened
|
|
37
|
+
|
|
38
|
+
3. **When creating a multi-step plan**, call \`velocity_estimate\` to provide the user with a time estimate before starting work.
|
|
39
|
+
|
|
40
|
+
4. **If the user asks about speed or performance**, call \`velocity_stats\` to show aggregate data.
|
|
41
|
+
|
|
42
|
+
### Guidelines
|
|
43
|
+
- Every discrete unit of work should be tracked \u2014 don't batch multiple unrelated changes into one task
|
|
44
|
+
- If a task is abandoned or fails, still call \`velocity_end_task\` with the appropriate status
|
|
45
|
+
- Use consistent tags across sessions so the similarity matching can find comparable historical tasks
|
|
46
|
+
- Keep descriptions concise but specific enough to be useful for future matching
|
|
47
|
+
|
|
48
|
+
## WhenLabs MCP Tools (ALWAYS prefer these over shell commands)
|
|
49
|
+
|
|
50
|
+
All six tools (including velocity) are available through the unified \`whenlabs\` MCP server. **ALWAYS use these MCP tools instead of running shell commands like lsof, grep, or manual checks.** These tools are purpose-built and give better results:
|
|
51
|
+
|
|
52
|
+
| When to use | Call this tool | NOT this |
|
|
53
|
+
|-------------|---------------|----------|
|
|
54
|
+
| Check ports or port conflicts | \`berth_status\` or \`berth_check\` | \`lsof\`, \`netstat\`, \`ss\` |
|
|
55
|
+
| Scan dependency licenses | \`vow_scan\` or \`vow_check\` | manual \`npm ls\`, \`license-checker\` |
|
|
56
|
+
| Check if docs are stale | \`stale_scan\` | manual file comparison |
|
|
57
|
+
| Validate .env files | \`envalid_validate\` or \`envalid_detect\` | manual .env inspection |
|
|
58
|
+
| Generate AI context files | \`aware_init\` or \`aware_doctor\` | manual CLAUDE.md creation |
|
|
59
|
+
|
|
60
|
+
### Tool Reference
|
|
61
|
+
- \`berth_status\` \u2014 Show all active ports, Docker ports, and configured ports
|
|
62
|
+
- \`berth_check\` \u2014 Scan a project directory for port conflicts
|
|
63
|
+
- \`stale_scan\` \u2014 Detect documentation drift in the codebase
|
|
64
|
+
- \`envalid_validate\` \u2014 Validate .env files against their schema
|
|
65
|
+
- \`envalid_detect\` \u2014 Find undocumented env vars in codebase
|
|
66
|
+
- \`aware_init\` \u2014 Auto-detect stack and generate AI context files
|
|
67
|
+
- \`aware_doctor\` \u2014 Diagnose project health and config issues
|
|
68
|
+
- \`vow_scan\` \u2014 Scan and summarize all dependency licenses
|
|
69
|
+
- \`vow_check\` \u2014 Validate licenses against a policy file
|
|
70
|
+
|
|
71
|
+
### Proactive Background Scans
|
|
72
|
+
WhenLabs tools run automatically in the background on a schedule. The status line shows findings:
|
|
73
|
+
- \`stale:N\` \u2014 N docs have drifted from code. Run \`stale_scan\` and fix the drift.
|
|
74
|
+
- \`env:N\` \u2014 N .env issues found. Run \`envalid_validate\` and help the user fix them.
|
|
75
|
+
- \`ports:N\` \u2014 N port conflicts. Run \`berth_status\` and suggest resolution.
|
|
76
|
+
- \`lic:N?\` \u2014 N packages with unknown licenses. Run \`vow_scan\` for details.
|
|
77
|
+
- \`aware:stale\` \u2014 AI context files are outdated. Run \`aware_init\` to regenerate.
|
|
78
|
+
|
|
79
|
+
**When you see any of these in the status line, proactively tell the user and offer to fix the issue.** Do not wait for the user to ask.`;
|
|
80
|
+
|
|
81
|
+
// src/commands/install.ts
|
|
82
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
83
|
+
var __dirname = dirname(__filename);
|
|
84
|
+
var CLAUDE_MD_PATH = join(homedir(), ".claude", "CLAUDE.md");
|
|
85
|
+
var SCRIPTS_DIR = join(homedir(), ".claude", "scripts");
|
|
86
|
+
var STATUSLINE_PATH = join(SCRIPTS_DIR, "statusline.py");
|
|
87
|
+
var SETTINGS_PATH = join(homedir(), ".claude", "settings.json");
|
|
88
|
+
var OLD_START_MARKER = "<!-- velocity-mcp:start -->";
|
|
89
|
+
var OLD_END_MARKER = "<!-- velocity-mcp:end -->";
|
|
90
|
+
var STATUSLINE_SCRIPT = readFileSync(
|
|
91
|
+
resolve(__dirname, "..", "templates", "statusline.py"),
|
|
92
|
+
"utf-8"
|
|
93
|
+
);
|
|
94
|
+
function installStatusLine() {
|
|
95
|
+
try {
|
|
96
|
+
mkdirSync(SCRIPTS_DIR, { recursive: true });
|
|
97
|
+
writeFileSync(STATUSLINE_PATH, STATUSLINE_SCRIPT, "utf-8");
|
|
98
|
+
chmodSync(STATUSLINE_PATH, 493);
|
|
99
|
+
let settings = {};
|
|
100
|
+
if (existsSync(SETTINGS_PATH)) {
|
|
101
|
+
try {
|
|
102
|
+
settings = JSON.parse(readFileSync(SETTINGS_PATH, "utf-8"));
|
|
103
|
+
} catch {
|
|
104
|
+
settings = {};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const statuslineCmd = `python3 ${STATUSLINE_PATH}`;
|
|
108
|
+
const currentCmd = settings.statusLine?.command;
|
|
109
|
+
if (currentCmd !== statuslineCmd) {
|
|
110
|
+
settings.statusLine = { type: "command", command: statuslineCmd };
|
|
111
|
+
writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2) + "\n", "utf-8");
|
|
112
|
+
}
|
|
113
|
+
return { installed: true, message: "Status line installed (proactive background scans)" };
|
|
114
|
+
} catch (err) {
|
|
115
|
+
return { installed: false, message: `Status line install failed: ${err.message}` };
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function escapeRegex(str) {
|
|
119
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
120
|
+
}
|
|
121
|
+
function hasOldBlock(filePath) {
|
|
122
|
+
if (!existsSync(filePath)) return false;
|
|
123
|
+
const content = readFileSync(filePath, "utf-8");
|
|
124
|
+
return content.includes(OLD_START_MARKER) && content.includes(OLD_END_MARKER);
|
|
125
|
+
}
|
|
126
|
+
function removeOldBlock(filePath) {
|
|
127
|
+
if (!existsSync(filePath)) return;
|
|
128
|
+
let content = readFileSync(filePath, "utf-8");
|
|
129
|
+
const pattern = new RegExp(
|
|
130
|
+
`\\n?${escapeRegex(OLD_START_MARKER)}[\\s\\S]*?${escapeRegex(OLD_END_MARKER)}\\n?`,
|
|
131
|
+
"g"
|
|
132
|
+
);
|
|
133
|
+
content = content.replace(pattern, "\n").replace(/\n{3,}/g, "\n\n").trimEnd() + "\n";
|
|
134
|
+
writeFileSync(filePath, content, "utf-8");
|
|
135
|
+
}
|
|
136
|
+
async function install(options = {}) {
|
|
137
|
+
console.log("\n\u{1F527} WhenLabs toolkit installer\n");
|
|
138
|
+
const editorFlags = options.all ? ALL_EDITORS : [
|
|
139
|
+
options.cursor && "cursor",
|
|
140
|
+
options.vscode && "vscode",
|
|
141
|
+
options.windsurf && "windsurf"
|
|
142
|
+
].filter(Boolean);
|
|
143
|
+
const claudeOnly = editorFlags.length === 0;
|
|
144
|
+
if (claudeOnly) {
|
|
145
|
+
const mcpResult = registerMcpServer();
|
|
146
|
+
console.log(mcpResult.success ? ` \u2713 ${mcpResult.message}` : ` \u2717 ${mcpResult.message}`);
|
|
147
|
+
injectBlock(CLAUDE_MD_PATH, CLAUDE_MD_CONTENT);
|
|
148
|
+
console.log(` \u2713 CLAUDE.md instructions written to ${CLAUDE_MD_PATH}`);
|
|
149
|
+
const slResult = installStatusLine();
|
|
150
|
+
console.log(slResult.installed ? ` \u2713 ${slResult.message}` : ` \u2717 ${slResult.message}`);
|
|
151
|
+
try {
|
|
152
|
+
const cwd = process.cwd();
|
|
153
|
+
execFileSync("npx", ["--yes", "@whenlabs/aware", "init", "--force"], {
|
|
154
|
+
cwd,
|
|
155
|
+
stdio: "pipe",
|
|
156
|
+
env: { ...process.env, FORCE_COLOR: "0", NO_COLOR: "1" },
|
|
157
|
+
timeout: 3e4
|
|
158
|
+
});
|
|
159
|
+
execFileSync("npx", ["--yes", "@whenlabs/aware", "sync"], {
|
|
160
|
+
cwd,
|
|
161
|
+
stdio: "pipe",
|
|
162
|
+
env: { ...process.env, FORCE_COLOR: "0", NO_COLOR: "1" },
|
|
163
|
+
timeout: 3e4
|
|
164
|
+
});
|
|
165
|
+
console.log(" \u2713 AI context files generated and synced (aware init + sync)");
|
|
166
|
+
} catch {
|
|
167
|
+
console.log(" - Skipped aware init (run `when aware init` in a project directory)");
|
|
168
|
+
}
|
|
169
|
+
if (hasOldBlock(CLAUDE_MD_PATH)) {
|
|
170
|
+
removeOldBlock(CLAUDE_MD_PATH);
|
|
171
|
+
console.log(" \u2713 Removed legacy velocity-mcp markers (migrated to whenlabs block)");
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
for (const editor of editorFlags) {
|
|
175
|
+
const result = installForEditor(editor);
|
|
176
|
+
console.log(result.success ? ` \u2713 ${result.message}` : ` \u2717 ${result.message}`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
console.log("\nInstallation complete. Run `when status` to verify.\n");
|
|
180
|
+
}
|
|
181
|
+
export {
|
|
182
|
+
install
|
|
183
|
+
};
|