blackops-onboard 0.1.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.
Files changed (3) hide show
  1. package/README.md +28 -0
  2. package/bin/onboard.mjs +176 -0
  3. package/package.json +33 -0
package/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # blackops-onboard
2
+
3
+ Agent-first onboarding for [BlackOps Center](https://blackopscenter.com).
4
+
5
+ ```bash
6
+ npx blackops-onboard
7
+ ```
8
+
9
+ That command:
10
+
11
+ 1. Provisions an onboarding token for you.
12
+ 2. Adds a `blackops` MCP server entry to your Claude Code settings (`~/.claude/settings.json`).
13
+ 3. Prints a prompt to paste into Claude Code.
14
+
15
+ From there, the agent walks you through account creation, brand-voice capture, social-account OAuth, and publishing your first content across X, Threads, LinkedIn, and your new blog — entirely conversationally.
16
+
17
+ ## Re-running
18
+
19
+ Re-running detects an existing config at `~/.blackops/config.json`. You can keep the existing token (and re-paste the saved prompt) or overwrite to start fresh.
20
+
21
+ ## Environment
22
+
23
+ - `BLACKOPS_INSTALL_URL` — override the install endpoint (default `https://blackopscenter.com/api/install`).
24
+
25
+ ## Requirements
26
+
27
+ - Node.js 18+
28
+ - [Claude Code](https://claude.com/claude-code)
@@ -0,0 +1,176 @@
1
+ #!/usr/bin/env node
2
+ // BlackOps Center agent-first onboarding CLI.
3
+ //
4
+ // What this does:
5
+ // 1. POSTs to https://blackopscenter.com/api/install to mint an onboarding token.
6
+ // 2. Writes ~/.blackops/config.json with token + MCP URL.
7
+ // 3. Adds a `blackops` MCP server entry to Claude Code's settings.json.
8
+ // 4. Prints the onboarding prompt for the user to paste into Claude Code.
9
+ //
10
+ // Re-runs are idempotent: an existing ~/.blackops/config.json will prompt the
11
+ // user before overwriting.
12
+
13
+ import fs from 'node:fs'
14
+ import path from 'node:path'
15
+ import os from 'node:os'
16
+ import readline from 'node:readline/promises'
17
+
18
+ const VERSION = '0.1.0'
19
+ const INSTALL_URL = process.env.BLACKOPS_INSTALL_URL || 'https://blackopscenter.com/api/install'
20
+ const CONFIG_DIR = path.join(os.homedir(), '.blackops')
21
+ const CONFIG_PATH = path.join(CONFIG_DIR, 'config.json')
22
+
23
+ const RESET = '\x1b[0m'
24
+ const BOLD = '\x1b[1m'
25
+ const DIM = '\x1b[2m'
26
+ const GREEN = '\x1b[32m'
27
+ const CYAN = '\x1b[36m'
28
+ const YELLOW = '\x1b[33m'
29
+ const RED = '\x1b[31m'
30
+
31
+ const log = (s = '') => process.stdout.write(`${s}\n`)
32
+ const err = (s) => process.stderr.write(`${RED}${s}${RESET}\n`)
33
+
34
+ async function confirm(question) {
35
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
36
+ try {
37
+ const answer = await rl.question(`${question} (y/N) `)
38
+ return /^y(es)?$/i.test(answer.trim())
39
+ } finally {
40
+ rl.close()
41
+ }
42
+ }
43
+
44
+ function findClaudeCodeSettingsPath() {
45
+ // Claude Code stores user-level settings in ~/.claude/settings.json on macOS/Linux.
46
+ // (The same file holds permissions, hooks, and MCP servers.)
47
+ const candidates = [
48
+ path.join(os.homedir(), '.claude', 'settings.json'),
49
+ ]
50
+ for (const p of candidates) {
51
+ if (fs.existsSync(p)) return p
52
+ }
53
+ return candidates[0] // first candidate; we'll create it
54
+ }
55
+
56
+ function readJsonSafe(filePath) {
57
+ try {
58
+ const raw = fs.readFileSync(filePath, 'utf8')
59
+ return JSON.parse(raw)
60
+ } catch {
61
+ return null
62
+ }
63
+ }
64
+
65
+ function writeJsonAtomic(filePath, value) {
66
+ fs.mkdirSync(path.dirname(filePath), { recursive: true })
67
+ const tmp = `${filePath}.tmp.${process.pid}`
68
+ fs.writeFileSync(tmp, `${JSON.stringify(value, null, 2)}\n`, 'utf8')
69
+ fs.renameSync(tmp, filePath)
70
+ }
71
+
72
+ async function callInstallEndpoint() {
73
+ const response = await fetch(INSTALL_URL, {
74
+ method: 'POST',
75
+ headers: { 'Content-Type': 'application/json' },
76
+ body: JSON.stringify({ cli_version: VERSION }),
77
+ })
78
+ if (!response.ok) {
79
+ const text = await response.text().catch(() => '')
80
+ throw new Error(`install endpoint returned ${response.status}: ${text || 'no body'}`)
81
+ }
82
+ const data = await response.json()
83
+ if (!data?.token || !data?.mcp_url) {
84
+ throw new Error('install endpoint returned an invalid response')
85
+ }
86
+ return data
87
+ }
88
+
89
+ function injectClaudeCodeMcp({ mcpUrl, mcpServerName, token }) {
90
+ const settingsPath = findClaudeCodeSettingsPath()
91
+ const settings = readJsonSafe(settingsPath) ?? {}
92
+ settings.mcpServers = settings.mcpServers ?? {}
93
+
94
+ // Use the SSE/HTTP transport — Claude Code supports `type: "http"` MCP servers.
95
+ settings.mcpServers[mcpServerName] = {
96
+ type: 'http',
97
+ url: mcpUrl,
98
+ headers: {
99
+ Authorization: `Bearer ${token}`,
100
+ },
101
+ }
102
+
103
+ writeJsonAtomic(settingsPath, settings)
104
+ return settingsPath
105
+ }
106
+
107
+ async function main() {
108
+ log(`${BOLD}${CYAN}BlackOps Center — agent-first onboarding${RESET}`)
109
+ log(`${DIM}v${VERSION}${RESET}`)
110
+ log()
111
+
112
+ // Idempotency check — if the user already has a config, ask before overwriting.
113
+ if (fs.existsSync(CONFIG_PATH)) {
114
+ log(`${YELLOW}Existing config found at ${CONFIG_PATH}.${RESET}`)
115
+ const overwrite = await confirm('Overwrite and start fresh?')
116
+ if (!overwrite) {
117
+ log('Keeping existing config. Re-paste the prompt below to resume:')
118
+ log()
119
+ const existing = readJsonSafe(CONFIG_PATH)
120
+ log(existing?.prompt ?? '(no saved prompt)')
121
+ return
122
+ }
123
+ }
124
+
125
+ // 1. Mint onboarding token.
126
+ let install
127
+ try {
128
+ log(`${DIM}Provisioning onboarding token…${RESET}`)
129
+ install = await callInstallEndpoint()
130
+ } catch (e) {
131
+ err(`Failed to reach BlackOps install endpoint: ${e.message}`)
132
+ process.exit(1)
133
+ }
134
+
135
+ // 2. Save config locally.
136
+ const config = {
137
+ token: install.token,
138
+ mcp_url: install.mcp_url,
139
+ mcp_server_name: install.mcp_server_name || 'blackops',
140
+ token_id: install.token_id,
141
+ expires_at: install.expires_at,
142
+ prompt: install.prompt,
143
+ cli_version: VERSION,
144
+ installed_at: new Date().toISOString(),
145
+ }
146
+ writeJsonAtomic(CONFIG_PATH, config)
147
+ log(`${GREEN}✓${RESET} Saved config to ${CONFIG_PATH}`)
148
+
149
+ // 3. Wire up Claude Code MCP.
150
+ let settingsPath
151
+ try {
152
+ settingsPath = injectClaudeCodeMcp({
153
+ mcpUrl: config.mcp_url,
154
+ mcpServerName: config.mcp_server_name,
155
+ token: config.token,
156
+ })
157
+ log(`${GREEN}✓${RESET} Added MCP server "${config.mcp_server_name}" to ${settingsPath}`)
158
+ } catch (e) {
159
+ err(`Could not write Claude Code settings: ${e.message}`)
160
+ log('You can configure manually by adding this MCP server to your Claude Code settings:')
161
+ log(JSON.stringify({ [config.mcp_server_name]: { type: 'http', url: config.mcp_url, headers: { Authorization: `Bearer ${config.token}` } } }, null, 2))
162
+ }
163
+
164
+ // 4. Print onboarding prompt for the user.
165
+ log()
166
+ log(`${BOLD}Open Claude Code and paste this prompt to begin:${RESET}`)
167
+ log()
168
+ log(`${CYAN}${config.prompt}${RESET}`)
169
+ log()
170
+ log(`${DIM}Token expires: ${config.expires_at}${RESET}`)
171
+ }
172
+
173
+ main().catch((e) => {
174
+ err(`Unexpected error: ${e?.stack ?? e}`)
175
+ process.exit(1)
176
+ })
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "blackops-onboard",
3
+ "version": "0.1.0",
4
+ "description": "Agent-first onboarding for BlackOps Center. Run via `npx blackops-onboard` to provision your account through Claude Code.",
5
+ "type": "module",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "bin": {
10
+ "blackops-onboard": "./bin/onboard.mjs"
11
+ },
12
+ "files": [
13
+ "bin",
14
+ "README.md"
15
+ ],
16
+ "engines": {
17
+ "node": ">=18"
18
+ },
19
+ "license": "UNLICENSED",
20
+ "homepage": "https://blackopscenter.com",
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "https://github.com/bennewton999/2024-blog.git",
24
+ "directory": "packages/blackops-onboard"
25
+ },
26
+ "keywords": [
27
+ "blackopscenter",
28
+ "claude-code",
29
+ "mcp",
30
+ "onboarding",
31
+ "cli"
32
+ ]
33
+ }