fraim 2.0.129 → 2.0.130
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/src/ai-hub/catalog.js +7 -4
- package/dist/src/cli/commands/init-project.js +55 -121
- package/dist/src/cli/commands/setup.js +68 -43
- package/dist/src/cli/commands/workspace-config.js +31 -0
- package/dist/src/cli/fraim.js +2 -0
- package/dist/src/cli/setup/ide-global-integration.js +19 -0
- package/dist/src/cli/setup/user-level-sync.js +5 -0
- package/dist/src/cli/utils/project-bootstrap.js +3 -3
- package/dist/src/core/fraim-config-contract.js +145 -0
- package/dist/src/core/fraim-config-schema.generated.js +296 -0
- package/dist/src/core/utils/setup-preferences.js +41 -0
- package/dist/src/first-run/server.js +59 -4
- package/dist/src/first-run/session-service.js +255 -364
- package/dist/src/first-run/types.js +10 -21
- package/dist/src/local-mcp-server/stdio-server.js +28 -29
- package/dist/src/local-mcp-server/usage-collector.js +3 -0
- package/index.js +1 -1
- package/package.json +7 -5
- package/public/ai-hub/script.js +187 -1
- package/public/first-run/error-frame.js +100 -100
- package/public/first-run/index.html +5 -6
- package/public/first-run/script.js +275 -238
- package/public/first-run/styles.css +603 -395
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Generated from src/core/types.ts.
|
|
4
|
+
* This file exists so runtime validation and config token checks read the same persisted config shape the agent sees.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.SUPPORTED_FRAIM_CONFIG_PATHS = exports.FRAIM_CONFIG_SCHEMA = void 0;
|
|
8
|
+
exports.FRAIM_CONFIG_SCHEMA = {
|
|
9
|
+
"kind": "object",
|
|
10
|
+
"properties": {
|
|
11
|
+
"version": {
|
|
12
|
+
"kind": "string",
|
|
13
|
+
"required": true
|
|
14
|
+
},
|
|
15
|
+
"project": {
|
|
16
|
+
"kind": "object",
|
|
17
|
+
"properties": {
|
|
18
|
+
"name": {
|
|
19
|
+
"kind": "string",
|
|
20
|
+
"required": true
|
|
21
|
+
},
|
|
22
|
+
"industry": {
|
|
23
|
+
"kind": "string"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"required": true
|
|
27
|
+
},
|
|
28
|
+
"repository": {
|
|
29
|
+
"kind": "object",
|
|
30
|
+
"properties": {
|
|
31
|
+
"provider": {
|
|
32
|
+
"kind": "enum",
|
|
33
|
+
"values": [
|
|
34
|
+
"github",
|
|
35
|
+
"ado",
|
|
36
|
+
"gitlab"
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
"owner": {
|
|
40
|
+
"kind": "string"
|
|
41
|
+
},
|
|
42
|
+
"name": {
|
|
43
|
+
"kind": "string"
|
|
44
|
+
},
|
|
45
|
+
"organization": {
|
|
46
|
+
"kind": "string"
|
|
47
|
+
},
|
|
48
|
+
"project": {
|
|
49
|
+
"kind": "string"
|
|
50
|
+
},
|
|
51
|
+
"namespace": {
|
|
52
|
+
"kind": "string"
|
|
53
|
+
},
|
|
54
|
+
"projectPath": {
|
|
55
|
+
"kind": "string"
|
|
56
|
+
},
|
|
57
|
+
"url": {
|
|
58
|
+
"kind": "string"
|
|
59
|
+
},
|
|
60
|
+
"defaultBranch": {
|
|
61
|
+
"kind": "string"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"issueTracking": {
|
|
66
|
+
"kind": "object",
|
|
67
|
+
"properties": {
|
|
68
|
+
"provider": {
|
|
69
|
+
"kind": "enum",
|
|
70
|
+
"values": [
|
|
71
|
+
"jira",
|
|
72
|
+
"github",
|
|
73
|
+
"ado",
|
|
74
|
+
"linear",
|
|
75
|
+
"gitlab"
|
|
76
|
+
],
|
|
77
|
+
"required": true
|
|
78
|
+
},
|
|
79
|
+
"owner": {
|
|
80
|
+
"kind": "string"
|
|
81
|
+
},
|
|
82
|
+
"name": {
|
|
83
|
+
"kind": "string"
|
|
84
|
+
},
|
|
85
|
+
"organization": {
|
|
86
|
+
"kind": "string"
|
|
87
|
+
},
|
|
88
|
+
"project": {
|
|
89
|
+
"kind": "string"
|
|
90
|
+
},
|
|
91
|
+
"namespace": {
|
|
92
|
+
"kind": "string"
|
|
93
|
+
},
|
|
94
|
+
"projectPath": {
|
|
95
|
+
"kind": "string"
|
|
96
|
+
},
|
|
97
|
+
"baseUrl": {
|
|
98
|
+
"kind": "string"
|
|
99
|
+
},
|
|
100
|
+
"projectKey": {
|
|
101
|
+
"kind": "string"
|
|
102
|
+
},
|
|
103
|
+
"branchPattern": {
|
|
104
|
+
"kind": "string"
|
|
105
|
+
},
|
|
106
|
+
"apiToken": {
|
|
107
|
+
"kind": "string"
|
|
108
|
+
},
|
|
109
|
+
"email": {
|
|
110
|
+
"kind": "string"
|
|
111
|
+
},
|
|
112
|
+
"apiKey": {
|
|
113
|
+
"kind": "string"
|
|
114
|
+
},
|
|
115
|
+
"teamId": {
|
|
116
|
+
"kind": "string"
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
"mode": {
|
|
121
|
+
"kind": "enum",
|
|
122
|
+
"values": [
|
|
123
|
+
"conversational",
|
|
124
|
+
"integrated",
|
|
125
|
+
"split"
|
|
126
|
+
]
|
|
127
|
+
},
|
|
128
|
+
"customizations": {
|
|
129
|
+
"kind": "object",
|
|
130
|
+
"properties": {
|
|
131
|
+
"architectureDoc": {
|
|
132
|
+
"kind": "string"
|
|
133
|
+
},
|
|
134
|
+
"designSystem": {
|
|
135
|
+
"kind": "object",
|
|
136
|
+
"properties": {
|
|
137
|
+
"path": {
|
|
138
|
+
"kind": "string"
|
|
139
|
+
},
|
|
140
|
+
"brand": {
|
|
141
|
+
"kind": "string"
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
"validation": {
|
|
146
|
+
"kind": "object",
|
|
147
|
+
"properties": {
|
|
148
|
+
"buildCommand": {
|
|
149
|
+
"kind": "string"
|
|
150
|
+
},
|
|
151
|
+
"testSuiteCommand": {
|
|
152
|
+
"kind": "string"
|
|
153
|
+
},
|
|
154
|
+
"smokeTestCommand": {
|
|
155
|
+
"kind": "string"
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
"postCleanupHook": {
|
|
160
|
+
"kind": "string"
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
"remoteUrl": {
|
|
165
|
+
"kind": "string"
|
|
166
|
+
},
|
|
167
|
+
"apiKey": {
|
|
168
|
+
"kind": "string"
|
|
169
|
+
},
|
|
170
|
+
"competitors": {
|
|
171
|
+
"kind": "record",
|
|
172
|
+
"value": {
|
|
173
|
+
"kind": "string"
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
"compliance": {
|
|
177
|
+
"kind": "object",
|
|
178
|
+
"properties": {
|
|
179
|
+
"regulations": {
|
|
180
|
+
"kind": "array",
|
|
181
|
+
"element": {
|
|
182
|
+
"kind": "string"
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
"compliance_specifications": {
|
|
186
|
+
"kind": "record",
|
|
187
|
+
"value": {
|
|
188
|
+
"kind": "string"
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
"learning": {
|
|
194
|
+
"kind": "object",
|
|
195
|
+
"properties": {
|
|
196
|
+
"lastSynthesisDate": {
|
|
197
|
+
"kind": "string"
|
|
198
|
+
},
|
|
199
|
+
"scoreThreshold": {
|
|
200
|
+
"kind": "number"
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
"customer-communication": {
|
|
205
|
+
"kind": "object",
|
|
206
|
+
"properties": {
|
|
207
|
+
"productName": {
|
|
208
|
+
"kind": "string",
|
|
209
|
+
"required": true
|
|
210
|
+
},
|
|
211
|
+
"productUrl": {
|
|
212
|
+
"kind": "string",
|
|
213
|
+
"required": true
|
|
214
|
+
},
|
|
215
|
+
"senderDisplayName": {
|
|
216
|
+
"kind": "string",
|
|
217
|
+
"required": true
|
|
218
|
+
},
|
|
219
|
+
"senderEmail": {
|
|
220
|
+
"kind": "string",
|
|
221
|
+
"required": true
|
|
222
|
+
},
|
|
223
|
+
"senderReplyTo": {
|
|
224
|
+
"kind": "string"
|
|
225
|
+
},
|
|
226
|
+
"newsletterAudienceProvider": {
|
|
227
|
+
"kind": "string"
|
|
228
|
+
},
|
|
229
|
+
"deliveryProvider": {
|
|
230
|
+
"kind": "string",
|
|
231
|
+
"required": true
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
"required": true
|
|
237
|
+
};
|
|
238
|
+
exports.SUPPORTED_FRAIM_CONFIG_PATHS = [
|
|
239
|
+
"version",
|
|
240
|
+
"project",
|
|
241
|
+
"project.name",
|
|
242
|
+
"project.industry",
|
|
243
|
+
"repository",
|
|
244
|
+
"repository.provider",
|
|
245
|
+
"repository.owner",
|
|
246
|
+
"repository.name",
|
|
247
|
+
"repository.organization",
|
|
248
|
+
"repository.project",
|
|
249
|
+
"repository.namespace",
|
|
250
|
+
"repository.projectPath",
|
|
251
|
+
"repository.url",
|
|
252
|
+
"repository.defaultBranch",
|
|
253
|
+
"issueTracking",
|
|
254
|
+
"issueTracking.provider",
|
|
255
|
+
"issueTracking.owner",
|
|
256
|
+
"issueTracking.name",
|
|
257
|
+
"issueTracking.organization",
|
|
258
|
+
"issueTracking.project",
|
|
259
|
+
"issueTracking.namespace",
|
|
260
|
+
"issueTracking.projectPath",
|
|
261
|
+
"issueTracking.baseUrl",
|
|
262
|
+
"issueTracking.projectKey",
|
|
263
|
+
"issueTracking.branchPattern",
|
|
264
|
+
"issueTracking.apiToken",
|
|
265
|
+
"issueTracking.email",
|
|
266
|
+
"issueTracking.apiKey",
|
|
267
|
+
"issueTracking.teamId",
|
|
268
|
+
"mode",
|
|
269
|
+
"customizations",
|
|
270
|
+
"customizations.architectureDoc",
|
|
271
|
+
"customizations.designSystem",
|
|
272
|
+
"customizations.designSystem.path",
|
|
273
|
+
"customizations.designSystem.brand",
|
|
274
|
+
"customizations.validation",
|
|
275
|
+
"customizations.validation.buildCommand",
|
|
276
|
+
"customizations.validation.testSuiteCommand",
|
|
277
|
+
"customizations.validation.smokeTestCommand",
|
|
278
|
+
"customizations.postCleanupHook",
|
|
279
|
+
"remoteUrl",
|
|
280
|
+
"apiKey",
|
|
281
|
+
"competitors",
|
|
282
|
+
"compliance",
|
|
283
|
+
"compliance.regulations",
|
|
284
|
+
"compliance.compliance_specifications",
|
|
285
|
+
"learning",
|
|
286
|
+
"learning.lastSynthesisDate",
|
|
287
|
+
"learning.scoreThreshold",
|
|
288
|
+
"customer-communication",
|
|
289
|
+
"customer-communication.productName",
|
|
290
|
+
"customer-communication.productUrl",
|
|
291
|
+
"customer-communication.senderDisplayName",
|
|
292
|
+
"customer-communication.senderEmail",
|
|
293
|
+
"customer-communication.senderReplyTo",
|
|
294
|
+
"customer-communication.newsletterAudienceProvider",
|
|
295
|
+
"customer-communication.deliveryProvider"
|
|
296
|
+
];
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.writeSetupHandoffChoice = writeSetupHandoffChoice;
|
|
7
|
+
exports.readSetupHandoffChoice = readSetupHandoffChoice;
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const project_fraim_paths_1 = require("./project-fraim-paths");
|
|
11
|
+
const PREFS_FILE = 'preferences.json';
|
|
12
|
+
function getPrefsPath() {
|
|
13
|
+
return path_1.default.join((0, project_fraim_paths_1.getUserFraimDirPath)(), PREFS_FILE);
|
|
14
|
+
}
|
|
15
|
+
function writeSetupHandoffChoice(choice) {
|
|
16
|
+
const dir = (0, project_fraim_paths_1.getUserFraimDirPath)();
|
|
17
|
+
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
18
|
+
const filePath = getPrefsPath();
|
|
19
|
+
let existing = {};
|
|
20
|
+
try {
|
|
21
|
+
existing = JSON.parse(fs_1.default.readFileSync(filePath, 'utf8'));
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// file doesn't exist or is invalid JSON — start fresh
|
|
25
|
+
}
|
|
26
|
+
existing.setupHandoffChoice = choice;
|
|
27
|
+
fs_1.default.writeFileSync(filePath, JSON.stringify(existing, null, 2));
|
|
28
|
+
}
|
|
29
|
+
function readSetupHandoffChoice() {
|
|
30
|
+
try {
|
|
31
|
+
const raw = fs_1.default.readFileSync(getPrefsPath(), 'utf8');
|
|
32
|
+
const data = JSON.parse(raw);
|
|
33
|
+
if (data.setupHandoffChoice === 'ide' || data.setupHandoffChoice === 'hub') {
|
|
34
|
+
return data.setupHandoffChoice;
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -1,4 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
37
|
};
|
|
@@ -9,6 +42,7 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
9
42
|
const path_1 = __importDefault(require("path"));
|
|
10
43
|
const child_process_1 = require("child_process");
|
|
11
44
|
const session_service_1 = require("./session-service");
|
|
45
|
+
const setup_preferences_1 = require("../core/utils/setup-preferences");
|
|
12
46
|
function resolveFirstRunPublicDir() {
|
|
13
47
|
const candidates = [
|
|
14
48
|
path_1.default.resolve(process.cwd(), 'public/first-run'),
|
|
@@ -29,7 +63,7 @@ function resolveFirstRunPublicDir() {
|
|
|
29
63
|
* Implementation notes:
|
|
30
64
|
* - Async (`spawn`, not `spawnSync`). The folder dialog blocks until the
|
|
31
65
|
* user dismisses it, which can be many seconds. With `spawnSync` the
|
|
32
|
-
* entire Node event loop freezes during that time
|
|
66
|
+
* entire Node event loop freezes during that time - every other HTTP
|
|
33
67
|
* request to the FRE server gets `ERR_ABORTED`, and the FRE looks dead.
|
|
34
68
|
* - Windows: PowerShell needs `-STA` (Single-Threaded Apartment) for
|
|
35
69
|
* `System.Windows.Forms.FolderBrowserDialog` to work. We also create a
|
|
@@ -39,6 +73,7 @@ function resolveFirstRunPublicDir() {
|
|
|
39
73
|
* broken).
|
|
40
74
|
*/
|
|
41
75
|
function pickProjectPath() {
|
|
76
|
+
// Return contract: Promise<string | null>
|
|
42
77
|
if (process.platform === 'win32') {
|
|
43
78
|
const script = [
|
|
44
79
|
'Add-Type -AssemblyName System.Windows.Forms',
|
|
@@ -171,7 +206,7 @@ class FirstRunServer {
|
|
|
171
206
|
this.app.post('/api/first-run/finish', (_req, res) => {
|
|
172
207
|
// Note: /finish writes the next-prompt artifact but does NOT trigger
|
|
173
208
|
// process shutdown. In v1 the Hub server is started in-process by
|
|
174
|
-
// /open-hub
|
|
209
|
+
// /open-hub - if we resolved the finishPromise here, runFirstRun
|
|
175
210
|
// would call server.stop() and the parent process would exit,
|
|
176
211
|
// taking the just-started Hub down with it. The Hub handoff has
|
|
177
212
|
// to keep the parent alive. The CLI exits when the user Ctrl+Cs
|
|
@@ -179,7 +214,27 @@ class FirstRunServer {
|
|
|
179
214
|
const result = this.sessionService.finish();
|
|
180
215
|
return res.json(result);
|
|
181
216
|
});
|
|
182
|
-
|
|
217
|
+
this.app.get('/api/first-run/ide-commands', async (_req, res) => {
|
|
218
|
+
try {
|
|
219
|
+
const { detectInstalledIDEs } = await Promise.resolve().then(() => __importStar(require('../cli/setup/ide-detector')));
|
|
220
|
+
const { describeOnboardingInvocationSurfaces } = await Promise.resolve().then(() => __importStar(require('../cli/setup/ide-global-integration')));
|
|
221
|
+
const configuredIDEs = detectInstalledIDEs();
|
|
222
|
+
const commands = describeOnboardingInvocationSurfaces(configuredIDEs);
|
|
223
|
+
return res.json({ commands });
|
|
224
|
+
}
|
|
225
|
+
catch (error) {
|
|
226
|
+
return res.status(500).json({ error: error instanceof Error ? error.message : 'Could not load IDE commands.' });
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
this.app.post('/api/first-run/set-preference', (req, res) => {
|
|
230
|
+
const { choice } = req.body || {};
|
|
231
|
+
if (choice !== 'ide' && choice !== 'hub') {
|
|
232
|
+
return res.status(400).json({ error: 'choice must be "ide" or "hub"' });
|
|
233
|
+
}
|
|
234
|
+
(0, setup_preferences_1.writeSetupHandoffChoice)(choice);
|
|
235
|
+
return res.json({ ok: true });
|
|
236
|
+
});
|
|
237
|
+
// Hub-launch helper - starts an AiHubServer for the chosen project and
|
|
183
238
|
// opens the user's browser. v2 (#355) replaces the in-process spawn with
|
|
184
239
|
// a durable launcher binary that survives independently.
|
|
185
240
|
this.app.post('/api/first-run/open-hub', async (_req, res) => {
|
|
@@ -187,7 +242,7 @@ class FirstRunServer {
|
|
|
187
242
|
const result = await this.sessionService.openHub();
|
|
188
243
|
// Write the next-prompt artifact as a side effect of opening the
|
|
189
244
|
// Hub so the client doesn't need a separate /finish call. We
|
|
190
|
-
// intentionally do NOT resolve the finishPromise
|
|
245
|
+
// intentionally do NOT resolve the finishPromise - see /finish
|
|
191
246
|
// handler comment above.
|
|
192
247
|
if (result.ok) {
|
|
193
248
|
this.sessionService.finish();
|