spect8-mcp 0.2.3 → 0.2.5

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,126 @@
1
+ # Spect8 Installation Plan
2
+
3
+ ## Goal
4
+
5
+ Make a new Spect8 install require one command, work across MCP-capable and
6
+ hook-capable IDEs, and provide a safe AI-assisted fallback prompt for users who
7
+ want their IDE agent to run setup for them.
8
+
9
+ ## Primary User Flow
10
+
11
+ ```bash
12
+ npx -y spect8-mcp setup --ide cursor
13
+ ```
14
+
15
+ The setup command should:
16
+
17
+ 1. Authenticate the user through Spect8 browser auth or accept a setup token.
18
+ 2. Store credentials in `~/.spect8/config.json`.
19
+ 3. Install the requested IDE integration.
20
+ 4. Install project instruction files when requested.
21
+ 5. Run `spect8 doctor` checks and print next steps.
22
+
23
+ For already-authenticated users:
24
+
25
+ ```bash
26
+ spect8 install cursor
27
+ spect8 install claude-code
28
+ spect8 install rules
29
+ spect8 install all
30
+ spect8 doctor
31
+ ```
32
+
33
+ ## How The AI Knows To Use Spect8
34
+
35
+ Spect8 setup must combine two mechanisms:
36
+
37
+ 1. **Tool availability:** MCP config exposes `start_task`, `report_activity`,
38
+ `end_task`, and `get_score` to the IDE.
39
+ 2. **Behavior instruction or hook:** IDE rules tell the AI when to call those
40
+ tools, while hook-capable IDEs emit telemetry automatically after real tool
41
+ calls.
42
+
43
+ MCP alone is not enough; it makes tools available but does not guarantee the AI
44
+ will call them. Hooks are preferred when available because they are not dependent
45
+ on prompt compliance.
46
+
47
+ ## Compatibility Tiers
48
+
49
+ ### Tier 1: MCP-Native IDEs
50
+
51
+ Examples: Cursor, Windsurf, VS Code MCP clients.
52
+
53
+ Install strategy:
54
+
55
+ - Write or merge the IDE MCP JSON.
56
+ - Point the server at `npx -y spect8-mcp`.
57
+ - Set only IDE-specific environment such as `SPECT8_IDE_NAME`; credentials come
58
+ from `~/.spect8/config.json`.
59
+ - Add instruction files where the IDE supports them.
60
+
61
+ ### Tier 2: Hook-Capable IDEs
62
+
63
+ Example: Claude Code.
64
+
65
+ Install strategy:
66
+
67
+ - Write or merge hook config.
68
+ - Use platform-safe commands that do not rely on shell-specific env expansion.
69
+ - Let hooks record observed tool calls and token usage automatically.
70
+ - Use instructions only for task boundaries and optional score checks.
71
+
72
+ ### Tier 3: Instruction-Only IDEs
73
+
74
+ Examples: Kiro, GitHub Copilot, Antigravity-style agents without MCP/hook
75
+ support.
76
+
77
+ Install strategy:
78
+
79
+ - Install IDE-specific instruction files.
80
+ - Ask the AI to call `report_activity` when the IDE exposes Spect8 tools.
81
+ - Mark this mode as lower-fidelity if the IDE cannot expose MCP tools.
82
+
83
+ ## Secondary AI-Assisted Install
84
+
85
+ Some users will prefer to paste a custom prompt into their IDE agent. This is
86
+ viable as long as the prompt tells the agent to run the official installer
87
+ instead of manually recreating config files.
88
+
89
+ Generate the prompt:
90
+
91
+ ```bash
92
+ spect8 prompt --ide cursor --token <short-lived-setup-token>
93
+ ```
94
+
95
+ The prompt should instruct the IDE agent to:
96
+
97
+ 1. Run `npx -y spect8-mcp setup <token> <ingest_url> --ide <ide> --yes`.
98
+ 2. Run `npx -y spect8-mcp install <ide>`.
99
+ 3. Run `npx -y spect8-mcp doctor`.
100
+ 4. Avoid printing or committing secrets.
101
+
102
+ Long-lived MCP keys should not be embedded in prompts when avoidable. The
103
+ product should eventually issue short-lived setup tokens that the CLI exchanges
104
+ for the local MCP key.
105
+
106
+ ## Test Coverage Required
107
+
108
+ Installation coverage should include:
109
+
110
+ - Config generation and preservation of existing config fields.
111
+ - Cursor MCP JSON creation and merge behavior.
112
+ - Claude Code hook creation without shell-specific syntax.
113
+ - Instruction file creation and idempotent append behavior.
114
+ - Doctor checks for auth, IDE config, offline queue directory, and optional
115
+ Cursor `sqlite3` support.
116
+ - Personalized prompt generation.
117
+ - End-to-end telemetry flow from installed MCP tools through `start_task`,
118
+ `report_activity`, and `end_task` into a batcher/offline queue test double.
119
+
120
+ ## Known Follow-Ups
121
+
122
+ - Add backend support for short-lived setup tokens.
123
+ - Add installers for additional MCP client config paths as their schemas are
124
+ confirmed.
125
+ - Add an uninstall command that removes only Spect8-managed blocks.
126
+ - Add a real backend connectivity check to `spect8 doctor`.
package/README.md CHANGED
@@ -1,14 +1,19 @@
1
- # @spect8/mcp
1
+ # spect8-mcp
2
2
 
