@rigstate/cli 0.7.34 → 0.7.36
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.
- package/dist/index.cjs +4220 -9314
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +4192 -9314
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
- package/src/commands/env.ts +3 -6
- package/src/commands/focus.ts +3 -6
- package/src/commands/genesis.ts +305 -0
- package/src/commands/init.ts +4 -5
- package/src/commands/link.ts +25 -19
- package/src/commands/plan.ts +22 -5
- package/src/commands/sync.ts +7 -12
- package/src/commands/watch.ts +3 -7
- package/src/index.ts +8 -0
- package/src/utils/config.ts +79 -4
- package/src/utils/manifest.ts +62 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rigstate/cli",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.36",
|
|
4
4
|
"description": "Rigstate CLI - Code audit, sync and supervision tool",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@rigstate/rules-engine": "*",
|
|
19
19
|
"@rigstate/shared": "*",
|
|
20
|
-
"uuid": "^9.0.1",
|
|
21
20
|
"@types/diff": "^7.0.2",
|
|
22
21
|
"@types/inquirer": "^9.0.9",
|
|
23
22
|
"axios": "^1.6.5",
|
|
@@ -29,7 +28,9 @@
|
|
|
29
28
|
"dotenv": "^16.4.1",
|
|
30
29
|
"glob": "^10.3.10",
|
|
31
30
|
"inquirer": "^9.3.8",
|
|
32
|
-
"ora": "^8.0.1"
|
|
31
|
+
"ora": "^8.0.1",
|
|
32
|
+
"simple-git": "^3.31.1",
|
|
33
|
+
"uuid": "^9.0.1"
|
|
33
34
|
},
|
|
34
35
|
"devDependencies": {
|
|
35
36
|
"@types/node": "^20.11.5",
|
|
@@ -50,4 +51,4 @@
|
|
|
50
51
|
],
|
|
51
52
|
"author": "Rigstate",
|
|
52
53
|
"license": "MIT"
|
|
53
|
-
}
|
|
54
|
+
}
|
package/src/commands/env.ts
CHANGED
|
@@ -141,12 +141,9 @@ export function createEnvPullCommand() {
|
|
|
141
141
|
projectId = getProjectId();
|
|
142
142
|
|
|
143
143
|
if (!projectId) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
const manifest = JSON.parse(content);
|
|
148
|
-
projectId = manifest.project_id;
|
|
149
|
-
} catch (e) { }
|
|
144
|
+
const { loadManifest } = await import('../utils/manifest.js');
|
|
145
|
+
const manifest = await loadManifest();
|
|
146
|
+
if (manifest?.project_id) projectId = manifest.project_id;
|
|
150
147
|
}
|
|
151
148
|
|
|
152
149
|
if (!projectId) {
|
package/src/commands/focus.ts
CHANGED
|
@@ -30,12 +30,9 @@ export function createFocusCommand() {
|
|
|
30
30
|
|
|
31
31
|
projectId = getProjectId();
|
|
32
32
|
if (!projectId) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const manifest = JSON.parse(content);
|
|
37
|
-
projectId = manifest.project_id;
|
|
38
|
-
} catch (e) { }
|
|
33
|
+
const { loadManifest } = await import('../utils/manifest.js');
|
|
34
|
+
const manifest = await loadManifest();
|
|
35
|
+
if (manifest?.project_id) projectId = manifest.project_id;
|
|
39
36
|
}
|
|
40
37
|
|
|
41
38
|
if (!projectId) {
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import ora from 'ora';
|
|
5
|
+
import axios from 'axios';
|
|
6
|
+
import { getApiKey, getApiUrl, getProjectId } from '../utils/config.js';
|
|
7
|
+
|
|
8
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
9
|
+
// Types
|
|
10
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
11
|
+
interface GenesisStep {
|
|
12
|
+
id: string;
|
|
13
|
+
title: string;
|
|
14
|
+
step_number: number;
|
|
15
|
+
icon: string;
|
|
16
|
+
verification_path?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface GenesisStatusResponse {
|
|
20
|
+
success: boolean;
|
|
21
|
+
data: {
|
|
22
|
+
genesis_complete: boolean;
|
|
23
|
+
genesis_steps: GenesisStep[];
|
|
24
|
+
genesis_count: number;
|
|
25
|
+
total_roadmap_steps: number;
|
|
26
|
+
detected_template: string;
|
|
27
|
+
detected_stack_key: string;
|
|
28
|
+
project_name: string;
|
|
29
|
+
};
|
|
30
|
+
error?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface GenesisTriggerResponse {
|
|
34
|
+
success: boolean;
|
|
35
|
+
data: {
|
|
36
|
+
project_name: string;
|
|
37
|
+
template: string;
|
|
38
|
+
stack_key: string;
|
|
39
|
+
steps_created: number;
|
|
40
|
+
steps: GenesisStep[];
|
|
41
|
+
existing_steps_shifted: number;
|
|
42
|
+
message: string;
|
|
43
|
+
};
|
|
44
|
+
error?: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
48
|
+
// Command Definition
|
|
49
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
50
|
+
export function createGenesisCommand(): Command {
|
|
51
|
+
return new Command('genesis')
|
|
52
|
+
.description('Initialize project foundation (Phase 0). Detects stack and injects foundation steps.')
|
|
53
|
+
.option('--force', 'Re-run genesis even if already initialized (use with caution)')
|
|
54
|
+
.option('--status', 'Check genesis status without triggering')
|
|
55
|
+
.option('--project-id <id>', 'Override project ID (defaults to linked project)')
|
|
56
|
+
.action(async (options) => {
|
|
57
|
+
const apiKey = getApiKey();
|
|
58
|
+
const apiUrl = getApiUrl();
|
|
59
|
+
const projectId = options.projectId || getProjectId();
|
|
60
|
+
|
|
61
|
+
if (!projectId) {
|
|
62
|
+
console.error(chalk.red('❌ No project linked. Run: rigstate link'));
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!apiKey) {
|
|
67
|
+
console.error(chalk.red('❌ Not authenticated. Run: rigstate login'));
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (options.status) {
|
|
72
|
+
await checkGenesisStatus(projectId, apiKey, apiUrl);
|
|
73
|
+
} else {
|
|
74
|
+
await triggerGenesis(projectId, apiKey, apiUrl, options.force ?? false);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
80
|
+
// Status Check
|
|
81
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
82
|
+
export async function checkGenesisStatus(
|
|
83
|
+
projectId: string,
|
|
84
|
+
apiKey: string,
|
|
85
|
+
apiUrl: string
|
|
86
|
+
): Promise<{ complete: boolean; stepCount: number }> {
|
|
87
|
+
// ── Offline-first: check local manifest cache ─────────────────────────────
|
|
88
|
+
try {
|
|
89
|
+
const { loadManifest } = await import('../utils/manifest.js');
|
|
90
|
+
const manifest = await loadManifest();
|
|
91
|
+
if (manifest?.genesis_complete) {
|
|
92
|
+
// Local cache hit — skip API call
|
|
93
|
+
return { complete: true, stepCount: 0 }; // stepCount not cached, but complete is enough
|
|
94
|
+
}
|
|
95
|
+
} catch {
|
|
96
|
+
// Ignore manifest read errors
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const spinner = ora('Checking Genesis status...').start();
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
const response = await axios.get<GenesisStatusResponse>(
|
|
103
|
+
`${apiUrl}/api/v1/genesis`,
|
|
104
|
+
{
|
|
105
|
+
params: { project_id: projectId },
|
|
106
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
107
|
+
timeout: 10000
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
spinner.stop();
|
|
112
|
+
|
|
113
|
+
if (!response.data.success) {
|
|
114
|
+
console.log(chalk.yellow(`⚠️ Could not check genesis status: ${response.data.error}`));
|
|
115
|
+
return { complete: false, stepCount: 0 };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const { data } = response.data;
|
|
119
|
+
|
|
120
|
+
console.log('');
|
|
121
|
+
console.log(chalk.bold('🏗️ GENESIS STATUS'));
|
|
122
|
+
console.log(chalk.dim('────────────────────────────────────────'));
|
|
123
|
+
console.log(`${chalk.bold('Project:')} ${chalk.cyan(data.project_name)}`);
|
|
124
|
+
console.log(`${chalk.bold('Stack:')} ${chalk.magenta(data.detected_template)}`);
|
|
125
|
+
console.log(`${chalk.bold('Genesis:')} ${data.genesis_complete ? chalk.green('✅ Complete') : chalk.yellow('⚠️ Pending')}`);
|
|
126
|
+
console.log(`${chalk.bold('Foundation:')} ${chalk.white(data.genesis_count)} steps`);
|
|
127
|
+
console.log(`${chalk.bold('Total Roadmap:')} ${chalk.white(data.total_roadmap_steps)} steps`);
|
|
128
|
+
|
|
129
|
+
if (data.genesis_complete && data.genesis_steps.length > 0) {
|
|
130
|
+
console.log('');
|
|
131
|
+
console.log(chalk.dim('Foundation Steps:'));
|
|
132
|
+
data.genesis_steps.forEach(step => {
|
|
133
|
+
console.log(` ${step.icon} ${chalk.bold(`T-${step.step_number}`)}: ${step.title}`);
|
|
134
|
+
});
|
|
135
|
+
} else if (!data.genesis_complete) {
|
|
136
|
+
console.log('');
|
|
137
|
+
console.log(chalk.yellow('⚡ Genesis not yet initialized.'));
|
|
138
|
+
console.log(chalk.dim(' Run: ') + chalk.white('rigstate genesis'));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
console.log(chalk.dim('────────────────────────────────────────'));
|
|
142
|
+
console.log('');
|
|
143
|
+
|
|
144
|
+
return { complete: data.genesis_complete, stepCount: data.genesis_count };
|
|
145
|
+
|
|
146
|
+
} catch (err: any) {
|
|
147
|
+
spinner.stop();
|
|
148
|
+
if (err.response?.status === 422) {
|
|
149
|
+
console.log(chalk.yellow('⚠️ Genesis pending: Complete onboarding with Frank first.'));
|
|
150
|
+
console.log(chalk.dim(' Then run: rigstate genesis'));
|
|
151
|
+
}
|
|
152
|
+
return { complete: false, stepCount: 0 };
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
158
|
+
// Trigger Genesis
|
|
159
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
160
|
+
export async function triggerGenesis(
|
|
161
|
+
projectId: string,
|
|
162
|
+
apiKey: string,
|
|
163
|
+
apiUrl: string,
|
|
164
|
+
force = false
|
|
165
|
+
): Promise<boolean> {
|
|
166
|
+
console.log('');
|
|
167
|
+
console.log(chalk.bold.blue('🏗️ GENESIS PROTOCOL'));
|
|
168
|
+
console.log(chalk.dim('Initializing project foundation...'));
|
|
169
|
+
console.log('');
|
|
170
|
+
|
|
171
|
+
const spinner = ora('Detecting tech stack...').start();
|
|
172
|
+
|
|
173
|
+
try {
|
|
174
|
+
// Step 1: Check status first (unless force)
|
|
175
|
+
if (!force) {
|
|
176
|
+
const statusRes = await axios.get<GenesisStatusResponse>(
|
|
177
|
+
`${apiUrl}/api/v1/genesis`,
|
|
178
|
+
{
|
|
179
|
+
params: { project_id: projectId },
|
|
180
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
181
|
+
timeout: 10000
|
|
182
|
+
}
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
if (statusRes.data.success && statusRes.data.data.genesis_complete) {
|
|
186
|
+
spinner.stop();
|
|
187
|
+
console.log(chalk.green('✅ Genesis already complete.'));
|
|
188
|
+
console.log(chalk.dim(` ${statusRes.data.data.genesis_count} foundation steps already in roadmap.`));
|
|
189
|
+
console.log(chalk.dim(' Use --force to re-initialize.'));
|
|
190
|
+
console.log('');
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (statusRes.data.success) {
|
|
195
|
+
spinner.text = `Stack detected: ${statusRes.data.data.detected_template}. Generating foundation...`;
|
|
196
|
+
}
|
|
197
|
+
} else {
|
|
198
|
+
spinner.text = 'Force mode: Re-generating foundation...';
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Step 2: Trigger Genesis
|
|
202
|
+
const response = await axios.post<GenesisTriggerResponse>(
|
|
203
|
+
`${apiUrl}/api/v1/genesis`,
|
|
204
|
+
{ project_id: projectId, force },
|
|
205
|
+
{
|
|
206
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
207
|
+
timeout: 60000 // AI enrichment can take time
|
|
208
|
+
}
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
spinner.stop();
|
|
212
|
+
|
|
213
|
+
if (!response.data.success) {
|
|
214
|
+
// Handle specific error cases
|
|
215
|
+
if ((response as any).status === 409) {
|
|
216
|
+
console.log(chalk.yellow('⚠️ Genesis already initialized. Use --force to re-run.'));
|
|
217
|
+
return true;
|
|
218
|
+
}
|
|
219
|
+
if ((response as any).status === 422) {
|
|
220
|
+
console.log('');
|
|
221
|
+
console.log(chalk.yellow('⚠️ Cannot initialize Genesis yet.'));
|
|
222
|
+
console.log(chalk.dim(' Complete onboarding with Frank first to define your tech stack.'));
|
|
223
|
+
console.log(chalk.dim(' Then run: ') + chalk.white('rigstate genesis'));
|
|
224
|
+
console.log('');
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
console.error(chalk.red(`❌ Genesis failed: ${response.data.error}`));
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const { data } = response.data;
|
|
232
|
+
|
|
233
|
+
// ── Success Output ────────────────────────────────────────────────────
|
|
234
|
+
console.log(chalk.bold.green('✅ GENESIS COMPLETE'));
|
|
235
|
+
console.log(chalk.dim('────────────────────────────────────────'));
|
|
236
|
+
console.log(`${chalk.bold('Project:')} ${chalk.cyan(data.project_name)}`);
|
|
237
|
+
console.log(`${chalk.bold('Stack:')} ${chalk.magenta(data.template)}`);
|
|
238
|
+
console.log(`${chalk.bold('Created:')} ${chalk.white(data.steps_created)} foundation steps`);
|
|
239
|
+
|
|
240
|
+
if (data.existing_steps_shifted > 0) {
|
|
241
|
+
console.log(`${chalk.bold('Shifted:')} ${chalk.dim(`${data.existing_steps_shifted} existing steps moved down`)}`);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
console.log('');
|
|
245
|
+
console.log(chalk.bold('📋 Foundation Steps:'));
|
|
246
|
+
data.steps.forEach(step => {
|
|
247
|
+
console.log(` ${step.icon} ${chalk.bold(`T-${step.step_number}`)}: ${step.title}`);
|
|
248
|
+
if (step.verification_path) {
|
|
249
|
+
console.log(` ${chalk.dim(`Verify: ${step.verification_path}`)}`);
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
console.log('');
|
|
254
|
+
console.log(chalk.bold.yellow('⚡ NEXT MOVE:'));
|
|
255
|
+
if (data.steps.length > 0) {
|
|
256
|
+
const firstStep = data.steps[0];
|
|
257
|
+
console.log(` ${chalk.white(`> rigstate work start ${firstStep.id}`)} ${chalk.dim(`(Start: ${firstStep.title})`)}`);
|
|
258
|
+
}
|
|
259
|
+
console.log(chalk.dim('────────────────────────────────────────'));
|
|
260
|
+
console.log('');
|
|
261
|
+
|
|
262
|
+
// ── Persist genesis status to local manifest (enables offline checks) ──
|
|
263
|
+
try {
|
|
264
|
+
const { saveManifest } = await import('../utils/manifest.js');
|
|
265
|
+
await saveManifest({
|
|
266
|
+
genesis_complete: true,
|
|
267
|
+
genesis_template: data.template,
|
|
268
|
+
genesis_stack_key: data.stack_key,
|
|
269
|
+
genesis_initialized_at: new Date().toISOString()
|
|
270
|
+
});
|
|
271
|
+
} catch {
|
|
272
|
+
// Non-critical: local cache write failure doesn't break the flow
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return true;
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
} catch (err: any) {
|
|
279
|
+
spinner.stop();
|
|
280
|
+
|
|
281
|
+
// Handle axios error responses
|
|
282
|
+
if (err.response?.status === 409) {
|
|
283
|
+
console.log(chalk.green('✅ Genesis already complete.'));
|
|
284
|
+
console.log(chalk.dim(' Use --force to re-initialize.'));
|
|
285
|
+
return true;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (err.response?.status === 422) {
|
|
289
|
+
console.log('');
|
|
290
|
+
console.log(chalk.yellow('⚠️ Genesis pending: Onboarding not complete.'));
|
|
291
|
+
console.log(chalk.dim(' Finish the Frank conversation to define your tech stack.'));
|
|
292
|
+
console.log(chalk.dim(' Then run: ') + chalk.white('rigstate genesis'));
|
|
293
|
+
console.log('');
|
|
294
|
+
return false;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (err.code === 'ECONNREFUSED' || err.code === 'ENOTFOUND') {
|
|
298
|
+
console.log(chalk.dim(' (Genesis skipped: API unreachable)'));
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
console.error(chalk.red(`❌ Genesis error: ${err.response?.data?.error || err.message}`));
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
}
|
package/src/commands/init.ts
CHANGED
|
@@ -181,13 +181,12 @@ export function createInitCommand() {
|
|
|
181
181
|
setProjectId(projectId);
|
|
182
182
|
|
|
183
183
|
// Write local manifest
|
|
184
|
-
const
|
|
185
|
-
|
|
184
|
+
const { saveManifest } = await import('../utils/manifest.js');
|
|
185
|
+
await saveManifest({
|
|
186
186
|
project_id: projectId,
|
|
187
|
-
|
|
187
|
+
linked_at: new Date().toISOString(),
|
|
188
188
|
api_url: apiUrl
|
|
189
|
-
};
|
|
190
|
-
await fs.writeFile(manifestPath, JSON.stringify(manifestContent, null, 2), 'utf-8');
|
|
189
|
+
});
|
|
191
190
|
|
|
192
191
|
// Initialize git if needed
|
|
193
192
|
try {
|
package/src/commands/link.ts
CHANGED
|
@@ -74,33 +74,23 @@ export function createLinkCommand() {
|
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
const content: any = {
|
|
80
|
-
project_id: projectId,
|
|
81
|
-
linked_at: new Date().toISOString()
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
// Only store api_url locally if it's NOT the production default
|
|
85
|
-
const currentUrl = getApiUrl();
|
|
86
|
-
if (currentUrl !== 'https://app.rigstate.com') {
|
|
87
|
-
content.api_url = currentUrl;
|
|
88
|
-
}
|
|
89
|
-
|
|
77
|
+
const cwd = process.cwd();
|
|
90
78
|
try {
|
|
91
|
-
|
|
92
|
-
await
|
|
79
|
+
const { saveManifest } = await import('../utils/manifest.js');
|
|
80
|
+
const targetFile = await saveManifest({
|
|
81
|
+
project_id: projectId,
|
|
82
|
+
linked_at: new Date().toISOString(),
|
|
83
|
+
api_url: getApiUrl() !== 'https://app.rigstate.com' ? getApiUrl() : undefined
|
|
84
|
+
});
|
|
93
85
|
|
|
94
|
-
await fs.writeFile(manifestPath, JSON.stringify(content, null, 2), 'utf-8');
|
|
95
86
|
console.log(chalk.green(`✔ Linked to project ID: ${projectId}`));
|
|
96
|
-
console.log(chalk.dim(`Created local
|
|
87
|
+
console.log(chalk.dim(`Created local identity manifest at ${path.relative(cwd, targetFile)}`));
|
|
97
88
|
|
|
98
89
|
// === SMART AUTOMATION ===
|
|
99
90
|
console.log('');
|
|
100
91
|
console.log(chalk.bold('🤖 Rigstate Automation Detected'));
|
|
101
92
|
console.log('');
|
|
102
93
|
|
|
103
|
-
const { getApiKey: _getApiKey, getApiUrl: _getApiUrl } = await import('../utils/config.js');
|
|
104
94
|
const apiKey = getApiKey();
|
|
105
95
|
const apiUrl = getApiUrl();
|
|
106
96
|
|
|
@@ -120,12 +110,28 @@ export function createLinkCommand() {
|
|
|
120
110
|
await installHooks(process.cwd());
|
|
121
111
|
await hardenGitIgnore(process.cwd());
|
|
122
112
|
|
|
113
|
+
// 4. Genesis Protocol (Smart Detection)
|
|
114
|
+
console.log(chalk.blue('🏗️ Checking Genesis status...'));
|
|
115
|
+
const { checkGenesisStatus, triggerGenesis } = await import('./genesis.js');
|
|
116
|
+
const genesisStatus = await checkGenesisStatus(projectId, apiKey, apiUrl);
|
|
117
|
+
|
|
118
|
+
if (!genesisStatus.complete) {
|
|
119
|
+
// Try to trigger automatically — will fail gracefully if spec not ready
|
|
120
|
+
const triggered = await triggerGenesis(projectId, apiKey, apiUrl, false);
|
|
121
|
+
if (!triggered) {
|
|
122
|
+
console.log(chalk.dim(' 💡 Run "rigstate genesis" after completing onboarding with Frank.'));
|
|
123
|
+
}
|
|
124
|
+
} else {
|
|
125
|
+
console.log(chalk.green(` ✔ Genesis complete (${genesisStatus.stepCount} foundation steps ready)`));
|
|
126
|
+
}
|
|
127
|
+
|
|
123
128
|
console.log('');
|
|
124
129
|
console.log(chalk.bold.green('🚀 Link Complete! Your environment is ready.'));
|
|
125
130
|
|
|
126
|
-
//
|
|
131
|
+
// 5. Tactical Suggestion
|
|
127
132
|
const { suggestNextMove } = await import('./suggest.js');
|
|
128
133
|
await suggestNextMove(projectId, apiKey, apiUrl);
|
|
134
|
+
|
|
129
135
|
} else {
|
|
130
136
|
console.log('');
|
|
131
137
|
console.log(chalk.bold.green('🚀 Link Complete!'));
|
package/src/commands/plan.ts
CHANGED
|
@@ -43,9 +43,9 @@ export async function executePlan(taskId?: string) {
|
|
|
43
43
|
const tasks: any[] = response.data.data.roadmap || [];
|
|
44
44
|
|
|
45
45
|
const choices = tasks
|
|
46
|
-
.filter(t => ['ACTIVE', 'IN_PROGRESS', 'PENDING'].includes(t.status))
|
|
46
|
+
.filter(t => ['ACTIVE', 'IN_PROGRESS', 'PENDING', 'LOCKED'].includes(t.status))
|
|
47
47
|
.map(t => ({
|
|
48
|
-
name:
|
|
48
|
+
name: `${t.status === 'LOCKED' ? '🔒 ' : ''}T-${t.step_number}: ${t.title}${t.origin_id === 'GENESIS' ? chalk.dim(' [Foundation]') : ''}`,
|
|
49
49
|
value: t
|
|
50
50
|
}));
|
|
51
51
|
|
|
@@ -137,15 +137,32 @@ ${taskDescription}
|
|
|
137
137
|
// 4. Update Status (Optional - maybe set to IN_PROGRESS?)
|
|
138
138
|
// For now, let's keep it pure planning.
|
|
139
139
|
|
|
140
|
+
// 4. Trigger Bridge Task (Autonomous Bridge)
|
|
141
|
+
try {
|
|
142
|
+
spinner.start('📡 Signaling Frank to start drafting...');
|
|
143
|
+
await axios.post(`${apiUrl}/api/v1/agent/bridge`, {
|
|
144
|
+
project_id: projectId,
|
|
145
|
+
task_id: realId,
|
|
146
|
+
status: 'APPROVED',
|
|
147
|
+
proposal: `draft_plan:${taskId}`,
|
|
148
|
+
summary: `Requesting implementation plan for ${taskTitle}`
|
|
149
|
+
}, {
|
|
150
|
+
headers: { 'Authorization': `Bearer ${apiKey}` }
|
|
151
|
+
});
|
|
152
|
+
spinner.succeed('Signal sent to Agent Bridge.');
|
|
153
|
+
} catch (e) {
|
|
154
|
+
spinner.info(chalk.dim('Agent Bridge signal skipped (non-critical).'));
|
|
155
|
+
}
|
|
156
|
+
|
|
140
157
|
console.log('');
|
|
141
158
|
console.log(chalk.bold.blue('🚀 Planning Mode Activated'));
|
|
142
159
|
console.log(chalk.dim('────────────────────────────────────────'));
|
|
143
160
|
console.log(`1. Context loaded into: ${chalk.bold('.rigstate/CURRENT_CONTEXT.md')}`);
|
|
144
161
|
console.log(`2. Plan template ready: ${chalk.bold('IMPLEMENTATION_PLAN.md')}`);
|
|
145
162
|
console.log('');
|
|
146
|
-
console.log(chalk.
|
|
147
|
-
console.log(
|
|
148
|
-
console.log(
|
|
163
|
+
console.log(chalk.green('✨ FRANK IS ON IT!'));
|
|
164
|
+
console.log(chalk.dim(' He has received the bridge signal and will begin drafting shortly.'));
|
|
165
|
+
console.log(chalk.dim(' No further manual steps required once he wakes up.'));
|
|
149
166
|
console.log('');
|
|
150
167
|
|
|
151
168
|
} catch (e: any) {
|
package/src/commands/sync.ts
CHANGED
|
@@ -30,12 +30,9 @@ export function createSyncCommand() {
|
|
|
30
30
|
|
|
31
31
|
// Check local .rigstate manifest
|
|
32
32
|
if (!projectId) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const manifest = JSON.parse(manifestContent);
|
|
37
|
-
if (manifest.project_id) projectId = manifest.project_id;
|
|
38
|
-
} catch (e) { }
|
|
33
|
+
const { loadManifest } = await import('../utils/manifest.js');
|
|
34
|
+
const manifest = await loadManifest();
|
|
35
|
+
if (manifest?.project_id) projectId = manifest.project_id;
|
|
39
36
|
}
|
|
40
37
|
|
|
41
38
|
// Check global config
|
|
@@ -79,14 +76,12 @@ export function createSyncCommand() {
|
|
|
79
76
|
|
|
80
77
|
// 4b. Write Context Manifest (.rigstate) - CONTEXT GUARD
|
|
81
78
|
try {
|
|
82
|
-
const
|
|
83
|
-
|
|
79
|
+
const { saveManifest } = await import('../utils/manifest.js');
|
|
80
|
+
await saveManifest({
|
|
84
81
|
project_id: projectId,
|
|
85
|
-
|
|
86
|
-
last_synced: timestamp,
|
|
82
|
+
linked_at: timestamp, // Using timestamp as linked_at for consistency
|
|
87
83
|
api_url: apiUrl
|
|
88
|
-
};
|
|
89
|
-
await fs.writeFile(manifestPath, JSON.stringify(manifestContent, null, 2), 'utf-8');
|
|
84
|
+
});
|
|
90
85
|
} catch (e) {
|
|
91
86
|
// Fail silently
|
|
92
87
|
}
|
package/src/commands/watch.ts
CHANGED
|
@@ -42,13 +42,9 @@ export function createWatchCommand() {
|
|
|
42
42
|
|
|
43
43
|
projectId = getProjectId();
|
|
44
44
|
if (!projectId) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const content = await fs.readFile(manifestPath, 'utf-8');
|
|
49
|
-
const manifest = JSON.parse(content);
|
|
50
|
-
projectId = manifest.project_id;
|
|
51
|
-
} catch (e) { }
|
|
45
|
+
const { loadManifest } = await import('../utils/manifest.js');
|
|
46
|
+
const manifest = await loadManifest();
|
|
47
|
+
if (manifest?.project_id) projectId = manifest.project_id;
|
|
52
48
|
}
|
|
53
49
|
|
|
54
50
|
if (!projectId) {
|
package/src/index.ts
CHANGED
|
@@ -23,6 +23,7 @@ import { createReleaseCommand } from './commands/release.js';
|
|
|
23
23
|
import { createRoadmapCommand } from './commands/roadmap.js';
|
|
24
24
|
import { createCouncilCommand } from './commands/council.js';
|
|
25
25
|
import { createPlanCommand } from './commands/plan.js';
|
|
26
|
+
import { createGenesisCommand } from './commands/genesis.js';
|
|
26
27
|
import { checkVersion } from './utils/version.js';
|
|
27
28
|
import dotenv from 'dotenv';
|
|
28
29
|
|
|
@@ -63,6 +64,7 @@ program.addCommand(createReleaseCommand());
|
|
|
63
64
|
program.addCommand(createRoadmapCommand());
|
|
64
65
|
program.addCommand(createCouncilCommand());
|
|
65
66
|
program.addCommand(createPlanCommand());
|
|
67
|
+
program.addCommand(createGenesisCommand());
|
|
66
68
|
|
|
67
69
|
program.hook('preAction', async () => {
|
|
68
70
|
await checkVersion();
|
|
@@ -79,6 +81,12 @@ program.on('--help', () => {
|
|
|
79
81
|
console.log(chalk.cyan(' $ rigstate scan'));
|
|
80
82
|
console.log(chalk.dim(' Scan the current directory'));
|
|
81
83
|
console.log('');
|
|
84
|
+
console.log(chalk.cyan(' $ rigstate genesis'));
|
|
85
|
+
console.log(chalk.dim(' Initialize project foundation (auto-detects stack)'));
|
|
86
|
+
console.log('');
|
|
87
|
+
console.log(chalk.cyan(' $ rigstate genesis --status'));
|
|
88
|
+
console.log(chalk.dim(' Check genesis status without triggering'));
|
|
89
|
+
console.log('');
|
|
82
90
|
console.log(chalk.cyan(' $ rigstate scan ./src --project abc123'));
|
|
83
91
|
console.log(chalk.dim(' Scan a specific directory with project ID'));
|
|
84
92
|
console.log('');
|