@way_marks/cli 0.4.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 +213 -0
- package/dist/commands/init.js +325 -0
- package/dist/commands/logs.js +80 -0
- package/dist/commands/start.js +168 -0
- package/dist/commands/status.js +89 -0
- package/dist/commands/stop.js +75 -0
- package/dist/index.js +30 -0
- package/package.json +40 -0
package/README.md
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# Waymark
|
|
2
|
+
|
|
3
|
+
**Control what AI agents can do in your codebase.**
|
|
4
|
+
|
|
5
|
+
Waymark sits between your team and any AI agent.
|
|
6
|
+
Every file action is intercepted, logged, and checked
|
|
7
|
+
against your policies before it executes.
|
|
8
|
+
Dangerous commands are blocked. Sensitive paths
|
|
9
|
+
require human approval. Everything is reversible.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## The Problem
|
|
14
|
+
|
|
15
|
+
AI agents like Claude Code are powerful.
|
|
16
|
+
They can also write to your .env, run rm -rf,
|
|
17
|
+
or modify your database schema without asking.
|
|
18
|
+
|
|
19
|
+
You find out after it happens.
|
|
20
|
+
|
|
21
|
+
## The Solution
|
|
22
|
+
|
|
23
|
+
Waymark intercepts every action before it runs:
|
|
24
|
+
|
|
25
|
+
| Agent tries to... | Waymark does... |
|
|
26
|
+
|----------------------------|----------------------------------------|
|
|
27
|
+
| Write to .env | Blocks it instantly. Logged. |
|
|
28
|
+
| Run rm -rf | Blocks it instantly. Logged. |
|
|
29
|
+
| Pipe curl to bash | Blocks it instantly. Logged. |
|
|
30
|
+
| Modify src/db/schema.ts | Holds it. Asks for your approval. |
|
|
31
|
+
| Write to src/ | Allows it. Logged with full rollback. |
|
|
32
|
+
| Read any file | Logged with path and content snapshot. |
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
cd your-project
|
|
40
|
+
npx @way_marks/cli init
|
|
41
|
+
npx @way_marks/cli start
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Restart Claude Code. Done.
|
|
45
|
+
Waymark is now active in this project.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## How It Works
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
Your Prompt
|
|
53
|
+
↓
|
|
54
|
+
Claude Code
|
|
55
|
+
↓
|
|
56
|
+
Waymark MCP Server ← intercepts here
|
|
57
|
+
↓
|
|
58
|
+
Policy Engine
|
|
59
|
+
↓
|
|
60
|
+
allowed → executes + logged
|
|
61
|
+
blocked → stopped + logged
|
|
62
|
+
pending → held + approval required
|
|
63
|
+
↓
|
|
64
|
+
Dashboard: http://localhost:3001
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Dashboard
|
|
70
|
+
|
|
71
|
+
Open **http://localhost:3001** after running
|
|
72
|
+
`npx @way_marks/cli start`.
|
|
73
|
+
|
|
74
|
+
- See every agent action in real time
|
|
75
|
+
- Approve or reject pending actions
|
|
76
|
+
- Roll back any write with one click
|
|
77
|
+
- Filter by allowed / blocked / pending
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Configuration
|
|
82
|
+
|
|
83
|
+
Edit `waymark.config.json` in your project root:
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"policies": {
|
|
88
|
+
"allowedPaths": [
|
|
89
|
+
"./src/**",
|
|
90
|
+
"./data/**",
|
|
91
|
+
"./README.md"
|
|
92
|
+
],
|
|
93
|
+
"blockedPaths": [
|
|
94
|
+
"./.env",
|
|
95
|
+
"./.env.*",
|
|
96
|
+
"./package-lock.json",
|
|
97
|
+
"/etc/**"
|
|
98
|
+
],
|
|
99
|
+
"blockedCommands": [
|
|
100
|
+
"rm -rf",
|
|
101
|
+
"DROP TABLE",
|
|
102
|
+
"regex:\\|\\s*bash",
|
|
103
|
+
"regex:\\$\\(curl"
|
|
104
|
+
],
|
|
105
|
+
"requireApproval": [
|
|
106
|
+
"./src/db/**",
|
|
107
|
+
"./waymark.config.json"
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Policy Rules
|
|
114
|
+
|
|
115
|
+
**allowedPaths** — Agent can read and write these.
|
|
116
|
+
Supports glob patterns.
|
|
117
|
+
|
|
118
|
+
**blockedPaths** — Agent can never touch these.
|
|
119
|
+
Takes priority over allowedPaths.
|
|
120
|
+
|
|
121
|
+
**blockedCommands** — Bash commands containing
|
|
122
|
+
these strings are blocked. Prefix with `regex:`
|
|
123
|
+
for pattern matching.
|
|
124
|
+
|
|
125
|
+
**requireApproval** — Actions on these paths are
|
|
126
|
+
held until a human approves from the dashboard.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## CLI Commands
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
npx @way_marks/cli init # Set up Waymark in current project
|
|
134
|
+
npx @way_marks/cli start # Start dashboard + MCP server (background)
|
|
135
|
+
npx @way_marks/cli stop # Stop the running servers
|
|
136
|
+
npx @way_marks/cli status # Check if server is running
|
|
137
|
+
npx @way_marks/cli logs # View recent actions in terminal
|
|
138
|
+
npx @way_marks/cli logs --pending # Show only pending actions
|
|
139
|
+
npx @way_marks/cli logs --blocked # Show only blocked actions
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Slack Notifications
|
|
145
|
+
|
|
146
|
+
Get notified when an agent action needs approval:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
# Add to .env in your project
|
|
150
|
+
WAYMARK_SLACK_WEBHOOK_URL=https://hooks.slack.com/...
|
|
151
|
+
WAYMARK_SLACK_CHANNEL=#engineering
|
|
152
|
+
WAYMARK_BASE_URL=http://localhost:3001
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Create a Slack webhook at:
|
|
156
|
+
api.slack.com/apps → Incoming Webhooks
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Works With
|
|
161
|
+
|
|
162
|
+
- **Claude Code** — native MCP integration,
|
|
163
|
+
zero configuration after init
|
|
164
|
+
- **Any MCP-compatible agent** — register
|
|
165
|
+
the Waymark MCP server in your agent config
|
|
166
|
+
- More integrations coming
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Requirements
|
|
171
|
+
|
|
172
|
+
- Node.js 18 or higher
|
|
173
|
+
- Claude Code (for MCP integration)
|
|
174
|
+
- macOS or Linux (Windows support coming)
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Roadmap
|
|
179
|
+
|
|
180
|
+
- [ ] Team approval routing
|
|
181
|
+
(assign approvals to specific teammates)
|
|
182
|
+
- [ ] Session-level rollback
|
|
183
|
+
(undo an entire agent run at once)
|
|
184
|
+
- [ ] CLI agent wrapping
|
|
185
|
+
(waymark run <any-agent-command>)
|
|
186
|
+
- [ ] Proxy mode
|
|
187
|
+
(drop-in for any OpenAI-compatible agent)
|
|
188
|
+
- [ ] Email notifications
|
|
189
|
+
- [ ] Windows support
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Contributing
|
|
194
|
+
|
|
195
|
+
Waymark is MIT licensed and open to contributions.
|
|
196
|
+
|
|
197
|
+
1. Fork the repo
|
|
198
|
+
2. Create a feature branch
|
|
199
|
+
3. Open a pull request
|
|
200
|
+
|
|
201
|
+
Please open an issue before starting large changes.
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## License
|
|
206
|
+
|
|
207
|
+
MIT — see [LICENSE](LICENSE)
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
Built for developers who want to use AI agents
|
|
212
|
+
seriously — without giving them unsupervised
|
|
213
|
+
access to production systems.
|
|
@@ -0,0 +1,325 @@
|
|
|
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 os = __importStar(require("os"));
|
|
40
|
+
const readline = __importStar(require("readline"));
|
|
41
|
+
const child_process_1 = require("child_process");
|
|
42
|
+
const DEFAULT_CONFIG = {
|
|
43
|
+
version: '1',
|
|
44
|
+
policies: {
|
|
45
|
+
allowedPaths: [
|
|
46
|
+
'./src/**',
|
|
47
|
+
'./data/**',
|
|
48
|
+
'./README.md',
|
|
49
|
+
'./CLAUDE.md'
|
|
50
|
+
],
|
|
51
|
+
blockedPaths: [
|
|
52
|
+
'./.env',
|
|
53
|
+
'./.env.*',
|
|
54
|
+
'./package-lock.json',
|
|
55
|
+
'/etc/**',
|
|
56
|
+
'/usr/**'
|
|
57
|
+
],
|
|
58
|
+
blockedCommands: [
|
|
59
|
+
'rm -rf',
|
|
60
|
+
'DROP TABLE',
|
|
61
|
+
'DROP DATABASE',
|
|
62
|
+
'chmod 777',
|
|
63
|
+
'regex:\\|\\s*bash',
|
|
64
|
+
'regex:\\|\\s*sh\\b',
|
|
65
|
+
'regex:\\$\\(curl',
|
|
66
|
+
'regex:\\$\\(wget',
|
|
67
|
+
'wget '
|
|
68
|
+
],
|
|
69
|
+
requireApproval: [
|
|
70
|
+
'./src/db/**',
|
|
71
|
+
'./waymark.config.json'
|
|
72
|
+
],
|
|
73
|
+
maxBashOutputBytes: 10000
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
const WAYMARK_MARKER = '<!-- waymark -->';
|
|
77
|
+
function kebabCase(str) {
|
|
78
|
+
return str
|
|
79
|
+
.toLowerCase()
|
|
80
|
+
.replace(/[\s_]+/g, '-')
|
|
81
|
+
.replace(/[^a-z0-9-]/g, '')
|
|
82
|
+
.replace(/-+/g, '-')
|
|
83
|
+
.replace(/^-|-$/g, '');
|
|
84
|
+
}
|
|
85
|
+
function generateClaudeMd(projectName, port) {
|
|
86
|
+
return `---
|
|
87
|
+
# ⚠️ WAYMARK ACTIVE — MANDATORY INSTRUCTIONS
|
|
88
|
+
|
|
89
|
+
## You are operating under Waymark agent control
|
|
90
|
+
|
|
91
|
+
Waymark is active in this project (${projectName}).
|
|
92
|
+
All file and shell operations MUST go through
|
|
93
|
+
Waymark MCP tools. No exceptions.
|
|
94
|
+
|
|
95
|
+
## MANDATORY tool usage
|
|
96
|
+
|
|
97
|
+
You MUST replace ALL built-in file and shell
|
|
98
|
+
operations with Waymark MCP equivalents:
|
|
99
|
+
|
|
100
|
+
| Operation | Built-in (DO NOT USE) | Waymark (ALWAYS USE) |
|
|
101
|
+
|------------------------|-----------------------|----------------------|
|
|
102
|
+
| Write or edit a file | write_file | mcp__waymark-${projectName}__write_file |
|
|
103
|
+
| Read a file | read_file | mcp__waymark-${projectName}__read_file |
|
|
104
|
+
| Run shell commands | bash / run_command | mcp__waymark-${projectName}__bash |
|
|
105
|
+
|
|
106
|
+
This applies to ALL tasks in this project —
|
|
107
|
+
refactoring, creating files, running tests,
|
|
108
|
+
installing packages, git operations, everything.
|
|
109
|
+
|
|
110
|
+
## What Waymark does with each action
|
|
111
|
+
|
|
112
|
+
- Allowed paths → executes normally, logged
|
|
113
|
+
- Blocked paths → stopped, you will see why
|
|
114
|
+
- Sensitive paths → held for human approval,
|
|
115
|
+
do not retry, tell the user to check dashboard
|
|
116
|
+
|
|
117
|
+
## If a Waymark tool returns a block decision
|
|
118
|
+
|
|
119
|
+
Accept the block. Do not attempt to work around it
|
|
120
|
+
using built-in tools. Tell the user what was blocked
|
|
121
|
+
and why. Suggest they update waymark.config.json
|
|
122
|
+
if the block was unintended.
|
|
123
|
+
|
|
124
|
+
## If Waymark MCP tools are unavailable
|
|
125
|
+
|
|
126
|
+
Do NOT fall back to built-in file tools.
|
|
127
|
+
Stop and tell the user:
|
|
128
|
+
|
|
129
|
+
"Waymark MCP server is not running for this project.
|
|
130
|
+
Please run in your terminal:
|
|
131
|
+
npx @way_marks/cli start
|
|
132
|
+
|
|
133
|
+
Then restart Claude Code and try again."
|
|
134
|
+
|
|
135
|
+
## Dashboard
|
|
136
|
+
|
|
137
|
+
All actions are visible at: http://localhost:${port}
|
|
138
|
+
Approve pending actions there.
|
|
139
|
+
Roll back any write there.
|
|
140
|
+
|
|
141
|
+
## This file was generated by Waymark
|
|
142
|
+
Do not delete or modify this file.
|
|
143
|
+
It controls how Claude Code behaves in this project.
|
|
144
|
+
---
|
|
145
|
+
`;
|
|
146
|
+
}
|
|
147
|
+
function prompt(question) {
|
|
148
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
149
|
+
return new Promise(resolve => {
|
|
150
|
+
rl.question(question, answer => { rl.close(); resolve(answer.trim()); });
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
function getClaudeDesktopConfigPath() {
|
|
154
|
+
const platform = process.platform;
|
|
155
|
+
if (platform === 'darwin') {
|
|
156
|
+
return path.join(os.homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
|
|
157
|
+
}
|
|
158
|
+
else if (platform === 'win32') {
|
|
159
|
+
return path.join(process.env.APPDATA || os.homedir(), 'Claude', 'claude_desktop_config.json');
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
return path.join(os.homedir(), '.config', 'Claude', 'claude_desktop_config.json');
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
function resolveServerBin() {
|
|
166
|
+
try {
|
|
167
|
+
return require.resolve('@way_marks/server/dist/mcp/server.js');
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
return path.resolve(__dirname, '../../../server/dist/mcp/server.js');
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
async function run() {
|
|
174
|
+
const projectRoot = process.cwd();
|
|
175
|
+
const projectName = kebabCase(path.basename(projectRoot));
|
|
176
|
+
const mcpKey = `waymark-${projectName}`;
|
|
177
|
+
const dbPath = path.join(projectRoot, '.waymark', 'waymark.db');
|
|
178
|
+
const defaultPort = 3001;
|
|
179
|
+
console.log(`Initializing Waymark in: ${projectRoot}`);
|
|
180
|
+
// Step 1 — Detect project
|
|
181
|
+
const hasPackageJson = fs.existsSync(path.join(projectRoot, 'package.json'));
|
|
182
|
+
const hasGit = fs.existsSync(path.join(projectRoot, '.git'));
|
|
183
|
+
if (!hasPackageJson && !hasGit) {
|
|
184
|
+
console.warn('Warning: No package.json or .git found. Continuing anyway.');
|
|
185
|
+
}
|
|
186
|
+
// Step 2 — Install @way_marks/server (skip if already resolvable or in monorepo)
|
|
187
|
+
let serverBin;
|
|
188
|
+
try {
|
|
189
|
+
serverBin = require.resolve('@way_marks/server/dist/mcp/server.js');
|
|
190
|
+
console.log('✓ @way_marks/server already installed');
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
const monorepoFallback = path.resolve(__dirname, '../../../server/dist/mcp/server.js');
|
|
194
|
+
if (fs.existsSync(monorepoFallback)) {
|
|
195
|
+
serverBin = monorepoFallback;
|
|
196
|
+
console.log('✓ Using local @way_marks/server (monorepo)');
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
console.log('Installing @way_marks/server...');
|
|
200
|
+
const result = (0, child_process_1.spawnSync)('npm', ['install', '--save-dev', '@way_marks/server'], {
|
|
201
|
+
stdio: 'inherit',
|
|
202
|
+
cwd: projectRoot
|
|
203
|
+
});
|
|
204
|
+
if (result.status !== 0) {
|
|
205
|
+
console.error('Failed to install @way_marks/server');
|
|
206
|
+
process.exit(1);
|
|
207
|
+
}
|
|
208
|
+
serverBin = resolveServerBin();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// Step 3 — Create waymark.config.json
|
|
212
|
+
const configPath = path.join(projectRoot, 'waymark.config.json');
|
|
213
|
+
if (fs.existsSync(configPath)) {
|
|
214
|
+
const answer = await prompt('waymark.config.json exists. Overwrite? (y/N) ');
|
|
215
|
+
if (answer.toLowerCase() !== 'y') {
|
|
216
|
+
console.log('Keeping existing waymark.config.json');
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
fs.writeFileSync(configPath, JSON.stringify(DEFAULT_CONFIG, null, 2) + '\n');
|
|
220
|
+
console.log('✓ Created waymark.config.json');
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
fs.writeFileSync(configPath, JSON.stringify(DEFAULT_CONFIG, null, 2) + '\n');
|
|
225
|
+
console.log('✓ Created waymark.config.json');
|
|
226
|
+
}
|
|
227
|
+
// Step 4 — Create/append CLAUDE.md
|
|
228
|
+
const claudeMdPath = path.join(projectRoot, 'CLAUDE.md');
|
|
229
|
+
const claudeMdContent = generateClaudeMd(projectName, defaultPort);
|
|
230
|
+
if (fs.existsSync(claudeMdPath)) {
|
|
231
|
+
const existing = fs.readFileSync(claudeMdPath, 'utf8');
|
|
232
|
+
if (existing.includes(WAYMARK_MARKER)) {
|
|
233
|
+
console.log('✓ CLAUDE.md already has Waymark section');
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
fs.appendFileSync(claudeMdPath, `\n${WAYMARK_MARKER}\n${claudeMdContent}`);
|
|
237
|
+
console.log('✓ Appended Waymark section to CLAUDE.md');
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
fs.writeFileSync(claudeMdPath, `${WAYMARK_MARKER}\n${claudeMdContent}`);
|
|
242
|
+
console.log('✓ Created CLAUDE.md — Claude Code will now use Waymark automatically');
|
|
243
|
+
}
|
|
244
|
+
// Step 5 — Update .gitignore
|
|
245
|
+
const gitignorePath = path.join(projectRoot, '.gitignore');
|
|
246
|
+
const gitignoreContent = fs.existsSync(gitignorePath)
|
|
247
|
+
? fs.readFileSync(gitignorePath, 'utf8')
|
|
248
|
+
: '';
|
|
249
|
+
const linesToAdd = ['.waymark/', 'waymark.db', 'data/waymark.db']
|
|
250
|
+
.filter(line => !gitignoreContent.includes(line));
|
|
251
|
+
if (linesToAdd.length > 0) {
|
|
252
|
+
const section = '\n# Waymark\n' + linesToAdd.join('\n') + '\n';
|
|
253
|
+
fs.appendFileSync(gitignorePath, section);
|
|
254
|
+
console.log('✓ Updated .gitignore');
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
console.log('✓ .gitignore already up to date');
|
|
258
|
+
}
|
|
259
|
+
// Step 6 — Register MCP in both Claude configs
|
|
260
|
+
const nodeBin = process.execPath;
|
|
261
|
+
const mcpEntry = {
|
|
262
|
+
command: nodeBin,
|
|
263
|
+
args: [serverBin, '--project-root', projectRoot, '--db-path', dbPath]
|
|
264
|
+
};
|
|
265
|
+
// Claude Desktop config — add/update this project's entry only
|
|
266
|
+
const desktopConfigPath = getClaudeDesktopConfigPath();
|
|
267
|
+
try {
|
|
268
|
+
const desktopDir = path.dirname(desktopConfigPath);
|
|
269
|
+
if (!fs.existsSync(desktopDir))
|
|
270
|
+
fs.mkdirSync(desktopDir, { recursive: true });
|
|
271
|
+
const desktopConfig = fs.existsSync(desktopConfigPath)
|
|
272
|
+
? JSON.parse(fs.readFileSync(desktopConfigPath, 'utf8'))
|
|
273
|
+
: { mcpServers: {} };
|
|
274
|
+
if (!desktopConfig.mcpServers)
|
|
275
|
+
desktopConfig.mcpServers = {};
|
|
276
|
+
desktopConfig.mcpServers[mcpKey] = mcpEntry;
|
|
277
|
+
fs.writeFileSync(desktopConfigPath, JSON.stringify(desktopConfig, null, 2) + '\n');
|
|
278
|
+
console.log(`✓ Registered MCP server "${mcpKey}" in Claude Desktop config`);
|
|
279
|
+
}
|
|
280
|
+
catch (err) {
|
|
281
|
+
console.warn(`Warning: Could not update Claude Desktop config: ${err.message}`);
|
|
282
|
+
}
|
|
283
|
+
// .mcp.json (Claude Code project-level)
|
|
284
|
+
const mcpJsonPath = path.join(projectRoot, '.mcp.json');
|
|
285
|
+
try {
|
|
286
|
+
const mcpJson = fs.existsSync(mcpJsonPath)
|
|
287
|
+
? JSON.parse(fs.readFileSync(mcpJsonPath, 'utf8'))
|
|
288
|
+
: { mcpServers: {} };
|
|
289
|
+
if (!mcpJson.mcpServers)
|
|
290
|
+
mcpJson.mcpServers = {};
|
|
291
|
+
mcpJson.mcpServers[mcpKey] = { type: 'stdio', ...mcpEntry, cwd: projectRoot };
|
|
292
|
+
fs.writeFileSync(mcpJsonPath, JSON.stringify(mcpJson, null, 2) + '\n');
|
|
293
|
+
console.log(`✓ Created/updated .mcp.json for Claude Code`);
|
|
294
|
+
}
|
|
295
|
+
catch (err) {
|
|
296
|
+
console.warn(`Warning: Could not update .mcp.json: ${err.message}`);
|
|
297
|
+
}
|
|
298
|
+
// Step 7 — Success summary
|
|
299
|
+
const col = 43;
|
|
300
|
+
const pad = (s) => s + ' '.repeat(Math.max(0, col - 2 - s.length));
|
|
301
|
+
console.log('');
|
|
302
|
+
console.log('┌' + '─'.repeat(col) + '┐');
|
|
303
|
+
console.log(`│ ${pad('✅ Waymark initialized')} │`);
|
|
304
|
+
console.log(`│ ${pad('')} │`);
|
|
305
|
+
console.log(`│ ${pad(`Project: ${projectName}`)} │`);
|
|
306
|
+
console.log(`│ ${pad('Database: .waymark/waymark.db')} │`);
|
|
307
|
+
console.log(`│ ${pad(`MCP key: ${mcpKey}`)} │`);
|
|
308
|
+
console.log(`│ ${pad('')} │`);
|
|
309
|
+
console.log(`│ ${pad('Files created:')} │`);
|
|
310
|
+
console.log(`│ ${pad(' waymark.config.json')} │`);
|
|
311
|
+
console.log(`│ ${pad(' CLAUDE.md')} │`);
|
|
312
|
+
console.log(`│ ${pad(' .waymark/ (gitignored)')} │`);
|
|
313
|
+
console.log(`│ ${pad('')} │`);
|
|
314
|
+
console.log(`│ ${pad('Next steps:')} │`);
|
|
315
|
+
console.log(`│ ${pad('1. Run: npx @way_marks/cli start')} │`);
|
|
316
|
+
console.log(`│ ${pad('2. Restart Claude Code')} │`);
|
|
317
|
+
console.log(`│ ${pad('3. Open this project in Claude')} │`);
|
|
318
|
+
console.log(`│ ${pad('4. Dashboard: http://localhost:3001')} │`);
|
|
319
|
+
console.log(`│ ${pad(' (port may differ if 3001 is taken)')} │`);
|
|
320
|
+
console.log(`│ ${pad('')} │`);
|
|
321
|
+
console.log(`│ ${pad('Waymark is now always-on in this')} │`);
|
|
322
|
+
console.log(`│ ${pad('project. Claude will use Waymark')} │`);
|
|
323
|
+
console.log(`│ ${pad('tools automatically via CLAUDE.md')} │`);
|
|
324
|
+
console.log('└' + '─'.repeat(col) + '┘');
|
|
325
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.run = run;
|
|
4
|
+
const BASE = 'http://localhost:3001';
|
|
5
|
+
function parseIso(iso) {
|
|
6
|
+
const normalized = iso.includes('T') ? iso : iso.replace(' ', 'T');
|
|
7
|
+
const withZ = normalized.endsWith('Z') ? normalized : normalized + 'Z';
|
|
8
|
+
return new Date(withZ);
|
|
9
|
+
}
|
|
10
|
+
function relativeTime(iso) {
|
|
11
|
+
const diffMs = Date.now() - parseIso(iso).getTime();
|
|
12
|
+
const mins = Math.floor(diffMs / 60000);
|
|
13
|
+
if (mins < 1)
|
|
14
|
+
return 'just now';
|
|
15
|
+
if (mins < 60)
|
|
16
|
+
return `${mins}m ago`;
|
|
17
|
+
const hours = Math.floor(mins / 60);
|
|
18
|
+
if (hours < 24)
|
|
19
|
+
return `${hours}h ago`;
|
|
20
|
+
return `${Math.floor(hours / 24)}d ago`;
|
|
21
|
+
}
|
|
22
|
+
function truncate(str, len) {
|
|
23
|
+
if (!str)
|
|
24
|
+
return '—';
|
|
25
|
+
const s = str.split('/').pop() || str;
|
|
26
|
+
return s.length > len ? s.slice(0, len - 1) + '…' : s;
|
|
27
|
+
}
|
|
28
|
+
function pad(str, len) {
|
|
29
|
+
return str.padEnd(len).slice(0, len);
|
|
30
|
+
}
|
|
31
|
+
async function run() {
|
|
32
|
+
const args = process.argv.slice(3);
|
|
33
|
+
const limitIdx = args.indexOf('--limit');
|
|
34
|
+
const limit = limitIdx !== -1 ? parseInt(args[limitIdx + 1], 10) || 20 : 20;
|
|
35
|
+
const pendingOnly = args.includes('--pending');
|
|
36
|
+
const blockedOnly = args.includes('--blocked');
|
|
37
|
+
let rows;
|
|
38
|
+
try {
|
|
39
|
+
const res = await fetch(`${BASE}/api/actions`);
|
|
40
|
+
if (!res.ok)
|
|
41
|
+
throw new Error('Bad response');
|
|
42
|
+
rows = await res.json();
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
console.log('Waymark is not running. Start with: npx @way_marks/cli start');
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (pendingOnly)
|
|
49
|
+
rows = rows.filter((r) => r.status === 'pending');
|
|
50
|
+
if (blockedOnly)
|
|
51
|
+
rows = rows.filter((r) => r.status === 'blocked');
|
|
52
|
+
rows = rows.slice(0, limit);
|
|
53
|
+
if (rows.length === 0) {
|
|
54
|
+
console.log('No actions found.');
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
console.log(pad('Time', 10) + ' ' +
|
|
58
|
+
pad('Tool', 12) + ' ' +
|
|
59
|
+
pad('Path / Command', 40) + ' ' +
|
|
60
|
+
pad('Decision', 10) + ' ' +
|
|
61
|
+
'Status');
|
|
62
|
+
console.log('─'.repeat(86));
|
|
63
|
+
for (const r of rows) {
|
|
64
|
+
const target = r.target_path
|
|
65
|
+
? truncate(r.target_path, 40)
|
|
66
|
+
: (() => {
|
|
67
|
+
try {
|
|
68
|
+
return truncate(JSON.parse(r.input_payload || '{}').command || '—', 40);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return '—';
|
|
72
|
+
}
|
|
73
|
+
})();
|
|
74
|
+
console.log(pad(relativeTime(r.created_at), 10) + ' ' +
|
|
75
|
+
pad(r.tool_name, 12) + ' ' +
|
|
76
|
+
pad(target, 40) + ' ' +
|
|
77
|
+
pad(r.decision || '—', 10) + ' ' +
|
|
78
|
+
r.status);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
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 net = __importStar(require("net"));
|
|
40
|
+
const child_process_1 = require("child_process");
|
|
41
|
+
function resolveServerBin(name) {
|
|
42
|
+
const file = name === 'mcp' ? 'mcp/server.js' : 'api/server.js';
|
|
43
|
+
try {
|
|
44
|
+
return require.resolve(`@way_marks/server/dist/${file}`);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return path.resolve(__dirname, `../../../server/dist/${file}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function openBrowser(url) {
|
|
51
|
+
try {
|
|
52
|
+
const cmd = process.platform === 'darwin' ? 'open'
|
|
53
|
+
: process.platform === 'win32' ? 'start'
|
|
54
|
+
: 'xdg-open';
|
|
55
|
+
(0, child_process_1.execSync)(`${cmd} ${url}`, { stdio: 'ignore' });
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// ignore — browser open is best-effort
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function isAlive(pid) {
|
|
62
|
+
try {
|
|
63
|
+
process.kill(pid, 0);
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function kebabCase(str) {
|
|
71
|
+
return str
|
|
72
|
+
.toLowerCase()
|
|
73
|
+
.replace(/[\s_]+/g, '-')
|
|
74
|
+
.replace(/[^a-z0-9-]/g, '')
|
|
75
|
+
.replace(/-+/g, '-')
|
|
76
|
+
.replace(/^-|-$/g, '');
|
|
77
|
+
}
|
|
78
|
+
function findAvailablePort(preferred) {
|
|
79
|
+
return new Promise((resolve) => {
|
|
80
|
+
const server = net.createServer();
|
|
81
|
+
server.listen(preferred, () => {
|
|
82
|
+
const port = server.address().port;
|
|
83
|
+
server.close(() => resolve(port));
|
|
84
|
+
});
|
|
85
|
+
server.on('error', () => {
|
|
86
|
+
if (preferred >= 3010) {
|
|
87
|
+
console.error('No available ports found between 3001-3010. Stop other Waymark projects first.');
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
resolve(findAvailablePort(preferred + 1));
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
async function run() {
|
|
95
|
+
const projectRoot = process.cwd();
|
|
96
|
+
const configPath = path.join(projectRoot, 'waymark.config.json');
|
|
97
|
+
const waymarkDir = path.join(projectRoot, '.waymark');
|
|
98
|
+
const pidFile = path.join(waymarkDir, 'waymark.pid');
|
|
99
|
+
if (!fs.existsSync(configPath)) {
|
|
100
|
+
console.error('waymark.config.json not found. Run: npx @way_marks/cli init');
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
// Guard: already running
|
|
104
|
+
if (fs.existsSync(pidFile)) {
|
|
105
|
+
try {
|
|
106
|
+
const saved = JSON.parse(fs.readFileSync(pidFile, 'utf8'));
|
|
107
|
+
if (isAlive(saved.api) || isAlive(saved.mcp)) {
|
|
108
|
+
const port = saved.port || 3001;
|
|
109
|
+
console.log('Waymark is already running.');
|
|
110
|
+
console.log(`Dashboard: http://localhost:${port}`);
|
|
111
|
+
console.log('Run "npx @way_marks/cli stop" to stop it.');
|
|
112
|
+
process.exit(0);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// stale/corrupt PID file — continue to start
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const port = await findAvailablePort(3001);
|
|
120
|
+
const dbPath = path.join(projectRoot, '.waymark', 'waymark.db');
|
|
121
|
+
const projectName = kebabCase(path.basename(projectRoot));
|
|
122
|
+
const nodeBin = process.execPath;
|
|
123
|
+
const mcpBin = resolveServerBin('mcp');
|
|
124
|
+
const apiBin = resolveServerBin('api');
|
|
125
|
+
const env = {
|
|
126
|
+
...process.env,
|
|
127
|
+
WAYMARK_PROJECT_ROOT: projectRoot,
|
|
128
|
+
WAYMARK_DB_PATH: dbPath,
|
|
129
|
+
WAYMARK_PORT: String(port),
|
|
130
|
+
};
|
|
131
|
+
const apiProc = (0, child_process_1.spawn)(nodeBin, [apiBin], {
|
|
132
|
+
env,
|
|
133
|
+
stdio: 'ignore',
|
|
134
|
+
detached: true
|
|
135
|
+
});
|
|
136
|
+
const mcpProc = (0, child_process_1.spawn)(nodeBin, [
|
|
137
|
+
mcpBin,
|
|
138
|
+
'--project-root', projectRoot,
|
|
139
|
+
'--db-path', dbPath,
|
|
140
|
+
'--port', String(port),
|
|
141
|
+
], {
|
|
142
|
+
env,
|
|
143
|
+
stdio: 'ignore',
|
|
144
|
+
detached: true
|
|
145
|
+
});
|
|
146
|
+
apiProc.unref();
|
|
147
|
+
mcpProc.unref();
|
|
148
|
+
// Ensure .waymark directory exists
|
|
149
|
+
if (!fs.existsSync(waymarkDir))
|
|
150
|
+
fs.mkdirSync(waymarkDir, { recursive: true });
|
|
151
|
+
// Write .waymark/config.json
|
|
152
|
+
fs.writeFileSync(path.join(waymarkDir, 'config.json'), JSON.stringify({ port, projectRoot, projectName, startedAt: new Date().toISOString() }, null, 2) + '\n');
|
|
153
|
+
// Write PID file
|
|
154
|
+
fs.writeFileSync(pidFile, JSON.stringify({
|
|
155
|
+
api: apiProc.pid,
|
|
156
|
+
mcp: mcpProc.pid,
|
|
157
|
+
port,
|
|
158
|
+
startedAt: new Date().toISOString()
|
|
159
|
+
}, null, 2) + '\n');
|
|
160
|
+
// Open browser after short delay for server startup
|
|
161
|
+
setTimeout(() => {
|
|
162
|
+
openBrowser(`http://localhost:${port}`);
|
|
163
|
+
console.log('Waymark started (background)');
|
|
164
|
+
console.log(`Dashboard: http://localhost:${port}`);
|
|
165
|
+
console.log('MCP server: active (stdio)');
|
|
166
|
+
console.log('Run "npx @way_marks/cli stop" to stop.');
|
|
167
|
+
}, 1500);
|
|
168
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
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
|
+
async function run() {
|
|
40
|
+
const projectRoot = process.cwd();
|
|
41
|
+
const configPath = path.join(projectRoot, '.waymark', 'config.json');
|
|
42
|
+
if (!fs.existsSync(configPath)) {
|
|
43
|
+
console.log('Waymark not initialized in this directory.');
|
|
44
|
+
console.log('Run: npx @way_marks/cli init');
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
let waymarkConfig;
|
|
48
|
+
try {
|
|
49
|
+
waymarkConfig = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
console.log('Waymark config is corrupt. Re-run: npx @way_marks/cli init');
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const { port, projectName, startedAt } = waymarkConfig;
|
|
56
|
+
const mcpKey = `waymark-${projectName}`;
|
|
57
|
+
const base = `http://localhost:${port}`;
|
|
58
|
+
// Check if server is running (2s timeout)
|
|
59
|
+
let running = false;
|
|
60
|
+
let pending = 0;
|
|
61
|
+
try {
|
|
62
|
+
const controller = new AbortController();
|
|
63
|
+
const timer = setTimeout(() => controller.abort(), 2000);
|
|
64
|
+
const res = await fetch(`${base}/api/actions?count=true`, { signal: controller.signal });
|
|
65
|
+
clearTimeout(timer);
|
|
66
|
+
if (res.ok) {
|
|
67
|
+
running = true;
|
|
68
|
+
const data = await res.json();
|
|
69
|
+
pending = data.count;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch { /* not running */ }
|
|
73
|
+
console.log('Waymark — Project Status');
|
|
74
|
+
console.log('─'.repeat(35));
|
|
75
|
+
console.log(`Project: ${projectName}`);
|
|
76
|
+
console.log(`Root: ${projectRoot}`);
|
|
77
|
+
console.log(`Database: .waymark/waymark.db`);
|
|
78
|
+
console.log(`Port: ${port}`);
|
|
79
|
+
console.log(`Dashboard: ${base}`);
|
|
80
|
+
console.log(`MCP key: ${mcpKey}`);
|
|
81
|
+
console.log('─'.repeat(35));
|
|
82
|
+
console.log(`Server: ${running ? 'running ✅' : 'not running ❌'}`);
|
|
83
|
+
if (running)
|
|
84
|
+
console.log(`Pending: ${pending} actions`);
|
|
85
|
+
if (!running)
|
|
86
|
+
console.log(`Start with: npx @way_marks/cli start`);
|
|
87
|
+
if (startedAt)
|
|
88
|
+
console.log(`Started: ${startedAt}`);
|
|
89
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
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
|
+
function tryKill(pid) {
|
|
40
|
+
try {
|
|
41
|
+
process.kill(pid, 'SIGTERM');
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function run() {
|
|
49
|
+
const pidFile = path.join(process.cwd(), '.waymark', 'waymark.pid');
|
|
50
|
+
if (!fs.existsSync(pidFile)) {
|
|
51
|
+
console.log('Waymark is not running.');
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
let saved;
|
|
55
|
+
try {
|
|
56
|
+
saved = JSON.parse(fs.readFileSync(pidFile, 'utf8'));
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
fs.unlinkSync(pidFile);
|
|
60
|
+
console.log('Waymark is not running.');
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const killedApi = tryKill(saved.api);
|
|
64
|
+
const killedMcp = tryKill(saved.mcp);
|
|
65
|
+
try {
|
|
66
|
+
fs.unlinkSync(pidFile);
|
|
67
|
+
}
|
|
68
|
+
catch { /* already gone */ }
|
|
69
|
+
if (killedApi || killedMcp) {
|
|
70
|
+
console.log('Waymark stopped.');
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
console.log('Waymark was not running (stale PID file removed).');
|
|
74
|
+
}
|
|
75
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
const command = process.argv[2];
|
|
4
|
+
switch (command) {
|
|
5
|
+
case 'init':
|
|
6
|
+
require('./commands/init').run();
|
|
7
|
+
break;
|
|
8
|
+
case 'start':
|
|
9
|
+
require('./commands/start').run();
|
|
10
|
+
break;
|
|
11
|
+
case 'stop':
|
|
12
|
+
require('./commands/stop').run();
|
|
13
|
+
break;
|
|
14
|
+
case 'status':
|
|
15
|
+
require('./commands/status').run();
|
|
16
|
+
break;
|
|
17
|
+
case 'logs':
|
|
18
|
+
require('./commands/logs').run();
|
|
19
|
+
break;
|
|
20
|
+
default:
|
|
21
|
+
console.log('Usage: npx @way_marks/cli <init|start|stop|status|logs>');
|
|
22
|
+
console.log('');
|
|
23
|
+
console.log('Commands:');
|
|
24
|
+
console.log(' init Set up Waymark in the current project');
|
|
25
|
+
console.log(' start Start the Waymark dashboard and MCP server');
|
|
26
|
+
console.log(' stop Stop the running Waymark servers');
|
|
27
|
+
console.log(' status Show current Waymark status and pending count');
|
|
28
|
+
console.log(' logs Show recent action log');
|
|
29
|
+
process.exit(command ? 1 : 0);
|
|
30
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@way_marks/cli",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Control what AI agents can do in your codebase",
|
|
5
|
+
"author": "Waymark <hello@waymarks.dev>",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"homepage": "https://github.com/waymarks/waymark",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/waymarks/waymark.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/waymarks/waymark/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"ai-agents",
|
|
17
|
+
"claude-code",
|
|
18
|
+
"mcp",
|
|
19
|
+
"security",
|
|
20
|
+
"developer-tools",
|
|
21
|
+
"llm",
|
|
22
|
+
"agent-control"
|
|
23
|
+
],
|
|
24
|
+
"bin": {
|
|
25
|
+
"waymark": "./dist/index.js"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist/**"
|
|
29
|
+
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsc"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@way_marks/server": "0.4.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/node": "^20.11.5",
|
|
38
|
+
"typescript": "^5.3.3"
|
|
39
|
+
}
|
|
40
|
+
}
|