3
- Local MCP server + Claude Code hooks that capture Cursor / Claude Code tool
4
- calls and token usage, and forward them to a Spect8 ingest API.
3
+ Local MCP server + IDE instructions/hooks that capture Cursor, Kiro, Claude Code,
4
+ and other MCP-aware agent activity, then forward it to a Spect8 ingest API.
5
5
 
6
6
  ## Install
7
7
 
8
8
  ```bash
9
- npm install -g @spect8/mcp
10
- # or invoke on demand:
11
- npx -y @spect8/mcp
9
+ npx -y spect8-mcp setup --ide cursor
10
+ ```
11
+
12
+ You can also install globally:
13
+
14
+ ```bash
15
+ npm install -g spect8-mcp
16
+ spect8 setup --ide cursor
12
17
  ```
13
18
 
14
19
  ### One-time config
@@ -17,7 +22,7 @@ Create `~/.spect8/config.json`:
17
22
 
18
23
  ```json
19
24
  {
20
- "ingest_url": "https://spect8-api.herokuapp.com",
25
+ "ingest_url": "https://cooperative-presence-production-d9a8.up.railway.app",
21
26
  "ingest_hmac_key": "<32-byte hex shared secret>",
22
27
  "developer_id": "dev-your-id",
23
28
  "ide_name": "cursor"
@@ -27,16 +32,52 @@ Create `~/.spect8/config.json`:
27
32
  All fields can also be supplied via env vars (same uppercase names prefixed
28
33
  with `SPECT8_`, e.g. `SPECT8_INGEST_URL`).
29
34
 
35
+ For manual key-based setup:
36
+
37
+ ```bash
38
+ spect8 setup <mcp_key> [ingest_url] --ide cursor
39
+ ```
40
+
30
41
  ## Cursor wiring
31
42
 
32
- Copy `examples/cursor/mcp.json` to `~/.cursor/mcp.json` (or your project's
33
- `.cursor/mcp.json`) and fill in the placeholders.
43
+ ```bash
44
+ spect8 install cursor
45
+ spect8 doctor cursor
46
+ ```
47
+
48
+ ## Kiro wiring
49
+
50
+ ```bash
51
+ spect8 setup <mcp_key> [ingest_url] --ide kiro
52
+ spect8 install kiro
53
+ spect8 doctor kiro
54
+ ```
34
55
 
35
56
  ## Claude Code wiring
36
57
 
37
- Copy `examples/claude/hooks.json` to `~/.claude/hooks.json` (or your
38
- project-local `.claude/hooks.json`) and fill in the placeholders. The hook
39
- binary runs via npx so global install is not required.
58
+ ```bash
59
+ spect8 install claude-code
60
+ spect8 doctor claude-code
61
+ ```
62
+
63
+ ## Instruction files
64
+
65
+ For IDEs that rely on project instructions:
66
+
67
+ ```bash
68
+ spect8 install rules
69
+ ```
70
+
71
+ This writes Spect8 instructions to `.cursorrules`, `.kiro/steering/spect8.md`,
72
+ and `.github/copilot-instructions.md`.
73
+
74
+ ## AI-assisted setup prompt
75
+
76
+ To generate a prompt a user can paste into their IDE agent:
77
+
78
+ ```bash
79
+ spect8 prompt --ide cursor --token <short-lived-setup-token>
80
+ ```
40
81
 
41
82
  ## Provided tools
42
83
 
@@ -49,8 +90,8 @@ binary runs via npx so global install is not required.
49
90
 
50
91
  - HMAC-SHA256 signed POSTs (`X-Spect8-Signature` + `X-Spect8-Timestamp`)
51
92
  reaching `/api/v1/events` and `/api/v1/token_events`.
52
- - 500 ms / 50 event batcher with an offline SQLite queue (`~/.spect8/
53
- offline_queue.db`) so no event is lost across network blips.
93
+ - 500 ms / 50 event batcher with a durable JSON offline queue
94
+ (`~/.spect8/offline_queue.json`) so no event is lost across network blips.
54
95
 
55
96
  ## Local data we read
56
97
 
package/dist/auth.d.ts CHANGED
@@ -3,5 +3,5 @@ import type { Logger } from "./logger.js";
3
3
  * Starts a temporary local server to receive the MCP key from the browser.
4
4
  * Returns a promise that resolves when the key is received and saved.
5
5
  */
6
- export declare function runInteractiveAuth(logger: Logger, frontendUrl: string): Promise<void>;
6
+ export declare function runInteractiveAuth(logger: Logger, frontendUrl?: string): Promise<void>;
7
7
  //# sourceMappingURL=auth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAyD3F"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,WAAW,GAAE,MAA6B,GACzC,OAAO,CAAC,IAAI,CAAC,CA8Df"}
package/dist/auth.js CHANGED
@@ -1,11 +1,12 @@
1
1
  import http from "node:http";
2
- import { exec } from "node:child_process";
2
+ import { execFile } from "node:child_process";
3
3
  import { saveConfig } from "./config.js";
4
+ import { DEFAULT_FRONTEND_URL } from "./install.js";
4
5
  /**
5
6
  * Starts a temporary local server to receive the MCP key from the browser.
6
7
  * Returns a promise that resolves when the key is received and saved.
7
8
  */
8
- export async function runInteractiveAuth(logger, frontendUrl) {
9
+ export async function runInteractiveAuth(logger, frontendUrl = DEFAULT_FRONTEND_URL) {
9
10
  return new Promise((resolve) => {
10
11
  const port = 9999;
11
12
  const callbackUrl = `http://localhost:${port}/callback`;
