@way_marks/cli 4.0.2 → 4.3.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.
@@ -0,0 +1,189 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.run = run;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const http = __importStar(require("http"));
40
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
41
+ function getPort() {
42
+ const projectRoot = process.cwd();
43
+ const configPath = path.join(projectRoot, '.waymark', 'config.json');
44
+ if (!fs.existsSync(configPath))
45
+ return null;
46
+ try {
47
+ const cfg = JSON.parse(fs.readFileSync(configPath, 'utf8'));
48
+ return cfg.port ?? null;
49
+ }
50
+ catch {
51
+ return null;
52
+ }
53
+ }
54
+ function fetchJson(url) {
55
+ return new Promise((resolve, reject) => {
56
+ const req = http.get(url, { headers: { Accept: 'application/json' } }, (res) => {
57
+ let data = '';
58
+ res.on('data', (chunk) => { data += chunk; });
59
+ res.on('end', () => {
60
+ try {
61
+ resolve(JSON.parse(data));
62
+ }
63
+ catch {
64
+ reject(new Error(`Invalid JSON from ${url}`));
65
+ }
66
+ });
67
+ });
68
+ req.setTimeout(3000, () => { req.destroy(); reject(new Error('Request timed out')); });
69
+ req.on('error', reject);
70
+ });
71
+ }
72
+ function ageStr(ms) {
73
+ const secs = Math.floor((Date.now() - ms) / 1000);
74
+ if (secs < 60)
75
+ return `${secs}s`;
76
+ if (secs < 3600)
77
+ return `${Math.floor(secs / 60)}m`;
78
+ return `${Math.floor(secs / 3600)}h`;
79
+ }
80
+ function pad(s, w) {
81
+ return s.length >= w ? s.slice(0, w) : s + ' '.repeat(w - s.length);
82
+ }
83
+ function statusIcon(status) {
84
+ switch (status) {
85
+ case 'thinking': return '🤔';
86
+ case 'waiting': return '⏳';
87
+ case 'done': return '✅';
88
+ case 'error': return '❌';
89
+ default: return '❔';
90
+ }
91
+ }
92
+ // ─── Parse args ───────────────────────────────────────────────────────────────
93
+ function parseArgs(argv) {
94
+ let agent = 'all';
95
+ let active = false;
96
+ let json = false;
97
+ let limit = 20;
98
+ for (let i = 0; i < argv.length; i++) {
99
+ if (argv[i] === '--agent' && argv[i + 1]) {
100
+ agent = argv[++i];
101
+ continue;
102
+ }
103
+ if (argv[i] === '--active') {
104
+ active = true;
105
+ continue;
106
+ }
107
+ if (argv[i] === '--json') {
108
+ json = true;
109
+ continue;
110
+ }
111
+ if (argv[i] === '--limit' && argv[i + 1]) {
112
+ limit = parseInt(argv[++i], 10) || 20;
113
+ continue;
114
+ }
115
+ }
116
+ return { agent, active, json, limit };
117
+ }
118
+ // ─── Main ─────────────────────────────────────────────────────────────────────
119
+ async function run() {
120
+ const args = parseArgs(process.argv.slice(3));
121
+ // Find port
122
+ const envPort = process.env.WAYMARK_PORT;
123
+ const port = envPort ? parseInt(envPort, 10) : getPort();
124
+ if (!port) {
125
+ console.error('Waymark not initialized. Run: npx @way_marks/cli init && npx @way_marks/cli start');
126
+ process.exit(1);
127
+ }
128
+ const base = `http://localhost:${port}/api/agent-monitor`;
129
+ let qs = '';
130
+ if (args.agent !== 'all')
131
+ qs += `agent=${encodeURIComponent(args.agent)}&`;
132
+ if (args.active)
133
+ qs += 'status=active&';
134
+ const url = `${base}/sessions${qs ? '?' + qs.replace(/&$/, '') : ''}`;
135
+ let data;
136
+ try {
137
+ data = await fetchJson(url);
138
+ }
139
+ catch (err) {
140
+ console.error(`Cannot reach Waymark server on port ${port}: ${err.message}`);
141
+ console.error('Start it with: npx @way_marks/cli start');
142
+ process.exit(1);
143
+ }
144
+ const sessions = data.sessions.slice(0, args.limit);
145
+ if (args.json) {
146
+ console.log(JSON.stringify(sessions, null, 2));
147
+ return;
148
+ }
149
+ if (sessions.length === 0) {
150
+ console.log('No agent sessions found.');
151
+ if (args.agent !== 'all')
152
+ console.log(`(filtered by --agent ${args.agent})`);
153
+ if (args.active)
154
+ console.log('(filtered by --active)');
155
+ return;
156
+ }
157
+ // ── Table output ─────────────────────────────────────────────────────────────
158
+ const COL = { agent: 8, pid: 7, status: 9, ctx: 7, tokens: 9, task: 32, age: 6 };
159
+ const header = [
160
+ pad('Agent', COL.agent),
161
+ pad('PID', COL.pid),
162
+ pad('Status', COL.status),
163
+ pad('Ctx %', COL.ctx),
164
+ pad('Tokens', COL.tokens),
165
+ pad('Current task', COL.task),
166
+ pad('Age', COL.age),
167
+ ].join(' ');
168
+ const divider = '─'.repeat(header.length);
169
+ console.log(`\nAgent sessions — ${data.count} total${args.limit < data.count ? ` (showing ${args.limit})` : ''}`);
170
+ console.log(divider);
171
+ console.log(header);
172
+ console.log(divider);
173
+ for (const s of sessions) {
174
+ const tokens = s.totalInputTokens + s.totalOutputTokens;
175
+ const task = s.currentTasks?.[0] ?? '—';
176
+ const row = [
177
+ pad(s.agentCli, COL.agent),
178
+ pad(String(s.pid), COL.pid),
179
+ `${statusIcon(s.status)} ${pad(s.status, COL.status - 2)}`,
180
+ pad(`${Math.round(s.contextPercent)}%`, COL.ctx),
181
+ pad(tokens > 0 ? String(tokens) : '—', COL.tokens),
182
+ pad(task.length > COL.task ? task.slice(0, COL.task - 1) + '…' : task, COL.task),
183
+ pad(ageStr(s.startedAt), COL.age),
184
+ ].join(' ');
185
+ console.log(row);
186
+ }
187
+ console.log(divider);
188
+ console.log(`Dashboard: http://localhost:${port}`);
189
+ }
@@ -47,7 +47,8 @@ const DEFAULT_CONFIG = {
47
47
  './src/**',
48
48
  './data/**',
49
49
  './README.md',
50
- './CLAUDE.md'
50
+ './CLAUDE.md',
51
+ './COPILOT.md'
51
52
  ],
