@respan/cli 0.4.1 → 0.5.1

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.
@@ -8,6 +8,9 @@ export default class IntegrateClaudeCode extends BaseCommand {
8
8
  'project-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
9
  'base-url': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
10
10
  attrs: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
11
+ 'customer-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ 'span-name': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
+ 'workflow-name': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
14
  'dry-run': import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
15
  'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
16
  profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
@@ -1,15 +1,19 @@
1
1
  import * as fs from 'node:fs';
2
2
  import { execSync } from 'node:child_process';
3
3
  import { BaseCommand } from '../../lib/base-command.js';
4
- import { integrateFlags, deepMerge, readJsonFile, writeJsonFile, writeTextFile, expandHome, parseAttrs, getHookScript, resolveScope, findProjectRoot, DEFAULT_BASE_URL, } from '../../lib/integrate.js';
4
+ import { integrateFlags, deepMerge, readJsonFile, writeJsonFile, writeTextFile, expandHome, parseAttrs, getHookScript, resolveScope, findProjectRoot, } from '../../lib/integrate.js';
5
5
  class IntegrateClaudeCode extends BaseCommand {
6
6
  async run() {
7
7
  const { flags } = await this.parse(IntegrateClaudeCode);
8
8
  this.globalFlags = flags;
9
9
  try {
10
- const apiKey = this.resolveApiKey();
10
+ // Verify the user is authenticated (key is read by hook from ~/.config/respan/)
11
+ this.resolveApiKey();
11
12
  const baseUrl = flags['base-url'];
12
13
  const projectId = flags['project-id'];
14
+ const customerId = flags['customer-id'];
15
+ const spanName = flags['span-name'];
16
+ const workflowName = flags['workflow-name'];
13
17
  const attrs = parseAttrs(flags.attrs);
14
18
  const dryRun = flags['dry-run'];
15
19
  // Claude Code default: both global + local
@@ -89,20 +93,10 @@ class IntegrateClaudeCode extends BaseCommand {
89
93
  const projectRoot = findProjectRoot();
90
94
  const localSettingsPath = `${projectRoot}/.claude/settings.local.json`;
91
95
  const localSettings = readJsonFile(localSettingsPath);
96
+ // settings.local.json: enable flag only (API key from ~/.config/respan/)
92
97
  const envBlock = {
93
98
  TRACE_TO_RESPAN: 'true',
94
- RESPAN_API_KEY: apiKey,
95
99
  };
96
- if (baseUrl !== DEFAULT_BASE_URL) {
97
- envBlock.RESPAN_BASE_URL = baseUrl;
98
- }
99
- const metadata = { ...attrs };
100
- if (projectId) {
101
- metadata.project_id = projectId;
102
- }
103
- if (Object.keys(metadata).length > 0) {
104
- envBlock.RESPAN_METADATA = JSON.stringify(metadata);
105
- }
106
100
  const mergedLocal = deepMerge(localSettings, { env: envBlock });
107
101
  if (dryRun) {
108
102
  this.log(`[dry-run] Would update: ${localSettingsPath}`);
@@ -112,6 +106,36 @@ class IntegrateClaudeCode extends BaseCommand {
112
106
  writeJsonFile(localSettingsPath, mergedLocal);
113
107
  this.log(`Updated project settings: ${localSettingsPath}`);
114
108
  }
109
+ // respan.json: non-secret config (known fields + custom properties)
110
+ const respanConfigPath = `${projectRoot}/.claude/respan.json`;
111
+ const respanConfig = readJsonFile(respanConfigPath);
112
+ const newConfig = { ...respanConfig };
113
+ if (customerId) {
114
+ newConfig.customer_id = customerId;
115
+ }
116
+ if (spanName) {
117
+ newConfig.span_name = spanName;
118
+ }
119
+ if (workflowName) {
120
+ newConfig.workflow_name = workflowName;
121
+ }
122
+ if (projectId) {
123
+ newConfig.project_id = projectId;
124
+ }
125
+ // Custom attrs go as top-level keys (unknown keys = custom properties)
126
+ for (const [k, v] of Object.entries(attrs)) {
127
+ newConfig[k] = v;
128
+ }
129
+ if (Object.keys(newConfig).length > 0) {
130
+ if (dryRun) {
131
+ this.log(`[dry-run] Would write: ${respanConfigPath}`);
132
+ this.log(JSON.stringify(newConfig, null, 2));
133
+ }
134
+ else {
135
+ writeJsonFile(respanConfigPath, newConfig);
136
+ this.log(`Wrote Respan config: ${respanConfigPath}`);
137
+ }
138
+ }
115
139
  }
116
140
  // ── Done ──────────────────────────────────────────────────────
117
141
  this.log('');
@@ -126,7 +150,15 @@ class IntegrateClaudeCode extends BaseCommand {
126
150
  this.log('Claude Code tracing enabled for this project.');
127
151
  }
128
152
  this.log('');
129
- this.log('Set dynamic metadata before a session:');
153
+ this.log('Auth: ~/.config/respan/credentials.json (from `respan auth login`)');
154
+ this.log('Config: .claude/respan.json (shareable, non-secret)');
155
+ this.log('');
156
+ this.log('Set properties via integrate flags or edit .claude/respan.json:');
157
+ this.log(' respan integrate claude-code --customer-id "frank" --span-name "my-app"');
158
+ this.log(' respan integrate claude-code --attrs \'{"team":"platform","env":"staging"}\'');
159
+ this.log('');
160
+ this.log('Override per-session with env vars:');
161
+ this.log(' export RESPAN_CUSTOMER_ID="your-name"');
130
162
  this.log(" export RESPAN_METADATA='{\"task_id\":\"T-123\"}'");
131
163
  }
132
164
  catch (error) {
@@ -8,6 +8,9 @@ export default class IntegrateCodexCli extends BaseCommand {
8
8
  'project-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
9
  'base-url': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
10
10
  attrs: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
11
+ 'customer-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ 'span-name': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
+ 'workflow-name': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
14
  'dry-run': import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
15
  'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
16
  profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
@@ -8,6 +8,9 @@ export default class IntegrateGeminiCli extends BaseCommand {
8
8
  'project-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
9
  'base-url': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
10
10
  attrs: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
11
+ 'customer-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ 'span-name': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
+ 'workflow-name': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
14
  'dry-run': import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
15
  'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
16
  profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
@@ -8,6 +8,9 @@ export default class IntegrateOpencode extends BaseCommand {
8
8
  'project-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
9
  'base-url': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
10
10
  attrs: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
11
+ 'customer-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ 'span-name': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
+ 'workflow-name': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
14
  'dry-run': import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
15
  'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
16
  profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
@@ -6,6 +6,9 @@ export declare const integrateFlags: {
6
6
  'project-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
7
  'base-url': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
8
8
  attrs: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
9
+ 'customer-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ 'span-name': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
+ 'workflow-name': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
12
  'dry-run': import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
13
  };
11
14
  export type Scope = 'local' | 'global' | 'both';
@@ -31,6 +31,16 @@ export const integrateFlags = {
31
31
  description: "Custom attributes JSON (e.g. '{\"env\":\"prod\"}')",
32
32
  default: '{}',
33
33
  }),
34
+ 'customer-id': Flags.string({
35
+ description: 'Customer/user identifier for traces (e.g. your name or email)',
36
+ env: 'RESPAN_CUSTOMER_ID',
37
+ }),
38
+ 'span-name': Flags.string({
39
+ description: 'Root span name for traces (default: claude-code)',
40
+ }),
41
+ 'workflow-name': Flags.string({
42
+ description: 'Workflow name for traces (default: claude-code)',
43
+ }),
34
44
  'dry-run': Flags.boolean({
35
45
  description: 'Preview changes without writing files',
36
46
  default: false,
@@ -1671,6 +1671,28 @@
1671
1671
  "multiple": false,
1672
1672
  "type": "option"
1673
1673
  },
1674
+ "customer-id": {
1675
+ "description": "Customer/user identifier for traces (e.g. your name or email)",
1676
+ "env": "RESPAN_CUSTOMER_ID",
1677
+ "name": "customer-id",
1678
+ "hasDynamicHelp": false,
1679
+ "multiple": false,
1680
+ "type": "option"
1681
+ },
1682
+ "span-name": {
1683
+ "description": "Root span name for traces (default: claude-code)",
1684
+ "name": "span-name",
1685
+ "hasDynamicHelp": false,
1686
+ "multiple": false,
1687
+ "type": "option"
1688
+ },
1689
+ "workflow-name": {
1690
+ "description": "Workflow name for traces (default: claude-code)",
1691
+ "name": "workflow-name",
1692
+ "hasDynamicHelp": false,
1693
+ "multiple": false,
1694
+ "type": "option"
1695
+ },
1674
1696
  "dry-run": {
1675
1697
  "description": "Preview changes without writing files",
1676
1698
  "name": "dry-run",
@@ -1781,6 +1803,28 @@
1781
1803
  "multiple": false,
1782
1804
  "type": "option"
1783
1805
  },
1806
+ "customer-id": {
1807
+ "description": "Customer/user identifier for traces (e.g. your name or email)",
1808
+ "env": "RESPAN_CUSTOMER_ID",
1809
+ "name": "customer-id",
1810
+ "hasDynamicHelp": false,
1811
+ "multiple": false,
1812
+ "type": "option"
1813
+ },
1814
+ "span-name": {
1815
+ "description": "Root span name for traces (default: claude-code)",
1816
+ "name": "span-name",
1817
+ "hasDynamicHelp": false,
1818
+ "multiple": false,
1819
+ "type": "option"
1820
+ },
1821
+ "workflow-name": {
1822
+ "description": "Workflow name for traces (default: claude-code)",
1823
+ "name": "workflow-name",
1824
+ "hasDynamicHelp": false,
1825
+ "multiple": false,
1826
+ "type": "option"
1827
+ },
1784
1828
  "dry-run": {
1785
1829
  "description": "Preview changes without writing files",
1786
1830
  "name": "dry-run",
@@ -1891,6 +1935,28 @@
1891
1935
  "multiple": false,
1892
1936
  "type": "option"
1893
1937
  },
1938
+ "customer-id": {
1939
+ "description": "Customer/user identifier for traces (e.g. your name or email)",
1940
+ "env": "RESPAN_CUSTOMER_ID",
1941
+ "name": "customer-id",
1942
+ "hasDynamicHelp": false,
1943
+ "multiple": false,
1944
+ "type": "option"
1945
+ },
1946
+ "span-name": {
1947
+ "description": "Root span name for traces (default: claude-code)",
1948
+ "name": "span-name",
1949
+ "hasDynamicHelp": false,
1950
+ "multiple": false,
1951
+ "type": "option"
1952
+ },
1953
+ "workflow-name": {
1954
+ "description": "Workflow name for traces (default: claude-code)",
1955
+ "name": "workflow-name",
1956
+ "hasDynamicHelp": false,
1957
+ "multiple": false,
1958
+ "type": "option"
1959
+ },
1894
1960
  "dry-run": {
1895
1961
  "description": "Preview changes without writing files",
1896
1962
  "name": "dry-run",
@@ -2001,6 +2067,28 @@
2001
2067
  "multiple": false,
2002
2068
  "type": "option"
2003
2069
  },
2070
+ "customer-id": {
2071
+ "description": "Customer/user identifier for traces (e.g. your name or email)",
2072
+ "env": "RESPAN_CUSTOMER_ID",
2073
+ "name": "customer-id",
2074
+ "hasDynamicHelp": false,
2075
+ "multiple": false,
2076
+ "type": "option"
2077
+ },
2078
+ "span-name": {
2079
+ "description": "Root span name for traces (default: claude-code)",
2080
+ "name": "span-name",
2081
+ "hasDynamicHelp": false,
2082
+ "multiple": false,
2083
+ "type": "option"
2084
+ },
2085
+ "workflow-name": {
2086
+ "description": "Workflow name for traces (default: claude-code)",
2087
+ "name": "workflow-name",
2088
+ "hasDynamicHelp": false,
2089
+ "multiple": false,
2090
+ "type": "option"
2091
+ },
2004
2092
  "dry-run": {
2005
2093
  "description": "Preview changes without writing files",
2006
2094
  "name": "dry-run",
@@ -3370,5 +3458,5 @@
3370
3458
  ]
3371
3459
  }
3372
3460
  },
3373
- "version": "0.4.1"
3461
+ "version": "0.5.1"
3374
3462
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@respan/cli",
3
- "version": "0.4.1",
3
+ "version": "0.5.1",
4
4
  "description": "Respan CLI - manage your LLM observability from the command line",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -9,7 +9,7 @@
9
9
  "respan": "./bin/run.js"
10
10
  },
11
11
  "scripts": {
12
- "build": "tsc && cp -r src/assets dist/assets",
12
+ "build": "tsc && rm -rf dist/assets && cp -r src/assets dist/assets",
13
13
  "clean": "rm -rf dist",
14
14
  "dev": "node --loader ts-node/esm bin/dev.js",
15
15
  "postpack": "rm -f oclif.manifest.json",