@rigstate/cli 0.7.32 → 0.7.35

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rigstate/cli",
3
- "version": "0.7.32",
3
+ "version": "0.7.35",
4
4
  "description": "Rigstate CLI - Code audit, sync and supervision tool",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -50,4 +50,4 @@
50
50
  ],
51
51
  "author": "Rigstate",
52
52
  "license": "MIT"
53
- }
53
+ }
@@ -141,12 +141,9 @@ export function createEnvPullCommand() {
141
141
  projectId = getProjectId();
142
142
 
143
143
  if (!projectId) {
144
- try {
145
- const manifestPath = path.join(process.cwd(), '.rigstate');
146
- const content = await fs.readFile(manifestPath, 'utf-8');
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) {
@@ -30,12 +30,9 @@ export function createFocusCommand() {
30
30
 
31
31
  projectId = getProjectId();
32
32
  if (!projectId) {
33
- try {
34
- const manifestPath = path.join(process.cwd(), '.rigstate');
35
- const content = await fs.readFile(manifestPath, 'utf-8');
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) {
@@ -181,13 +181,12 @@ export function createInitCommand() {
181
181
  setProjectId(projectId);
182
182
 
183
183
  // Write local manifest
184
- const manifestPath = path.join(process.cwd(), '.rigstate');
185
- const manifestContent = {
184
+ const { saveManifest } = await import('../utils/manifest.js');
185
+ await saveManifest({
186
186
  project_id: projectId,
187
- last_linked: new Date().toISOString(),
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 {
@@ -74,33 +74,23 @@ export function createLinkCommand() {
74
74
  }
75
75
  }
76
76
 
77
- const manifestPath = path.join(process.cwd(), '.rigstate');
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
- // Ensure .rigstate dir exists
92
- await fs.mkdir(path.dirname(manifestPath), { recursive: true });
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 context manifest at .rigstate`));
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
 
@@ -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.yellow('👉 NEXT STEP:'));
147
- console.log(` Open ${chalk.bold('IMPLEMENTATION_PLAN.md')} in your IDE.`);
148
- console.log(` Tell Frank: ${chalk.italic('"Read the context and draft the plan."')}`);
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) {
@@ -3,8 +3,7 @@ import chalk from 'chalk';
3
3
  import ora from 'ora';
4
4
  import { getApiKey, getApiUrl } from '../utils/config.js';
5
5
  import axios from 'axios';
6
- import { createRequire } from 'module';
7
- const require = createRequire(import.meta.url);
6
+ import { CLI_VERSION } from '../utils/version.js';
8
7
 
9
8
  interface SyncResult {
10
9
  projectId: string;
@@ -14,7 +13,7 @@ interface SyncResult {
14
13
  }
15
14
 
16
15
  // Core Logic (Exported for re-use)
17
- export async function syncProjectRules(projectId: string, apiKey: string, apiUrl: string, dryRun = false): Promise<boolean> {
16
+ export async function syncProjectRules(projectId: string, apiKey: string, apiUrl: string, dryRun = false, version: string = CLI_VERSION): Promise<boolean> {
18
17
  const spinner = ora('🛡️ Frank Protocol: Initializing retroactive sync...').start();
19
18
  let success = true;
20
19
 
@@ -87,7 +86,7 @@ export async function syncProjectRules(projectId: string, apiKey: string, apiUrl
87
86
 
88
87
  const governanceBlock = `${START_MARKER}
89
88
  # 🛡️ Rigstate Governance (Do not edit this block manually)
90
- # The following rules are enforced by the Rigstate Daemon (v${require('../../package.json').version}).
89
+ # The following rules are enforced by the Rigstate Daemon (v${version}).
91
90
  # Failure to adhere to these rules will be flagged during the 'work' cycle.
92
91
 
93
92
  # YOU MUST ADHERE TO THESE PROACTIVE RULES:
@@ -30,12 +30,9 @@ export function createSyncCommand() {
30
30
 
31
31
  // Check local .rigstate manifest
32
32
  if (!projectId) {
33
- try {
34
- const manifestPath = path.join(process.cwd(), '.rigstate');
35
- const manifestContent = await fs.readFile(manifestPath, 'utf-8');
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 manifestPath = path.join(process.cwd(), '.rigstate');
83
- const manifestContent = {
79
+ const { saveManifest } = await import('../utils/manifest.js');
80
+ await saveManifest({
84
81
  project_id: projectId,
85
- project_name: project,
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
  }
@@ -42,13 +42,9 @@ export function createWatchCommand() {
42
42
 
43
43
  projectId = getProjectId();
44
44
  if (!projectId) {
45
- // Try to read from local manifest
46
- try {
47
- const manifestPath = path.join(process.cwd(), '.rigstate');
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) {
@@ -1,6 +1,8 @@
1
1
  import Conf from 'conf';
2
2
  import axios from 'axios';
3
3
  import chalk from 'chalk';
4
+ import fs from 'fs';
5
+ import path from 'path';
4
6
 
5
7
  interface RigstateConfig {
6
8
  apiKey?: string;
@@ -20,6 +22,29 @@ const config = new Conf<RigstateConfig>({
20
22
  * @throws {Error} If no API key is found (user not logged in)
21
23
  */
22
24
  export function getApiKey(): string {
25
+ // 1. Check local manifest first (Folder Affinity)
26
+ try {
27
+ const cwd = process.cwd();
28
+ const manifestPaths = [
29
+ path.join(cwd, '.rigstate', 'identity.json'),
30
+ path.join(cwd, '.rigstate')
31
+ ];
32
+
33
+ for (const manifestPath of manifestPaths) {
34
+ if (fs.existsSync(manifestPath) && fs.statSync(manifestPath).isFile()) {
35
+ const content = fs.readFileSync(manifestPath, 'utf-8');
36
+ const manifest = JSON.parse(content);
37
+ if (manifest.api_key) return manifest.api_key;
38
+ }
39
+ }
40
+ } catch (e) { /* Fallback */ }
41
+
42
+ // 2. Check environment variable
43
+ if (process.env.RIGSTATE_API_KEY) {
44
+ return process.env.RIGSTATE_API_KEY;
45
+ }
46
+
47
+ // 3. Fall back to global config
23
48
  const apiKey = config.get('apiKey');
24
49
  if (!apiKey) {
25
50
  throw new Error(
@@ -40,7 +65,40 @@ export function setApiKey(key: string): void {
40
65
  * Get the default project ID (if set)
41
66
  */
42
67
  export function getProjectId(): string | undefined {
43
- return config.get('projectId');
68
+ // 1. Check local manifest first (Folder Affinity)
69
+ try {
70
+ const cwd = process.cwd();
71
+ const manifestPaths = [
72
+ path.join(cwd, '.rigstate', 'identity.json'),
73
+ path.join(cwd, '.rigstate')
74
+ ];
75
+
76
+ for (const manifestPath of manifestPaths) {
77
+ if (fs.existsSync(manifestPath) && fs.statSync(manifestPath).isFile()) {
78
+ const content = fs.readFileSync(manifestPath, 'utf-8');
79
+ const manifest = JSON.parse(content);
80
+ if (manifest.project_id) {
81
+ console.log(chalk.dim(` [Auth] Context: Project ID ${manifest.project_id.substring(0, 8)}... (from ${path.basename(manifestPath)})`));
82
+ return manifest.project_id;
83
+ }
84
+ }
85
+ }
86
+ } catch (e: any) {
87
+ console.log(chalk.red(` [Error] Failed to read context: ${e.message}`));
88
+ }
89
+
90
+ // 2. Check environment variable
91
+ if (process.env.RIGSTATE_PROJECT_ID) {
92
+ console.log(chalk.dim(` [Auth] Context: Project ID ${process.env.RIGSTATE_PROJECT_ID.substring(0, 8)}... (from ENV)`));
93
+ return process.env.RIGSTATE_PROJECT_ID;
94
+ }
95
+
96
+ // 3. Fall back to global config
97
+ const globalId = config.get('projectId');
98
+ if (globalId) {
99
+ console.log(chalk.dim(` [Auth] Context: Project ID ${globalId.substring(0, 8)}... (from GLOBAL CONFIG)`));
100
+ }
101
+ return globalId;
44
102
  }
45
103
 
46
104
  /**
@@ -55,16 +113,33 @@ export function setProjectId(projectId: string): void {
55
113
  * Priority: Environment variable > Stored config > Production default
56
114
  */
57
115
  export function getApiUrl(): string {
58
- // 1. Check environment variable first
116
+ // 1. Check local manifest first
117
+ try {
118
+ const cwd = process.cwd();
119
+ const manifestPaths = [
120
+ path.join(cwd, '.rigstate', 'identity.json'),
121
+ path.join(cwd, '.rigstate')
122
+ ];
123
+
124
+ for (const manifestPath of manifestPaths) {
125
+ if (fs.existsSync(manifestPath) && fs.statSync(manifestPath).isFile()) {
126
+ const content = fs.readFileSync(manifestPath, 'utf-8');
127
+ const manifest = JSON.parse(content);
128
+ if (manifest.api_url) return manifest.api_url;
129
+ }
130
+ }
131
+ } catch (e) { /* Fallback */ }
132
+
133
+ // 2. Check environment variable next
59
134
  if (process.env.RIGSTATE_API_URL) {
60
135
  return process.env.RIGSTATE_API_URL;
61
136
  }
62
- // 2. Check stored config
137
+ // 3. Check stored config
63
138
  const storedUrl = config.get('apiUrl');
64
139
  if (storedUrl) {
65
140
  return storedUrl;
66
141
  }
67
- // 3. Default to production
142
+ // 4. Default to production
68
143
  return 'https://app.rigstate.com';
69
144
  }
70
145
 
@@ -1,18 +1,69 @@
1
1
  import fs from 'fs/promises';
2
+ import fsSync from 'fs';
2
3
  import path from 'path';
3
4
 
4
5
  export interface RigstateManifest {
5
6
  project_id: string;
6
7
  api_url?: string;
7
8
  linked_at?: string;
9
+ api_key?: string;
8
10
  }
9
11
 
10
12
  export async function loadManifest(): Promise<RigstateManifest | null> {
13
+ const cwd = process.cwd();
14
+ const manifestPaths = [
15
+ path.join(cwd, '.rigstate', 'identity.json'),
16
+ path.join(cwd, '.rigstate')
17
+ ];
18
+
19
+ for (const p of manifestPaths) {
20
+ try {
21
+ if (fsSync.existsSync(p) && fsSync.statSync(p).isFile()) {
22
+ const content = await fs.readFile(p, 'utf-8');
23
+ const data = JSON.parse(content);
24
+
25
+ // Handle both flat manifest and identity.json schema
26
+ return {
27
+ project_id: data.project?.id || data.project_id,
28
+ api_url: data.api_url,
29
+ linked_at: data.linked_at || data.project?.created_at,
30
+ api_key: data.api_key
31
+ };
32
+ }
33
+ } catch (e) {
34
+ continue;
35
+ }
36
+ }
37
+ return null;
38
+ }
39
+
40
+ /**
41
+ * Saves project context to the local manifest.
42
+ * Prioritizes .rigstate/identity.json if the directory exists.
43
+ */
44
+ export async function saveManifest(data: Partial<RigstateManifest>): Promise<string> {
45
+ const cwd = process.cwd();
46
+ const rigstatePath = path.join(cwd, '.rigstate');
47
+ let targetFile = rigstatePath;
48
+
11
49
  try {
12
- const manifestPath = path.join(process.cwd(), '.rigstate');
13
- const content = await fs.readFile(manifestPath, 'utf-8');
14
- return JSON.parse(content);
15
- } catch {
16
- return null;
50
+ const stats = await fs.stat(rigstatePath);
51
+ if (stats.isDirectory()) {
52
+ targetFile = path.join(rigstatePath, 'identity.json');
53
+ }
54
+ } catch (e) {
55
+ // Doesn't exist, will be created as file/dir below
17
56
  }
57
+
58
+ // Load existing to merge
59
+ const existing = await loadManifest() || {} as RigstateManifest;
60
+ const merged = { ...existing, ...data };
61
+
62
+ // If we need to create a directory for identity.json
63
+ if (targetFile.endsWith('identity.json')) {
64
+ await fs.mkdir(rigstatePath, { recursive: true });
65
+ }
66
+
67
+ await fs.writeFile(targetFile, JSON.stringify(merged, null, 2), 'utf-8');
68
+ return targetFile;
18
69
  }
@@ -1 +1,6 @@
1
- export async function checkVersion() {}
1
+ // Single source of truth for version to avoid require/import issues with package.json in ESM/TS
2
+ export const CLI_VERSION = '0.7.34';
3
+
4
+ export async function checkVersion() {
5
+ // Placeholder for future update checks
6
+ }