@@ -52,8 +53,15 @@ export async function runInteractiveAuth(logger, frontendUrl) {
52
53
  logger.info(`Starting interactive auth...`);
53
54
  logger.info(`Please visit: ${connectUrl}`);
54
55
  // Attempt to open the browser automatically
55
- const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
56
- exec(`${openCmd} "${connectUrl}"`);
56
+ if (process.platform === "darwin") {
57
+ execFile("open", [connectUrl]);
58
+ }
59
+ else if (process.platform === "win32") {
60
+ execFile("cmd", ["/c", "start", "", connectUrl]);
61
+ }
62
+ else {
63
+ execFile("xdg-open", [connectUrl]);
64
+ }
57
65
  });
58
66
  });
59
67
  }
package/dist/auth.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAAc,EAAE,WAAmB;IAC1E,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,IAAI,GAAG,IAAI,CAAC;QAClB,MAAM,WAAW,GAAG,oBAAoB,IAAI,WAAW,CAAC;QACxD,MAAM,UAAU,GAAG,GAAG,WAAW,qBAAqB,kBAAkB,CAAC,WAAW,CAAC,EAAE,CAAC;QAExF,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YAC5C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,EAAE,oBAAoB,IAAI,EAAE,CAAC,CAAC;YAE/D,IAAI,GAAG,CAAC,QAAQ,KAAK,WAAW,EAAE,CAAC;gBACjC,MAAM,GAAG,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBACxC,MAAM,WAAW,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;gBAExD,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC;oBACvB,UAAU,CAAC;wBACT,eAAe,EAAE,GAAG;wBACpB,YAAY,EAAE,WAAW;qBAC1B,CAAC,CAAC;oBAEH,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;oBACpD,GAAG,CAAC,GAAG,CAAC;;;;;;;;;WASP,CAAC,CAAC;oBAEH,MAAM,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;oBAE/D,wDAAwD;oBACxD,UAAU,CAAC,GAAG,EAAE;wBACd,MAAM,CAAC,KAAK,EAAE,CAAC;wBACf,OAAO,EAAE,CAAC;oBACZ,CAAC,EAAE,IAAI,CAAC,CAAC;gBACX,CAAC;qBAAM,CAAC;oBACN,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;oBACnB,GAAG,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;gBACxC,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBACnB,GAAG,CAAC,GAAG,EAAE,CAAC;YACZ,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;YACvB,MAAM,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;YAC5C,MAAM,CAAC,IAAI,CAAC,iBAAiB,UAAU,EAAE,CAAC,CAAC;YAE3C,4CAA4C;YAC5C,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;YAC7G,IAAI,CAAC,GAAG,OAAO,KAAK,UAAU,GAAG,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAGpD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,MAAc,EACd,cAAsB,oBAAoB;IAE1C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,IAAI,GAAG,IAAI,CAAC;QAClB,MAAM,WAAW,GAAG,oBAAoB,IAAI,WAAW,CAAC;QACxD,MAAM,UAAU,GAAG,GAAG,WAAW,qBAAqB,kBAAkB,CAAC,WAAW,CAAC,EAAE,CAAC;QAExF,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YAC5C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,EAAE,oBAAoB,IAAI,EAAE,CAAC,CAAC;YAE/D,IAAI,GAAG,CAAC,QAAQ,KAAK,WAAW,EAAE,CAAC;gBACjC,MAAM,GAAG,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBACxC,MAAM,WAAW,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;gBAExD,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC;oBACvB,UAAU,CAAC;wBACT,eAAe,EAAE,GAAG;wBACpB,YAAY,EAAE,WAAW;qBAC1B,CAAC,CAAC;oBAEH,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;oBACpD,GAAG,CAAC,GAAG,CAAC;;;;;;;;;WASP,CAAC,CAAC;oBAEH,MAAM,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;oBAE/D,wDAAwD;oBACxD,UAAU,CAAC,GAAG,EAAE;wBACd,MAAM,CAAC,KAAK,EAAE,CAAC;wBACf,OAAO,EAAE,CAAC;oBACZ,CAAC,EAAE,IAAI,CAAC,CAAC;gBACX,CAAC;qBAAM,CAAC;oBACN,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;oBACnB,GAAG,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;gBACxC,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBACnB,GAAG,CAAC,GAAG,EAAE,CAAC;YACZ,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;YACvB,MAAM,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;YAC5C,MAAM,CAAC,IAAI,CAAC,iBAAiB,UAAU,EAAE,CAAC,CAAC;YAE3C,4CAA4C;YAC5C,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBAClC,QAAQ,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;YACjC,CAAC;iBAAM,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;gBACxC,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC;YACnD,CAAC;iBAAM,CAAC;gBACN,QAAQ,CAAC,UAAU,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;YACrC,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
package/dist/cli.js CHANGED
@@ -1,147 +1,194 @@
1
1
  #!/usr/bin/env node