52
53
  blockedPaths: [
53
54
  './.env',
@@ -152,6 +153,68 @@ function prompt(question) {
152
153
  rl.question(question, answer => { rl.close(); resolve(answer.trim()); });
153
154
  });
154
155
  }
156
+ function generateCopilotMd(projectName) {
157
+ return `---
158
+ # ⚠️ WAYMARK ACTIVE — MANDATORY INSTRUCTIONS
159
+
160
+ ## You are operating under Waymark agent control
161
+
162
+ Waymark is active in this project (${projectName}).
163
+ All file and shell operations MUST go through
164
+ Waymark MCP tools. No exceptions.
165
+
166
+ ## MANDATORY tool usage
167
+
168
+ You MUST replace ALL built-in file and shell
169
+ operations with Waymark MCP equivalents:
170
+
171
+ | Operation | Built-in (DO NOT USE) | Waymark (ALWAYS USE) |
172
+ |------------------------|-----------------------|----------------------|
173
+ | Write or edit a file | write_file | mcp__waymark-${projectName}__write_file |
174
+ | Read a file | read_file | mcp__waymark-${projectName}__read_file |
175
+ | Run shell commands | bash / run_command | mcp__waymark-${projectName}__bash |
176
+
177
+ This applies to ALL tasks in this project —
178
+ refactoring, creating files, running tests,
179
+ installing packages, git operations, everything.
180
+
181
+ ## What Waymark does with each action
182
+
183
+ - Allowed paths → executes normally, logged
184
+ - Blocked paths → stopped, you will see why
185
+ - Sensitive paths → held for human approval,
186
+ do not retry, tell the user to check dashboard
187
+
188
+ ## If a Waymark tool returns a block decision
189
+
190
+ Accept the block. Do not attempt to work around it
191
+ using built-in tools. Tell the user what was blocked
192
+ and why. Suggest they update waymark.config.json
193
+ if the block was unintended.
194
+
195
+ ## If Waymark MCP tools are unavailable
196
+
197
+ Do NOT fall back to built-in file tools.
198
+ Stop and tell the user:
199
+
200
+ "Waymark MCP server is not running for this project.
201
+ Please run in your terminal:
202
+ npx @way_marks/cli start
203
+
204
+ Then restart GitHub Copilot CLI and try again."
205
+
206
+ ## Dashboard
207
+
208
+ All actions are visible at: http://localhost:3001
209
+ Approve pending actions there.
210
+ Roll back any write there.
211
+
212
+ ## This file was generated by Waymark
213
+ Do not delete or modify this file.
214
+ It controls how GitHub Copilot CLI behaves in this project.
215
+ ---
216
+ `;
217
+ }
155
218
  function getClaudeDesktopConfigPath() {
156
219
  const platform = process.platform;
157
220
  if (platform === 'darwin') {
@@ -164,6 +227,10 @@ function getClaudeDesktopConfigPath() {
164
227
  return path.join(os.homedir(), '.config', 'Claude', 'claude_desktop_config.json');
165
228
  }
166
229
  }
230
+ /** Path to GitHub Copilot CLI's MCP config file. */
231
+ function getCopilotMcpConfigPath() {
232
+ return path.join(os.homedir(), '.copilot', 'mcp-config.json');
233
+ }
167
234
  function resolveServerBin() {
168
235
  try {
169
236
  return require.resolve('@way_marks/server/dist/mcp/server.js');
@@ -180,8 +247,8 @@ async function selectPlatforms() {
180
247
  console.log('│ 1. Claude Desktop / Claude Code (RECOMMENDED) ✓ │');
181
248
  console.log('│ → Best experience. Full Waymark features. │');
182
249
  console.log('│ │');
183
- console.log('│ 2. GitHub Copilot CLI (EXPERIMENTAL) ⚠ │');
184
- console.log('│ → Terminal support. CLI-only (no VSCode). │');
250
+ console.log('│ 2. GitHub Copilot CLI │');
251
+ console.log('│ → MCP-native. Full monitoring + policy control. │');
185
252
  console.log('│ │');
186
253
  console.log('│ 3. Both (Claude + GitHub Copilot CLI) │');
187
254
  console.log('│ → Setup for both. Easy to switch. │');
@@ -298,8 +365,8 @@ async function run() {
298
365
  console.log('✓ .gitignore already up to date');
299
366
  }
300
367
  // Step 6 — Register MCP in both Claude configs (only if Claude selected)
368
+ const nodeBin = process.execPath;
301
369
  if (selectedPlatforms.includes('claude')) {
302
- const nodeBin = process.execPath;
303
370
  const mcpEntry = {
304
371
  command: nodeBin,
305
372
  args: [serverBin, '--project-root', projectRoot, '--db-path', dbPath]
@@ -341,21 +408,53 @@ async function run() {
341
408
  else {
342
409
  console.log('⊘ Skipping MCP registration (Claude not selected)');
343
410
  }
344
- // Step 6b — Show Copilot CLI instructions (if Copilot CLI selected)
411
+ // Step 6b — Register Copilot CLI MCP + generate COPILOT.md (if Copilot CLI selected)
345
412
  if (selectedPlatforms.includes('copilot-cli')) {
346
- console.log('');
347
- console.log('📋 GitHub Copilot CLI Setup');
348
- console.log('─'.repeat(50));
349
- console.log('⚠️ Copilot CLI support requires manual setup.');
350
- console.log('See COPILOT_CLI.md for step-by-step instructions.');
351
- console.log('');
352
- console.log('Quick start:');
353
- console.log('1. Find copilot binary: which copilot');
354
- console.log('2. Run: npx @way_marks/cli init-copilot-wrapper');
355
- console.log('3. Test: copilot --version');
356
- console.log('');
413
+ // Register in ~/.copilot/mcp-config.json (user-level, applies to all projects)
414
+ const copilotMcpPath = getCopilotMcpConfigPath();
415
+ try {
416
+ const copilotMcpDir = path.dirname(copilotMcpPath);
417
+ if (!fs.existsSync(copilotMcpDir))
418
+ fs.mkdirSync(copilotMcpDir, { recursive: true });
419
+ const copilotMcpConfig = fs.existsSync(copilotMcpPath)
420
+ ? JSON.parse(fs.readFileSync(copilotMcpPath, 'utf8'))
421
+ : { mcpServers: {} };
422
+ if (!copilotMcpConfig.mcpServers)
423
+ copilotMcpConfig.mcpServers = {};
424
+ copilotMcpConfig.mcpServers[mcpKey] = {
425
+ type: 'local',
426
+ command: nodeBin,
427
+ args: [serverBin, '--project-root', projectRoot, '--db-path', dbPath],
428
+ tools: ['*'],
429
+ };
430
+ fs.writeFileSync(copilotMcpPath, JSON.stringify(copilotMcpConfig, null, 2) + '\n');
431
+ console.log(`✓ Registered MCP server "${mcpKey}" in ~/.copilot/mcp-config.json`);
432
+ }
433
+ catch (err) {
434
+ console.warn(`Warning: Could not update Copilot CLI MCP config: ${err.message}`);
435
+ }
436
+ // Generate COPILOT.md (like CLAUDE.md — tells Copilot CLI to use Waymark tools)
437
+ const copilotMdPath = path.join(projectRoot, 'COPILOT.md');
438
+ const copilotMdContent = generateCopilotMd(projectName);
439
+ if (fs.existsSync(copilotMdPath)) {
440
+ const existing = fs.readFileSync(copilotMdPath, 'utf8');
441
+ if (existing.includes(WAYMARK_MARKER)) {
442
+ console.log('✓ COPILOT.md already has Waymark section');
443
+ }
444
+ else {
445
+ fs.appendFileSync(copilotMdPath, `\n${WAYMARK_MARKER}\n${copilotMdContent}`);
446
+ console.log('✓ Appended Waymark section to COPILOT.md');
447
+ }
448
+ }
449
+ else {
450
+ fs.writeFileSync(copilotMdPath, `${WAYMARK_MARKER}\n${copilotMdContent}`);
451
+ console.log('✓ Created COPILOT.md — GitHub Copilot CLI will now use Waymark automatically');
452
+ }
453
+ }
454
+ else {
455
+ console.log('⊘ Skipping Copilot CLI registration (not selected)');
357
456
  }
358
- // Step 7 — Success summary (updated for platform selection)
457
+ // Step 7 — Success summary
359
458
  const col = 50;
360
459
  const pad = (s) => s + ' '.repeat(Math.max(0, col - 2 - s.length));
361
460
  console.log('');
@@ -367,12 +466,14 @@ async function run() {
367
466
  console.log(`│ ${pad(`Platforms: ${selectedPlatforms.join(', ')}`)} │`);
368
467
  console.log(`│ ${pad('')} │`);
369
468
  console.log(`│ ${pad('Files created:')} │`);
370
- console.log(`│ ${pad(' waymark.config.json (with platforms)')} │`);
469
+ console.log(`│ ${pad(' waymark.config.json')} │`);
371
470
  if (selectedPlatforms.includes('claude')) {
372
471
  console.log(`│ ${pad(' CLAUDE.md')} │`);
472
+ console.log(`│ ${pad(' .mcp.json')} │`);
373
473
  }
374
474
  if (selectedPlatforms.includes('copilot-cli')) {
375
- console.log(`│ ${pad(' (see COPILOT_CLI.md setup)')} │`);
475
+ console.log(`│ ${pad(' COPILOT.md')} │`);
476
+ console.log(`│ ${pad(' ~/.copilot/mcp-config.json (updated)')} │`);
376
477
  }
377
478
  console.log(`│ ${pad(' .waymark/ (gitignored)')} │`);
378
479
  console.log(`│ ${pad('')} │`);
@@ -388,7 +489,9 @@ async function run() {
388
489
  console.log(`│ ${pad('')} │`);
389
490
  }
390
491
  console.log(`│ ${pad('Next steps (Copilot CLI):')} │`);
391
- console.log(`│ ${pad('1. See COPILOT_CLI.md for wrapper setup')} │`);
492
+ console.log(`│ ${pad('1. Run: npx @way_marks/cli start')} │`);
493
+ console.log(`│ ${pad('2. Restart GitHub Copilot CLI')} │`);
494
+ console.log(`│ ${pad('3. Open project with: copilot')} │`);
392
495
  }
393
496
  console.log(`│ ${pad('')} │`);
394
497
  console.log(`│ ${pad('For more info:')} │`);
package/dist/index.js CHANGED
@@ -29,6 +29,7 @@ function printHelp() {
29
29
  console.log(' resume Resume a paused project');
30
30
  console.log(' status Show current Waymark status and pending count');
31
31
  console.log(' logs Show recent action log');
32
+ console.log(' agents List running AI agent sessions');
32
33
  console.log(' list List all registered Waymark projects');
33
34
  console.log(' open Open a project dashboard or start it');
34
35
  console.log('');
@@ -74,6 +75,9 @@ switch (command) {
74
75
  case 'logs':
75
76
  require('./commands/logs').run();
76
77
  break;
78
+ case 'agents':
79
+ require('./commands/agents').run();
80
+ break;
77
81
  case 'list':
78
82
  require('./commands/list').run();
79
83
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@way_marks/cli",
3
- "version": "4.0.2",
3
+ "version": "4.3.0",
4
4
  "description": "Control what AI agents can do in your codebase",
5
5
  "author": "Waymark <hello@waymarks.dev>",
6
6
  "license": "MIT",
@@ -43,7 +43,7 @@
43
43
  ]
44
44
  },
45
45
  "dependencies": {
46
- "@way_marks/server": "4.0.2"
46
+ "@way_marks/server": "4.3.0"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@types/jest": "^30.0.0",