@productbrain/cli 0.1.0-beta.29 → 0.1.0-beta.32

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 (106) hide show
  1. package/README.md +62 -178
  2. package/dist/__tests__/constants.test.d.ts +2 -0
  3. package/dist/__tests__/constants.test.d.ts.map +1 -0
  4. package/dist/__tests__/constants.test.js +94 -0
  5. package/dist/__tests__/constants.test.js.map +1 -0
  6. package/dist/__tests__/errors.test.d.ts +2 -0
  7. package/dist/__tests__/errors.test.d.ts.map +1 -0
  8. package/dist/__tests__/errors.test.js +117 -0
  9. package/dist/__tests__/errors.test.js.map +1 -0
  10. package/dist/__tests__/glossary.test.d.ts +2 -0
  11. package/dist/__tests__/glossary.test.d.ts.map +1 -0
  12. package/dist/__tests__/glossary.test.js +32 -0
  13. package/dist/__tests__/glossary.test.js.map +1 -0
  14. package/dist/__tests__/login.test.d.ts +2 -0
  15. package/dist/__tests__/login.test.d.ts.map +1 -0
  16. package/dist/__tests__/login.test.js +168 -0
  17. package/dist/__tests__/login.test.js.map +1 -0
  18. package/dist/__tests__/profiles.test.d.ts +2 -0
  19. package/dist/__tests__/profiles.test.d.ts.map +1 -0
  20. package/dist/__tests__/profiles.test.js +168 -0
  21. package/dist/__tests__/profiles.test.js.map +1 -0
  22. package/dist/__tests__/setup.test.d.ts +2 -0
  23. package/dist/__tests__/setup.test.d.ts.map +1 -0
  24. package/dist/__tests__/setup.test.js +170 -0
  25. package/dist/__tests__/setup.test.js.map +1 -0
  26. package/dist/commands/capture.d.ts.map +1 -1
  27. package/dist/commands/capture.js +23 -2
  28. package/dist/commands/capture.js.map +1 -1
  29. package/dist/commands/doctor.d.ts +18 -0
  30. package/dist/commands/doctor.d.ts.map +1 -0
  31. package/dist/commands/doctor.js +211 -0
  32. package/dist/commands/doctor.js.map +1 -0
  33. package/dist/commands/doctor.test.d.ts +7 -0
  34. package/dist/commands/doctor.test.d.ts.map +1 -0
  35. package/dist/commands/doctor.test.js +265 -0
  36. package/dist/commands/doctor.test.js.map +1 -0
  37. package/dist/commands/login.d.ts +4 -0
  38. package/dist/commands/login.d.ts.map +1 -1
  39. package/dist/commands/login.js +53 -27
  40. package/dist/commands/login.js.map +1 -1
  41. package/dist/commands/profile.d.ts +24 -0
  42. package/dist/commands/profile.d.ts.map +1 -0
  43. package/dist/commands/profile.js +82 -0
  44. package/dist/commands/profile.js.map +1 -0
  45. package/dist/commands/promote.d.ts.map +1 -1
  46. package/dist/commands/promote.js +3 -2
  47. package/dist/commands/promote.js.map +1 -1
  48. package/dist/commands/setup.d.ts +16 -0
  49. package/dist/commands/setup.d.ts.map +1 -0
  50. package/dist/commands/setup.js +213 -0
  51. package/dist/commands/setup.js.map +1 -0
  52. package/dist/formatters/promote.d.ts +1 -0
  53. package/dist/formatters/promote.d.ts.map +1 -1
  54. package/dist/formatters/promote.js +1 -0
  55. package/dist/formatters/promote.js.map +1 -1
  56. package/dist/index.js +251 -284
  57. package/dist/index.js.map +1 -1
  58. package/dist/lib/activation.d.ts +28 -0
  59. package/dist/lib/activation.d.ts.map +1 -0
  60. package/dist/lib/activation.js +57 -0
  61. package/dist/lib/activation.js.map +1 -0
  62. package/dist/lib/activation.test.d.ts +6 -0
  63. package/dist/lib/activation.test.d.ts.map +1 -0
  64. package/dist/lib/activation.test.js +121 -0
  65. package/dist/lib/activation.test.js.map +1 -0
  66. package/dist/lib/client.d.ts +19 -2
  67. package/dist/lib/client.d.ts.map +1 -1
  68. package/dist/lib/client.js +71 -11
  69. package/dist/lib/client.js.map +1 -1
  70. package/dist/lib/config.d.ts +9 -3
  71. package/dist/lib/config.d.ts.map +1 -1
  72. package/dist/lib/config.js +54 -15
  73. package/dist/lib/config.js.map +1 -1
  74. package/dist/lib/constants.d.ts +21 -0
  75. package/dist/lib/constants.d.ts.map +1 -0
  76. package/dist/lib/constants.js +39 -0
  77. package/dist/lib/constants.js.map +1 -0
  78. package/dist/lib/errors.d.ts +57 -0
  79. package/dist/lib/errors.d.ts.map +1 -0
  80. package/dist/lib/errors.js +65 -0
  81. package/dist/lib/errors.js.map +1 -0
  82. package/dist/lib/glossary.d.ts +19 -0
  83. package/dist/lib/glossary.d.ts.map +1 -0
  84. package/dist/lib/glossary.js +53 -0
  85. package/dist/lib/glossary.js.map +1 -0
  86. package/dist/lib/profiles.d.ts +34 -0
  87. package/dist/lib/profiles.d.ts.map +1 -0
  88. package/dist/lib/profiles.js +173 -0
  89. package/dist/lib/profiles.js.map +1 -0
  90. package/dist/lib/runner.d.ts +2 -0
  91. package/dist/lib/runner.d.ts.map +1 -1
  92. package/dist/lib/runner.js +33 -4
  93. package/dist/lib/runner.js.map +1 -1
  94. package/dist/lib/style.d.ts +65 -0
  95. package/dist/lib/style.d.ts.map +1 -0
  96. package/dist/lib/style.js +108 -0
  97. package/dist/lib/style.js.map +1 -0
  98. package/dist/lib/style.test.d.ts +7 -0
  99. package/dist/lib/style.test.d.ts.map +1 -0
  100. package/dist/lib/style.test.js +195 -0
  101. package/dist/lib/style.test.js.map +1 -0
  102. package/dist/lib/telemetry.d.ts +15 -0
  103. package/dist/lib/telemetry.d.ts.map +1 -0
  104. package/dist/lib/telemetry.js +29 -0
  105. package/dist/lib/telemetry.js.map +1 -0
  106. package/package.json +1 -1
