@warpmetrics/coder 0.1.0 → 0.1.3

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 (2) hide show
  1. package/bin/init.js +91 -56
  2. package/package.json +2 -2
package/bin/init.js CHANGED
@@ -19,47 +19,78 @@ function log(msg) {
19
19
  console.log(msg);
20
20
  }
21
21
 
22
+ function getExistingSecrets() {
23
+ try {
24
+ execSync('gh --version', { stdio: 'ignore' });
25
+ } catch {
26
+ return null; // gh not available
27
+ }
28
+ try {
29
+ const output = execSync('gh secret list', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'ignore'] });
30
+ const names = output.split('\n').map(line => line.split('\t')[0].trim()).filter(Boolean);
31
+ return new Set(names);
32
+ } catch {
33
+ return new Set(); // gh available but couldn't list (e.g. no repo context)
34
+ }
35
+ }
36
+
22
37
  async function main() {
23
38
  log('');
24
39
  log(' warp-coder \u2014 Agent pipeline for implementing GitHub issues');
25
40
  log('');
26
41
 
42
+ const existingSecrets = getExistingSecrets();
43
+ const ghAvailable = existingSecrets !== null;
44
+
27
45
  // 1. Anthropic API key
28
- const anthropicKey = await ask(' ? Anthropic API key: ');
29
- if (!anthropicKey.startsWith('sk-ant-')) {
46
+ let anthropicKey = null;
47
+ if (existingSecrets?.has('ANTHROPIC_API_KEY')) {
48
+ log(' \u2713 ANTHROPIC_API_KEY already set');
49
+ const replace = await ask(' Replace it? (y/N): ');
50
+ if (replace.toLowerCase() === 'y') {
51
+ anthropicKey = await ask(' ? Anthropic API key: ');
52
+ }
53
+ } else {
54
+ anthropicKey = await ask(' ? Anthropic API key: ');
55
+ }
56
+ if (anthropicKey && !anthropicKey.startsWith('sk-ant-')) {
30
57
  log(' \u26a0 Warning: key doesn\'t start with sk-ant- \u2014 make sure this is a valid Anthropic API key');
31
58
  }
32
59
 
33
60
  // 2. WarpMetrics API key
34
- const wmKey = await ask(' ? WarpMetrics API key (get one at warpmetrics.com/app/api-keys): ');
35
- if (!wmKey.startsWith('wm_')) {
61
+ let wmKey = null;
62
+ if (existingSecrets?.has('WARPMETRICS_API_KEY')) {
63
+ log(' \u2713 WARPMETRICS_API_KEY already set');
64
+ const replace = await ask(' Replace it? (y/N): ');
65
+ if (replace.toLowerCase() === 'y') {
66
+ wmKey = await ask(' ? WarpMetrics API key (get one at warpmetrics.com/app/api-keys): ');
67
+ }
68
+ } else {
69
+ wmKey = await ask(' ? WarpMetrics API key (get one at warpmetrics.com/app/api-keys): ');
70
+ }
71
+ if (wmKey && !wmKey.startsWith('wm_')) {
36
72
  log(' \u26a0 Warning: key doesn\'t start with wm_ \u2014 make sure this is a valid WarpMetrics API key');
37
73
  }
38
74
 
39
75
  log('');
40
76
 
41
77
  // 3. Set GitHub secrets
42
- let ghAvailable = false;
43
- try {
44
- execSync('gh --version', { stdio: 'ignore' });
45
- ghAvailable = true;
46
- } catch {
47
- ghAvailable = false;
48
- }
49
-
50
78
  if (ghAvailable) {
51
- log(' Setting GitHub secrets...');
52
- try {
53
- execSync('gh secret set ANTHROPIC_API_KEY', { input: anthropicKey, stdio: ['pipe', 'ignore', 'ignore'] });
54
- log(' \u2713 ANTHROPIC_API_KEY set');
55
- } catch (e) {
56
- log(` \u2717 Failed to set ANTHROPIC_API_KEY: ${e.message}`);
79
+ if (anthropicKey) {
80
+ try {
81
+ execSync('gh secret set ANTHROPIC_API_KEY', { input: anthropicKey, stdio: ['pipe', 'ignore', 'ignore'] });
82
+ log(' \u2713 ANTHROPIC_API_KEY set');
83
+ } catch (e) {
84
+ log(` \u2717 Failed to set ANTHROPIC_API_KEY: ${e.message}`);
85
+ }
57
86
  }
58
- try {
59
- execSync('gh secret set WARPMETRICS_API_KEY', { input: wmKey, stdio: ['pipe', 'ignore', 'ignore'] });
60
- log(' \u2713 WARPMETRICS_API_KEY set');
61
- } catch (e) {
62
- log(` \u2717 Failed to set WARPMETRICS_API_KEY: ${e.message}`);
87
+ if (wmKey) {
88
+ try {
89
+ execSync('gh secret set WARPMETRICS_API_KEY', { input: wmKey, stdio: ['pipe', 'ignore', 'ignore'] });
90
+ log(' \u2713 WARPMETRICS_API_KEY set');
91
+ } catch (e) {
92
+ log(` \u2717 Failed to set WARPMETRICS_API_KEY: ${e.message}`);
93
+ }
63
94
  }
64
95
  } else {
65
96
  log(' gh (GitHub CLI) not found. Set these secrets manually:');
@@ -80,43 +111,47 @@ async function main() {
80
111
  log('');
81
112
 
82
113
  // 6. Register outcome classifications
83
- log(' Registering outcome classifications with WarpMetrics...');
84
- const classifications = [
85
- { name: 'PR Created', classification: 'success' },
86
- { name: 'Fixes Applied', classification: 'success' },
87
- { name: 'Issue Understood', classification: 'success' },
88
- { name: 'Needs Clarification', classification: 'neutral' },
89
- { name: 'Needs Human', classification: 'neutral' },
90
- { name: 'Implementation Failed', classification: 'failure' },
91
- { name: 'Tests Failed', classification: 'failure' },
92
- { name: 'Revision Failed', classification: 'failure' },
93
- { name: 'Max Retries', classification: 'failure' },
94
- ];
95
-
96
- let classOk = true;
97
- for (const { name, classification } of classifications) {
98
- try {
99
- const res = await fetch(`https://api.warpmetrics.com/v1/outcomes/classifications/${encodeURIComponent(name)}`, {
100
- method: 'PUT',
101
- headers: {
102
- Authorization: `Bearer ${wmKey}`,
103
- 'Content-Type': 'application/json',
104
- },
105
- body: JSON.stringify({ classification }),
106
- });
107
- if (!res.ok) {
114
+ if (wmKey) {
115
+ log(' Registering outcome classifications with WarpMetrics...');
116
+ const classifications = [
117
+ { name: 'PR Created', classification: 'success' },
118
+ { name: 'Fixes Applied', classification: 'success' },
119
+ { name: 'Issue Understood', classification: 'success' },
120
+ { name: 'Needs Clarification', classification: 'neutral' },
121
+ { name: 'Needs Human', classification: 'neutral' },
122
+ { name: 'Implementation Failed', classification: 'failure' },
123
+ { name: 'Tests Failed', classification: 'failure' },
124
+ { name: 'Revision Failed', classification: 'failure' },
125
+ { name: 'Max Retries', classification: 'failure' },
126
+ ];
127
+
128
+ let classOk = true;
129
+ for (const { name, classification } of classifications) {
130
+ try {
131
+ const res = await fetch(`https://api.warpmetrics.com/v1/outcomes/classifications/${encodeURIComponent(name)}`, {
132
+ method: 'PUT',
133
+ headers: {
134
+ Authorization: `Bearer ${wmKey}`,
135
+ 'Content-Type': 'application/json',
136
+ },
137
+ body: JSON.stringify({ classification }),
138
+ });
139
+ if (!res.ok) {
140
+ classOk = false;
141
+ console.warn(` \u26a0 Failed to set classification ${name}: ${res.status}`);
142
+ }
143
+ } catch (e) {
108
144
  classOk = false;
109
- console.warn(` \u26a0 Failed to set classification ${name}: ${res.status}`);
145
+ console.warn(` \u26a0 Failed to set classification ${name}: ${e.message}`);
110
146
  }
111
- } catch (e) {
112
- classOk = false;
113
- console.warn(` \u26a0 Failed to set classification ${name}: ${e.message}`);
114
147
  }
115
- }
116
- if (classOk) {
117
- log(' \u2713 Outcomes configured');
148
+ if (classOk) {
149
+ log(' \u2713 Outcomes configured');
150
+ } else {
151
+ log(' \u26a0 Some classifications failed \u2014 you can set them manually in the WarpMetrics dashboard');
152
+ }
118
153
  } else {
119
- log(' \u26a0 Some classifications failed \u2014 you can set them manually in the WarpMetrics dashboard');
154
+ log(' Skipping outcome classifications (WarpMetrics key not provided)');
120
155
  }
121
156
 
122
157
  // 7. Check for warp-review
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@warpmetrics/coder",
3
- "version": "0.1.0",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "description": "Agent pipeline for implementing GitHub issues with Claude Code. Powered by WarpMetrics.",
6
6
  "bin": {
@@ -19,7 +19,7 @@
19
19
  "license": "MIT",
20
20
  "repository": {
21
21
  "type": "git",
22
- "url": "https://github.com/warpmetrics/warp-coder"
22
+ "url": "https://github.com/warpmetrics/coder"
23
23
  },
24
24
  "keywords": [
25
25
  "agent",