@martin0309205/prism 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 (51) hide show
  1. package/README.md +87 -0
  2. package/assets/systemd/prism@.service +21 -0
  3. package/dist/artifacts.d.ts +9 -0
  4. package/dist/artifacts.js +77 -0
  5. package/dist/artifacts.js.map +1 -0
  6. package/dist/cli/commands/daemon.d.ts +2 -0
  7. package/dist/cli/commands/daemon.js +90 -0
  8. package/dist/cli/commands/daemon.js.map +1 -0
  9. package/dist/cli/commands/doctor.d.ts +2 -0
  10. package/dist/cli/commands/doctor.js +69 -0
  11. package/dist/cli/commands/doctor.js.map +1 -0
  12. package/dist/cli/commands/generate.d.ts +2 -0
  13. package/dist/cli/commands/generate.js +89 -0
  14. package/dist/cli/commands/generate.js.map +1 -0
  15. package/dist/cli/commands/onboard.d.ts +2 -0
  16. package/dist/cli/commands/onboard.js +131 -0
  17. package/dist/cli/commands/onboard.js.map +1 -0
  18. package/dist/cli/commands/serve.d.ts +2 -0
  19. package/dist/cli/commands/serve.js +51 -0
  20. package/dist/cli/commands/serve.js.map +1 -0
  21. package/dist/cli/commands/update.d.ts +2 -0
  22. package/dist/cli/commands/update.js +38 -0
  23. package/dist/cli/commands/update.js.map +1 -0
  24. package/dist/cli/index.d.ts +2 -0
  25. package/dist/cli/index.js +29 -0
  26. package/dist/cli/index.js.map +1 -0
  27. package/dist/config.d.ts +34 -0
  28. package/dist/config.js +88 -0
  29. package/dist/config.js.map +1 -0
  30. package/dist/daemon.d.ts +16 -0
  31. package/dist/daemon.js +72 -0
  32. package/dist/daemon.js.map +1 -0
  33. package/dist/index.d.ts +4 -0
  34. package/dist/index.js +3 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/instances.d.ts +2 -0
  37. package/dist/instances.js +16 -0
  38. package/dist/instances.js.map +1 -0
  39. package/dist/logger.d.ts +9 -0
  40. package/dist/logger.js +23 -0
  41. package/dist/logger.js.map +1 -0
  42. package/dist/runner.d.ts +19 -0
  43. package/dist/runner.js +89 -0
  44. package/dist/runner.js.map +1 -0
  45. package/dist/surfaces/http.d.ts +12 -0
  46. package/dist/surfaces/http.js +96 -0
  47. package/dist/surfaces/http.js.map +1 -0
  48. package/dist/surfaces/slack.d.ts +9 -0
  49. package/dist/surfaces/slack.js +123 -0
  50. package/dist/surfaces/slack.js.map +1 -0
  51. package/package.json +51 -0