@@ -1,8 +1,12 @@
1
1
  /**
2
2
  * CLI config — reads PRODUCTBRAIN_API_KEY + CONVEX_SITE_URL from:
3
- * 1. Environment variables
4
- * 2. ~/.config/productbrain/.env (works from any directory)
5
- * 3. CWD .env.mcp / packages/mcp-server/.env.mcp / .env
3
+ * 1. Environment variables (always highest priority)
4
+ * 2. Profile system (~/.config/productbrain/profiles/{name}.env)
5
+ * 3. Legacy ~/.config/productbrain/.env (auto-migrated to profiles on first use)
6
+ * 4. CWD .env.mcp / packages/mcp-server/.env.mcp / .env
7
+ *
8
+ * Config loading is lazy — loadEnv() runs on first getConfig()/getConfigOrGuide() call.
9
+ * This enables profile switching without import-time side effects (TEN-1276).
6
10
  *
7
11
  * When key is missing and retry is provided (TTY), runs guided flow per docs/cli-unauthenticated-user-journey.md.
8
12
  */
@@ -10,12 +14,15 @@ import { readFileSync, existsSync, mkdirSync, writeFileSync } from 'fs';
10
14
  import { resolve } from 'path';
11
15
  import { homedir } from 'os';
12
16
  import { createInterface } from 'readline';
13
- const DEFAULT_SITE_URL = 'https://trustworthy-kangaroo-277.convex.site';
17
+ import { DEFAULT_SITE_URL, isDevMode } from './constants.js';
18
+ import { resolveProfileConfig } from './profiles.js';
14
19
  const HOME_CONFIG_DIR = resolve(homedir(), '.config', 'productbrain');
15
20
  const HOME_ENV_PATH = resolve(HOME_CONFIG_DIR, '.env');
16
21
  const CWD_ENV_PATHS = ['.env.mcp', 'packages/mcp-server/.env.mcp', '.env'];
17
22
  // Short error when not TTY (scripts/pipes must not hang)
18
23
  const NON_TTY_MESSAGE = 'No API key. Set PRODUCTBRAIN_API_KEY or run pb login.';