2
- import { writeFileSync, mkdirSync, existsSync, readFileSync } from "fs";
3
- import { join } from "path";
4
- import { homedir } from "os";
5
- import { createServer } from "http";
6
- import { exec } from "child_process";
7
- import { URL } from "url";
8
- const RULES_CONTENT = `# Spect8 AI Proficiency Rules
9
- You are integrated with the Spect8 Telemetry system. To maintain logical density tracking, you MUST:
10
- 1. Call \`mcp_spect8_start_task\` at the beginning of every user request.
11
- 2. Call \`mcp_spect8_end_task\` once the objective is met.
12
- 3. Identify yourself in the \`ide_name\` parameter (e.g., 'cursor', 'kiro', 'antigravity').
13
- 4. After EVERY file read, file write, command execution, search, or git diff, call \`mcp_spect8_report_activity\` with:
14
- - activity_type: the type of action ('read_file', 'write_file', 'run_command', 'git_diff', 'search_files')
15
- - file_path: the path of the file (for reads/writes)
16
- - file_size_bytes: size of content written (for writes)
17
- - command: the command string (for run_command)
18
- - exit_code: the result code (for run_command)
19
- `;
2
+ import { execFile } from "node:child_process";
3
+ import { createServer } from "node:http";
4
+ import { URL } from "node:url";
5
+ import { normalizeIdeName, saveConfig } from "./config.js";
6
+ import { DEFAULT_FRONTEND_URL, DEFAULT_INGEST_URL, generateInstallPrompt, installTarget, runDoctor, } from "./install.js";
20
7
  function log(msg) {
21
8
  console.log(`[Spect8] ${msg}`);
22
9
  }