package/README.md ADDED
@@ -0,0 +1,87 @@
1
+ # Prism
2
+
3
+ > **Mnemos remembers. Prism delivers.**
4
+
5
+ Prism is a thin connector around [Claude Code](https://claude.com/claude-code). It listens for a request (Slack mention, HTTP call, or CLI invocation), spawns `claude -p "<prompt>"` in a working directory that has the right skills available, lets Claude do its job (query the brain, look up brand tokens, generate the artifact), then ships the output files back to the caller.
6
+
7
+ That's the whole product. No custom LLM client. No custom skill format. No custom brain client.
8
+
9
+ ## Architecture
10
+
11
+ ```
12
+ surfaces runner
13
+ ┌────────────┐ ┌──────────────────────┐
14
+ │ Slack bot │────┐ │ │
15
+ ├────────────┤ │ │ spawn 'claude -p' │
16
+ │ POST /api/ │────┼───▶│ in temp workdir │
17
+ │ generate │ │ │ │
18
+ ├────────────┤ │ │ capture new files │
19
+ │ CLI │────┘ │ in cwd after exit │
20
+ └────────────┘ └──────────────────────┘
21
+
22
+
23
+ Claude Code (the LLM)
24
+
25
+ ~/.claude/skills/:
26
+ ├─ ask-mnemos-astry
27
+ ├─ astry-design-system
28
+ ├─ astry-pdf
29
+ └─ ...
30
+ ```
31
+
32
+ ## Install
33
+
34
+ ```bash
35
+ npm install -g prism
36
+ prism onboard
37
+ ```
38
+
39
+ `prism onboard` walks through:
40
+
41
+ - Picking an instance name
42
+ - Slack Socket Mode tokens (optional)
43
+ - HTTP API key (optional)
44
+ - Brain endpoint + key (read by `ask-mnemos-astry` skill)
45
+ - Verifying `claude` is on `PATH` and authenticated
46
+
47
+ ## Usage
48
+
49
+ ### CLI
50
+
51
+ ```bash
52
+ prism generate "fais un PDF récap du meeting Endemol" --out ./
53
+ ```
54
+
55
+ ### HTTP
56
+
57
+ ```bash
58
+ curl -X POST http://localhost:18790/api/generate \
59
+ -H "Authorization: Bearer prism_live_..." \
60
+ -H "Content-Type: application/json" \
61
+ -d '{"brief": "fais un récap du meeting Endemol kickoff du 6 mai"}'
62
+ ```
63
+
64
+ ### Slack
65
+
66
+ Mention `@prism` in any channel the bot has access to:
67
+
68
+ ```
69
+ @prism fais-moi un PDF du meeting Endemol de ce matin
70
+ ```
71
+
72
+ ## Required skills (operator install)
73
+
74
+ Prism does not ship skills. The operator installs them under the user that runs Prism:
75
+
76
+ ```bash
77
+ ls ~/.claude/skills/
78
+ # ask-mnemos-astry/
79
+ # astry-design-system/
80
+ # astry-pdf/
81
+ ```
82
+
83
+ `prism doctor` reports which expected skills are missing.
84
+
85
+ ## License
86
+
87
+ UNLICENSED — internal Astry tooling.
@@ -0,0 +1,21 @@
1
+ [Unit]
2
+ Description=Prism agent (instance %i)
3
+ After=network-online.target
4
+ Wants=network-online.target
5
+
6
+ [Service]
7
+ Type=simple
8
+ ExecStart=__PRISM_BIN__ serve -i %i
9
+ Restart=on-failure
10
+ RestartSec=5s
11
+ KillSignal=SIGTERM
12
+ TimeoutStopSec=30s
13
+ Environment=NODE_ENV=production
14
+ Environment=PRISM_INSTANCE=%i
15
+ # claude requires a writable HOME and access to ~/.claude
16
+ Environment=HOME=__HOME__
17
+ StandardOutput=append:__INSTANCE_DIR__/%i/logs/prism.log
18
+ StandardError=append:__INSTANCE_DIR__/%i/logs/prism.err.log
19
+
20
+ [Install]
21
+ WantedBy=default.target
@@ -0,0 +1,9 @@
1
+ export interface ArtifactRecord {
2
+ filename: string;
3
+ path: string;
4
+ size_bytes: number;
5
+ }
6
+ export declare function artifactsRoot(instance: string, override?: string): string;
7
+ export declare function persistArtifacts(instance: string, jobId: string, files: string[], override?: string): ArtifactRecord[];
8
+ export declare function pruneArtifacts(instance: string, retentionDays: number, override?: string): number;
9
+ export declare function mimeTypeFor(filename: string): string;
@@ -0,0 +1,77 @@
1
+ import { copyFileSync, existsSync, mkdirSync, readdirSync, rmSync, statSync } from 'node:fs';
2
+ import { join, basename } from 'node:path';
3
+ import { instanceRoot } from './config.js';
4
+ export function artifactsRoot(instance, override) {
5
+ return override ?? join(instanceRoot(instance), 'artifacts');
6
+ }
7
+ export function persistArtifacts(instance, jobId, files, override) {
8
+ const root = artifactsRoot(instance, override);
9
+ const dir = join(root, jobId);
10
+ mkdirSync(dir, { recursive: true });
11
+ const out = [];
12
+ for (const src of files) {
13
+ if (!existsSync(src))
14
+ continue;
15
+ const name = uniqueName(dir, basename(src));
16
+ const dst = join(dir, name);
17
+ copyFileSync(src, dst);
18
+ out.push({ filename: name, path: dst, size_bytes: statSync(dst).size });
19
+ }
20
+ return out;
21
+ }
22
+ export function pruneArtifacts(instance, retentionDays, override) {
23
+ const root = artifactsRoot(instance, override);
24
+ if (!existsSync(root))
25
+ return 0;
26
+ const cutoff = Date.now() - retentionDays * 24 * 60 * 60 * 1000;
27
+ let removed = 0;
28
+ for (const name of readdirSync(root)) {
29
+ const full = join(root, name);
30
+ try {
31
+ const st = statSync(full);
32
+ if (st.mtimeMs < cutoff) {
33
+ rmSync(full, { recursive: true, force: true });
34
+ removed += 1;
35
+ }
36
+ }
37
+ catch {
38
+ // ignore
39
+ }
40
+ }
41
+ return removed;
42
+ }
43
+ function uniqueName(dir, name) {
44
+ if (!existsSync(join(dir, name)))
45
+ return name;
46
+ const dot = name.lastIndexOf('.');
47
+ const stem = dot > 0 ? name.slice(0, dot) : name;
48
+ const ext = dot > 0 ? name.slice(dot) : '';
49
+ let i = 1;
50
+ while (existsSync(join(dir, `${stem}-${i}${ext}`)))
51
+ i += 1;
52
+ return `${stem}-${i}${ext}`;
53
+ }
54
+ export function mimeTypeFor(filename) {
55
+ const ext = filename.toLowerCase().split('.').pop() ?? '';
56
+ const map = {
57
+ pdf: 'application/pdf',
58
+ png: 'image/png',
59
+ jpg: 'image/jpeg',
60
+ jpeg: 'image/jpeg',
61
+ gif: 'image/gif',
62
+ svg: 'image/svg+xml',
63
+ webp: 'image/webp',
64
+ txt: 'text/plain',
65
+ md: 'text/markdown',
66
+ html: 'text/html',
67
+ htm: 'text/html',
68
+ json: 'application/json',
69
+ csv: 'text/csv',
70
+ docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
71
+ xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
72
+ pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
73
+ zip: 'application/zip',
74
+ };
75
+ return map[ext] ?? 'application/octet-stream';
76
+ }
77
+ //# sourceMappingURL=artifacts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifacts.js","sourceRoot":"","sources":["../src/artifacts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function daemonCmd(program: Command): void;
@@ -0,0 +1,90 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { detectPrismBin, ensureInstancePaths, installUnit, systemctl, uninstallUnit, unitName, unitPath } from '../../daemon.js';
3
+ import { listInstances } from '../../instances.js';
4
+ export function daemonCmd(program) {
5
+ const daemon = program
6
+ .command('daemon')
7
+ .description('Manage the systemd user service for prism instances (Linux only).');
8
+ daemon
9
+ .command('install')
10
+ .description('Render prism@.service into ~/.config/systemd/user and enable+start the instance.')
11
+ .option('-i, --instance <name>', 'instance to enable+start', 'default')
12
+ .option('--prism-bin <path>', 'override the prism binary path')
13
+ .option('--no-start', 'install the unit without starting it')
14
+ .action((opts) => {
15
+ assertLinux();
16
+ ensureInstancePaths(opts.instance);
17
+ const bin = opts.prismBin ?? detectPrismBin();
18
+ const path = installUnit(bin);
19
+ console.error(`✓ unit installed: ${path}`);
20
+ const unit = unitName(opts.instance);
21
+ systemctl(['enable', unit], { check: true });
22
+ console.error(`✓ enabled ${unit}`);
23
+ if (opts.start !== false) {
24
+ systemctl(['restart', unit], { check: true });
25
+ console.error(`✓ started ${unit}`);
26
+ }
27
+ });
28
+ daemon
29
+ .command('start')
30
+ .argument('[instance]', 'instance name', 'default')
31
+ .description('Start (or restart) the prism systemd unit for an instance.')
32
+ .action((instance) => {
33
+ assertLinux();
34
+ systemctl(['restart', unitName(instance)], { check: true });
35
+ console.error(`✓ ${unitName(instance)} restarted`);
36
+ });
37
+ daemon
38
+ .command('stop')
39
+ .argument('[instance]', 'instance name', 'default')
40
+ .description('Stop the prism systemd unit for an instance.')
41
+ .action((instance) => {
42
+ assertLinux();
43
+ systemctl(['stop', unitName(instance)], { check: true });
44
+ console.error(`✓ ${unitName(instance)} stopped`);
45
+ });
46
+ daemon
47
+ .command('status')
48
+ .argument('[instance]', 'instance name (omit for all)')
49
+ .description('Show systemd status for one or all prism instances.')
50
+ .action((instance) => {
51
+ assertLinux();
52
+ const list = instance ? [instance] : listInstances();
53
+ if (list.length === 0) {
54
+ console.error('no instances found');
55
+ return;
56
+ }
57
+ for (const inst of list) {
58
+ const r = systemctl(['status', unitName(inst), '--no-pager']);
59
+ process.stdout.write(`\n=== ${unitName(inst)} ===\n${r.stdout}${r.stderr}`);
60
+ }
61
+ });
62
+ daemon
63
+ .command('logs')
64
+ .argument('[instance]', 'instance name', 'default')
65
+ .option('-f, --follow', 'follow logs')
66
+ .option('-n, --lines <n>', 'number of recent lines', '200')
67
+ .description('Tail journalctl for the prism systemd unit.')
68
+ .action((instance, opts) => {
69
+ assertLinux();
70
+ const args = ['--user', '--user-unit', unitName(instance), '-n', String(opts.lines)];
71
+ if (opts.follow)
72
+ args.push('-f');
73
+ spawnSync('journalctl', args, { stdio: 'inherit' });
74
+ });
75
+ daemon
76
+ .command('uninstall')
77
+ .description('Remove the systemd unit. Existing instance configs/artifacts are kept on disk.')
78
+ .action(() => {
79
+ assertLinux();
80
+ uninstallUnit();
81
+ console.error(`✓ removed ${unitPath()}`);
82
+ });
83
+ }
84
+ function assertLinux() {
85
+ if (process.platform !== 'linux') {
86
+ console.error('error: prism daemon commands require Linux + systemd');
87
+ process.exit(1);
88
+ }
89
+ }
90
+ //# sourceMappingURL=daemon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon.js","sourceRoot":"","sources":["../../../src/cli/commands/daemon.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function doctorCmd(program: Command): void;
@@ -0,0 +1,69 @@
1
+ import { execFileSync, spawnSync } from 'node:child_process';
2
+ import { existsSync, readdirSync } from 'node:fs';
3
+ import { homedir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ import { loadConfig, instanceRoot } from '../../config.js';
6
+ const EXPECTED_SKILLS = ['ask-mnemos-astry', 'astry-design-system', 'astry-pdf'];
7
+ export function doctorCmd(program) {
8
+ program
9
+ .command('doctor')
10
+ .description('Verify claude is installed/authenticated and expected skills are present.')
11
+ .option('-i, --instance <name>', 'prism instance to inspect', 'default')
12
+ .action((opts) => {
13
+ const config = loadConfig(opts.instance);
14
+ let ok = true;
15
+ const root = instanceRoot(opts.instance);
16
+ if (!existsSync(root)) {
17
+ printWarn(`instance directory missing: ${root} (run 'prism onboard' first)`);
18
+ }
19
+ else {
20
+ printOk(`instance dir: ${root}`);
21
+ }
22
+ const claudeBin = config.claude.bin;
23
+ const which = spawnSync(process.platform === 'win32' ? 'where' : 'which', [claudeBin], {
24
+ encoding: 'utf8',
25
+ });
26
+ if (which.status !== 0 || !which.stdout.trim()) {
27
+ printErr(`'${claudeBin}' not found on PATH`);
28
+ ok = false;
29
+ }
30
+ else {
31
+ printOk(`claude binary: ${which.stdout.trim().split(/\r?\n/)[0]}`);
32
+ try {
33
+ const version = execFileSync(claudeBin, ['--version'], { encoding: 'utf8' }).trim();
34
+ printOk(`claude version: ${version}`);
35
+ }
36
+ catch (err) {
37
+ printWarn(`could not run 'claude --version': ${err.message}`);
38
+ }
39
+ }
40
+ const skillsDir = join(homedir(), '.claude', 'skills');
41
+ if (!existsSync(skillsDir)) {
42
+ printErr(`~/.claude/skills missing — claude not authenticated under this user?`);
43
+ ok = false;
44
+ }
45
+ else {
46
+ const installed = new Set(readdirSync(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name));
47
+ for (const name of EXPECTED_SKILLS) {
48
+ if (installed.has(name)) {
49
+ printOk(`skill: ${name}`);
50
+ }
51
+ else {
52
+ printWarn(`skill missing: ${name} — install at ${join(skillsDir, name)}`);
53
+ }
54
+ }
55
+ }
56
+ printOk(`config loaded: instance=${config.instance}, http=${config.surfaces.http.enabled}, slack=${config.surfaces.slack.enabled}`);
57
+ if (!ok) {
58
+ process.stderr.write('\nprism doctor: issues detected.\n');
59
+ process.exit(1);
60
+ }
61
+ else {
62
+ process.stderr.write('\nprism doctor: all checks passed.\n');
63
+ }
64
+ });
65
+ }
66
+ function printOk(msg) { process.stderr.write(`[ok] ${msg}\n`); }
67
+ function printWarn(msg) { process.stderr.write(`[warn] ${msg}\n`); }
68
+ function printErr(msg) { process.stderr.write(`[err] ${msg}\n`); }
69
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function generateCmd(program: Command): void;
@@ -0,0 +1,89 @@
1
+ import { copyFileSync, existsSync, mkdirSync, statSync } from 'node:fs';
2
+ import { basename, resolve, join } from 'node:path';
3
+ import { generate } from '../../runner.js';
4
+ import { loadConfig, loadEnvFile } from '../../config.js';
5
+ export function generateCmd(program) {
6
+ program
7
+ .command('generate')
8
+ .description('Run claude -p with the given brief and ship back the files it creates.')
9
+ .argument('<brief...>', 'natural-language brief for claude')
10
+ .option('-o, --out <dir>', 'directory to copy generated files into', process.cwd())
11
+ .option('-i, --instance <name>', 'prism instance to use', 'default')
12
+ .option('--workdir <dir>', 'override the temp workdir (default: fresh tmpdir)')
13
+ .option('--timeout <ms>', 'timeout in ms', (v) => parseInt(v, 10))
14
+ .option('--claude-bin <path>', 'override the claude binary')
15
+ .option('--quiet', 'do not stream stdout to terminal')
16
+ .option('--json', 'emit a JSON summary on stdout instead of human output')
17
+ .action(async (briefParts, opts) => {
18
+ const brief = briefParts.join(' ').trim();
19
+ if (!brief) {
20
+ console.error('error: empty brief');
21
+ process.exit(2);
22
+ }
23
+ const config = loadConfig(opts.instance);
24
+ const env = loadEnvFile(opts.instance);
25
+ const outDir = resolve(opts.out);
26
+ mkdirSync(outDir, { recursive: true });
27
+ const result = await generate({
28
+ brief,
29
+ workdir: opts.workdir,
30
+ timeout_ms: opts.timeout ?? config.claude.timeout_ms,
31
+ claude_bin: opts.claudeBin ?? config.claude.bin,
32
+ env,
33
+ on_stdout: opts.quiet || opts.json ? undefined : (chunk) => process.stdout.write(chunk),
34
+ on_stderr: opts.quiet || opts.json ? undefined : (chunk) => process.stderr.write(chunk),
35
+ });
36
+ const copied = [];
37
+ for (const src of result.files) {
38
+ if (!existsSync(src))
39
+ continue;
40
+ const dst = uniqueDest(outDir, basename(src));
41
+ copyFileSync(src, dst);
42
+ copied.push({ src, dst, size: statSync(dst).size });
43
+ }
44
+ if (opts.json) {
45
+ process.stdout.write(JSON.stringify({
46
+ text: result.text,
47
+ files: copied.map((c) => ({ path: c.dst, size_bytes: c.size })),
48
+ exit_code: result.exit_code,
49
+ duration_ms: result.duration_ms,
50
+ timed_out: result.timed_out,
51
+ workdir: result.workdir,
52
+ }, null, 2) + '\n');
53
+ }
54
+ else {
55
+ if (copied.length === 0) {
56
+ process.stderr.write('\n[prism] no new files created in workdir.\n');
57
+ }
58
+ else {
59
+ process.stderr.write(`\n[prism] ${copied.length} file(s) written to ${outDir}:\n`);
60
+ for (const c of copied) {
61
+ process.stderr.write(` ${c.dst} (${formatSize(c.size)})\n`);
62
+ }
63
+ }
64
+ }
65
+ process.exit(result.exit_code === 0 ? 0 : result.exit_code);
66
+ });
67
+ }
68
+ function uniqueDest(dir, name) {
69
+ let candidate = join(dir, name);
70
+ if (!existsSync(candidate))
71
+ return candidate;
72
+ const dot = name.lastIndexOf('.');
73
+ const stem = dot > 0 ? name.slice(0, dot) : name;
74
+ const ext = dot > 0 ? name.slice(dot) : '';
75
+ let i = 1;
76
+ while (existsSync(candidate)) {
77
+ candidate = join(dir, `${stem}-${i}${ext}`);
78
+ i += 1;
79
+ }
80
+ return candidate;
81
+ }
82
+ function formatSize(bytes) {
83
+ if (bytes < 1024)
84
+ return `${bytes} B`;
85
+ if (bytes < 1024 * 1024)
86
+ return `${(bytes / 1024).toFixed(1)} KB`;
87
+ return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
88
+ }
89
+ //# sourceMappingURL=generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../../../src/cli/commands/generate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function onboardCmd(program: Command): void;
@@ -0,0 +1,131 @@
1
+ import prompts from 'prompts';
2
+ import { existsSync, mkdirSync, writeFileSync, chmodSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { stringify as stringifyYaml } from 'yaml';
5
+ import { defaultConfig, instanceRoot } from '../../config.js';
6
+ export function onboardCmd(program) {
7
+ program
8
+ .command('onboard')
9
+ .description('Interactive wizard to create a new prism instance.')
10
+ .option('-i, --instance <name>', 'instance name (default: prompted)')
11
+ .option('--force', 'overwrite existing instance config')
12
+ .action(async (opts) => {
13
+ const answers = await prompts([
14
+ {
15
+ type: opts.instance ? null : 'text',
16
+ name: 'instance',
17
+ message: 'Instance name',
18
+ initial: 'default',
19
+ validate: (v) => /^[a-z0-9_-]+$/.test(v) ? true : 'lowercase letters, digits, _ or - only',
20
+ },
21
+ {
22
+ type: 'toggle',
23
+ name: 'slack_enabled',
24
+ message: 'Enable the Slack surface?',
25
+ initial: true,
26
+ active: 'yes',
27
+ inactive: 'no',
28
+ },
29
+ {
30
+ type: (_, values) => (values.slack_enabled ? 'password' : null),
31
+ name: 'slack_bot_token',
32
+ message: 'SLACK_BOT_TOKEN (xoxb-...)',
33
+ validate: (v) => v.startsWith('xoxb-') ? true : 'expected xoxb- token',
34
+ },
35
+ {
36
+ type: (_, values) => (values.slack_enabled ? 'password' : null),
37
+ name: 'slack_app_token',
38
+ message: 'SLACK_APP_TOKEN (xapp-... for Socket Mode)',
39
+ validate: (v) => v.startsWith('xapp-') ? true : 'expected xapp- token',
40
+ },
41
+ {
42
+ type: (_, values) => (values.slack_enabled ? 'text' : null),
43
+ name: 'slack_channels',
44
+ message: 'Allowlist channel IDs (comma-separated, blank = all)',
45
+ initial: '',
46
+ },
47
+ {
48
+ type: 'toggle',
49
+ name: 'http_enabled',
50
+ message: 'Enable the HTTP API?',
51
+ initial: true,
52
+ active: 'yes',
53
+ inactive: 'no',
54
+ },
55
+ {
56
+ type: (_, values) => (values.http_enabled ? 'number' : null),
57
+ name: 'http_port',
58
+ message: 'HTTP port',
59
+ initial: 18790,
60
+ },
61
+ {
62
+ type: (_, values) => (values.http_enabled ? 'password' : null),
63
+ name: 'http_api_key',
64
+ message: 'HTTP API key (will be required for /api/generate)',
65
+ validate: (v) => v.length >= 16 ? true : 'use at least 16 characters',
66
+ },
67
+ {
68
+ type: 'text',
69
+ name: 'mnemos_brain_url',
70
+ message: 'Mnemos brain URL (read by ask-mnemos-astry skill, blank = skip)',
71
+ initial: 'https://brain.astry.agency',
72
+ },
73
+ {
74
+ type: (_, values) => (values.mnemos_brain_url ? 'password' : null),
75
+ name: 'mnemos_api_key',
76
+ message: 'Mnemos API key (brn_live_...)',
77
+ },
78
+ {
79
+ type: 'text',
80
+ name: 'claude_bin',
81
+ message: "Path to claude binary (or just 'claude' if on PATH)",
82
+ initial: 'claude',
83
+ },
84
+ ], { onCancel: () => { process.exit(130); } });
85
+ const instance = opts.instance ?? answers.instance;
86
+ const root = instanceRoot(instance);
87
+ if (existsSync(root) && !opts.force) {
88
+ console.error(`error: ${root} already exists. Use --force to overwrite.`);
89
+ process.exit(1);
90
+ }
91
+ mkdirSync(root, { recursive: true });
92
+ mkdirSync(join(root, 'artifacts'), { recursive: true });
93
+ mkdirSync(join(root, 'logs'), { recursive: true });
94
+ const config = defaultConfig(instance);
95
+ config.surfaces.slack.enabled = !!answers.slack_enabled;
96
+ config.surfaces.slack.allowlist_channels = answers.slack_channels
97
+ ? String(answers.slack_channels).split(',').map((s) => s.trim()).filter(Boolean)
98
+ : [];
99
+ config.surfaces.http.enabled = !!answers.http_enabled;
100
+ if (answers.http_port)
101
+ config.surfaces.http.port = Number(answers.http_port);
102
+ config.claude.bin = String(answers.claude_bin);
103
+ const configPath = join(root, 'config.yaml');
104
+ writeFileSync(configPath, stringifyYaml(config), 'utf8');
105
+ const envLines = ['# Prism instance secrets', '# DO NOT commit this file'];
106
+ if (answers.slack_bot_token)
107
+ envLines.push(`SLACK_BOT_TOKEN=${answers.slack_bot_token}`);
108
+ if (answers.slack_app_token)
109
+ envLines.push(`SLACK_APP_TOKEN=${answers.slack_app_token}`);
110
+ if (answers.http_api_key)
111
+ envLines.push(`PRISM_HTTP_API_KEY=${answers.http_api_key}`);
112
+ if (answers.mnemos_brain_url)
113
+ envLines.push(`MNEMOS_BRAIN_URL=${answers.mnemos_brain_url}`);
114
+ if (answers.mnemos_api_key)
115
+ envLines.push(`MNEMOS_API_KEY=${answers.mnemos_api_key}`);
116
+ const envPath = join(root, '.env');
117
+ writeFileSync(envPath, envLines.join('\n') + '\n', { mode: 0o600 });
118
+ try {
119
+ chmodSync(envPath, 0o600);
120
+ }
121
+ catch { /* windows */ }
122
+ console.log(`\n✓ instance "${instance}" written to ${root}`);
123
+ console.log(` config: ${configPath}`);
124
+ console.log(` env: ${envPath}`);
125
+ console.log(`\nNext steps:`);
126
+ console.log(` prism doctor -i ${instance} # verify claude + skills`);
127
+ console.log(` prism serve -i ${instance} # run surfaces in foreground`);
128
+ console.log(` prism daemon install -i ${instance} # install systemd service (Linux)`);
129
+ });
130
+ }
131
+ //# sourceMappingURL=onboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onboard.js","sourceRoot":"","sources":["../../../src/cli/commands/onboard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function serveCmd(program: Command): void;