@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.
@@ -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,75 @@
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;
10
+ // Genesis Protocol status (cached locally to avoid API calls)
11
+ genesis_complete?: boolean;
12
+ genesis_template?: string;
13
+ genesis_stack_key?: string;
14
+ genesis_initialized_at?: string;
8
15
  }
9
16
 
17
+
10
18
  export async function loadManifest(): Promise<RigstateManifest | null> {
19
+ const cwd = process.cwd();
20
+ const manifestPaths = [
21
+ path.join(cwd, '.rigstate', 'identity.json'),
22
+ path.join(cwd, '.rigstate')
23
+ ];
24
+
25
+ for (const p of manifestPaths) {
26
+ try {
27
+ if (fsSync.existsSync(p) && fsSync.statSync(p).isFile()) {
28
+ const content = await fs.readFile(p, 'utf-8');
29
+ const data = JSON.parse(content);
30
+
31
+ // Handle both flat manifest and identity.json schema
32
+ return {
33
+ project_id: data.project?.id || data.project_id,
34
+ api_url: data.api_url,
35
+ linked_at: data.linked_at || data.project?.created_at,
36
+ api_key: data.api_key
37
+ };
38
+ }
39
+ } catch (e) {
40
+ continue;
41
+ }
42
+ }
43
+ return null;
44
+ }
45
+
46
+ /**
47
+ * Saves project context to the local manifest.
48
+ * Prioritizes .rigstate/identity.json if the directory exists.
49
+ */
50
+ export async function saveManifest(data: Partial<RigstateManifest>): Promise<string> {
51
+ const cwd = process.cwd();
52
+ const rigstatePath = path.join(cwd, '.rigstate');
53
+ let targetFile = rigstatePath;
54
+
11
55
  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;
56
+ const stats = await fs.stat(rigstatePath);
57
+ if (stats.isDirectory()) {
58
+ targetFile = path.join(rigstatePath, 'identity.json');
59
+ }
60
+ } catch (e) {
61
+ // Doesn't exist, will be created as file/dir below
17
62
  }
63
+
64
+ // Load existing to merge
65
+ const existing = await loadManifest() || {} as RigstateManifest;
66
+ const merged = { ...existing, ...data };
67
+
68
+ // If we need to create a directory for identity.json
69
+ if (targetFile.endsWith('identity.json')) {
70
+ await fs.mkdir(rigstatePath, { recursive: true });
71
+ }
72
+
73
+ await fs.writeFile(targetFile, JSON.stringify(merged, null, 2), 'utf-8');
74
+ return targetFile;
18
75
  }