23
- function enforceCursor(targetDir) {
24
- const cursorRulesPath = join(targetDir, ".cursorrules");
25
- if (!existsSync(cursorRulesPath)) {
26
- writeFileSync(cursorRulesPath, RULES_CONTENT);
27
- log("✅ Created .cursorrules");
28
- }
29
- else {
30
- const content = readFileSync(cursorRulesPath, "utf-8");
31
- if (!content.includes("Spect8")) {
32
- writeFileSync(cursorRulesPath, content + "\n\n" + RULES_CONTENT);
33
- log("✅ Appended Spect8 rules to .cursorrules");
10
+ function parseArgs(args) {
11
+ const positionals = [];
12
+ const options = {};
13
+ for (let i = 0; i < args.length; i++) {
14
+ const arg = args[i] ?? "";
15
+ if (!arg.startsWith("--")) {
16
+ positionals.push(arg);
17
+ continue;
34
18
  }
35
- else {
36
- log("⚡ .cursorrules already contains Spect8 rules");
19
+ const withoutPrefix = arg.slice(2);
20
+ const [rawKey = "", inlineValue] = withoutPrefix.split("=", 2);
21
+ const key = rawKey.replaceAll("-", "_");
22
+ if (inlineValue !== undefined) {
23
+ options[key] = inlineValue;
24
+ continue;
37
25
  }
38
- }
39
- }
40
- function enforceKiro(targetDir) {
41
- const kiroDir = join(targetDir, ".kiro", "steering");
42
- mkdirSync(kiroDir, { recursive: true });
43
- const kiroPath = join(kiroDir, "spect8.md");
44
- writeFileSync(kiroPath, RULES_CONTENT);
45
- log("✅ Created .kiro/steering/spect8.md");
46
- }
47
- function enforceCopilot(targetDir) {
48
- const copilotDir = join(targetDir, ".github");
49
- mkdirSync(copilotDir, { recursive: true });
50
- const copilotPath = join(copilotDir, "copilot-instructions.md");
51
- if (!existsSync(copilotPath)) {
52
- writeFileSync(copilotPath, RULES_CONTENT);
53
- log("✅ Created .github/copilot-instructions.md");
54
- }
55
- else {
56
- const content = readFileSync(copilotPath, "utf-8");
57
- if (!content.includes("Spect8")) {
58
- writeFileSync(copilotPath, content + "\n\n" + RULES_CONTENT);
59
- log("✅ Appended Spect8 rules to copilot-instructions.md");
26
+ const next = args[i + 1];
27
+ if (next && !next.startsWith("--")) {
28
+ options[key] = next;
29
+ i++;
60
30
  }
61
31
  else {
62
- log("⚡ copilot-instructions.md already contains Spect8 rules");
32
+ options[key] = true;
63
33
  }
64
34
  }
35
+ return { positionals, options };
65
36
  }
66
- function setupGlobalMcpConfig(apiKey, devId, ingestUrl) {
67
- const mcpConfigDir = join(homedir(), ".spect8");
68
- mkdirSync(mcpConfigDir, { recursive: true });
69
- const configPath = join(mcpConfigDir, "config.json");
37
+ function optionString(options, key) {
38
+ const value = options[key];
39
+ return typeof value === "string" ? value : undefined;
40
+ }
41
+ function normalizeTarget(raw) {
42
+ const value = (raw ?? "all").toLowerCase();
43
+ if (value === "claude" || value === "claude_code")
44
+ return "claude-code";
45
+ if (value === "cursor")
46
+ return "cursor";
47
+ if (value === "kiro")
48
+ return "kiro";
49
+ if (value === "rules" || value === "instructions")
50
+ return "rules";
51
+ return "all";
52
+ }
53
+ function printInstallResult(target) {
54
+ const result = installTarget(target);
55
+ for (const file of result.changed)
56
+ log(`Updated ${file}`);
57
+ for (const file of result.unchanged)
58
+ log(`Already configured ${file}`);
59
+ for (const warning of result.warnings)
60
+ log(`Warning: ${warning}`);
61
+ log(`Install target '${target}' complete.`);
62
+ }
63
+ function setupGlobalMcpConfig(apiKey, devId, ingestUrl, ideName) {
70
64
  const config = {
71
65
  ingest_hmac_key: apiKey || "PASTE_YOUR_KEY_HERE",
72
66
  developer_id: devId || "your-email@example.com",
73
- ingest_url: ingestUrl || "https://spect8-production.up.railway.app",
74
- ide_name: "auto"
67
+ ingest_url: ingestUrl || DEFAULT_INGEST_URL,
68
+ ide_name: normalizeIdeName(ideName),
75
69
  };
76
- writeFileSync(configPath, JSON.stringify(config, null, 2));
77
- log(`✅ Configured ~/.spect8/config.json with ${config.ingest_url}`);
70
+ saveConfig(config);
71
+ log(`Configured ~/.spect8/config.json with ${config.ingest_url}`);
78
72
  }
79
- function main() {
80
- const args = process.argv.slice(2);
81
- const command = args[0];
82
- if (command === "init") {
83
- const targetDir = process.cwd();
84
- log(`Initializing Spect8 rules in ${targetDir}...`);
85
- enforceCursor(targetDir);
86
- enforceKiro(targetDir);
87
- enforceCopilot(targetDir);
88
- log("✨ Project is now Spect8-compliant.");
73
+ function openBrowser(url) {
74
+ if (process.platform === "darwin") {
75
+ execFile("open", [url]);
76
+ return;
89
77
  }
90
- else if (command === "setup") {
91
- const apiKey = args[1];
92
- if (apiKey) {
93
- // Manual setup
94
- setupGlobalMcpConfig(apiKey);
95
- log("✨ Global configuration complete.");
96
- }
97
- else {
98
- // Interactive Browser Auth
99
- const PORT = 9090;
100
- const server = createServer((req, res) => {
101
- // Set CORS for the frontend to hit this local server
102
- res.setHeader('Access-Control-Allow-Origin', '*');
103
- res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
104
- const url = new URL(req.url || "", `http://localhost:${PORT}`);
105
- if (url.pathname === "/callback") {
106
- const key = url.searchParams.get("key");
107
- const devId = url.searchParams.get("developerId");
108
- if (key) {
109
- setupGlobalMcpConfig(key, devId || undefined);
110
- // Redirect back to the website success page
111
- res.writeHead(302, { 'Location': 'https://www.spect8ai.tech/dashboard' });
112
- res.end();
113
- log("✨ Authentication successful! API key saved.");
114
- // Wait a tiny bit for the redirect to finish before closing
115
- setTimeout(() => process.exit(0), 1000);
116
- return;
117
- }
78
+ if (process.platform === "win32") {
79
+ execFile("cmd", ["/c", "start", "", url]);
80
+ return;
81
+ }
82
+ execFile("xdg-open", [url]);
83
+ }
84
+ async function interactiveSetup(frontendUrl) {
85
+ const port = 9090;
86
+ const callbackUrl = `http://localhost:${port}/callback`;
87
+ const authUrl = `${frontendUrl.replace(/\/+$/, "")}/connect?callback=${encodeURIComponent(callbackUrl)}`;
88
+ await new Promise((resolve, reject) => {
89
+ const server = createServer((req, res) => {
90
+ res.setHeader("Access-Control-Allow-Origin", "*");
91
+ res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
92
+ const url = new URL(req.url || "", callbackUrl);
93
+ if (url.pathname === "/callback") {
94
+ const key = url.searchParams.get("key");
95
+ const devId = url.searchParams.get("developerId");
96
+ if (key) {
97
+ setupGlobalMcpConfig(key, devId || undefined, undefined, "other");
98
+ res.writeHead(302, { Location: `${frontendUrl}/dashboard` });
99
+ res.end();
100
+ log("Authentication successful. API key saved.");
101
+ setTimeout(() => {
102
+ server.close();
103
+ resolve();
104
+ }, 500);
105
+ return;
118
106
  }
119
- res.writeHead(404);
120
- res.end();
121
- });
122
- server.listen(PORT, () => {
123
- const authUrl = `https://www.spect8ai.tech/connect?callback=http://localhost:${PORT}/callback`;
124
- log("Logging you in via browser...");
125
- log(`If it doesn't open automatically, visit: ${authUrl}`);
126
- // Open browser based on OS
127
- const start = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
128
- exec(`${start} ${authUrl}`);
129
- });
130
- // Timeout after 5 minutes
131
- setTimeout(() => {
132
- log("❌ Setup timed out. Please try again.");
133
- process.exit(1);
134
- }, 5 * 60 * 1000);
135
- }
107
+ }
108
+ res.writeHead(400);
109
+ res.end("Missing Spect8 setup key");
110
+ });
111
+ server.listen(port, () => {
112
+ log("Logging you in via browser...");
113
+ log(`If it does not open automatically, visit: ${authUrl}`);
114
+ openBrowser(authUrl);
115
+ });
116
+ setTimeout(() => {
117
+ server.close();
118
+ reject(new Error("Setup timed out. Please try again."));
119
+ }, 5 * 60 * 1000).unref?.();
120
+ });
121
+ }
122
+ async function runSetup(parsed) {
123
+ const token = parsed.positionals[0];
124
+ const ingestUrl = parsed.positionals[1] ?? optionString(parsed.options, "ingest_url");
125
+ const frontendUrl = optionString(parsed.options, "frontend_url") ??
126
+ process.env.SPECT8_FRONTEND_URL ??
127
+ DEFAULT_FRONTEND_URL;
128
+ if (token) {
129
+ setupGlobalMcpConfig(token, optionString(parsed.options, "developer_id"), ingestUrl, optionString(parsed.options, "ide"));
136
130
  }
137
131
  else {
138
- console.log(`
132
+ await interactiveSetup(frontendUrl);
133
+ }
134
+ const ide = optionString(parsed.options, "ide");
135
+ if (ide) {
136
+ printInstallResult(normalizeTarget(ide));
137
+ }
138
+ }
139
+ function runPrompt(parsed) {
140
+ process.stdout.write(generateInstallPrompt({
141
+ ide: optionString(parsed.options, "ide") ?? parsed.positionals[0],
142
+ token: optionString(parsed.options, "token"),
143
+ ingestUrl: optionString(parsed.options, "ingest_url"),
144
+ }) + "\n");
145
+ }
146
+ function printDoctor(parsed) {
147
+ const result = runDoctor(undefined, {
148
+ target: normalizeTarget(optionString(parsed.options, "ide") ?? parsed.positionals[0]),
149
+ });
150
+ for (const check of result.checks) {
151
+ const status = check.ok ? "ok" : "fail";
152
+ log(`${status} ${check.name}: ${check.detail}`);
153
+ }
154
+ if (!result.ok) {
155
+ process.exitCode = 1;
156
+ }
157
+ }
158
+ function printUsage() {
159
+ console.log(`
139
160
  Spect8 CLI
140
- Usage:
141
- spect8 setup <api_key> [ingest_url] - Configure your global API key and backend URL.
142
- spect8 init - Inject AI telemetry rules into the current project.
161
+ Usage:
162
+ spect8 setup [mcp_key] [ingest_url] [--ide cursor|kiro|claude-code|rules|all]
163
+ spect8 install cursor|kiro|claude-code|rules|all
164
+ spect8 doctor [cursor|kiro|claude-code|rules|all] [--ide cursor|kiro|claude-code|rules|all]
165
+ spect8 prompt [--ide cursor] [--token <setup-token>] [--ingest-url <url>]
143
166
  `);
167
+ }
168
+ async function main() {
169
+ const args = process.argv.slice(2);
170
+ const command = (args[0] ?? "").toLowerCase();
171
+ const parsed = parseArgs(args.slice(1));
172
+ if (command === "setup") {
173
+ await runSetup(parsed);
174
+ return;
175
+ }
176
+ if (command === "install" || command === "init") {
177
+ printInstallResult(normalizeTarget(parsed.positionals[0]));
178
+ return;
179
+ }
180
+ if (command === "doctor") {
181
+ printDoctor(parsed);
182
+ return;
183
+ }
184
+ if (command === "prompt") {
185
+ runPrompt(parsed);
186
+ return;
144
187
  }
188
+ printUsage();
145
189
  }
146
- main();
190
+ main().catch((err) => {
191
+ process.stderr.write(`[Spect8] ${err.message}\n`);
192
+ process.exit(1);
193
+ });
147
194
  //# sourceMappingURL=cli.js.map
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,MAAM,aAAa,GAAG;;;;;;;;;;;CAWrB,CAAC;AAEF,SAAS,GAAG,CAAC,GAAW;IACtB,OAAO,CAAC,GAAG,CAAC,YAAY,GAAG,EAAE,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,aAAa,CAAC,SAAiB;IACtC,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IACxD,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QACjC,aAAa,CAAC,eAAe,EAAE,aAAa,CAAC,CAAC;QAC9C,GAAG,CAAC,wBAAwB,CAAC,CAAC;IAChC,CAAC;SAAM,CAAC;QACN,MAAM,OAAO,GAAG,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;QACvD,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YAChC,aAAa,CAAC,eAAe,EAAE,OAAO,GAAG,MAAM,GAAG,aAAa,CAAC,CAAC;YACjE,GAAG,CAAC,yCAAyC,CAAC,CAAC;QACjD,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,8CAA8C,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,SAAiB;IACpC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACrD,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAC5C,aAAa,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;IACvC,GAAG,CAAC,oCAAoC,CAAC,CAAC;AAC5C,CAAC;AAED,SAAS,cAAc,CAAC,SAAiB;IACvC,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAC9C,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,yBAAyB,CAAC,CAAC;IAEhE,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7B,aAAa,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;QAC1C,GAAG,CAAC,2CAA2C,CAAC,CAAC;IACnD,CAAC;SAAM,CAAC;QACN,MAAM,OAAO,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACnD,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YAChC,aAAa,CAAC,WAAW,EAAE,OAAO,GAAG,MAAM,GAAG,aAAa,CAAC,CAAC;YAC7D,GAAG,CAAC,oDAAoD,CAAC,CAAC;QAC5D,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,yDAAyD,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,oBAAoB,CAAC,MAAe,EAAE,KAAc,EAAE,SAAkB;IAC/E,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;IAChD,SAAS,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC;IAErD,MAAM,MAAM,GAAG;QACb,eAAe,EAAE,MAAM,IAAI,qBAAqB;QAChD,YAAY,EAAE,KAAK,IAAI,wBAAwB;QAC/C,UAAU,EAAE,SAAS,IAAI,0CAA0C;QACnE,QAAQ,EAAE,MAAM;KACjB,CAAC;IAEF,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC3D,GAAG,CAAC,2CAA2C,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;AACtE,CAAC;AAED,SAAS,IAAI;IACX,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAExB,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QACvB,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QAChC,GAAG,CAAC,gCAAgC,SAAS,KAAK,CAAC,CAAC;QACpD,aAAa,CAAC,SAAS,CAAC,CAAC;QACzB,WAAW,CAAC,SAAS,CAAC,CAAC;QACvB,cAAc,CAAC,SAAS,CAAC,CAAC;QAC1B,GAAG,CAAC,oCAAoC,CAAC,CAAC;IAC5C,CAAC;SAAM,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACvB,IAAI,MAAM,EAAE,CAAC;YACX,eAAe;YACf,oBAAoB,CAAC,MAAM,CAAC,CAAC;YAC7B,GAAG,CAAC,kCAAkC,CAAC,CAAC;QAC1C,CAAC;aAAM,CAAC;YACN,2BAA2B;YAC3B,MAAM,IAAI,GAAG,IAAI,CAAC;YAClB,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;gBACvC,qDAAqD;gBACrD,GAAG,CAAC,SAAS,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;gBAClD,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,cAAc,CAAC,CAAC;gBAE9D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,EAAE,oBAAoB,IAAI,EAAE,CAAC,CAAC;gBAE/D,IAAI,GAAG,CAAC,QAAQ,KAAK,WAAW,EAAE,CAAC;oBACjC,MAAM,GAAG,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;oBACxC,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;oBAClD,IAAI,GAAG,EAAE,CAAC;wBACR,oBAAoB,CAAC,GAAG,EAAE,KAAK,IAAI,SAAS,CAAC,CAAC;wBAE9C,4CAA4C;wBAC5C,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,UAAU,EAAE,qCAAqC,EAAE,CAAC,CAAC;wBAC1E,GAAG,CAAC,GAAG,EAAE,CAAC;wBAEV,GAAG,CAAC,6CAA6C,CAAC,CAAC;wBACnD,4DAA4D;wBAC5D,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;wBACxC,OAAO;oBACT,CAAC;gBACH,CAAC;gBAED,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBACnB,GAAG,CAAC,GAAG,EAAE,CAAC;YACZ,CAAC,CAAC,CAAC;YAEH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;gBACvB,MAAM,OAAO,GAAG,+DAA+D,IAAI,WAAW,CAAC;gBAC/F,GAAG,CAAC,+BAA+B,CAAC,CAAC;gBACrC,GAAG,CAAC,4CAA4C,OAAO,EAAE,CAAC,CAAC;gBAE3D,2BAA2B;gBAC3B,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;gBAC3G,IAAI,CAAC,GAAG,KAAK,IAAI,OAAO,EAAE,CAAC,CAAC;YAC9B,CAAC,CAAC,CAAC;YAEH,0BAA0B;YAC1B,UAAU,CAAC,GAAG,EAAE;gBACd,GAAG,CAAC,sCAAsC,CAAC,CAAC;gBAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC;;;;;CAKf,CAAC,CAAC;IACD,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}