24
+ /** Track whether env has been loaded to avoid redundant file reads. */
25
+ let envLoaded = false;
19
26
  function parseEnvContent(content) {
20
27
  for (const line of content.split('\n')) {
21
28
  const m = line.match(/^([^#=]+)=(.*)$/);
@@ -25,9 +32,25 @@ function parseEnvContent(content) {
25
32
  }
26
33
  }
27
34
  function loadEnv() {
35
+ if (envLoaded)
36
+ return;
37
+ envLoaded = true;
38
+ // 1. Try profile system first (handles auto-migration from legacy .env)
39
+ const profileConfig = resolveProfileConfig();
40
+ if (profileConfig) {
41
+ // Only set if not already set by env vars (env vars always win)
42
+ if (!process.env.PRODUCTBRAIN_API_KEY) {
43
+ process.env.PRODUCTBRAIN_API_KEY = profileConfig.apiKey;
44
+ }
45
+ if (!process.env.CONVEX_SITE_URL && profileConfig.siteUrl) {
46
+ process.env.CONVEX_SITE_URL = profileConfig.siteUrl;
47
+ }
48
+ }
49
+ // 2. Legacy home config (in case profiles didn't find it)
28
50
  if (existsSync(HOME_ENV_PATH)) {
29
51
  parseEnvContent(readFileSync(HOME_ENV_PATH, 'utf8'));
30
52
  }
53
+ // 3. CWD env files
31
54
  for (const p of CWD_ENV_PATHS) {
32
55
  const full = resolve(process.cwd(), p);
33
56
  if (existsSync(full)) {
@@ -36,7 +59,10 @@ function loadEnv() {
36
59
  }
37
60
  }
38
61
  }
39
- loadEnv();
62
+ /** Reset env loaded state — used for profile switching. */
63
+ export function resetConfigCache() {
64
+ envLoaded = false;
65
+ }
40
66
  function question(rl, prompt) {
41
67
  return new Promise((resolve) => {
42
68
  rl.question(prompt, (answer) => resolve((answer ?? '').trim().toLowerCase()));
@@ -71,14 +97,23 @@ async function runGuidedFlow(retry) {
71
97
  console.log('Get your key: Product Brain app → Settings → API Keys. Then run: pb login');
72
98
  process.exit(0);
73
99
  }
74
- const content = [
75
- `# Product Brain CLI saved by guided setup`,
76
- `PRODUCTBRAIN_API_KEY=${apiKey}`,
77
- `CONVEX_SITE_URL=${DEFAULT_SITE_URL.replace(/\/$/, '')}`,
78
- '',
79
- ].join('\n');
80
- mkdirSync(HOME_CONFIG_DIR, { recursive: true });
81
- writeFileSync(HOME_ENV_PATH, content, { mode: 0o600 });
100
+ // Save as a named profile via the profile system
101
+ const { createProfile, getActiveProfile } = await import('./profiles.js');
102
+ const profileName = getActiveProfile() || 'default';
103
+ try {
104
+ createProfile(profileName, apiKey, DEFAULT_SITE_URL.replace(/\/$/, ''));
105
+ }
106
+ catch {
107
+ // Profile already exists fall back to legacy path
108
+ const content = [
109
+ `# Product Brain CLI — saved by guided setup`,
110
+ `PRODUCTBRAIN_API_KEY=${apiKey}`,
111
+ `CONVEX_SITE_URL=${DEFAULT_SITE_URL.replace(/\/$/, '')}`,
112
+ '',
113
+ ].join('\n');
114
+ mkdirSync(HOME_CONFIG_DIR, { recursive: true });
115
+ writeFileSync(HOME_ENV_PATH, content, { mode: 0o600 });
116
+ }
82
117
  process.env.PRODUCTBRAIN_API_KEY = apiKey;
83
118
  process.env.CONVEX_SITE_URL = DEFAULT_SITE_URL.replace(/\/$/, '');
84
119
  console.log('Saved your key. Running your command…\n');
@@ -86,12 +121,14 @@ async function runGuidedFlow(retry) {
86
121
  return true;
87
122
  }
88
123
  export function getConfig() {
124
+ loadEnv();
89
125
  const apiKey = process.env.PRODUCTBRAIN_API_KEY ?? '';
90
126
  const siteUrl = (process.env.CONVEX_SITE_URL ?? DEFAULT_SITE_URL).replace(/\/$/, '');
91
127
  if (!apiKey || !apiKey.startsWith('pb_sk_')) {
92
128
  throw new Error(NON_TTY_MESSAGE);
93
129
  }
94
- if (!siteUrl.startsWith('https://')) {
130
+ const allowHttp = isDevMode() && siteUrl.startsWith('http://localhost');
131
+ if (!siteUrl.startsWith('https://') && !allowHttp) {
95
132
  throw new Error(`CONVEX_SITE_URL must use HTTPS (got "${siteUrl.slice(0, 30)}…"). API keys must not be sent over unencrypted connections.`);
96
133
  }
97
134
  return { apiKey, siteUrl };
@@ -102,9 +139,11 @@ export function getConfig() {
102
139
  * @returns Config, or null if we ran retry (caller should return without running again).
103
140
  */
104
141
  export async function getConfigOrGuide(retry) {
142
+ loadEnv();
105
143
  const apiKey = process.env.PRODUCTBRAIN_API_KEY ?? '';
106
144
  const siteUrl = (process.env.CONVEX_SITE_URL ?? DEFAULT_SITE_URL).replace(/\/$/, '');
107
- if (apiKey.startsWith('pb_sk_') && siteUrl.startsWith('https://')) {
145
+ const allowHttp = isDevMode() && siteUrl.startsWith('http://localhost');
146
+ if (apiKey.startsWith('pb_sk_') && (siteUrl.startsWith('https://') || allowHttp)) {
108
147
  return { apiKey, siteUrl };
109
148
  }
110
149
  if (!process.stdin.isTTY) {
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * CLI constants — single source of truth for URLs and environment switching.
3
+ * WP-301 Slice 0: Extract hardcoded URLs, add PB_ENV awareness.
4
+ */
5
+ /** Production Convex HTTP Actions endpoint. */
6
+ export declare const DEFAULT_SITE_URL = "https://gateway.productbrain.io";
7
+ /**
8
+ * Resolve the Convex site URL based on PB_ENV.
9
+ * - PB_ENV=dev → local Convex dev server
10
+ * - PB_ENV=production or unset → production URL
11
+ */
12
+ export declare function resolveSiteUrl(): string;
13
+ /**
14
+ * Resolve the web app URL based on PB_ENV.
15
+ * - PB_ENV=dev → localhost:5173
16
+ * - PB_ENV=production or unset → work.productbrain.io
17
+ */
18
+ export declare function resolveAppUrl(): string;
19
+ /** Whether the CLI is running in dev mode. */
20
+ export declare function isDevMode(): boolean;
21
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/lib/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,+CAA+C;AAC/C,eAAO,MAAM,gBAAgB,oCAAoC,CAAC;AAWlE;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAIvC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAItC;AAED,8CAA8C;AAC9C,wBAAgB,SAAS,IAAI,OAAO,CAEnC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * CLI constants — single source of truth for URLs and environment switching.
3
+ * WP-301 Slice 0: Extract hardcoded URLs, add PB_ENV awareness.
4
+ */
5
+ /** Production Convex HTTP Actions endpoint. */
6
+ export const DEFAULT_SITE_URL = 'https://gateway.productbrain.io';
7
+ /** Production web app URL. */
8
+ const PROD_APP_URL = 'https://work.productbrain.io';
9
+ /** Local Convex dev server URL. */
10
+ const DEV_SITE_URL = 'http://localhost:5176';
11
+ /** Local web app URL. */
12
+ const DEV_APP_URL = 'http://localhost:5173';
13
+ /**
14
+ * Resolve the Convex site URL based on PB_ENV.
15
+ * - PB_ENV=dev → local Convex dev server
16
+ * - PB_ENV=production or unset → production URL
17
+ */
18
+ export function resolveSiteUrl() {
19
+ const env = process.env.PB_ENV?.toLowerCase();
20
+ if (env === 'dev')
21
+ return DEV_SITE_URL;
22
+ return DEFAULT_SITE_URL;
23
+ }
24
+ /**
25
+ * Resolve the web app URL based on PB_ENV.
26
+ * - PB_ENV=dev → localhost:5173
27
+ * - PB_ENV=production or unset → work.productbrain.io
28
+ */
29
+ export function resolveAppUrl() {
30
+ const env = process.env.PB_ENV?.toLowerCase();
31
+ if (env === 'dev')
32
+ return DEV_APP_URL;
33
+ return PROD_APP_URL;
34
+ }
35
+ /** Whether the CLI is running in dev mode. */
36
+ export function isDevMode() {
37
+ return process.env.PB_ENV?.toLowerCase() === 'dev';
38
+ }
39
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/lib/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,+CAA+C;AAC/C,MAAM,CAAC,MAAM,gBAAgB,GAAG,iCAAiC,CAAC;AAElE,8BAA8B;AAC9B,MAAM,YAAY,GAAG,8BAA8B,CAAC;AAEpD,mCAAmC;AACnC,MAAM,YAAY,GAAG,uBAAuB,CAAC;AAE7C,yBAAyB;AACzB,MAAM,WAAW,GAAG,uBAAuB,CAAC;AAE5C;;;;GAIG;AACH,MAAM,UAAU,cAAc;IAC5B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC;IAC9C,IAAI,GAAG,KAAK,KAAK;QAAE,OAAO,YAAY,CAAC;IACvC,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC;IAC9C,IAAI,GAAG,KAAK,KAAK;QAAE,OAAO,WAAW,CAAC;IACtC,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,8CAA8C;AAC9C,MAAM,UAAU,SAAS;IACvB,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,KAAK,CAAC;AACrD,CAAC"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * CLIError — structured error taxonomy for the Product Brain CLI.
3
+ *
4
+ * WP-302 Slice 0: Error Taxonomy + Commander Migration.
5
+ * WP-302 Slice 2: Profile error codes added.
6
+ * Every CLI error carries a machine-readable code, category, and actionable guidance.
7
+ * The global error handler in index.ts formats these for JSON or human output.
8
+ */
9
+ /** Error categories — groups of related failure modes. */
10
+ export type ErrorCategory = 'auth' | 'network' | 'config' | 'validation' | 'session' | 'profile' | 'internal';
11
+ /** Known error codes — extend as new failure modes are discovered. */
12
+ export declare const ErrorCode: {
13
+ readonly AUTH_MISSING: "AUTH_MISSING";
14
+ readonly AUTH_INVALID: "AUTH_INVALID";
15
+ readonly AUTH_DENIED: "AUTH_DENIED";
16
+ readonly NETWORK_UNREACHABLE: "NETWORK_UNREACHABLE";
17
+ readonly NETWORK_TIMEOUT: "NETWORK_TIMEOUT";
18
+ readonly CONFIG_MISSING: "CONFIG_MISSING";
19
+ readonly CONFIG_INVALID: "CONFIG_INVALID";
20
+ readonly SESSION_REQUIRED: "SESSION_REQUIRED";
21
+ readonly VALIDATION_FAILED: "VALIDATION_FAILED";
22
+ readonly PROFILE_NOT_FOUND: "PROFILE_NOT_FOUND";
23
+ readonly PROFILE_ALREADY_EXISTS: "PROFILE_ALREADY_EXISTS";
24
+ readonly PROFILE_IS_ACTIVE: "PROFILE_IS_ACTIVE";
25
+ readonly PROFILE_IS_LAST: "PROFILE_IS_LAST";
26
+ readonly PROFILE_NAME_INVALID: "PROFILE_NAME_INVALID";
27
+ readonly INTERNAL: "INTERNAL";
28
+ };
29
+ export type ErrorCodeValue = (typeof ErrorCode)[keyof typeof ErrorCode];
30
+ /**
31
+ * Structured CLI error with machine-readable fields.
32
+ *
33
+ * Usage:
34
+ * throw new CLIError('No API key configured', {
35
+ * code: ErrorCode.AUTH_MISSING,
36
+ * category: 'auth',
37
+ * guidance: 'Run `pb login` to configure your API key.',
38
+ * });
39
+ */
40
+ export declare class CLIError extends Error {
41
+ readonly code: ErrorCodeValue;
42
+ readonly category: ErrorCategory;
43
+ readonly guidance?: string;
44
+ constructor(message: string, options?: {
45
+ code?: ErrorCodeValue;
46
+ category?: ErrorCategory;
47
+ guidance?: string;
48
+ });
49
+ /** Serialize for JSON error output. */
50
+ toJSON(): {
51
+ error: string;
52
+ code: string;
53
+ category: string;
54
+ guidance?: string;
55
+ };
56
+ }
57
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,0DAA0D;AAC1D,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC;AAE9G,sEAAsE;AACtE,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;CAuBZ,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,OAAO,SAAS,CAAC,CAAC;AAExE;;;;;;;;;GASG;AACH,qBAAa,QAAS,SAAQ,KAAK;IACjC,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;gBAGzB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QACR,IAAI,CAAC,EAAE,cAAc,CAAC;QACtB,QAAQ,CAAC,EAAE,aAAa,CAAC;QACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB;IASH,uCAAuC;IACvC,MAAM,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE;CAQ/E"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * CLIError — structured error taxonomy for the Product Brain CLI.
3
+ *
4
+ * WP-302 Slice 0: Error Taxonomy + Commander Migration.
5
+ * WP-302 Slice 2: Profile error codes added.
6
+ * Every CLI error carries a machine-readable code, category, and actionable guidance.
7
+ * The global error handler in index.ts formats these for JSON or human output.
8
+ */
9
+ /** Known error codes — extend as new failure modes are discovered. */
10
+ export const ErrorCode = {
11
+ // Auth
12
+ AUTH_MISSING: 'AUTH_MISSING',
13
+ AUTH_INVALID: 'AUTH_INVALID',
14
+ AUTH_DENIED: 'AUTH_DENIED',
15
+ // Network
16
+ NETWORK_UNREACHABLE: 'NETWORK_UNREACHABLE',
17
+ NETWORK_TIMEOUT: 'NETWORK_TIMEOUT',
18
+ // Config
19
+ CONFIG_MISSING: 'CONFIG_MISSING',
20
+ CONFIG_INVALID: 'CONFIG_INVALID',
21
+ // Session
22
+ SESSION_REQUIRED: 'SESSION_REQUIRED',
23
+ // Validation
24
+ VALIDATION_FAILED: 'VALIDATION_FAILED',
25
+ // Profile (WP-302 S2)
26
+ PROFILE_NOT_FOUND: 'PROFILE_NOT_FOUND',
27
+ PROFILE_ALREADY_EXISTS: 'PROFILE_ALREADY_EXISTS',
28
+ PROFILE_IS_ACTIVE: 'PROFILE_IS_ACTIVE',
29
+ PROFILE_IS_LAST: 'PROFILE_IS_LAST',
30
+ PROFILE_NAME_INVALID: 'PROFILE_NAME_INVALID',
31
+ // Internal
32
+ INTERNAL: 'INTERNAL',
33
+ };
34
+ /**
35
+ * Structured CLI error with machine-readable fields.
36
+ *
37
+ * Usage:
38
+ * throw new CLIError('No API key configured', {
39
+ * code: ErrorCode.AUTH_MISSING,
40
+ * category: 'auth',
41
+ * guidance: 'Run `pb login` to configure your API key.',
42
+ * });
43
+ */
44
+ export class CLIError extends Error {
45
+ code;
46
+ category;
47
+ guidance;
48
+ constructor(message, options) {
49
+ super(message);
50
+ this.name = 'CLIError';
51
+ this.code = options?.code ?? ErrorCode.INTERNAL;
52
+ this.category = options?.category ?? 'internal';
53
+ this.guidance = options?.guidance;
54
+ }
55
+ /** Serialize for JSON error output. */
56
+ toJSON() {
57
+ return {
58
+ error: this.message,
59
+ code: this.code,
60
+ category: this.category,
61
+ ...(this.guidance ? { guidance: this.guidance } : {}),
62
+ };
63
+ }
64
+ }
65
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,sEAAsE;AACtE,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,OAAO;IACP,YAAY,EAAE,cAAc;IAC5B,YAAY,EAAE,cAAc;IAC5B,WAAW,EAAE,aAAa;IAC1B,UAAU;IACV,mBAAmB,EAAE,qBAAqB;IAC1C,eAAe,EAAE,iBAAiB;IAClC,SAAS;IACT,cAAc,EAAE,gBAAgB;IAChC,cAAc,EAAE,gBAAgB;IAChC,UAAU;IACV,gBAAgB,EAAE,kBAAkB;IACpC,aAAa;IACb,iBAAiB,EAAE,mBAAmB;IACtC,sBAAsB;IACtB,iBAAiB,EAAE,mBAAmB;IACtC,sBAAsB,EAAE,wBAAwB;IAChD,iBAAiB,EAAE,mBAAmB;IACtC,eAAe,EAAE,iBAAiB;IAClC,oBAAoB,EAAE,sBAAsB;IAC5C,WAAW;IACX,QAAQ,EAAE,UAAU;CACZ,CAAC;AAIX;;;;;;;;;GASG;AACH,MAAM,OAAO,QAAS,SAAQ,KAAK;IACxB,IAAI,CAAiB;IACrB,QAAQ,CAAgB;IACxB,QAAQ,CAAU;IAE3B,YACE,OAAe,EACf,OAIC;QAED,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,OAAO,EAAE,IAAI,IAAI,SAAS,CAAC,QAAQ,CAAC;QAChD,IAAI,CAAC,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,UAAU,CAAC;QAChD,IAAI,CAAC,QAAQ,GAAG,OAAO,EAAE,QAAQ,CAAC;IACpC,CAAC;IAED,uCAAuC;IACvC,MAAM;QACJ,OAAO;YACL,KAAK,EAAE,IAAI,CAAC,OAAO;YACnB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACtD,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * glossary.ts — Key CLI terms and their definitions.
3
+ *
4
+ * Provides a static glossary of Product Brain CLI terminology,
5
+ * plus a formatter for TTY output.
6
+ *
7
+ * WP-302 Slice 4.
8
+ */
9
+ export interface GlossaryEntry {
10
+ term: string;
11
+ definition: string;
12
+ }
13
+ export declare const GLOSSARY: GlossaryEntry[];
14
+ /**
15
+ * Format the glossary for TTY output.
16
+ * Returns a multi-line string with bold terms and dimmed definitions.
17
+ */
18
+ export declare function formatGlossary(): string;
19
+ //# sourceMappingURL=glossary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glossary.d.ts","sourceRoot":"","sources":["../../src/lib/glossary.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,QAAQ,EAAE,aAAa,EA6BnC,CAAC;AAEF;;;GAGG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAUvC"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * glossary.ts — Key CLI terms and their definitions.
3
+ *
4
+ * Provides a static glossary of Product Brain CLI terminology,
5
+ * plus a formatter for TTY output.
6
+ *
7
+ * WP-302 Slice 4.
8
+ */
9
+ import { bold, dim } from './style.js';
10
+ export const GLOSSARY = [
11
+ {
12
+ term: 'workspace',
13
+ definition: 'Your product knowledge space. One workspace = one product.',
14
+ },
15
+ {
16
+ term: 'entry',
17
+ definition: 'A unit of product knowledge (bet, decision, tension, standard, etc.).',
18
+ },
19
+ {
20
+ term: 'collection',
21
+ definition: 'A group of related entries (work-packages, decisions, tensions, etc.).',
22
+ },
23
+ {
24
+ term: 'relation',
25
+ definition: 'A typed link between entries (part_of, depends_on, addresses, etc.).',
26
+ },
27
+ {
28
+ term: 'session',
29
+ definition: 'A tracked write session. Required before creating or updating entries.',
30
+ },
31
+ {
32
+ term: 'capture',
33
+ definition: 'Create a new entry on the Chain via pb capture.',
34
+ },
35
+ {
36
+ term: 'profile',
37
+ definition: 'A named workspace configuration with API key and endpoint.',
38
+ },
39
+ ];
40
+ /**
41
+ * Format the glossary for TTY output.
42
+ * Returns a multi-line string with bold terms and dimmed definitions.
43
+ */
44
+ export function formatGlossary() {
45
+ const lines = [];
46
+ const maxTermLen = Math.max(...GLOSSARY.map((g) => g.term.length));
47
+ for (const entry of GLOSSARY) {
48
+ const paddedTerm = entry.term.padEnd(maxTermLen);
49
+ lines.push(` ${bold(paddedTerm)} ${dim(entry.definition)}`);
50
+ }
51
+ return lines.join('\n');
52
+ }
53
+ //# sourceMappingURL=glossary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glossary.js","sourceRoot":"","sources":["../../src/lib/glossary.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAOvC,MAAM,CAAC,MAAM,QAAQ,GAAoB;IACvC;QACE,IAAI,EAAE,WAAW;QACjB,UAAU,EAAE,4DAA4D;KACzE;IACD;QACE,IAAI,EAAE,OAAO;QACb,UAAU,EAAE,uEAAuE;KACpF;IACD;QACE,IAAI,EAAE,YAAY;QAClB,UAAU,EAAE,wEAAwE;KACrF;IACD;QACE,IAAI,EAAE,UAAU;QAChB,UAAU,EAAE,sEAAsE;KACnF;IACD;QACE,IAAI,EAAE,SAAS;QACf,UAAU,EAAE,wEAAwE;KACrF;IACD;QACE,IAAI,EAAE,SAAS;QACf,UAAU,EAAE,iDAAiD;KAC9D;IACD;QACE,IAAI,EAAE,SAAS;QACf,UAAU,EAAE,4DAA4D;KACzE;CACF,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,cAAc;IAC5B,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IAEnE,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;QAC7B,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QACjD,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,UAAU,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IAChE,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Profile storage and resolution — multi-workspace support for the Product Brain CLI.
3
+ * WP-302 Slice 2: Workspace Profiles + Config Refactor.
4
+ *
5
+ * Profile directory: ~/.config/productbrain/profiles/
6
+ * Active profile tracked in: ~/.config/productbrain/active-profile
7
+ * Resolution order: PB_PROFILE env > active-profile file > "default" > legacy .env
8
+ */
9
+ declare const HOME_CONFIG_DIR: string;
10
+ declare const PROFILES_DIR: string;
11
+ declare const ACTIVE_PROFILE_PATH: string;
12
+ declare const LEGACY_ENV_PATH: string;
13
+ export interface ProfileConfig {
14
+ apiKey: string;
15
+ siteUrl?: string;
16
+ }
17
+ /** List all profile names (sorted). */
18
+ export declare function listProfiles(): string[];
19
+ /** Get the active profile name. */
20
+ export declare function getActiveProfile(): string | null;
21
+ /** Create a new profile. */
22
+ export declare function createProfile(name: string, apiKey: string, siteUrl?: string): void;
23
+ /** Switch the active profile. */
24
+ export declare function useProfile(name: string): void;
25
+ /** Delete a profile. Cannot delete the last profile or the active profile. */
26
+ export declare function deleteProfile(name: string): void;
27
+ /**
28
+ * Resolve config from the active profile.
29
+ * Resolution order: PB_PROFILE env > active-profile file > "default" > legacy .env
30
+ * Returns null if no profile or config is available.
31
+ */
32
+ export declare function resolveProfileConfig(): ProfileConfig | null;
33
+ export { PROFILES_DIR, ACTIVE_PROFILE_PATH, LEGACY_ENV_PATH, HOME_CONFIG_DIR };
34
+ //# sourceMappingURL=profiles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profiles.d.ts","sourceRoot":"","sources":["../../src/lib/profiles.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,QAAA,MAAM,eAAe,QAAgD,CAAC;AACtE,QAAA,MAAM,YAAY,QAAuC,CAAC;AAC1D,QAAA,MAAM,mBAAmB,QAA6C,CAAC;AACvE,QAAA,MAAM,eAAe,QAAmC,CAAC;AAKzD,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAoDD,uCAAuC;AACvC,wBAAgB,YAAY,IAAI,MAAM,EAAE,CAOvC;AAED,mCAAmC;AACnC,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAWhD;AAED,4BAA4B;AAC5B,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAwBlF;AAED,iCAAiC;AACjC,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAS7C;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAmBhD;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,aAAa,GAAG,IAAI,CAgC3D;AAGD,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,eAAe,EAAE,eAAe,EAAE,CAAC"}
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Profile storage and resolution — multi-workspace support for the Product Brain CLI.
3
+ * WP-302 Slice 2: Workspace Profiles + Config Refactor.
4
+ *
5
+ * Profile directory: ~/.config/productbrain/profiles/
6
+ * Active profile tracked in: ~/.config/productbrain/active-profile
7
+ * Resolution order: PB_PROFILE env > active-profile file > "default" > legacy .env
8
+ */
9
+ import { existsSync, readFileSync, writeFileSync, unlinkSync, mkdirSync, readdirSync } from 'fs';
10
+ import { resolve } from 'path';
11
+ import { homedir } from 'os';
12
+ import { CLIError, ErrorCode } from './errors.js';
13
+ const HOME_CONFIG_DIR = resolve(homedir(), '.config', 'productbrain');
14
+ const PROFILES_DIR = resolve(HOME_CONFIG_DIR, 'profiles');
15
+ const ACTIVE_PROFILE_PATH = resolve(HOME_CONFIG_DIR, 'active-profile');
16
+ const LEGACY_ENV_PATH = resolve(HOME_CONFIG_DIR, '.env');
17
+ /** Profile name validation: lowercase alphanumeric + hyphens, 1-32 chars. */
18
+ const PROFILE_NAME_RE = /^[a-z0-9][a-z0-9-]{0,31}$/;
19
+ function validateProfileName(name) {
20
+ if (!PROFILE_NAME_RE.test(name)) {
21
+ throw new CLIError(`Invalid profile name "${name}". Must be 1-32 chars, lowercase alphanumeric + hyphens, starting with alphanumeric.`, { code: ErrorCode.PROFILE_NAME_INVALID, category: 'profile' });
22
+ }
23
+ }
24
+ function profilePath(name) {
25
+ return resolve(PROFILES_DIR, `${name}.env`);
26
+ }
27
+ function parseEnvFile(content) {
28
+ const vars = {};
29
+ for (const line of content.split('\n')) {
30
+ const m = line.match(/^([^#=]+)=(.*)$/);
31
+ if (m) {
32
+ vars[m[1].trim()] = m[2].trim().replace(/^["']|["']$/g, '');
33
+ }
34
+ }
35
+ return vars;
36
+ }
37
+ function readProfileFile(path) {
38
+ if (!existsSync(path))
39
+ return null;
40
+ const vars = parseEnvFile(readFileSync(path, 'utf8'));
41
+ const apiKey = vars['PRODUCTBRAIN_API_KEY'] || '';
42
+ if (!apiKey)
43
+ return null;
44
+ return {
45
+ apiKey,
46
+ siteUrl: vars['CONVEX_SITE_URL'] || undefined,
47
+ };
48
+ }
49
+ /**
50
+ * Auto-migrate legacy ~/.config/productbrain/.env to profiles/default.env.
51
+ * Only runs if legacy file exists AND no profiles directory exists.
52
+ */
53
+ function autoMigrate() {
54
+ if (existsSync(PROFILES_DIR))
55
+ return false;
56
+ if (!existsSync(LEGACY_ENV_PATH))
57
+ return false;
58
+ mkdirSync(PROFILES_DIR, { recursive: true });
59
+ const content = readFileSync(LEGACY_ENV_PATH, 'utf8');
60
+ writeFileSync(profilePath('default'), content, { mode: 0o600 });
61
+ writeFileSync(ACTIVE_PROFILE_PATH, 'default', { mode: 0o600 });
62
+ return true;
63
+ }
64
+ /** List all profile names (sorted). */
65
+ export function listProfiles() {
66
+ autoMigrate();
67
+ if (!existsSync(PROFILES_DIR))
68
+ return [];
69
+ return readdirSync(PROFILES_DIR)
70
+ .filter((f) => f.endsWith('.env'))
71
+ .map((f) => f.replace(/\.env$/, ''))
72
+ .sort();
73
+ }
74
+ /** Get the active profile name. */
75
+ export function getActiveProfile() {
76
+ // PB_PROFILE env var takes precedence
77
+ const envProfile = process.env.PB_PROFILE?.trim();
78
+ if (envProfile)
79
+ return envProfile;
80
+ if (existsSync(ACTIVE_PROFILE_PATH)) {
81
+ const name = readFileSync(ACTIVE_PROFILE_PATH, 'utf8').trim();
82
+ if (name)
83
+ return name;
84
+ }
85
+ return null;
86
+ }
87
+ /** Create a new profile. */
88
+ export function createProfile(name, apiKey, siteUrl) {
89
+ validateProfileName(name);
90
+ if (existsSync(profilePath(name))) {
91
+ throw new CLIError(`Profile "${name}" already exists.`, { code: ErrorCode.PROFILE_ALREADY_EXISTS, category: 'profile' });
92
+ }
93
+ mkdirSync(PROFILES_DIR, { recursive: true });
94
+ const lines = [
95
+ `# Product Brain CLI profile: ${name}`,
96
+ `PRODUCTBRAIN_API_KEY=${apiKey}`,
97
+ ];
98
+ if (siteUrl) {
99
+ lines.push(`CONVEX_SITE_URL=${siteUrl}`);
100
+ }
101
+ lines.push('');
102
+ writeFileSync(profilePath(name), lines.join('\n'), { mode: 0o600 });
103
+ // If this is the first profile, make it active
104
+ if (!existsSync(ACTIVE_PROFILE_PATH)) {
105
+ writeFileSync(ACTIVE_PROFILE_PATH, name, { mode: 0o600 });
106
+ }
107
+ }
108
+ /** Switch the active profile. */
109
+ export function useProfile(name) {
110
+ validateProfileName(name);
111
+ if (!existsSync(profilePath(name))) {
112
+ throw new CLIError(`Profile "${name}" does not exist.`, { code: ErrorCode.PROFILE_NOT_FOUND, category: 'profile' });
113
+ }
114
+ mkdirSync(HOME_CONFIG_DIR, { recursive: true });
115
+ writeFileSync(ACTIVE_PROFILE_PATH, name, { mode: 0o600 });
116
+ }
117
+ /** Delete a profile. Cannot delete the last profile or the active profile. */
118
+ export function deleteProfile(name) {
119
+ validateProfileName(name);
120
+ const path = profilePath(name);
121
+ if (!existsSync(path)) {
122
+ throw new CLIError(`Profile "${name}" does not exist.`, { code: ErrorCode.PROFILE_NOT_FOUND, category: 'profile' });
123
+ }
124
+ const profiles = listProfiles();
125
+ if (profiles.length <= 1) {
126
+ throw new CLIError(`Cannot delete the last profile "${name}".`, { code: ErrorCode.PROFILE_IS_LAST, category: 'profile' });
127
+ }
128
+ const active = getActiveProfile();
129
+ if (active === name) {
130
+ throw new CLIError(`Cannot delete the active profile "${name}". Switch to another profile first.`, { code: ErrorCode.PROFILE_IS_ACTIVE, category: 'profile', guidance: 'Run `pb profile use <other-profile>` first.' });
131
+ }
132
+ unlinkSync(path);
133
+ }
134
+ /**
135
+ * Resolve config from the active profile.
136
+ * Resolution order: PB_PROFILE env > active-profile file > "default" > legacy .env
137
+ * Returns null if no profile or config is available.
138
+ */
139
+ export function resolveProfileConfig() {
140
+ autoMigrate();
141
+ // 1. Check PB_PROFILE env var
142
+ const envProfile = process.env.PB_PROFILE?.trim();
143
+ if (envProfile) {
144
+ const config = readProfileFile(profilePath(envProfile));
145
+ if (config)
146
+ return config;
147
+ }
148
+ // 2. Check active-profile file
149
+ if (existsSync(ACTIVE_PROFILE_PATH)) {
150
+ const name = readFileSync(ACTIVE_PROFILE_PATH, 'utf8').trim();
151
+ if (name) {
152
+ const config = readProfileFile(profilePath(name));
153
+ if (config)
154
+ return config;
155
+ }
156
+ }
157
+ // 3. Check "default" profile
158
+ {
159
+ const config = readProfileFile(profilePath('default'));
160
+ if (config)
161
+ return config;
162
+ }
163
+ // 4. Fall back to legacy .env
164
+ {
165
+ const config = readProfileFile(LEGACY_ENV_PATH);
166
+ if (config)
167
+ return config;
168
+ }
169
+ return null;
170
+ }
171
+ // Exported for testing
172
+ export { PROFILES_DIR, ACTIVE_PROFILE_PATH, LEGACY_ENV_PATH, HOME_CONFIG_DIR };
173
+ //# sourceMappingURL=profiles.js.map