fraim-framework 2.0.146 → 2.0.147
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/hosts.js +36 -18
- package/package.json +1 -1
- package/public/ai-hub/index.html +67 -44
- package/public/ai-hub/script.js +347 -110
- package/public/ai-hub/styles.css +561 -264
- package/public/first-run/index.html +1 -0
- package/public/first-run/script.js +30 -18
- package/public/first-run/styles.css +73 -49
package/dist/src/ai-hub/hosts.js
CHANGED
|
@@ -253,22 +253,40 @@ function detectEmployees() {
|
|
|
253
253
|
};
|
|
254
254
|
});
|
|
255
255
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
function transformGeminiMessage(message) {
|
|
262
|
-
const match = message.match(/^[/$]fraim\s+(\S+)\n?([\s\S]*)$/);
|
|
256
|
+
function parseFraimInvocation(message) {
|
|
257
|
+
const trimmed = message.trim();
|
|
258
|
+
if (!trimmed)
|
|
259
|
+
return null;
|
|
260
|
+
const match = trimmed.match(/^[/$]fraim(?:\s+(\S+))?\s*([\s\S]*)$/);
|
|
263
261
|
if (!match)
|
|
262
|
+
return null;
|
|
263
|
+
return {
|
|
264
|
+
jobId: match[1] || null,
|
|
265
|
+
remainder: (match[2] || '').trim(),
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
// Rewrite UI-facing /fraim or $fraim invocations into direct MCP tool
|
|
269
|
+
// instructions for headless hosts. The Hub still shows the familiar
|
|
270
|
+
// invocation in the manager timeline, but the actual CLI child process
|
|
271
|
+
// receives an explicit instruction that works in non-interactive mode.
|
|
272
|
+
function transformHeadlessFraimMessage(message, kind) {
|
|
273
|
+
const parsed = parseFraimInvocation(message);
|
|
274
|
+
if (!parsed)
|
|
275
|
+
return message;
|
|
276
|
+
if (kind === 'continue') {
|
|
277
|
+
if (parsed.remainder) {
|
|
278
|
+
return `Continue the active FRAIM job with this manager coaching:\n\n${parsed.remainder}`;
|
|
279
|
+
}
|
|
280
|
+
return 'Continue the active FRAIM job using the current session context.';
|
|
281
|
+
}
|
|
282
|
+
if (!parsed.jobId)
|
|
264
283
|
return message;
|
|
265
|
-
const jobId = match[1];
|
|
266
|
-
const instructions = match[2].trim();
|
|
267
284
|
const parts = [
|
|
268
|
-
`Call the get_fraim_job MCP tool with job "${jobId}" to get the full job instructions, then follow them exactly.`,
|
|
285
|
+
`Call the get_fraim_job MCP tool with job "${parsed.jobId}" to get the full job instructions, then follow them exactly.`,
|
|
269
286
|
];
|
|
270
|
-
if (
|
|
271
|
-
parts.push(`\n\nUser instructions: ${
|
|
287
|
+
if (parsed.remainder) {
|
|
288
|
+
parts.push(`\n\nUser instructions: ${parsed.remainder}`);
|
|
289
|
+
}
|
|
272
290
|
return parts.join('');
|
|
273
291
|
}
|
|
274
292
|
// If ~/.gemini/settings.json has a wrong/test FRAIM_API_KEY, patch it with the
|
|
@@ -301,7 +319,7 @@ function buildStartPlan(hostId, message) {
|
|
|
301
319
|
return {
|
|
302
320
|
command: executableName('codex'),
|
|
303
321
|
args: ['exec', '--json', '--skip-git-repo-check', '--dangerously-bypass-approvals-and-sandbox'],
|
|
304
|
-
stdin: message,
|
|
322
|
+
stdin: transformHeadlessFraimMessage(message, 'start'),
|
|
305
323
|
};
|
|
306
324
|
}
|
|
307
325
|
if (hostId === 'gemini') {
|
|
@@ -309,13 +327,13 @@ function buildStartPlan(hostId, message) {
|
|
|
309
327
|
return {
|
|
310
328
|
command: executableName('gemini'),
|
|
311
329
|
args: ['--yolo', '--skip-trust'],
|
|
312
|
-
stdin:
|
|
330
|
+
stdin: transformHeadlessFraimMessage(message, 'start'),
|
|
313
331
|
};
|
|
314
332
|
}
|
|
315
333
|
return {
|
|
316
334
|
command: executableName('claude'),
|
|
317
335
|
args: ['-p', '--verbose', '--output-format', 'stream-json', '--dangerously-skip-permissions'],
|
|
318
|
-
stdin: message,
|
|
336
|
+
stdin: transformHeadlessFraimMessage(message, 'start'),
|
|
319
337
|
};
|
|
320
338
|
}
|
|
321
339
|
function buildContinuePlan(hostId, sessionId, message) {
|
|
@@ -323,7 +341,7 @@ function buildContinuePlan(hostId, sessionId, message) {
|
|
|
323
341
|
return {
|
|
324
342
|
command: executableName('codex'),
|
|
325
343
|
args: ['exec', 'resume', '--json', '--skip-git-repo-check', '--dangerously-bypass-approvals-and-sandbox', sessionId],
|
|
326
|
-
stdin: message,
|
|
344
|
+
stdin: transformHeadlessFraimMessage(message, 'continue'),
|
|
327
345
|
};
|
|
328
346
|
}
|
|
329
347
|
if (hostId === 'gemini') {
|
|
@@ -332,13 +350,13 @@ function buildContinuePlan(hostId, sessionId, message) {
|
|
|
332
350
|
return {
|
|
333
351
|
command: executableName('gemini'),
|
|
334
352
|
args: ['--yolo', '--skip-trust'],
|
|
335
|
-
stdin: message,
|
|
353
|
+
stdin: transformHeadlessFraimMessage(message, 'continue'),
|
|
336
354
|
};
|
|
337
355
|
}
|
|
338
356
|
return {
|
|
339
357
|
command: executableName('claude'),
|
|
340
358
|
args: ['-p', '--verbose', '--output-format', 'stream-json', '--dangerously-skip-permissions', '-r', sessionId],
|
|
341
|
-
stdin: message,
|
|
359
|
+
stdin: transformHeadlessFraimMessage(message, 'continue'),
|
|
342
360
|
};
|
|
343
361
|
}
|
|
344
362
|
function parseHostLine(hostId, line) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fraim-framework",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.147",
|
|
4
4
|
"description": "FRAIM: AI Workforce Infrastructure — the organizational capability that turns AI agents into an accountable workforce, their operators into capable AI managers, and executives into leaders with clear optics on AI proficiency.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
package/public/ai-hub/index.html
CHANGED
|
@@ -11,13 +11,16 @@
|
|
|
11
11
|
|
|
12
12
|
<div class="page">
|
|
13
13
|
|
|
14
|
-
<header class="header">
|
|
15
|
-
<
|
|
16
|
-
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
<header class="header">
|
|
15
|
+
<div class="header-copy">
|
|
16
|
+
<span class="header-eyebrow">FRAIM Hub</span>
|
|
17
|
+
<h1>AI Hub</h1>
|
|
18
|
+
</div>
|
|
19
|
+
<button class="project-button" type="button" id="project-button">
|
|
20
|
+
<span class="folder">Project</span>
|
|
21
|
+
<strong id="project-name">Choose a folder</strong>
|
|
22
|
+
</button>
|
|
23
|
+
</header>
|
|
21
24
|
|
|
22
25
|
<section class="welcome">
|
|
23
26
|
Hi <strong class="you">there</strong>, remember, you are the
|
|
@@ -63,13 +66,20 @@
|
|
|
63
66
|
</section>
|
|
64
67
|
|
|
65
68
|
<div class="layout">
|
|
66
|
-
<aside class="rail">
|
|
67
|
-
<button class="new-conv" type="button" id="new-conv-btn">+ New job</button>
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
<aside class="rail">
|
|
70
|
+
<button class="new-conv" type="button" id="new-conv-btn">+ New job</button>
|
|
71
|
+
<div class="rail-note">Alpha: browser shell for directing employees across your project.</div>
|
|
72
|
+
<!-- R2.4: team roster — horizontal row of avatar chips per hired persona -->
|
|
73
|
+
<section class="rail-section rail-section--employees">
|
|
74
|
+
<div class="rail-section-label">Hired employees</div>
|
|
75
|
+
<div class="team-roster" id="team-roster" hidden></div>
|
|
76
|
+
</section>
|
|
77
|
+
|
|
78
|
+
<section class="rail-section rail-section--runs">
|
|
79
|
+
<div class="rail-section-label">Runs</div>
|
|
80
|
+
<div class="conv-list" id="conv-list"></div>
|
|
81
|
+
</section>
|
|
82
|
+
</aside>
|
|
73
83
|
|
|
74
84
|
<main class="conversation" id="conversation">
|
|
75
85
|
<div class="empty-state" id="empty">
|
|
@@ -77,16 +87,25 @@
|
|
|
77
87
|
<p>Pick an existing job from the left, or click <strong>+ New job</strong> to give your employee something to work on.</p>
|
|
78
88
|
</div>
|
|
79
89
|
|
|
80
|
-
<div id="active-conv" hidden>
|
|
81
|
-
<div class="conv-
|
|
82
|
-
<
|
|
83
|
-
<div class="
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
+
<div id="active-conv" hidden>
|
|
91
|
+
<div class="conv-topline">
|
|
92
|
+
<div class="employee-identity" id="active-identity"></div>
|
|
93
|
+
<div class="run-state-pill" id="run-state-pill"></div>
|
|
94
|
+
</div>
|
|
95
|
+
|
|
96
|
+
<div class="conv-header">
|
|
97
|
+
<div class="title-block">
|
|
98
|
+
<h2 id="active-title"></h2>
|
|
99
|
+
<div class="conv-job" id="active-job"></div>
|
|
100
|
+
</div>
|
|
101
|
+
<div id="artifact-slot"></div>
|
|
102
|
+
</div>
|
|
103
|
+
|
|
104
|
+
<div class="summary-strip" id="summary-strip"></div>
|
|
105
|
+
|
|
106
|
+
<!-- Issue #347 R1: pizza tracker. Hidden when the active job
|
|
107
|
+
declares no phases. Populated by renderTracker() in script.js. -->
|
|
108
|
+
<div class="tracker" id="tracker" aria-label="Job progress" hidden>
|
|
90
109
|
<div class="tracker-rows" id="tracker-rows"></div>
|
|
91
110
|
<div class="tracker-note" id="tracker-note" hidden></div>
|
|
92
111
|
</div>
|
|
@@ -96,28 +115,32 @@
|
|
|
96
115
|
<span class="latest" id="latest"></span>
|
|
97
116
|
</div>
|
|
98
117
|
|
|
99
|
-
<
|
|
118
|
+
<section class="thread-surface" aria-label="Manager and employee thread">
|
|
119
|
+
<div class="thread-surface-label">Manager and employee thread</div>
|
|
120
|
+
<div class="messages" id="messages"></div>
|
|
121
|
+
</section>
|
|
100
122
|
|
|
101
123
|
<div class="coach">
|
|
102
|
-
<div class="coach-title-row">
|
|
103
|
-
<span class="section-title">Coach the employee</span>
|
|
104
|
-
<span class="active-employee-row">
|
|
105
|
-
<label for="active-employee-select" class="active-employee-label">
|
|
106
|
-
<select id="active-employee-select" class="employee-select inline"></select>
|
|
107
|
-
</span>
|
|
108
|
-
</div>
|
|
109
|
-
<textarea id="coach-text" placeholder="Tell the employee what to do next…"></textarea>
|
|
110
|
-
<div class="coach-actions">
|
|
111
|
-
<!-- Issue #347 R2: template picker. Hidden when the project
|
|
112
|
-
has no manager-job templates. -->
|
|
113
|
-
<button class="ghost" type="button" id="template-picker-btn" aria-haspopup="menu" aria-expanded="false" hidden>Use a template ▾</button>
|
|
114
|
-
<button class="send-button" type="button" id="send" disabled>Send</button>
|
|
115
|
-
<div class="template-popover" id="template-popover" role="menu" hidden></div>
|
|
116
|
-
</div>
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
124
|
+
<div class="coach-title-row">
|
|
125
|
+
<span class="section-title">Coach the employee</span>
|
|
126
|
+
<span class="active-employee-row">
|
|
127
|
+
<label for="active-employee-select" class="active-employee-label">tool</label>
|
|
128
|
+
<select id="active-employee-select" class="employee-select inline"></select>
|
|
129
|
+
</span>
|
|
130
|
+
</div>
|
|
131
|
+
<textarea id="coach-text" placeholder="Tell the employee what to do next…"></textarea>
|
|
132
|
+
<div class="coach-actions">
|
|
133
|
+
<!-- Issue #347 R2: template picker. Hidden when the project
|
|
134
|
+
has no manager-job templates. -->
|
|
135
|
+
<button class="ghost" type="button" id="template-picker-btn" aria-haspopup="menu" aria-expanded="false" hidden>Use a template ▾</button>
|
|
136
|
+
<button class="send-button" type="button" id="send" disabled>Send</button>
|
|
137
|
+
<div class="template-popover" id="template-popover" role="menu" hidden></div>
|
|
138
|
+
</div>
|
|
139
|
+
<div class="coach-note" id="coach-note"></div>
|
|
140
|
+
<!-- Issue #347 R4: run-level totals. Discoverable, not dominating.
|
|
141
|
+
Populated by renderTotals() each poll tick. -->
|
|
142
|
+
<div class="totals" id="totals" aria-label="Run totals" hidden></div>
|
|
143
|
+
</div>
|
|
121
144
|
|
|
122
145
|
<details class="micro" id="micro-manage">
|
|
123
146
|
<summary>Micro-manage — raw host details</summary>
|