@theaileverage/marionette 0.2.1 → 0.2.2
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/CHANGELOG.md +7 -0
- package/DESIGN.md +3 -3
- package/ORCHESTRATION.md +2 -2
- package/README.md +19 -4
- package/THIRD_PARTY_NOTICES.md +208 -0
- package/VERIFICATION.md +8 -0
- package/dist/cli.js +789 -121
- package/dist/herdr-protocol.d.ts +1916 -0
- package/dist/herdr-protocol.js +108 -0
- package/dist/herdr-sdk.d.ts +105 -0
- package/dist/herdr-sdk.js +105 -0
- package/dist/herdr-streams.d.ts +49 -0
- package/dist/herdr-streams.js +156 -0
- package/dist/herdr-transport.d.ts +50 -0
- package/dist/herdr-transport.js +232 -0
- package/dist/mcp.js +1 -1
- package/package.json +22 -5
- package/public/assets/{index-BCi4LMak.js → index-CCfdv-uF.js} +1 -1
- package/public/index.html +1 -1
- package/skills/marionette/SKILL.md +70 -0
- package/skills/marionette/references/coordination.md +63 -0
- package/skills/marionette/references/herdr-sdk.md +147 -0
- package/vendor/herdr-0.9.0/LICENSE +201 -0
- package/vendor/herdr-0.9.0/README.md +5 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import net from 'node:net';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { isAbsolute } from 'node:path';
|
|
4
|
+
export class HerdrError extends Error {
|
|
5
|
+
code;
|
|
6
|
+
constructor(code, message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.name = 'HerdrError';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function validateSocketPath(path) {
|
|
13
|
+
if (!isAbsolute(path) && !/^\\\\[.?]\\pipe\\[^\\]/.test(path))
|
|
14
|
+
throw new TypeError('An absolute Herdr socket path or Windows named pipe is required');
|
|
15
|
+
}
|
|
16
|
+
export function validateTimeout(value) {
|
|
17
|
+
if (value !== null && (!Number.isFinite(value) || value <= 0 || value > 2147483647))
|
|
18
|
+
throw new TypeError('timeoutMs must be a positive bounded duration or null');
|
|
19
|
+
}
|
|
20
|
+
function limit(value, name) {
|
|
21
|
+
if (!Number.isSafeInteger(value) || value <= 0)
|
|
22
|
+
throw new TypeError(`${name} must be a positive integer`);
|
|
23
|
+
return value;
|
|
24
|
+
}
|
|
25
|
+
/** Internal, single-reader NDJSON connection. JSON reads and binary writes stay separate. */
|
|
26
|
+
export class JsonConnection {
|
|
27
|
+
options;
|
|
28
|
+
id = randomUUID();
|
|
29
|
+
closed;
|
|
30
|
+
resolveClosed;
|
|
31
|
+
rejectClosed;
|
|
32
|
+
socket;
|
|
33
|
+
buffer = '';
|
|
34
|
+
queue = [];
|
|
35
|
+
queuedBytes = 0;
|
|
36
|
+
reader;
|
|
37
|
+
writes = new Set();
|
|
38
|
+
ended = false;
|
|
39
|
+
failure;
|
|
40
|
+
explicitClose = false;
|
|
41
|
+
maxMessageBytes;
|
|
42
|
+
maxQueuedEvents;
|
|
43
|
+
maxQueuedBytes;
|
|
44
|
+
abort;
|
|
45
|
+
constructor(socketPath, options = {}) {
|
|
46
|
+
this.options = options;
|
|
47
|
+
validateSocketPath(socketPath);
|
|
48
|
+
this.maxMessageBytes = limit(options.maxResponseBytes ?? 32 * 1024 * 1024, 'maxResponseBytes');
|
|
49
|
+
this.maxQueuedEvents = limit(options.maxQueuedEvents ?? 1024, 'maxQueuedEvents');
|
|
50
|
+
this.maxQueuedBytes = limit(options.maxQueuedBytes ?? this.maxMessageBytes, 'maxQueuedBytes');
|
|
51
|
+
if (options.signal?.aborted)
|
|
52
|
+
throw new HerdrError('herdr_aborted', 'Herdr operation was aborted');
|
|
53
|
+
this.closed = new Promise((resolve, reject) => {
|
|
54
|
+
this.resolveClosed = resolve;
|
|
55
|
+
this.rejectClosed = reject;
|
|
56
|
+
});
|
|
57
|
+
// Consumers may observe this promise; an unobserved stream error must not crash Node.
|
|
58
|
+
void this.closed.catch(() => { });
|
|
59
|
+
this.socket = net.createConnection(socketPath);
|
|
60
|
+
this.socket.setEncoding('utf8');
|
|
61
|
+
this.abort = () => this.fail(new HerdrError('herdr_aborted', 'Herdr operation was aborted'), true);
|
|
62
|
+
options.signal?.addEventListener('abort', this.abort, { once: true });
|
|
63
|
+
this.socket.on('error', (error) => this.fail(new HerdrError('herdr_unavailable', error.message)));
|
|
64
|
+
this.socket.on('close', () => {
|
|
65
|
+
this.ended = true;
|
|
66
|
+
this.detachAbort();
|
|
67
|
+
this.rejectWrites(this.error());
|
|
68
|
+
if (this.failure || !this.explicitClose)
|
|
69
|
+
this.rejectClosed(this.error());
|
|
70
|
+
else
|
|
71
|
+
this.resolveClosed();
|
|
72
|
+
this.deliver();
|
|
73
|
+
});
|
|
74
|
+
this.socket.on('data', (data) => this.receive(data));
|
|
75
|
+
}
|
|
76
|
+
error() {
|
|
77
|
+
return (this.failure ??
|
|
78
|
+
new HerdrError('herdr_disconnected', 'Herdr disconnected before acknowledgement or stream completion'));
|
|
79
|
+
}
|
|
80
|
+
detachAbort() {
|
|
81
|
+
this.options.signal?.removeEventListener('abort', this.abort);
|
|
82
|
+
}
|
|
83
|
+
rejectWrites(error) {
|
|
84
|
+
for (const reject of this.writes)
|
|
85
|
+
reject(error);
|
|
86
|
+
this.writes.clear();
|
|
87
|
+
}
|
|
88
|
+
fail(error, discard = false) {
|
|
89
|
+
if (this.explicitClose)
|
|
90
|
+
return;
|
|
91
|
+
this.failure ??= error;
|
|
92
|
+
this.ended = true;
|
|
93
|
+
this.buffer = '';
|
|
94
|
+
if (discard) {
|
|
95
|
+
this.queue = [];
|
|
96
|
+
this.queuedBytes = 0;
|
|
97
|
+
}
|
|
98
|
+
this.detachAbort();
|
|
99
|
+
this.socket.destroy();
|
|
100
|
+
this.rejectWrites(this.failure);
|
|
101
|
+
this.deliver();
|
|
102
|
+
}
|
|
103
|
+
close() {
|
|
104
|
+
this.explicitClose = true;
|
|
105
|
+
this.ended = true;
|
|
106
|
+
this.buffer = '';
|
|
107
|
+
this.queue = [];
|
|
108
|
+
this.queuedBytes = 0;
|
|
109
|
+
this.detachAbort();
|
|
110
|
+
this.socket.destroy();
|
|
111
|
+
this.rejectWrites(this.error());
|
|
112
|
+
this.deliver();
|
|
113
|
+
}
|
|
114
|
+
deliver() {
|
|
115
|
+
if (!this.reader)
|
|
116
|
+
return;
|
|
117
|
+
const reader = this.reader;
|
|
118
|
+
if (this.failure) {
|
|
119
|
+
this.reader = undefined;
|
|
120
|
+
reader.reject(this.failure);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const next = this.queue.shift();
|
|
124
|
+
if (next) {
|
|
125
|
+
this.reader = undefined;
|
|
126
|
+
this.queuedBytes -= next.bytes;
|
|
127
|
+
reader.resolve(next.value);
|
|
128
|
+
}
|
|
129
|
+
else if (this.ended) {
|
|
130
|
+
this.reader = undefined;
|
|
131
|
+
if (this.explicitClose)
|
|
132
|
+
reader.resolve(undefined);
|
|
133
|
+
else
|
|
134
|
+
reader.reject(this.error());
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
receive(data) {
|
|
138
|
+
if (this.ended)
|
|
139
|
+
return;
|
|
140
|
+
this.buffer += data;
|
|
141
|
+
let index;
|
|
142
|
+
while ((index = this.buffer.indexOf('\n')) >= 0) {
|
|
143
|
+
const line = this.buffer.slice(0, index);
|
|
144
|
+
this.buffer = this.buffer.slice(index + 1);
|
|
145
|
+
const bytes = Buffer.byteLength(line);
|
|
146
|
+
if (bytes > this.maxMessageBytes)
|
|
147
|
+
return this.fail(new HerdrError('herdr_response_too_large', 'Herdr message exceeded maxResponseBytes'), true);
|
|
148
|
+
let value;
|
|
149
|
+
try {
|
|
150
|
+
value = JSON.parse(line);
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
return this.fail(new HerdrError('herdr_invalid_response', String(error)), true);
|
|
154
|
+
}
|
|
155
|
+
// Each connection owns one request; graphics replies append a frame identifier.
|
|
156
|
+
if (value?.id !== undefined &&
|
|
157
|
+
value.id !== this.id &&
|
|
158
|
+
!String(value.id).startsWith(this.id + ':'))
|
|
159
|
+
continue;
|
|
160
|
+
if (value?.error)
|
|
161
|
+
return this.fail(new HerdrError(value.error.code, value.error.message), true);
|
|
162
|
+
if (this.queue.length >= this.maxQueuedEvents ||
|
|
163
|
+
this.queuedBytes + bytes > this.maxQueuedBytes)
|
|
164
|
+
return this.fail(new HerdrError('herdr_stream_overflow', 'Herdr consumer fell behind; stream closed without silently dropping events'), true);
|
|
165
|
+
this.queue.push({ value, bytes });
|
|
166
|
+
this.queuedBytes += bytes;
|
|
167
|
+
this.deliver();
|
|
168
|
+
}
|
|
169
|
+
if (Buffer.byteLength(this.buffer) > this.maxMessageBytes)
|
|
170
|
+
this.fail(new HerdrError('herdr_response_too_large', 'Herdr message exceeded maxResponseBytes'), true);
|
|
171
|
+
}
|
|
172
|
+
read() {
|
|
173
|
+
if (this.reader)
|
|
174
|
+
return Promise.reject(new Error('Only one reader may consume a Herdr connection'));
|
|
175
|
+
return new Promise((resolve, reject) => {
|
|
176
|
+
this.reader = { resolve, reject };
|
|
177
|
+
this.deliver();
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
write(data) {
|
|
181
|
+
if (this.ended)
|
|
182
|
+
return Promise.reject(this.error());
|
|
183
|
+
return new Promise((resolve, reject) => {
|
|
184
|
+
this.writes.add(reject);
|
|
185
|
+
this.socket.write(data, (error) => {
|
|
186
|
+
this.writes.delete(reject);
|
|
187
|
+
if (error) {
|
|
188
|
+
this.fail(new HerdrError('herdr_unavailable', error.message));
|
|
189
|
+
reject(this.error());
|
|
190
|
+
}
|
|
191
|
+
else if (this.failure)
|
|
192
|
+
reject(this.failure);
|
|
193
|
+
else
|
|
194
|
+
resolve();
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
async within(timeoutMs, action) {
|
|
199
|
+
validateTimeout(timeoutMs);
|
|
200
|
+
const timer = timeoutMs === null
|
|
201
|
+
? undefined
|
|
202
|
+
: setTimeout(() => this.fail(new HerdrError('herdr_timeout', 'Herdr response timed out; delivery may be ambiguous'), true), timeoutMs);
|
|
203
|
+
try {
|
|
204
|
+
return await action();
|
|
205
|
+
}
|
|
206
|
+
finally {
|
|
207
|
+
clearTimeout(timer);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
async start(method, params, timeoutMs) {
|
|
211
|
+
return this.within(timeoutMs, async () => {
|
|
212
|
+
await this.write(JSON.stringify({ id: this.id, method, params }) + '\n');
|
|
213
|
+
const message = await this.read();
|
|
214
|
+
if (!message || message.id !== this.id || !Object.hasOwn(message, 'result'))
|
|
215
|
+
throw new HerdrError('herdr_invalid_response', `${method}: missing correlated result`);
|
|
216
|
+
return message.result;
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
export async function socketRequest(socketPath, method, params, options = {}) {
|
|
221
|
+
const timeoutMs = options.timeoutMs === undefined ? 10000 : options.timeoutMs;
|
|
222
|
+
validateTimeout(timeoutMs);
|
|
223
|
+
// Validate serialization before opening a connection.
|
|
224
|
+
JSON.stringify(params);
|
|
225
|
+
const connection = new JsonConnection(socketPath, options);
|
|
226
|
+
try {
|
|
227
|
+
return (await connection.start(method, params, timeoutMs));
|
|
228
|
+
}
|
|
229
|
+
finally {
|
|
230
|
+
connection.close();
|
|
231
|
+
}
|
|
232
|
+
}
|
package/dist/mcp.js
CHANGED
|
@@ -21598,7 +21598,7 @@ var cleanupPolicySchema = external_exports.object({
|
|
|
21598
21598
|
}).strict();
|
|
21599
21599
|
|
|
21600
21600
|
// src/version.ts
|
|
21601
|
-
var VERSION = "0.2.
|
|
21601
|
+
var VERSION = "0.2.2";
|
|
21602
21602
|
|
|
21603
21603
|
// src/config.ts
|
|
21604
21604
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theaileverage/marionette",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22.13"
|
|
@@ -13,11 +13,12 @@
|
|
|
13
13
|
"test": "node --import tsx --test tests/*.test.ts",
|
|
14
14
|
"cli": "node --import tsx src/cli.ts",
|
|
15
15
|
"mcp": "node --import tsx src/mcp.ts",
|
|
16
|
-
"format": "prettier --write src web .github tests scripts *.json *.ts *.md",
|
|
17
|
-
"format:check": "prettier --check src web .github tests scripts *.json *.ts *.md",
|
|
16
|
+
"format": "prettier --write src web skills .github tests scripts *.json *.ts *.md",
|
|
17
|
+
"format:check": "prettier --check src web skills .github tests scripts *.json *.ts *.md",
|
|
18
18
|
"prepack": "npm run check && npm test && npm run build",
|
|
19
19
|
"release:prepare": "node scripts/release.mjs prepare",
|
|
20
|
-
"release:check": "node scripts/release.mjs check"
|
|
20
|
+
"release:check": "node scripts/release.mjs check",
|
|
21
|
+
"sdk:generate": "node scripts/generate-herdr-sdk.mjs"
|
|
21
22
|
},
|
|
22
23
|
"devDependencies": {
|
|
23
24
|
"@types/express": "^5.0.0",
|
|
@@ -52,7 +53,17 @@
|
|
|
52
53
|
"VERIFICATION.md",
|
|
53
54
|
"LICENSE",
|
|
54
55
|
"CONTRIBUTING.md",
|
|
55
|
-
"RELEASING.md"
|
|
56
|
+
"RELEASING.md",
|
|
57
|
+
"dist/herdr-sdk.js",
|
|
58
|
+
"dist/herdr-sdk.d.ts",
|
|
59
|
+
"skills/",
|
|
60
|
+
"dist/herdr-protocol.js",
|
|
61
|
+
"dist/herdr-protocol.d.ts",
|
|
62
|
+
"dist/herdr-streams.js",
|
|
63
|
+
"dist/herdr-streams.d.ts",
|
|
64
|
+
"dist/herdr-transport.js",
|
|
65
|
+
"dist/herdr-transport.d.ts",
|
|
66
|
+
"vendor/herdr-0.9.0/LICENSE"
|
|
56
67
|
],
|
|
57
68
|
"publishConfig": {
|
|
58
69
|
"access": "public"
|
|
@@ -65,5 +76,11 @@
|
|
|
65
76
|
"homepage": "https://github.com/theaileverage/marionette#readme",
|
|
66
77
|
"bugs": {
|
|
67
78
|
"url": "https://github.com/theaileverage/marionette/issues"
|
|
79
|
+
},
|
|
80
|
+
"exports": {
|
|
81
|
+
"./herdr-sdk": {
|
|
82
|
+
"types": "./dist/herdr-sdk.d.ts",
|
|
83
|
+
"import": "./dist/herdr-sdk.js"
|
|
84
|
+
}
|
|
68
85
|
}
|
|
69
86
|
}
|
|
@@ -164,4 +164,4 @@ Error generating stack: `+a.message+`
|
|
|
164
164
|
* This source code is licensed under the ISC license.
|
|
165
165
|
* See the LICENSE file in the root directory of this source tree.
|
|
166
166
|
*/const Hn=Qe("X",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);function Hy({id:b,onAction:k}){const[q,y]=P.useState();return c.createElement("details",{onToggle:M=>{M.currentTarget.open&&!q&&k("plan.get",{revisionId:b}).then(y)}},c.createElement("summary",null,"Review what changed"),c.createElement("pre",null,q?JSON.stringify({before:q.before,after:q.after},null,2):"Loading revision…"))}const Af=b=>String(b??"").split(`
|
|
167
|
-
`).map(k=>k.trim()).filter(Boolean),Qm=b=>b.replaceAll("-"," ");function Xm({task:b,tasks:k,onTask:q}){var M;const y=k.filter(W=>W.parentId===b.id);return c.createElement("button",{className:"outcome-task",onClick:()=>q(b.id)},c.createElement("span",{className:`status status-${b.status}`},Qm(b.status)),c.createElement("strong",null,b.title),c.createElement("span",null,b.kind," · ",b.model??"Configured runtime default; exact model unreported"),b.reasoning&&c.createElement("span",null,"Reasoning: ",b.reasoning),c.createElement("span",null,y.length," direct children · ",b.dependencies.length," dependencies"),b.required===!1&&c.createElement("span",null,"Explicitly removed from required work"),b.supersededBy&&c.createElement("span",null,"Superseded by ",((M=k.find(W=>W.id===b.supersededBy))==null?void 0:M.title)??b.supersededBy),(b.waitReason||b.error)&&c.createElement("span",{className:"board-warning"},b.waitReason??b.error),b.receipt&&c.createElement("span",null,b.receipt.summary))}function Zm({tasks:b,parentId:k,onTask:q,depth:y=0}){return y>7?c.createElement("p",null,"Invalid task tree: inspect the current records."):c.createElement("ul",{className:"outcome-tree"},b.filter(M=>M.parentId===k).map(M=>c.createElement("li",{key:M.id},c.createElement(Xm,{task:M,tasks:b,onTask:q}),b.some(W=>W.parentId===M.id)&&c.createElement(Zm,{tasks:b,parentId:M.id,onTask:q,depth:y+1}))))}function xy({data:b,projectId:k,canEdit:q,pending:y,onTask:M,onAddTask:W,onAction:D}){var L,ke;const[De,U]=P.useState("Board"),[O,$]=P.useState(""),[Y,H]=P.useState(!1),[le,_e]=P.useState(1),[Ee,Ve]=P.useState("all"),[qe,Je]=P.useState(""),Ue=b.profiles.filter(p=>(Ee==="all"||p.kind===Ee)&&`${p.name} ${p.model}`.toLowerCase().includes(qe.toLowerCase())),x=b.outcomes.find(p=>p.id===O)??b.outcomes[0],He=x?b.tasks.filter(p=>p.outcomeId===x.id):b.tasks,se=x?b.revisions.filter(p=>p.outcomeId===x.id):[],Z=(p,C,ae)=>D(p,C,ae).catch(()=>{}),Te=x?{outcomeId:x.id,expectedRevision:x.revision}:{};return c.createElement("div",{className:"outcome-board"},c.createElement("section",{className:"panel outcome-toolbar"},c.createElement("div",null,c.createElement("h2",null,"Outcomes and definitions of done"),c.createElement("p",null,"Understand what remains, who owns it, and the evidence required to finish.")),c.createElement("div",{className:"outcome-actions"},c.createElement("button",{disabled:!q||y,onClick:()=>H(!Y)},Y?"Close outcome form":"New outcome"),c.createElement("button",{disabled:!q||y,onClick:W},"Add task")),b.outcomes.length>0&&c.createElement("label",null,"Outcome",c.createElement("select",{"aria-label":"Select outcome",value:(x==null?void 0:x.id)??"",onChange:p=>$(p.target.value)},b.outcomes.map(p=>c.createElement("option",{key:p.id,value:p.id},p.status==="completed"?"✓ ":"",p.objective.slice(0,140))))),c.createElement("div",{className:"outcome-view-options",role:"group","aria-label":"Task board view"},["Board","Task tree","Dependencies"].map(p=>c.createElement("button",{key:p,"aria-pressed":De===p,onClick:()=>U(p)},p)))),Y&&c.createElement("section",{className:"panel outcome-section"},c.createElement("h3",null,"Define an observable result"),c.createElement("form",{onSubmit:async p=>{p.preventDefault();const C=new FormData(p.currentTarget),ae=Array.from({length:le},(ne,d)=>({id:`criterion-${d+1}`,description:String(C.get(`criterion-${d}`)),requiredEvidence:String(C.get(`evidence-${d}`))})),Oe=await Z("outcome.create",{outcome:{projectId:k,key:crypto.randomUUID(),objective:String(C.get("objective")),scope:Af(C.get("scope")),category:String(C.get("category")),criteria:ae,maxTurns:Number(C.get("maxTurns")),maxDepth:Number(C.get("maxDepth"))}},"Outcome and completion criteria saved");Oe&&($(Oe.id),H(!1))}},c.createElement("label",null,"Objective",c.createElement("textarea",{name:"objective",required:!0,rows:3,placeholder:"What must be true when this work is complete?"})),c.createElement("div",{className:"form-grid"},c.createElement("label",null,"Work category",c.createElement("select",{name:"category"},c.createElement("option",{value:"software"},"Software"),c.createElement("option",{value:"research"},"Research"),c.createElement("option",{value:"analysis"},"Analysis"),c.createElement("option",{value:"decision"},"Collaborative decision"))),c.createElement("label",null,"Owned paths, one per line",c.createElement("textarea",{name:"scope",required:!0,defaultValue:".",rows:2}))),Array.from({length:le},(p,C)=>c.createElement("fieldset",{key:C},c.createElement("legend",null,"Completion criterion ",C+1),c.createElement("label",null,"Observable requirement",c.createElement("input",{name:`criterion-${C}`,required:!0})),c.createElement("label",null,"Evidence needed",c.createElement("input",{name:`evidence-${C}`,required:!0,placeholder:"Test results, corroborated sources, or a recorded decision"})))),c.createElement("button",{type:"button",onClick:()=>_e(p=>Math.min(20,p+1)),disabled:le>=20},"Add criterion"),c.createElement("div",{className:"form-grid"},c.createElement("label",null,"Shared execution turn budget",c.createElement("input",{name:"maxTurns",type:"number",min:"1",max:"1000",defaultValue:"60",required:!0})),c.createElement("label",null,"Maximum delegation depth",c.createElement("input",{name:"maxDepth",type:"number",min:"0",max:"6",defaultValue:"3",required:!0}))),c.createElement("button",{disabled:y||!q},"Save outcome"))),x?c.createElement(c.Fragment,null,c.createElement("section",{key:`${x.id}:${x.revision}`,className:"panel outcome-section"},c.createElement("div",{className:"outcome-title"},c.createElement("h3",null,x.objective),c.createElement("span",{className:`status status-${x.status}`},x.status)),c.createElement("p",null,"Responsible lead: ",c.createElement("strong",null,x.leadOwner)," · Revision ",x.revision," ·"," ",x.turnsUsed," / ",x.maxTurns," shared turns"),c.createElement("p",null,"Scope: ",x.scope.join(", ")," · Delegation depth limit: ",x.maxDepth),c.createElement("ul",{className:"criteria-list"},x.criteria.map(p=>{const C=x.assessments.find(ae=>ae.criterionId===p.id&&ae.revision===x.revision);return c.createElement("li",{key:p.id},c.createElement("strong",null,p.description),c.createElement("p",null,"Required evidence: ",p.requiredEvidence),C&&c.createElement("p",null,"Reviewed by ",C.owner,": ",C.rationale,c.createElement("br",null),"Evidence: ",C.references.map(ae=>ae.path).join(", ")),c.createElement("details",null,c.createElement("summary",null,"Evaluate this criterion"),c.createElement("form",{onSubmit:ae=>{ae.preventDefault();const Oe=new FormData(ae.currentTarget);Z("outcome.assess",{...Te,criterionId:p.id,rationale:String(Oe.get("rationale")),references:Af(Oe.get("references"))},"Criterion evidence recorded")}},c.createElement("label",null,"Independent evaluation",c.createElement("textarea",{name:"rationale",required:!0,rows:2})),c.createElement("label",null,"Evidence files in this project, one per line",c.createElement("textarea",{name:"references",required:!0,rows:2})),c.createElement("button",{disabled:!q||y},"Record evaluation"))))})),c.createElement("details",null,c.createElement("summary",null,"Revise completion criteria"),c.createElement("form",{key:x.revision,onSubmit:p=>{p.preventDefault();const C=new FormData(p.currentTarget),ae=x.criteria.map((Oe,ne)=>({...Oe,description:String(C.get(`description-${ne}`)),requiredEvidence:String(C.get(`required-${ne}`))}));Z("outcome.revise",{...Te,criteria:ae,reason:String(C.get("reason"))},"Criteria revised; previous evidence retained in history")}},x.criteria.map((p,C)=>c.createElement("fieldset",{key:p.id},c.createElement("legend",null,p.id),c.createElement("label",null,"Requirement",c.createElement("input",{name:`description-${C}`,defaultValue:p.description,required:!0})),c.createElement("label",null,"Required evidence",c.createElement("input",{name:`required-${C}`,defaultValue:p.requiredEvidence,required:!0})))),c.createElement("label",null,"Why did the completion contract change?",c.createElement("textarea",{name:"reason",required:!0,rows:2})),c.createElement("button",{disabled:!q||y},"Save criteria revision"))),c.createElement("details",null,c.createElement("summary",null,"Review the integrated result"),c.createElement("form",{onSubmit:p=>{p.preventDefault();const C=new FormData(p.currentTarget);Z("outcome.integrate",{...Te,summary:String(C.get("summary")),references:Af(C.get("references"))},"Integrated result reviewed")}},c.createElement("label",null,"Integrated evaluation",c.createElement("textarea",{name:"summary",required:!0,rows:3,defaultValue:(L=x.integrated)==null?void 0:L.summary})),c.createElement("label",null,"Integration evidence files, one per line",c.createElement("textarea",{name:"references",required:!0,rows:2})),c.createElement("button",{disabled:!q||y},"Record integrated review"))),x.unmet.length>0?c.createElement("div",{className:"outcome-unmet"},c.createElement("strong",null,"What remains before completion"),c.createElement("ul",null,x.unmet.map((p,C)=>c.createElement("li",{key:C},p)))):c.createElement("p",{className:"board-success"},"All required work and current acceptance evidence pass."),c.createElement("button",{disabled:!q||y||x.status==="completed"||x.unmet.length>0,onClick:()=>void Z("outcome.complete",Te,"Outcome verified complete")},"Verify outcome complete")),De==="Board"&&c.createElement("section",{className:"outcome-columns","aria-label":"Outcome task board"},[{name:"Queued",statuses:["queued","preparing"]},{name:"In progress",statuses:["running","verifying","redirecting","cancelling"]},{name:"Waiting",statuses:["waiting","yielding","paused"]},{name:"Needs attention",statuses:["failed","blocked","uncertain","cancelled"]},{name:"Verified",statuses:["completed"]}].map(p=>c.createElement("div",{className:"outcome-column",key:p.name},c.createElement("h3",null,p.name," ",c.createElement("span",null,He.filter(C=>p.statuses.includes(C.status)).length)),He.filter(C=>p.statuses.includes(C.status)).map(C=>c.createElement(Xm,{key:C.id,task:C,tasks:He,onTask:M}))))),De==="Task tree"&&c.createElement("section",{className:"panel outcome-section","aria-label":"Outcome task tree"},c.createElement("h3",null,"Parent accountability and delegated work"),c.createElement(Zm,{tasks:He,onTask:M})),De==="Dependencies"&&c.createElement("section",{className:"panel outcome-section","aria-label":"Outcome dependencies"},c.createElement("h3",null,"Dependencies and verification order"),c.createElement("ul",{className:"dependency-list"},He.map(p=>c.createElement("li",{key:p.id},c.createElement("button",{onClick:()=>M(p.id)},p.title),c.createElement("span",null,p.dependencies.length?" waits for ":" has no dependencies"),p.dependencies.map(C=>{var ae,Oe;return c.createElement("button",{key:C,onClick:()=>M(C)},((ae=b.tasks.find(ne=>ne.id===C))==null?void 0:ae.title)??C," (",((Oe=b.tasks.find(ne=>ne.id===C))==null?void 0:Oe.status)??"missing",")")}))))),c.createElement("section",{className:"panel outcome-section"},c.createElement("h3",null,"Findings and plan revisions"),(ke=b.findings)==null?void 0:ke.filter(p=>p.outcomeId===x.id).map(p=>c.createElement("article",{key:p.id},c.createElement("strong",null,p.summary),c.createElement("p",null,p.evidence.join(", ")))),se.length?c.createElement("ol",{className:"revision-list"},[...se].reverse().map(p=>c.createElement("li",{key:p.id},c.createElement("strong",null,"Revision ",p.revision," · ",p.reason),c.createElement("p",null,p.owner," · ",new Date(p.createdAt).toLocaleString()),p.evidence.length>0&&c.createElement("p",null,"Finding references: ",p.evidence.join(", ")),c.createElement(Hy,{id:p.id,onAction:D})))):c.createElement("p",null,"No plan revisions yet.")),b.strategies.filter(p=>p.outcomeId===x.id).map(p=>{var C;return c.createElement("section",{className:"panel outcome-section",key:p.id},c.createElement("h3",null,Qm(p.kind)," · ",p.status),c.createElement("p",null,"Round ",p.round," / ",p.maxRounds," · Stop when:"," ",p.stopCondition),c.createElement("p",null,"Evaluate against: ",p.criteria),c.createElement("p",null,p.synthesis),(C=p.disagreements)!=null&&C.length?c.createElement("ul",null,p.disagreements.map((ae,Oe)=>c.createElement("li",{key:Oe},ae))):null)})):c.createElement("section",{className:"panel outcome-section"},c.createElement("h3",null,"No outcomes yet"),c.createElement("p",null,"Create an outcome with observable completion criteria, then assign bounded work to agents.")),c.createElement("section",{className:"panel outcome-section"},c.createElement("h3",null,"Capacity and continuation"),c.createElement("p",null,"Global slots: ",b.limits.global," · Project slots: ",b.limits.project," · Coordination turns delivered: ",b.coordination.turns),b.waits.filter(p=>!x||p.outcomeId===x.id).map(p=>{var C;return c.createElement("div",{className:"wait-card",key:p.id},c.createElement("strong",null,p.owner,": ",p.state),c.createElement("p",null,p.adapter.type==="herdr"?"Automatic continuation in the pinned Herdr session":"Continuation on the next user message"),p.error&&c.createElement("p",{className:"board-warning"},p.error),c.createElement("p",null,p.condition.tasks.length," required results · ",((C=p.eventIds)==null?void 0:C.length)??0," ","grouped events"))}),c.createElement("p",{className:"muted"},b.coordination.metricBoundary),b.coordination.usage.map(p=>c.createElement("p",{key:p.id},"Cache read: ",p.cacheReadTokens??"unavailable"," · Cache write:"," ",p.cacheWriteTokens??"unavailable"," · Uncached input:"," ",p.uncachedInputTokens??"unavailable"," · Cost:"," ",p.costUsd===null?"unavailable":`$${p.costUsd.toFixed(4)}`,c.createElement("br",null),"Source: ",p.source)),c.createElement("details",null,c.createElement("summary",null,"Configure shared execution limits"),c.createElement("form",{onSubmit:p=>{p.preventDefault();const C=new FormData(p.currentTarget);Z("limits.configure",{limits:{...b.limits,global:Number(C.get("global")),project:Number(C.get("project"))},reason:String(C.get("reason"))},"Shared limits updated")}},c.createElement("div",{className:"form-grid"},c.createElement("label",null,"Global slots",c.createElement("input",{name:"global",type:"number",min:"1",max:"32",defaultValue:b.limits.global,required:!0})),c.createElement("label",null,"Project slots",c.createElement("input",{name:"project",type:"number",min:"1",max:"8",defaultValue:b.limits.project,required:!0}))),c.createElement("label",null,"Reason",c.createElement("input",{name:"reason",required:!0})),c.createElement("button",{disabled:!q||y},"Save limits")))),c.createElement("section",{className:"panel outcome-section"},c.createElement("h3",null,"Model and capability profiles"),c.createElement("p",null,b.profiles.length," profiles. Discovery reads native catalogs; validation tests the exact selection."),c.createElement("div",{className:"outcome-actions"},c.createElement("label",null,"Runtime",c.createElement("select",{"aria-label":"Filter model runtime",value:Ee,onChange:p=>Ve(p.target.value)},c.createElement("option",{value:"all"},"All runtimes"),c.createElement("option",{value:"codex"},"Codex"),c.createElement("option",{value:"claude"},"Claude"),c.createElement("option",{value:"agy"},"AGY"))),c.createElement("label",null,"Find a model",c.createElement("input",{"aria-label":"Find a model",value:qe,onChange:p=>Je(p.target.value)})),["codex","claude","agy"].map(p=>c.createElement("button",{key:p,disabled:!q||y,onClick:()=>void Z("profile.discover",{kind:p},`${p} catalog refreshed`)},"Discover ",p," models"))),Ue.map(p=>c.createElement("div",{className:"profile-card",key:p.id},c.createElement("strong",null,p.name),c.createElement("p",null,p.kind," · ",p.model," · ",p.reasoning??"Default effort"," ·"," ",p.availability),c.createElement("p",null,"Supported effort:"," ",p.supportedReasoning.join(", ")||"No separate effort control"," · Categories:"," ",p.categories.join(", ")),c.createElement("p",null,p.strengths),c.createElement("p",null,p.availabilityEvidence),c.createElement("button",{disabled:!q||y,onClick:()=>void Z("profile.validate",{profileId:p.id},"Model availability probe finished")},"Validate exact model")))))}function jy({taskId:b,canEdit:k,pending:q,onAction:y}){var Te;const[M,W]=P.useState(),[D,De]=P.useState(""),[U,O]=P.useState(""),[$,Y]=P.useState("merged"),[H,le]=P.useState("refs/heads/main"),[_e,Ee]=P.useState(!1),[Ve,qe]=P.useState(""),[Je,Ue]=P.useState(!0),[x,He]=P.useState(!1),se=async(L,ke={})=>{De("");try{const p=await y(L,{taskId:b,reason:U,...ke}),C=L==="cleanup.preview"?p:await y("cleanup.preview",{taskId:b});W(C),Ue(C.policy.autoRelease),qe(C.policy.collectAfterHours===null?"":String(C.policy.collectAfterHours)),He(C.policy.deleteMergedBranches)}catch(p){De(String(p))}},Z=!k||q||!U.trim();return c.createElement("section",null,c.createElement("h3",null,"Delivery and cleanup"),c.createElement("p",null,"Completion keeps branches and worktrees. Release terminals after consuming results, then record delivery and preserve evidence before collection."),c.createElement("button",{disabled:q,onClick:()=>void se("cleanup.preview")},"Inspect cleanup eligibility"),D?c.createElement("p",{role:"alert"},D):null,M?c.createElement(c.Fragment,null,c.createElement("label",null,"Reason for cleanup or policy change",c.createElement("input",{value:U,onChange:L=>O(L.target.value)})),M.runs.map(L=>{var ke,p,C,ae;return c.createElement("div",{key:L.runId},c.createElement("p",null,"Worker ",L.tabId??L.runId,": ",((ke=L.cleanup)==null?void 0:ke.state)??"retained"),L.reasons.map((Oe,ne)=>c.createElement("p",{className:"muted",key:ne},Oe)),(p=L.cleanup)!=null&&p.error?c.createElement("p",null,L.cleanup.error):null,((C=L.cleanup)==null?void 0:C.state)==="uncertain"?c.createElement(c.Fragment,null,c.createElement("button",{disabled:Z,onClick:()=>void se("cleanup.reconcile",{runId:L.runId,resolution:"closed"})},"Confirm original tab is absent"),c.createElement("button",{disabled:Z,onClick:()=>void se("cleanup.reconcile",{runId:L.runId,resolution:"not-closed"})},"Confirm original worker remains")):((ae=L.cleanup)==null?void 0:ae.state)!=="closed"?c.createElement("button",{disabled:Z,onClick:()=>void se("cleanup.release",{runId:L.runId})},"Result inspected · release worker and tab"):null)}),M.collectionReasons.map((L,ke)=>c.createElement("p",{className:"muted",key:ke},L)),M.delivery?c.createElement("p",null,"Delivery: ",M.delivery.disposition," · ",M.delivery.head):null,M.archive?c.createElement(c.Fragment,null,c.createElement("p",null,"Archive: ",M.archive.phase," · ",M.archive.id),M.archive.error?c.createElement("p",{role:"alert"},M.archive.error):null,M.archive.phase!=="collected"||!M.archive.branchDeleted?c.createElement(c.Fragment,null,c.createElement("label",{className:"checkbox"},c.createElement("input",{type:"checkbox",checked:_e,onChange:L=>Ee(L.target.checked)})," ","Also delete the merged or explicitly abandoned local branch"),c.createElement("button",{disabled:Z,onClick:()=>void se("cleanup.collect",{archiveId:M.archive.id,deleteBranch:_e})},M.archive.phase==="collected"?"Collect retained branch":"Remove archived worktree")):null):null,(Te=M.archive)!=null&&Te.branchDeleted?null:c.createElement(c.Fragment,null,c.createElement("label",null,"Delivery decision",c.createElement("select",{value:$,onChange:L=>Y(L.target.value)},c.createElement("option",{value:"merged"},"Merged into target"),c.createElement("option",{value:"published"},"Published for review"),c.createElement("option",{value:"abandoned"},"Explicitly abandoned"))),$!=="abandoned"?c.createElement("label",null,"Verified target ref",c.createElement("input",{value:H,onChange:L=>le(L.target.value),placeholder:"refs/remotes/origin/main"})):null,c.createElement("button",{disabled:Z,onClick:()=>void se("cleanup.deliver",{disposition:$,...$!=="abandoned"?{targetRef:H}:{}})},"Record delivery decision"),M.archive?null:c.createElement("button",{disabled:Z||!M.delivery,onClick:()=>void se("cleanup.archive")},"Preserve evidence and seal finished tasks")),c.createElement("details",null,c.createElement("summary",null,"Project retention policy"),c.createElement("p",null,"Only enable collection when the user has authorized this retention policy. Blank retention keeps worktrees until an explicit collection request. Failed or abandoned work is never collected automatically."),c.createElement("label",{className:"checkbox"},c.createElement("input",{type:"checkbox",checked:Je,onChange:L=>Ue(L.target.checked)})," ","Automatically release workers after integrated outcome completion"),c.createElement("label",null,"Hours after recorded delivery before automatic collection",c.createElement("input",{type:"number",min:"0",max:"87600",value:Ve,onChange:L=>qe(L.target.value),placeholder:"Keep until explicitly collected"})),c.createElement("label",{className:"checkbox"},c.createElement("input",{type:"checkbox",checked:x,onChange:L=>He(L.target.checked)})," ","Also delete safely merged local branches"),c.createElement("button",{disabled:Z,onClick:()=>void se("cleanup.configure",{policy:{autoRelease:Je,collectAfterHours:Ve===""?null:Number(Ve),deleteMergedBranches:x}})},"Save authorized policy"))):null)}const Nf=b=>b.slice(0,8),tc=b=>JSON.stringify(b,null,2),jm=new Set(["preparing","running","redirecting","cancelling","verifying"]),By=new Set(["blocked","uncertain","failed"]);function Bm(b,k){const q=URL.createObjectURL(new Blob([tc(k)],{type:"application/json"})),y=document.createElement("a");y.href=q,y.download=b,y.click(),setTimeout(()=>URL.revokeObjectURL(q),1e3)}function Yy(){var N,R,j,J,te,oe,We;const[b,k]=P.useState(()=>{const m=new URLSearchParams(location.hash.slice(1)).get("token");return m&&(sessionStorage.setItem("marionette-token",m),history.replaceState(null,"",location.pathname)),m??sessionStorage.getItem("marionette-token")??""}),[q,y]=P.useState([]),[M,W]=P.useState(localStorage.getItem("marionette-project")??""),[D,De]=P.useState(null),[U,O]=P.useState("Overview"),[$,Y]=P.useState(null),[H,le]=P.useState(null),[_e,Ee]=P.useState(""),[Ve,qe]=P.useState(!1),[Je,Ue]=P.useState(!1),[x,He]=P.useState(null),[se,Z]=P.useState([]),[Te,L]=P.useState(""),[ke,p]=P.useState(""),[C]=P.useState(()=>{let m=localStorage.getItem("marionette-consumer");return m||(m="dashboard:"+crypto.randomUUID(),localStorage.setItem("marionette-consumer",m)),m});async function ae(m,K={}){var Ae;const G=await fetch("/api/call",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${b}`},body:JSON.stringify({action:m,input:K}),signal:AbortSignal.timeout(m.startsWith("cleanup.")?3e5:m==="profile.validate"?135e3:m==="profile.discover"?45e3:15e3)}),xe=await G.json();if(!G.ok)throw new Error(((Ae=xe.error)==null?void 0:Ae.message)??"Request failed");return xe.result}async function Oe(){var K;const m=await ae("project.list");y(m),m.some(G=>G.id===M)||W(((K=m[0])==null?void 0:K.id)??""),M&&De(await ae("project.briefing",{projectId:M,compact:!1}))}P.useEffect(()=>{De(null),Y(null),Z([]),He(JSON.parse(sessionStorage.getItem("marionette-lease:"+M)??"null")),localStorage.setItem("marionette-project",M)},[M]),P.useEffect(()=>{if(!b)return;let m=!1,K=!1,G=!0,xe=0;async function Ae(){var wt;if(!K){K=!0;try{const At=await ae("project.list");if(m)return;if(y(At),!At.some(xt=>xt.id===M)){W(((wt=At[0])==null?void 0:wt.id)??""),qe(!0);return}if(M){const[xt,xn]=await Promise.all([ae("project.briefing",{projectId:M,compact:!1}),ae("inbox.read",{projectId:M,consumer:C,limit:200})]);if(m)return;De(xt),Z(xn.events);const Pl=G?{events:[],cursor:xt.eventCursor}:await ae("inbox.read",{projectId:M,consumer:C,after:xe,limit:200});if(m)return;const Hl=Pl.events.filter(Ya=>["task.completed","task.failed","question.opened","worker.disconnected","lead.handover"].includes(Ya.type));!G&&Hl.length&&(L(Hl.at(-1).message),"Notification"in window&&Notification.permission==="granted"&&new Notification("Marionette",{body:Hl.at(-1).message,tag:"marionette"})),xe=Math.max(xe,Pl.cursor),G=!1}qe(!0)}catch{m||qe(!1)}finally{K=!1}}}Ae();const at=setInterval(Ae,2e3);return()=>{m=!0,clearInterval(at)}},[b,M,C]),P.useEffect(()=>{if(!Te)return;const m=setTimeout(()=>L(""),8e3);return()=>clearTimeout(m)},[Te]),P.useEffect(()=>{var Ae;if(!H&&!$)return;const m=document.activeElement,K=document.querySelector(H?".modal":".task-drawer"),G=()=>Array.from((K==null?void 0:K.querySelectorAll('button:not(:disabled),input,select,textarea,[tabindex="0"]'))??[]);(Ae=G()[0])==null||Ae.focus();const xe=at=>{if(at.key==="Escape"){H?le(null):Y(null);return}if(at.key==="Tab"){const wt=G(),At=wt[0],xt=wt.at(-1);at.shiftKey&&document.activeElement===At?(at.preventDefault(),xt==null||xt.focus()):!at.shiftKey&&document.activeElement===xt&&(at.preventDefault(),At==null||At.focus())}};return document.addEventListener("keydown",xe),()=>{document.removeEventListener("keydown",xe),m==null||m.focus()}},[H,$]);const ne=!!(x&&((N=D==null?void 0:D.lead)==null?void 0:N.owner)===x.owner&&((R=D==null?void 0:D.lead)==null?void 0:R.epoch)===x.epoch),d=D==null?void 0:D.tasks.find(m=>m.id===$),_=(D==null?void 0:D.questions.filter(m=>!m.answeredAt))??[];async function Q(m,K,G="Saved"){Ue(!0),Ee("");try{const xe=await ae(m,K);return await Oe(),L(G),xe}catch(xe){throw Ee(String(xe)),xe}finally{Ue(!1)}}function he(m){sessionStorage.setItem("marionette-lease:"+M,tc(m)),He(m)}async function me(m,K,G){d&&(await Q("task.control",{lease:x,taskId:d.id,key:crypto.randomUUID(),type:m,text:K,keys:G},"Control request queued"),le(null))}async function o(m){var xe;m.preventDefault();const K=new FormData(m.currentTarget),G=Ae=>String(K.get(Ae)??"");try{if(H==="connect"){const Ae=await Q("project.register",{name:G("name"),root:G("root"),session:G("session"),socketPath:G("socket"),workspaceId:G("workspace"),maxConcurrency:Number(G("concurrency"))},"Project connected");W(Ae.id)}else if(H==="lead"){const Ae=await Q("lead.acquire",{projectId:M,owner:G("owner"),agent:G("leadAgent"),expectedEpoch:((xe=D==null?void 0:D.lead)==null?void 0:xe.epoch)??0,takeover:!!(D!=null&&D.lead),reason:G("reason")},"You have control");he(Ae.lease)}else if(H==="handover"){const Ae=await Q("lead.handover",{lease:x,toOwner:G("owner"),agent:G("leadAgent"),reason:G("reason")},"Control transferred");Bm(`marionette-${G("owner")}-lease.json`,Ae.lease),sessionStorage.removeItem("marionette-lease:"+M),He(null)}else H==="assignment"?await Q("task.submit",{lease:x,assignment:{projectId:M,key:crypto.randomUUID(),title:G("title"),workstream:G("workstream"),kind:G("profileId")?D.profiles.find(Ae=>Ae.id===G("profileId")).kind:G("kind"),...G("outcomeId")?{outcomeId:G("outcomeId"),expectedTreeRevision:D.outcomes.find(Ae=>Ae.id===G("outcomeId")).revision}:{},...G("parentId")?{parentId:G("parentId")}:{},...G("profileId")?{profileId:G("profileId")}:{},canDelegate:K.get("canDelegate")==="on",prompt:G("prompt"),execution:G("execution")==="worktree"?{mode:"worktree",...G("baseRef").trim()?{baseRef:G("baseRef").trim()}:{}}:{mode:"shared"},ownership:G("ownership").split(",").map(Ae=>Ae.trim()).filter(Boolean),dependencies:K.getAll("dependency").map(String),checks:JSON.parse(G("checks")),maxAttempts:2}},"Assignment queued"):H==="decision"?await Q("decision.record",{lease:x,text:G("text"),rationale:G("reason")},"Decision recorded"):H==="redirect"||H==="reply"?await me(H,G("text")):H==="keys"?await me("keys",void 0,G("keys").trim().split(/\s+/)):H==="reconcile"&&await Q("task.reconcile",{lease:x,taskId:d==null?void 0:d.id,resolution:G("resolution"),reason:G("reason")},"Run reconciled");le(null)}catch(Ae){Ee(String(Ae))}}return b?c.createElement("div",{className:"app-shell"},c.createElement("aside",{className:"sidebar"},c.createElement("div",{className:"wordmark"},c.createElement("div",{className:"brand-mark"},c.createElement(zf,{size:22})),c.createElement("span",null,"marionette",c.createElement("span",{className:"wordmark-dot"},"."))),c.createElement("label",{className:"project-picker"},c.createElement("span",null,"PROJECT"),c.createElement("select",{"aria-label":"Current project",value:M,onChange:m=>W(m.target.value)},!q.length&&c.createElement("option",{value:""},"No project connected"),q.map(m=>c.createElement("option",{key:m.id,value:m.id},m.name)))),c.createElement("nav",{"aria-label":"Main navigation"},[{name:"Overview",icon:Dy},{name:"Outcomes",icon:qn},{name:"Workstreams",icon:Tf},{name:"Inbox",icon:Oy},{name:"Decisions",icon:Sf},{name:"Connection",icon:Ry}].map(({name:m,icon:K})=>c.createElement("button",{key:m,className:U===m?"nav-item chosen":"nav-item",onClick:()=>O(m)},c.createElement(K,{size:18}),m,m==="Inbox"&&se.length>0&&c.createElement("span",{className:"count"},se.length)))),c.createElement("div",{className:"sidebar-bottom"},c.createElement("div",{className:"server-status"},c.createElement("span",{className:"live-dot "+(Ve?"":"offline")}),Ve?"Supervisor connected":"Reconnecting…"),c.createElement("p",null,"Workers keep moving.",c.createElement("br",null),"Your conversation stays open."),c.createElement("button",{className:"subtle",onClick:()=>{Ee(""),le("connect")}},c.createElement(ec,{size:16})," Connect a project"))),c.createElement("main",{className:"main"},c.createElement("header",{className:"topbar"},c.createElement("div",{className:"breadcrumb"},"Workspace ",c.createElement(bf,{size:14}),c.createElement("strong",null,(D==null?void 0:D.project.name)??"Getting started")),c.createElement("button",{className:"icon-button",title:"Open inbox","aria-label":"Open inbox",onClick:()=>O("Inbox")},c.createElement(Pu,{size:19}),_.length>0&&c.createElement("span",{className:"notification-dot"}))),!Ve&&c.createElement("div",{className:"connection-warning",role:"status"},"Cannot reach the supervisor. Retrying every two seconds. Check the instance token or run"," ",c.createElement("code",null,"node dist/cli.js start"),". Your saved work is retained."),c.createElement("div",{className:"content"},c.createElement("div",{className:"page-heading"},c.createElement("div",null,c.createElement("p",{className:"eyebrow"},"PROJECT CONTROL"),c.createElement("h1",null,U==="Overview"?"Keep the whole project in view.":U),c.createElement("p",{className:"muted"},U==="Overview"?"One lead. Independent workers. A shared direction.":U==="Outcomes"?"Observable outcomes, accountable delegation, and verified completion.":U==="Workstreams"?"Bounded assignments, clear ownership, visible progress.":U==="Inbox"?"Completion updates and questions, saved until you acknowledge them.":U==="Decisions"?"The choices that keep every agent working toward the same outcome.":"Explicit connections. No reliance on the focused terminal.")),D&&c.createElement("button",{className:"primary",disabled:!ne,onClick:()=>{Ee(""),le("assignment")}},c.createElement(ec,{size:17})," New assignment")),_e&&!H&&c.createElement("div",{className:"error",role:"alert"},_e,c.createElement("button",{"aria-label":"Dismiss error",onClick:()=>Ee("")},c.createElement(Hn,{size:16}))),D?c.createElement(c.Fragment,null,c.createElement("section",{className:"lead-strip"},c.createElement("div",{className:"lead-avatar"},c.createElement(zf,{size:19})),c.createElement("div",null,c.createElement("strong",null,((j=D.lead)==null?void 0:j.owner)??"No lead has control yet",(J=D.lead)!=null&&J.agent?` · ${D.lead.agent}`:""),c.createElement("p",null,ne?"This dashboard holds dispatch control.":D.lead?`Control version ${D.lead.epoch} · Workers continue during handover.`:"Acquire control before assigning work.")),c.createElement("div",{className:"lead-actions"},ne?c.createElement(c.Fragment,null,c.createElement("span",{className:"pill green"},"You have control"),c.createElement("button",{onClick:()=>le("handover")},"Hand over ",c.createElement(ql,{size:15}))):c.createElement("button",{onClick:()=>le("lead")},D.lead?"Take control":"Acquire control"," ",c.createElement(ql,{size:15})))),U==="Outcomes"&&c.createElement(xy,{data:D,projectId:M,canEdit:ne,pending:Je,onTask:Y,onAddTask:()=>le("assignment"),onAction:(m,K,G)=>Q(m,{...K,lease:x},G)}),U==="Overview"&&c.createElement(c.Fragment,null,c.createElement("div",{className:"metrics"},[{label:"In progress",value:D.tasks.filter(m=>jm.has(m.status)).length,icon:Ty,color:"blue"},{label:"Needs attention",value:D.tasks.filter(m=>By.has(m.status)).length,icon:Pu,color:"amber"},{label:"Verified complete",value:D.tasks.filter(m=>m.status==="completed").length,icon:qn,color:"green"},{label:"Workstreams",value:new Set(D.tasks.map(m=>m.workstream)).size,icon:Tf,color:"purple"}].map(({label:m,value:K,icon:G,color:xe})=>c.createElement("div",{className:"metric",key:m},c.createElement("span",null,m,c.createElement(G,{size:17,className:xe})),c.createElement("strong",null,K.toString().padStart(2,"0"))))),_.length>0&&c.createElement("section",{className:"attention-card"},c.createElement("div",null,c.createElement(Pu,{size:19}),c.createElement("strong",null,_.length," ",_.length===1?"question needs":"questions need"," your attention")),c.createElement("p",null,_[0].text),c.createElement("button",{onClick:()=>Y(_[0].taskId)},"Review question ",c.createElement(ql,{size:16})))),(U==="Overview"||U==="Workstreams")&&c.createElement("section",{className:"panel"},c.createElement("div",{className:"panel-heading"},c.createElement("div",null,c.createElement("h2",null,U==="Overview"?"Work in motion":"All assignments"),c.createElement("p",null,D.tasks.length," assignments across your project")),c.createElement("input",{className:"search","aria-label":"Filter assignments",placeholder:"Filter assignments…",value:ke,onChange:m=>p(m.target.value)})),D.tasks.length===0?c.createElement("div",{className:"empty-inline"},c.createElement(Tf,{size:28}),c.createElement("h3",null,"Give your first worker a direction"),c.createElement("p",null,"Describe an outcome, assign ownership, and define how completion will be checked."),c.createElement("button",{disabled:!ne,onClick:()=>le("assignment")},"Create an assignment ",c.createElement(ec,{size:15}))):c.createElement("div",{className:"task-table",role:"group","aria-label":"Assignments"},c.createElement("div",{className:"table-labels"},c.createElement("span",null,"ASSIGNMENT"),c.createElement("span",null,"AGENT"),c.createElement("span",null,"STATUS"),c.createElement("span",null,"ATTEMPT")),D.tasks.filter(m=>(m.title+" "+m.workstream+" "+m.status).toLowerCase().includes(ke.toLowerCase())).map(m=>c.createElement("button",{className:"task-row",key:m.id,onClick:()=>Y(m.id)},c.createElement("span",{className:"task-name"},c.createElement("span",{className:"task-symbol "+m.kind},c.createElement(qy,{size:17})),c.createElement("span",null,c.createElement("strong",null,m.title),c.createElement("small",null,m.workstream," ",c.createElement("span",null,"·")," ",Nf(m.id)))),c.createElement("span",{className:"agent-label"},m.kind==="agy"?"AGY":m.kind==="codex"?"Codex":"Claude"),c.createElement("span",null,c.createElement(Ym,{status:m.status})),c.createElement("span",{className:"attempt"},m.attempt," / ",m.maxAttempts,c.createElement(bf,{size:16})))))),U==="Overview"&&c.createElement("div",{className:"bottom-grid"},c.createElement("section",{className:"panel small-panel"},c.createElement("div",{className:"panel-heading"},c.createElement("h2",null,"Latest decisions"),c.createElement("button",{className:"text-button",onClick:()=>O("Decisions")},"View all ",c.createElement(ql,{size:15}))),D.decisions.length?D.decisions.slice(-3).reverse().map(m=>c.createElement("div",{className:"decision-preview",key:m.id},c.createElement(Sf,{size:16}),c.createElement("div",null,c.createElement("strong",null,m.text),c.createElement("small",null,m.owner)))):c.createElement("p",{className:"empty-copy"},"Decisions made by the lead will appear here and travel with every handover.")),c.createElement("section",{className:"panel small-panel handoff-card"},c.createElement("p",{className:"eyebrow"},"PICK UP WHERE YOU LEFT OFF"),c.createElement("h2",null,"Desktop or terminal.",c.createElement("br",null),"The same project state."),c.createElement("p",null,"Take a current briefing into Codex desktop or a lead agent inside Herdr."),c.createElement("button",{onClick:()=>Bm("marionette-briefing.json",D)},c.createElement(Ny,{size:16})," Export briefing"))),U==="Inbox"&&c.createElement("section",{className:"panel"},c.createElement("div",{className:"panel-heading"},c.createElement("h2",null,"Project inbox ",c.createElement("span",{className:"muted"},"(",se.length,")")),c.createElement("div",{className:"button-group"},c.createElement("button",{onClick:async()=>{if("Notification"in window){const m=await Notification.requestPermission();L(m==="granted"?"Desktop alerts enabled while the dashboard is open":"Use the persistent inbox for all updates")}}},c.createElement(Pu,{size:16})," Desktop alerts"),c.createElement("button",{disabled:!se.length,onClick:()=>{var m;return void Q("inbox.ack",{projectId:M,consumer:C,cursor:(m=se.at(-1))==null?void 0:m.id},"Events acknowledged").then(()=>Z([])).catch(()=>{})}},c.createElement(Ay,{size:16})," Mark read"))),c.createElement("p",{className:"inbox-note"},"Events remain available to other consumers. Desktop alerts require this dashboard to be open. MCP inbox updates do not wake an idle Codex conversation."),se.length?se.slice().reverse().map(m=>c.createElement("button",{className:"inbox-event",key:m.id,onClick:()=>m.taskId&&Y(m.taskId)},c.createElement("span",{className:"event-dot "+(m.type.includes("completed")?"green-bg":m.type.includes("question")?"amber-bg":"")}),c.createElement("span",null,c.createElement("strong",null,m.message),c.createElement("small",null,m.type," · ",new Date(m.createdAt).toLocaleString())),c.createElement(bf,{size:16}))):c.createElement("div",{className:"empty-inline"},c.createElement(qn,{size:28}),c.createElement("h3",null,"You’re all caught up"),c.createElement("p",null,"New updates will appear here as workers make progress."))),U==="Decisions"&&c.createElement("section",{className:"panel"},c.createElement("div",{className:"panel-heading"},c.createElement("h2",null,"Project decisions"),c.createElement("button",{disabled:!ne,onClick:()=>le("decision")},c.createElement(ec,{size:16})," Record decision")),D.decisions.length?D.decisions.slice().reverse().map(m=>c.createElement("article",{className:"decision",key:m.id},c.createElement("p",{className:"eyebrow"},m.owner," · ",new Date(m.createdAt).toLocaleDateString()),c.createElement("h3",null,m.text),c.createElement("p",null,m.rationale))):c.createElement("div",{className:"empty-inline"},c.createElement(Sf,{size:28}),c.createElement("h3",null,"A shared source of direction"),c.createElement("p",null,"Record design choices, architecture decisions, and priorities for every agent."))),U==="Connection"&&c.createElement("section",{className:"panel connection-panel"},c.createElement("h2",null,"Connected workspace"),c.createElement("dl",null,[["Project",D.project.name],["Root directory",D.project.root],["Herdr session",D.project.session],["Workspace",D.project.workspaceId],["Socket",D.project.socketPath]].map(([m,K])=>c.createElement("div",{key:m},c.createElement("dt",null,m),c.createElement("dd",null,c.createElement("code",null,K))))),c.createElement("button",{onClick:()=>void Q("project.inspect",{projectId:M},"Herdr workspace connection verified").catch(()=>{})},c.createElement(xm,{size:16})," Check connection"),c.createElement("hr",null),c.createElement("h3",null,"Continue in Herdr"),c.createElement("p",null,"Attach to this named session:"),c.createElement("pre",null,"herdr --session ",D.project.session),c.createElement("p",null,"Configure the Marionette MCP server for your terminal lead, then acquire control with a fresh briefing. A handover lease can also be supplied to the CLI."),c.createElement("p",{className:"muted"},"Marionette never closes an existing session or uses the UI-focused pane as an implicit target."))):c.createElement("section",{className:"empty-state"},c.createElement(My,{size:32}),c.createElement("h2",null,"Connect your first workspace"),c.createElement("p",null,"Choose a project folder, Herdr session, and workspace. Marionette will operate only within that explicit connection."),c.createElement("button",{className:"primary",onClick:()=>le("connect")},"Connect workspace ",c.createElement(ql,{size:17}))),c.createElement("footer",null,"MARIONETTE ",c.createElement("span",null,"Local orchestration · Durable project state")))),d&&c.createElement("div",{className:"drawer-backdrop",onClick:()=>Y(null)},c.createElement("aside",{className:"task-drawer",role:"dialog","aria-modal":"true","aria-label":"Task details",onClick:m=>m.stopPropagation()},c.createElement("header",null,c.createElement("p",{className:"eyebrow"},d.workstream," / ",Nf(d.id)),c.createElement("button",{className:"icon-button","aria-label":"Close task details",onClick:()=>Y(null)},c.createElement(Hn,{size:21}))),c.createElement("h2",null,d.title),c.createElement("div",{className:"detail-meta"},c.createElement(Ym,{status:d.status}),c.createElement("span",null,d.kind,d.model?` · ${d.model}`:" · Runtime default (exact model unreported)"," · Revision ",d.revision," · Attempt ",d.attempt)),d.error&&c.createElement("div",{className:"error"},d.error),d.waitReason&&c.createElement("p",{className:"inbox-note"},d.waitReason),c.createElement("div",{className:"task-controls"},c.createElement("button",{disabled:!ne||["completed","cancelled","failed","uncertain"].includes(d.status),onClick:()=>le("redirect")},c.createElement(Uy,{size:15})," Redirect"),c.createElement("button",{disabled:!ne||!(jm.has(d.status)||d.status==="queued"),onClick:()=>void me("pause").catch(()=>{})},c.createElement(Cy,{size:15})," Pause"),c.createElement("button",{disabled:!ne||!["blocked","paused"].includes(d.status),onClick:()=>le("reply")},c.createElement(_y,{size:15})," Continue"),c.createElement("button",{disabled:!ne||["completed","cancelled","failed","uncertain"].includes(d.status),onClick:()=>void me("cancel").catch(()=>{})},c.createElement(Hn,{size:15})," Cancel"),["failed","cancelled"].includes(d.status)&&c.createElement("button",{disabled:!ne||d.attempt>=d.maxAttempts,onClick:()=>void Q("task.retry",{lease:x,taskId:d.id,key:crypto.randomUUID()},"Retry queued").catch(()=>{})},c.createElement(xm,{size:15})," Retry"),d.status==="uncertain"&&c.createElement("button",{disabled:!ne,onClick:()=>le("reconcile")},"Reconcile delivery")),_.filter(m=>m.taskId===d.id).map(m=>c.createElement("section",{className:"question",key:m.id},c.createElement("p",{className:"eyebrow"},m.native?"AGENT INPUT REQUIRED":"PENDING QUESTION"),c.createElement("p",null,m.text),c.createElement("button",{disabled:!ne,onClick:()=>le(m.native?"keys":"reply")},m.native?"Send explicit keys":"Answer question"," ",c.createElement(ql,{size:15})),m.native&&c.createElement("button",{disabled:!ne,onClick:()=>le("reply")},"Continue after resolving in Herdr"))),c.createElement("section",null,c.createElement("h3",null,"Assignment"),c.createElement("p",{className:"preserve"},d.prompt),c.createElement("h4",null,"Execution"),c.createElement("p",null,((te=d.execution)==null?void 0:te.mode)==="worktree"?"Isolated Git worktree":"Shared working directory"),c.createElement("p",{className:"preserve"},d.cwd),d.worktree?c.createElement(c.Fragment,null,c.createElement("p",{className:"preserve"},"Branch: ",d.worktree.branch),c.createElement("p",{className:"preserve"},"Base commit: ",d.worktree.baseCommit),c.createElement("p",{className:"preserve"},"Worktree (",d.worktree.state,"): ",d.worktree.path),c.createElement("p",{className:"muted"},"Available for your review, merge, or pull request workflow.")):null,c.createElement("h4",null,"Ownership"),c.createElement("div",{className:"chips"},d.ownership.map(m=>c.createElement("code",{key:m},m))),d.dependencies.length>0&&c.createElement(c.Fragment,null,c.createElement("h4",null,"Dependencies"),d.dependencies.map(m=>{var K;return c.createElement("button",{key:m,className:"text-button",onClick:()=>Y(m)},((K=D==null?void 0:D.tasks.find(G=>G.id===m))==null?void 0:K.title)??Nf(m))}))),c.createElement("section",null,c.createElement("h3",null,"Worker output ",c.createElement("span",{className:"live-label"},"LIVE")),c.createElement("pre",{className:"terminal-output"},d.output||"Output will appear after the worker starts.")),c.createElement(jy,{key:d.id,taskId:d.id,canEdit:ne,pending:Je,onAction:(m,K)=>Q(m,{...K,lease:x},m==="cleanup.preview"?"Cleanup eligibility refreshed":"Cleanup state saved")}),d.receipt&&c.createElement("section",null,c.createElement("h3",null,"Completion report"),c.createElement("p",null,d.receipt.summary),c.createElement("h4",null,"Artifacts"),d.receipt.artifacts.map(m=>c.createElement("div",{className:"artifact",key:m},c.createElement(qn,{size:15}),c.createElement("code",null,m))),d.receipt.evidence.map((m,K)=>c.createElement("p",{key:K,className:"preserve"},m))),c.createElement("section",null,c.createElement("h3",null,"Verification"),(oe=d.verification)!=null&&oe.length?d.verification.map((m,K)=>c.createElement("div",{className:"verification "+(m.passed?"pass":"fail"),key:K},c.createElement("strong",null,m.passed?"Passed":"Failed"),c.createElement("pre",null,m.detail))):c.createElement(c.Fragment,null,c.createElement("p",{className:"muted"},"Completion requires a current worker report and independent checks."),c.createElement("pre",null,tc(d.checks)))))),H&&c.createElement("div",{className:"modal-backdrop"},c.createElement("section",{className:"modal",role:"dialog","aria-modal":"true","aria-labelledby":"modal-title"},c.createElement("header",null,c.createElement("h2",{id:"modal-title"},{connect:"Connect a project",lead:D!=null&&D.lead?"Take over control":"Acquire control",handover:"Hand over control",assignment:"New assignment",decision:"Record a decision",redirect:"Redirect this worker",reply:"Continue this assignment",keys:"Resolve agent input",reconcile:"Reconcile uncertain delivery"}[H]),c.createElement("button",{className:"icon-button","aria-label":"Close dialog",onClick:()=>{le(null),Ee("")}},c.createElement(Hn,{size:21}))),c.createElement("form",{onSubmit:o},H==="connect"&&c.createElement(c.Fragment,null,c.createElement("p",null,"Connect to an existing Herdr workspace. No sessions or agents will be closed."),c.createElement(dt,{label:"Project name",name:"name"}),c.createElement(dt,{label:"Absolute project directory",name:"root",placeholder:"/Users/you/Code/project"}),c.createElement(dt,{label:"Herdr session name",name:"session",placeholder:"project-work"}),c.createElement(dt,{label:"Absolute Herdr socket path",name:"socket",placeholder:"/Users/you/.config/herdr/sessions/project-work/herdr.sock"}),c.createElement("div",{className:"form-grid"},c.createElement(dt,{label:"Workspace ID",name:"workspace",placeholder:"w1"}),c.createElement(dt,{label:"Concurrent workers",name:"concurrency",type:"number",defaultValue:"3"}))),(H==="lead"||H==="handover")&&c.createElement(c.Fragment,null,c.createElement("p",null,H==="handover"?"The current lease will become invalid. A private lease file for the receiving lead will download with the handover.":D!=null&&D.lead?`This explicitly replaces ${D.lead.owner}. Their existing lease will stop authorizing dispatch. Workers continue running.`:"Choose an identity for the lead controlling this project."),c.createElement(dt,{label:H==="handover"?"Receiving lead identity":"Your lead identity",name:"owner",defaultValue:H==="lead"?"dashboard":"",placeholder:"terminal-lead"}),c.createElement("label",null,"Lead agent",c.createElement("select",{name:"leadAgent",defaultValue:((We=D==null?void 0:D.lead)==null?void 0:We.agent)??"codex-desktop"},c.createElement("option",{value:"codex-desktop"},"Codex desktop"),c.createElement("option",{value:"codex"},"Codex CLI"),c.createElement("option",{value:"claude"},"Claude Code"),c.createElement("option",{value:"agy"},"AGY"))),c.createElement(dt,{label:"Reason for this change",name:"reason"})),H==="assignment"&&c.createElement(c.Fragment,null,c.createElement(dt,{label:"Title",name:"title",placeholder:"Build the settings screen"}),c.createElement("label",null,"Outcome",c.createElement("select",{name:"outcomeId"},c.createElement("option",{value:""},"Create an outcome from this assignment's checks"),D.outcomes.map(m=>c.createElement("option",{key:m.id,value:m.id},m.objective.slice(0,120))))),c.createElement("label",null,"Responsible parent",c.createElement("select",{name:"parentId"},c.createElement("option",{value:""},"Root lead"),D.tasks.filter(m=>m.canDelegate).map(m=>c.createElement("option",{key:m.id,value:m.id},m.title)))),c.createElement("label",null,"Exact model profile",c.createElement("select",{name:"profileId"},c.createElement("option",{value:""},"Use selected runtime configuration"),D.profiles.map(m=>c.createElement("option",{key:m.id,value:m.id,disabled:m.availability!=="available"},m.name," · ",m.model," (",m.availability,")")))),c.createElement("label",{className:"checkbox"},c.createElement("input",{type:"checkbox",name:"canDelegate"})," Allow this worker to coordinate children within its scope and shared budget"),c.createElement("div",{className:"form-grid"},c.createElement(dt,{label:"Workstream",name:"workstream",defaultValue:"Product"}),c.createElement("label",null,"Specialist",c.createElement("select",{name:"kind"},c.createElement("option",{value:"codex"},"Codex"),c.createElement("option",{value:"claude"},"Claude"),c.createElement("option",{value:"agy"},"AGY")))),c.createElement("label",null,"Objective and acceptance criteria",c.createElement("textarea",{name:"prompt",required:!0,rows:5,placeholder:"Describe the outcome and constraints…"})),c.createElement(dt,{label:"Owned paths (comma-separated files or directories)",name:"ownership",placeholder:"src/settings, tests/settings"}),c.createElement(Gy,null),c.createElement("label",null,"Verification checks (JSON)",c.createElement("textarea",{className:"code-input",name:"checks",rows:5,required:!0,defaultValue:tc([{type:"file",path:"src/settings.ts"},{type:"command",command:"npm",args:["test"],timeoutMs:3e4}])})),D.tasks.length>0&&c.createElement("fieldset",null,c.createElement("legend",null,"Wait for these assignments"),D.tasks.map(m=>c.createElement("label",{className:"checkbox",key:m.id},c.createElement("input",{type:"checkbox",name:"dependency",value:m.id}),m.title))),c.createElement("p",{className:"muted"},"Submission returns immediately. Overlapping paths in a shared directory wait. Separate worktrees can edit the same repository files concurrently. Dependencies and the worker limit still apply.")),H==="decision"&&c.createElement(c.Fragment,null,c.createElement("label",null,"Decision",c.createElement("textarea",{name:"text",required:!0,rows:3})),c.createElement(dt,{label:"Rationale",name:"reason"})),(H==="redirect"||H==="reply")&&c.createElement(c.Fragment,null,c.createElement("p",null,H==="redirect"?"The worker will be interrupted. These instructions replace its objective and invalidate earlier completion reports. Existing verification checks are retained.":"Your answer will be saved and sent with the current assignment. The worker must submit a fresh report."),c.createElement("label",null,H==="redirect"?"Replacement objective":"Answer or continuation instructions",c.createElement("textarea",{name:"text",required:!0,rows:6,defaultValue:H==="redirect"?d==null?void 0:d.prompt:""}))),H==="keys"&&c.createElement(c.Fragment,null,c.createElement("p",null,"Inspect the worker output first. Enter only the keys needed for the specific visible prompt. This does not automatically approve future actions."),c.createElement(dt,{label:"Keys, separated by spaces",name:"keys",placeholder:"enter"})),H==="reconcile"&&c.createElement(c.Fragment,null,c.createElement("p",null,"Use this only after inspecting the original worker. An uncertain request is never automatically replayed."),c.createElement("label",null,"Observed delivery",c.createElement("select",{name:"resolution"},c.createElement("option",{value:"delivered"},"The instructions were delivered"),c.createElement("option",{value:"not-delivered"},"Not delivered; worker is stopped"))),c.createElement(dt,{label:"Evidence and reason",name:"reason"})),_e&&c.createElement("div",{className:"error",role:"alert"},_e),c.createElement("div",{className:"modal-actions"},c.createElement("button",{type:"button",onClick:()=>le(null)},"Cancel"),c.createElement("button",{className:"primary",disabled:Je},Je?"Saving…":H==="assignment"?"Queue assignment":H==="handover"?"Transfer and download lease":"Confirm",c.createElement(ql,{size:16})))))),Te&&c.createElement("div",{className:"toast",role:"status"},c.createElement(qn,{size:18}),c.createElement("span",null,Te),c.createElement("button",{"aria-label":"Dismiss notification",onClick:()=>L("")},c.createElement(Hn,{size:16})))):c.createElement("main",{className:"welcome"},c.createElement("div",{className:"brand-mark"},c.createElement(zf,{size:26})),c.createElement("p",{className:"eyebrow"},"MARIONETTE"),c.createElement("h1",null,"Your project,",c.createElement("br",null),"working together."),c.createElement("p",null,"Open the local access link printed by ",c.createElement("code",null,"node dist/cli.js dashboard"),", or enter your instance token below."),c.createElement("form",{onSubmit:m=>{m.preventDefault();const K=new FormData(m.currentTarget).get("token");sessionStorage.setItem("marionette-token",K),k(K)}},c.createElement("label",null,"Instance token",c.createElement("input",{type:"password",name:"token",required:!0,autoComplete:"off"})),c.createElement("button",{className:"primary"},"Connect ",c.createElement(ql,{size:16}))))}function Gy(){const[b,k]=P.useState("shared");return c.createElement(c.Fragment,null,c.createElement("label",null,"Working environment",c.createElement("select",{name:"execution",value:b,onChange:q=>k(q.target.value)},c.createElement("option",{value:"shared"},"Shared directory"),c.createElement("option",{value:"worktree"},"Isolated Git worktree"))),b==="worktree"?c.createElement(c.Fragment,null,c.createElement("label",null,"Base branch or commit (optional)",c.createElement("input",{name:"baseRef",placeholder:"HEAD"})),c.createElement("p",{className:"muted"},"Marionette creates a branch and worktree from committed history. Uncommitted source changes are not copied. The result remains available for review, merge, or a pull request.")):null)}function dt({label:b,...k}){return c.createElement("label",null,b,c.createElement("input",{required:!0,...k}))}function Ym({status:b}){return c.createElement("span",{className:"status status-"+b},c.createElement("span",null),b.replaceAll("_"," "))}py.createRoot(document.getElementById("root")).render(c.createElement(Yy,null));
|
|
167
|
+
`).map(k=>k.trim()).filter(Boolean),Qm=b=>b.replaceAll("-"," ");function Xm({task:b,tasks:k,onTask:q}){var M;const y=k.filter(W=>W.parentId===b.id);return c.createElement("button",{className:"outcome-task",onClick:()=>q(b.id)},c.createElement("span",{className:`status status-${b.status}`},Qm(b.status)),c.createElement("strong",null,b.title),c.createElement("span",null,b.kind," · ",b.model??"Configured runtime default; exact model unreported"),b.reasoning&&c.createElement("span",null,"Reasoning: ",b.reasoning),c.createElement("span",null,y.length," direct children · ",b.dependencies.length," dependencies"),b.required===!1&&c.createElement("span",null,"Explicitly removed from required work"),b.supersededBy&&c.createElement("span",null,"Superseded by ",((M=k.find(W=>W.id===b.supersededBy))==null?void 0:M.title)??b.supersededBy),(b.waitReason||b.error)&&c.createElement("span",{className:"board-warning"},b.waitReason??b.error),b.receipt&&c.createElement("span",null,b.receipt.summary))}function Zm({tasks:b,parentId:k,onTask:q,depth:y=0}){return y>7?c.createElement("p",null,"Invalid task tree: inspect the current records."):c.createElement("ul",{className:"outcome-tree"},b.filter(M=>M.parentId===k).map(M=>c.createElement("li",{key:M.id},c.createElement(Xm,{task:M,tasks:b,onTask:q}),b.some(W=>W.parentId===M.id)&&c.createElement(Zm,{tasks:b,parentId:M.id,onTask:q,depth:y+1}))))}function xy({data:b,projectId:k,canEdit:q,pending:y,onTask:M,onAddTask:W,onAction:D}){var L,ke;const[De,U]=P.useState("Board"),[O,$]=P.useState(""),[Y,H]=P.useState(!1),[le,_e]=P.useState(1),[Ee,Ve]=P.useState("all"),[qe,Je]=P.useState(""),Ue=b.profiles.filter(p=>(Ee==="all"||p.kind===Ee)&&`${p.name} ${p.model}`.toLowerCase().includes(qe.toLowerCase())),x=b.outcomes.find(p=>p.id===O)??b.outcomes[0],He=x?b.tasks.filter(p=>p.outcomeId===x.id):b.tasks,se=x?b.revisions.filter(p=>p.outcomeId===x.id):[],Z=(p,C,ae)=>D(p,C,ae).catch(()=>{}),Te=x?{outcomeId:x.id,expectedRevision:x.revision}:{};return c.createElement("div",{className:"outcome-board"},c.createElement("section",{className:"panel outcome-toolbar"},c.createElement("div",null,c.createElement("h2",null,"Outcomes and definitions of done"),c.createElement("p",null,"Understand what remains, who owns it, and the evidence required to finish.")),c.createElement("div",{className:"outcome-actions"},c.createElement("button",{disabled:!q||y,onClick:()=>H(!Y)},Y?"Close outcome form":"New outcome"),c.createElement("button",{disabled:!q||y,onClick:W},"Add task")),b.outcomes.length>0&&c.createElement("label",null,"Outcome",c.createElement("select",{"aria-label":"Select outcome",value:(x==null?void 0:x.id)??"",onChange:p=>$(p.target.value)},b.outcomes.map(p=>c.createElement("option",{key:p.id,value:p.id},p.status==="completed"?"✓ ":"",p.objective.slice(0,140))))),c.createElement("div",{className:"outcome-view-options",role:"group","aria-label":"Task board view"},["Board","Task tree","Dependencies"].map(p=>c.createElement("button",{key:p,"aria-pressed":De===p,onClick:()=>U(p)},p)))),Y&&c.createElement("section",{className:"panel outcome-section"},c.createElement("h3",null,"Define an observable result"),c.createElement("form",{onSubmit:async p=>{p.preventDefault();const C=new FormData(p.currentTarget),ae=Array.from({length:le},(ne,d)=>({id:`criterion-${d+1}`,description:String(C.get(`criterion-${d}`)),requiredEvidence:String(C.get(`evidence-${d}`))})),Oe=await Z("outcome.create",{outcome:{projectId:k,key:crypto.randomUUID(),objective:String(C.get("objective")),scope:Af(C.get("scope")),category:String(C.get("category")),criteria:ae,maxTurns:Number(C.get("maxTurns")),maxDepth:Number(C.get("maxDepth"))}},"Outcome and completion criteria saved");Oe&&($(Oe.id),H(!1))}},c.createElement("label",null,"Objective",c.createElement("textarea",{name:"objective",required:!0,rows:3,placeholder:"What must be true when this work is complete?"})),c.createElement("div",{className:"form-grid"},c.createElement("label",null,"Work category",c.createElement("select",{name:"category"},c.createElement("option",{value:"software"},"Software"),c.createElement("option",{value:"research"},"Research"),c.createElement("option",{value:"analysis"},"Analysis"),c.createElement("option",{value:"decision"},"Collaborative decision"))),c.createElement("label",null,"Owned paths, one per line",c.createElement("textarea",{name:"scope",required:!0,defaultValue:".",rows:2}))),Array.from({length:le},(p,C)=>c.createElement("fieldset",{key:C},c.createElement("legend",null,"Completion criterion ",C+1),c.createElement("label",null,"Observable requirement",c.createElement("input",{name:`criterion-${C}`,required:!0})),c.createElement("label",null,"Evidence needed",c.createElement("input",{name:`evidence-${C}`,required:!0,placeholder:"Test results, corroborated sources, or a recorded decision"})))),c.createElement("button",{type:"button",onClick:()=>_e(p=>Math.min(20,p+1)),disabled:le>=20},"Add criterion"),c.createElement("div",{className:"form-grid"},c.createElement("label",null,"Shared execution turn budget",c.createElement("input",{name:"maxTurns",type:"number",min:"1",max:"1000",defaultValue:"60",required:!0})),c.createElement("label",null,"Maximum delegation depth",c.createElement("input",{name:"maxDepth",type:"number",min:"0",max:"6",defaultValue:"3",required:!0}))),c.createElement("button",{disabled:y||!q},"Save outcome"))),x?c.createElement(c.Fragment,null,c.createElement("section",{key:`${x.id}:${x.revision}`,className:"panel outcome-section"},c.createElement("div",{className:"outcome-title"},c.createElement("h3",null,x.objective),c.createElement("span",{className:`status status-${x.status}`},x.status)),c.createElement("p",null,"Responsible lead: ",c.createElement("strong",null,x.leadOwner)," · Revision ",x.revision," ·"," ",x.turnsUsed," / ",x.maxTurns," shared turns"),c.createElement("p",null,"Scope: ",x.scope.join(", ")," · Delegation depth limit: ",x.maxDepth),c.createElement("ul",{className:"criteria-list"},x.criteria.map(p=>{const C=x.assessments.find(ae=>ae.criterionId===p.id&&ae.revision===x.revision);return c.createElement("li",{key:p.id},c.createElement("strong",null,p.description),c.createElement("p",null,"Required evidence: ",p.requiredEvidence),C&&c.createElement("p",null,"Reviewed by ",C.owner,": ",C.rationale,c.createElement("br",null),"Evidence: ",C.references.map(ae=>ae.path).join(", ")),c.createElement("details",null,c.createElement("summary",null,"Evaluate this criterion"),c.createElement("form",{onSubmit:ae=>{ae.preventDefault();const Oe=new FormData(ae.currentTarget);Z("outcome.assess",{...Te,criterionId:p.id,rationale:String(Oe.get("rationale")),references:Af(Oe.get("references"))},"Criterion evidence recorded")}},c.createElement("label",null,"Independent evaluation",c.createElement("textarea",{name:"rationale",required:!0,rows:2})),c.createElement("label",null,"Evidence files in this project, one per line",c.createElement("textarea",{name:"references",required:!0,rows:2})),c.createElement("button",{disabled:!q||y},"Record evaluation"))))})),c.createElement("details",null,c.createElement("summary",null,"Revise completion criteria"),c.createElement("form",{key:x.revision,onSubmit:p=>{p.preventDefault();const C=new FormData(p.currentTarget),ae=x.criteria.map((Oe,ne)=>({...Oe,description:String(C.get(`description-${ne}`)),requiredEvidence:String(C.get(`required-${ne}`))}));Z("outcome.revise",{...Te,criteria:ae,reason:String(C.get("reason"))},"Criteria revised; previous evidence retained in history")}},x.criteria.map((p,C)=>c.createElement("fieldset",{key:p.id},c.createElement("legend",null,p.id),c.createElement("label",null,"Requirement",c.createElement("input",{name:`description-${C}`,defaultValue:p.description,required:!0})),c.createElement("label",null,"Required evidence",c.createElement("input",{name:`required-${C}`,defaultValue:p.requiredEvidence,required:!0})))),c.createElement("label",null,"Why did the completion contract change?",c.createElement("textarea",{name:"reason",required:!0,rows:2})),c.createElement("button",{disabled:!q||y},"Save criteria revision"))),c.createElement("details",null,c.createElement("summary",null,"Review the integrated result"),c.createElement("form",{onSubmit:p=>{p.preventDefault();const C=new FormData(p.currentTarget);Z("outcome.integrate",{...Te,summary:String(C.get("summary")),references:Af(C.get("references"))},"Integrated result reviewed")}},c.createElement("label",null,"Integrated evaluation",c.createElement("textarea",{name:"summary",required:!0,rows:3,defaultValue:(L=x.integrated)==null?void 0:L.summary})),c.createElement("label",null,"Integration evidence files, one per line",c.createElement("textarea",{name:"references",required:!0,rows:2})),c.createElement("button",{disabled:!q||y},"Record integrated review"))),x.unmet.length>0?c.createElement("div",{className:"outcome-unmet"},c.createElement("strong",null,"What remains before completion"),c.createElement("ul",null,x.unmet.map((p,C)=>c.createElement("li",{key:C},p)))):c.createElement("p",{className:"board-success"},"All required work and current acceptance evidence pass."),c.createElement("button",{disabled:!q||y||x.status==="completed"||x.unmet.length>0,onClick:()=>void Z("outcome.complete",Te,"Outcome verified complete")},"Verify outcome complete")),De==="Board"&&c.createElement("section",{className:"outcome-columns","aria-label":"Outcome task board"},[{name:"Queued",statuses:["queued","preparing"]},{name:"In progress",statuses:["running","verifying","redirecting","cancelling"]},{name:"Waiting",statuses:["waiting","yielding","paused"]},{name:"Needs attention",statuses:["failed","blocked","uncertain","cancelled"]},{name:"Verified",statuses:["completed"]}].map(p=>c.createElement("div",{className:"outcome-column",key:p.name},c.createElement("h3",null,p.name," ",c.createElement("span",null,He.filter(C=>p.statuses.includes(C.status)).length)),He.filter(C=>p.statuses.includes(C.status)).map(C=>c.createElement(Xm,{key:C.id,task:C,tasks:He,onTask:M}))))),De==="Task tree"&&c.createElement("section",{className:"panel outcome-section","aria-label":"Outcome task tree"},c.createElement("h3",null,"Parent accountability and delegated work"),c.createElement(Zm,{tasks:He,onTask:M})),De==="Dependencies"&&c.createElement("section",{className:"panel outcome-section","aria-label":"Outcome dependencies"},c.createElement("h3",null,"Dependencies and verification order"),c.createElement("ul",{className:"dependency-list"},He.map(p=>c.createElement("li",{key:p.id},c.createElement("button",{onClick:()=>M(p.id)},p.title),c.createElement("span",null,p.dependencies.length?" waits for ":" has no dependencies"),p.dependencies.map(C=>{var ae,Oe;return c.createElement("button",{key:C,onClick:()=>M(C)},((ae=b.tasks.find(ne=>ne.id===C))==null?void 0:ae.title)??C," (",((Oe=b.tasks.find(ne=>ne.id===C))==null?void 0:Oe.status)??"missing",")")}))))),c.createElement("section",{className:"panel outcome-section"},c.createElement("h3",null,"Findings and plan revisions"),(ke=b.findings)==null?void 0:ke.filter(p=>p.outcomeId===x.id).map(p=>c.createElement("article",{key:p.id},c.createElement("strong",null,p.summary),c.createElement("p",null,p.evidence.join(", ")))),se.length?c.createElement("ol",{className:"revision-list"},[...se].reverse().map(p=>c.createElement("li",{key:p.id},c.createElement("strong",null,"Revision ",p.revision," · ",p.reason),c.createElement("p",null,p.owner," · ",new Date(p.createdAt).toLocaleString()),p.evidence.length>0&&c.createElement("p",null,"Finding references: ",p.evidence.join(", ")),c.createElement(Hy,{id:p.id,onAction:D})))):c.createElement("p",null,"No plan revisions yet.")),b.strategies.filter(p=>p.outcomeId===x.id).map(p=>{var C;return c.createElement("section",{className:"panel outcome-section",key:p.id},c.createElement("h3",null,Qm(p.kind)," · ",p.status),c.createElement("p",null,"Round ",p.round," / ",p.maxRounds," · Stop when:"," ",p.stopCondition),c.createElement("p",null,"Evaluate against: ",p.criteria),c.createElement("p",null,p.synthesis),(C=p.disagreements)!=null&&C.length?c.createElement("ul",null,p.disagreements.map((ae,Oe)=>c.createElement("li",{key:Oe},ae))):null)})):c.createElement("section",{className:"panel outcome-section"},c.createElement("h3",null,"No outcomes yet"),c.createElement("p",null,"Create an outcome with observable completion criteria, then assign bounded work to agents.")),c.createElement("section",{className:"panel outcome-section"},c.createElement("h3",null,"Capacity and continuation"),c.createElement("p",null,"Global slots: ",b.limits.global," · Project slots: ",b.limits.project," · Coordination turns delivered: ",b.coordination.turns),b.waits.filter(p=>!x||p.outcomeId===x.id).map(p=>{var C;return c.createElement("div",{className:"wait-card",key:p.id},c.createElement("strong",null,p.owner,": ",p.state),c.createElement("p",null,p.adapter.type==="herdr"?"Automatic continuation in the pinned Herdr session":"Continuation on the next user message"),p.error&&c.createElement("p",{className:"board-warning"},p.error),c.createElement("p",null,p.condition.tasks.length," required results · ",((C=p.eventIds)==null?void 0:C.length)??0," ","grouped events"))}),c.createElement("p",{className:"muted"},b.coordination.metricBoundary),b.coordination.usage.map(p=>c.createElement("p",{key:p.id},"Cache read: ",p.cacheReadTokens??"unavailable"," · Cache write:"," ",p.cacheWriteTokens??"unavailable"," · Uncached input:"," ",p.uncachedInputTokens??"unavailable"," · Cost:"," ",p.costUsd===null?"unavailable":`$${p.costUsd.toFixed(4)}`,c.createElement("br",null),"Source: ",p.source)),c.createElement("details",null,c.createElement("summary",null,"Configure shared execution limits"),c.createElement("form",{onSubmit:p=>{p.preventDefault();const C=new FormData(p.currentTarget);Z("limits.configure",{limits:{...b.limits,global:Number(C.get("global")),project:Number(C.get("project"))},reason:String(C.get("reason"))},"Shared limits updated")}},c.createElement("div",{className:"form-grid"},c.createElement("label",null,"Global slots",c.createElement("input",{name:"global",type:"number",min:"1",max:"32",defaultValue:b.limits.global,required:!0})),c.createElement("label",null,"Project slots",c.createElement("input",{name:"project",type:"number",min:"1",max:"8",defaultValue:b.limits.project,required:!0}))),c.createElement("label",null,"Reason",c.createElement("input",{name:"reason",required:!0})),c.createElement("button",{disabled:!q||y},"Save limits")))),c.createElement("section",{className:"panel outcome-section"},c.createElement("h3",null,"Model and capability profiles"),c.createElement("p",null,b.profiles.length," profiles. Discovery reads native catalogs; validation tests the exact selection."),c.createElement("div",{className:"outcome-actions"},c.createElement("label",null,"Runtime",c.createElement("select",{"aria-label":"Filter model runtime",value:Ee,onChange:p=>Ve(p.target.value)},c.createElement("option",{value:"all"},"All runtimes"),c.createElement("option",{value:"codex"},"Codex"),c.createElement("option",{value:"claude"},"Claude"),c.createElement("option",{value:"agy"},"AGY"))),c.createElement("label",null,"Find a model",c.createElement("input",{"aria-label":"Find a model",value:qe,onChange:p=>Je(p.target.value)})),["codex","claude","agy"].map(p=>c.createElement("button",{key:p,disabled:!q||y,onClick:()=>void Z("profile.discover",{kind:p},`${p} catalog refreshed`)},"Discover ",p," models"))),Ue.map(p=>c.createElement("div",{className:"profile-card",key:p.id},c.createElement("strong",null,p.name),c.createElement("p",null,p.kind," · ",p.model," · ",p.reasoning??"Default effort"," ·"," ",p.availability),c.createElement("p",null,"Supported effort:"," ",p.supportedReasoning.join(", ")||"No separate effort control"," · Categories:"," ",p.categories.join(", ")),c.createElement("p",null,p.strengths),c.createElement("p",null,p.availabilityEvidence),c.createElement("button",{disabled:!q||y,onClick:()=>void Z("profile.validate",{profileId:p.id},"Model availability probe finished")},"Validate exact model")))))}function jy({taskId:b,canEdit:k,pending:q,onAction:y}){var Te;const[M,W]=P.useState(),[D,De]=P.useState(""),[U,O]=P.useState(""),[$,Y]=P.useState("merged"),[H,le]=P.useState("refs/heads/main"),[_e,Ee]=P.useState(!1),[Ve,qe]=P.useState(""),[Je,Ue]=P.useState(!0),[x,He]=P.useState(!1),se=async(L,ke={})=>{De("");try{const p=await y(L,{taskId:b,reason:U,...ke}),C=L==="cleanup.preview"?p:await y("cleanup.preview",{taskId:b});W(C),Ue(C.policy.autoRelease),qe(C.policy.collectAfterHours===null?"":String(C.policy.collectAfterHours)),He(C.policy.deleteMergedBranches)}catch(p){De(String(p))}},Z=!k||q||!U.trim();return c.createElement("section",null,c.createElement("h3",null,"Delivery and cleanup"),c.createElement("p",null,"Completion keeps branches and worktrees. Release terminals after consuming results, then record delivery and preserve evidence before collection."),c.createElement("button",{disabled:q,onClick:()=>void se("cleanup.preview")},"Inspect cleanup eligibility"),D?c.createElement("p",{role:"alert"},D):null,M?c.createElement(c.Fragment,null,c.createElement("label",null,"Reason for cleanup or policy change",c.createElement("input",{value:U,onChange:L=>O(L.target.value)})),M.runs.map(L=>{var ke,p,C,ae;return c.createElement("div",{key:L.runId},c.createElement("p",null,"Worker ",L.paneId??L.tabId??L.runId,": ",((ke=L.cleanup)==null?void 0:ke.state)??"retained"),L.reasons.map((Oe,ne)=>c.createElement("p",{className:"muted",key:ne},Oe)),(p=L.cleanup)!=null&&p.error?c.createElement("p",null,L.cleanup.error):null,((C=L.cleanup)==null?void 0:C.state)==="uncertain"?c.createElement(c.Fragment,null,c.createElement("button",{disabled:Z,onClick:()=>void se("cleanup.reconcile",{runId:L.runId,resolution:"closed"})},"Confirm original worker terminal is absent"),c.createElement("button",{disabled:Z,onClick:()=>void se("cleanup.reconcile",{runId:L.runId,resolution:"not-closed"})},"Confirm original worker remains")):((ae=L.cleanup)==null?void 0:ae.state)!=="closed"?c.createElement("button",{disabled:Z,onClick:()=>void se("cleanup.release",{runId:L.runId})},"Result inspected · release worker terminal"):null)}),M.collectionReasons.map((L,ke)=>c.createElement("p",{className:"muted",key:ke},L)),M.delivery?c.createElement("p",null,"Delivery: ",M.delivery.disposition," · ",M.delivery.head):null,M.archive?c.createElement(c.Fragment,null,c.createElement("p",null,"Archive: ",M.archive.phase," · ",M.archive.id),M.archive.error?c.createElement("p",{role:"alert"},M.archive.error):null,M.archive.phase!=="collected"||!M.archive.branchDeleted?c.createElement(c.Fragment,null,c.createElement("label",{className:"checkbox"},c.createElement("input",{type:"checkbox",checked:_e,onChange:L=>Ee(L.target.checked)})," ","Also delete the merged or explicitly abandoned local branch"),c.createElement("button",{disabled:Z,onClick:()=>void se("cleanup.collect",{archiveId:M.archive.id,deleteBranch:_e})},M.archive.phase==="collected"?"Collect retained branch":"Remove archived worktree")):null):null,(Te=M.archive)!=null&&Te.branchDeleted?null:c.createElement(c.Fragment,null,c.createElement("label",null,"Delivery decision",c.createElement("select",{value:$,onChange:L=>Y(L.target.value)},c.createElement("option",{value:"merged"},"Merged into target"),c.createElement("option",{value:"published"},"Published for review"),c.createElement("option",{value:"abandoned"},"Explicitly abandoned"))),$!=="abandoned"?c.createElement("label",null,"Verified target ref",c.createElement("input",{value:H,onChange:L=>le(L.target.value),placeholder:"refs/remotes/origin/main"})):null,c.createElement("button",{disabled:Z,onClick:()=>void se("cleanup.deliver",{disposition:$,...$!=="abandoned"?{targetRef:H}:{}})},"Record delivery decision"),M.archive?null:c.createElement("button",{disabled:Z||!M.delivery,onClick:()=>void se("cleanup.archive")},"Preserve evidence and seal finished tasks")),c.createElement("details",null,c.createElement("summary",null,"Project retention policy"),c.createElement("p",null,"Only enable collection when the user has authorized this retention policy. Blank retention keeps worktrees until an explicit collection request. Failed or abandoned work is never collected automatically."),c.createElement("label",{className:"checkbox"},c.createElement("input",{type:"checkbox",checked:Je,onChange:L=>Ue(L.target.checked)})," ","Automatically release workers after integrated outcome completion"),c.createElement("label",null,"Hours after recorded delivery before automatic collection",c.createElement("input",{type:"number",min:"0",max:"87600",value:Ve,onChange:L=>qe(L.target.value),placeholder:"Keep until explicitly collected"})),c.createElement("label",{className:"checkbox"},c.createElement("input",{type:"checkbox",checked:x,onChange:L=>He(L.target.checked)})," ","Also delete safely merged local branches"),c.createElement("button",{disabled:Z,onClick:()=>void se("cleanup.configure",{policy:{autoRelease:Je,collectAfterHours:Ve===""?null:Number(Ve),deleteMergedBranches:x}})},"Save authorized policy"))):null)}const Nf=b=>b.slice(0,8),tc=b=>JSON.stringify(b,null,2),jm=new Set(["preparing","running","redirecting","cancelling","verifying"]),By=new Set(["blocked","uncertain","failed"]);function Bm(b,k){const q=URL.createObjectURL(new Blob([tc(k)],{type:"application/json"})),y=document.createElement("a");y.href=q,y.download=b,y.click(),setTimeout(()=>URL.revokeObjectURL(q),1e3)}function Yy(){var N,R,j,J,te,oe,We;const[b,k]=P.useState(()=>{const m=new URLSearchParams(location.hash.slice(1)).get("token");return m&&(sessionStorage.setItem("marionette-token",m),history.replaceState(null,"",location.pathname)),m??sessionStorage.getItem("marionette-token")??""}),[q,y]=P.useState([]),[M,W]=P.useState(localStorage.getItem("marionette-project")??""),[D,De]=P.useState(null),[U,O]=P.useState("Overview"),[$,Y]=P.useState(null),[H,le]=P.useState(null),[_e,Ee]=P.useState(""),[Ve,qe]=P.useState(!1),[Je,Ue]=P.useState(!1),[x,He]=P.useState(null),[se,Z]=P.useState([]),[Te,L]=P.useState(""),[ke,p]=P.useState(""),[C]=P.useState(()=>{let m=localStorage.getItem("marionette-consumer");return m||(m="dashboard:"+crypto.randomUUID(),localStorage.setItem("marionette-consumer",m)),m});async function ae(m,K={}){var Ae;const G=await fetch("/api/call",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${b}`},body:JSON.stringify({action:m,input:K}),signal:AbortSignal.timeout(m.startsWith("cleanup.")?3e5:m==="profile.validate"?135e3:m==="profile.discover"?45e3:15e3)}),xe=await G.json();if(!G.ok)throw new Error(((Ae=xe.error)==null?void 0:Ae.message)??"Request failed");return xe.result}async function Oe(){var K;const m=await ae("project.list");y(m),m.some(G=>G.id===M)||W(((K=m[0])==null?void 0:K.id)??""),M&&De(await ae("project.briefing",{projectId:M,compact:!1}))}P.useEffect(()=>{De(null),Y(null),Z([]),He(JSON.parse(sessionStorage.getItem("marionette-lease:"+M)??"null")),localStorage.setItem("marionette-project",M)},[M]),P.useEffect(()=>{if(!b)return;let m=!1,K=!1,G=!0,xe=0;async function Ae(){var wt;if(!K){K=!0;try{const At=await ae("project.list");if(m)return;if(y(At),!At.some(xt=>xt.id===M)){W(((wt=At[0])==null?void 0:wt.id)??""),qe(!0);return}if(M){const[xt,xn]=await Promise.all([ae("project.briefing",{projectId:M,compact:!1}),ae("inbox.read",{projectId:M,consumer:C,limit:200})]);if(m)return;De(xt),Z(xn.events);const Pl=G?{events:[],cursor:xt.eventCursor}:await ae("inbox.read",{projectId:M,consumer:C,after:xe,limit:200});if(m)return;const Hl=Pl.events.filter(Ya=>["task.completed","task.failed","question.opened","worker.disconnected","lead.handover"].includes(Ya.type));!G&&Hl.length&&(L(Hl.at(-1).message),"Notification"in window&&Notification.permission==="granted"&&new Notification("Marionette",{body:Hl.at(-1).message,tag:"marionette"})),xe=Math.max(xe,Pl.cursor),G=!1}qe(!0)}catch{m||qe(!1)}finally{K=!1}}}Ae();const at=setInterval(Ae,2e3);return()=>{m=!0,clearInterval(at)}},[b,M,C]),P.useEffect(()=>{if(!Te)return;const m=setTimeout(()=>L(""),8e3);return()=>clearTimeout(m)},[Te]),P.useEffect(()=>{var Ae;if(!H&&!$)return;const m=document.activeElement,K=document.querySelector(H?".modal":".task-drawer"),G=()=>Array.from((K==null?void 0:K.querySelectorAll('button:not(:disabled),input,select,textarea,[tabindex="0"]'))??[]);(Ae=G()[0])==null||Ae.focus();const xe=at=>{if(at.key==="Escape"){H?le(null):Y(null);return}if(at.key==="Tab"){const wt=G(),At=wt[0],xt=wt.at(-1);at.shiftKey&&document.activeElement===At?(at.preventDefault(),xt==null||xt.focus()):!at.shiftKey&&document.activeElement===xt&&(at.preventDefault(),At==null||At.focus())}};return document.addEventListener("keydown",xe),()=>{document.removeEventListener("keydown",xe),m==null||m.focus()}},[H,$]);const ne=!!(x&&((N=D==null?void 0:D.lead)==null?void 0:N.owner)===x.owner&&((R=D==null?void 0:D.lead)==null?void 0:R.epoch)===x.epoch),d=D==null?void 0:D.tasks.find(m=>m.id===$),_=(D==null?void 0:D.questions.filter(m=>!m.answeredAt))??[];async function Q(m,K,G="Saved"){Ue(!0),Ee("");try{const xe=await ae(m,K);return await Oe(),L(G),xe}catch(xe){throw Ee(String(xe)),xe}finally{Ue(!1)}}function he(m){sessionStorage.setItem("marionette-lease:"+M,tc(m)),He(m)}async function me(m,K,G){d&&(await Q("task.control",{lease:x,taskId:d.id,key:crypto.randomUUID(),type:m,text:K,keys:G},"Control request queued"),le(null))}async function o(m){var xe;m.preventDefault();const K=new FormData(m.currentTarget),G=Ae=>String(K.get(Ae)??"");try{if(H==="connect"){const Ae=await Q("project.register",{name:G("name"),root:G("root"),session:G("session"),socketPath:G("socket"),workspaceId:G("workspace"),maxConcurrency:Number(G("concurrency"))},"Project connected");W(Ae.id)}else if(H==="lead"){const Ae=await Q("lead.acquire",{projectId:M,owner:G("owner"),agent:G("leadAgent"),expectedEpoch:((xe=D==null?void 0:D.lead)==null?void 0:xe.epoch)??0,takeover:!!(D!=null&&D.lead),reason:G("reason")},"You have control");he(Ae.lease)}else if(H==="handover"){const Ae=await Q("lead.handover",{lease:x,toOwner:G("owner"),agent:G("leadAgent"),reason:G("reason")},"Control transferred");Bm(`marionette-${G("owner")}-lease.json`,Ae.lease),sessionStorage.removeItem("marionette-lease:"+M),He(null)}else H==="assignment"?await Q("task.submit",{lease:x,assignment:{projectId:M,key:crypto.randomUUID(),title:G("title"),workstream:G("workstream"),kind:G("profileId")?D.profiles.find(Ae=>Ae.id===G("profileId")).kind:G("kind"),...G("outcomeId")?{outcomeId:G("outcomeId"),expectedTreeRevision:D.outcomes.find(Ae=>Ae.id===G("outcomeId")).revision}:{},...G("parentId")?{parentId:G("parentId")}:{},...G("profileId")?{profileId:G("profileId")}:{},canDelegate:K.get("canDelegate")==="on",prompt:G("prompt"),execution:G("execution")==="worktree"?{mode:"worktree",...G("baseRef").trim()?{baseRef:G("baseRef").trim()}:{}}:{mode:"shared"},ownership:G("ownership").split(",").map(Ae=>Ae.trim()).filter(Boolean),dependencies:K.getAll("dependency").map(String),checks:JSON.parse(G("checks")),maxAttempts:2}},"Assignment queued"):H==="decision"?await Q("decision.record",{lease:x,text:G("text"),rationale:G("reason")},"Decision recorded"):H==="redirect"||H==="reply"?await me(H,G("text")):H==="keys"?await me("keys",void 0,G("keys").trim().split(/\s+/)):H==="reconcile"&&await Q("task.reconcile",{lease:x,taskId:d==null?void 0:d.id,resolution:G("resolution"),reason:G("reason")},"Run reconciled");le(null)}catch(Ae){Ee(String(Ae))}}return b?c.createElement("div",{className:"app-shell"},c.createElement("aside",{className:"sidebar"},c.createElement("div",{className:"wordmark"},c.createElement("div",{className:"brand-mark"},c.createElement(zf,{size:22})),c.createElement("span",null,"marionette",c.createElement("span",{className:"wordmark-dot"},"."))),c.createElement("label",{className:"project-picker"},c.createElement("span",null,"PROJECT"),c.createElement("select",{"aria-label":"Current project",value:M,onChange:m=>W(m.target.value)},!q.length&&c.createElement("option",{value:""},"No project connected"),q.map(m=>c.createElement("option",{key:m.id,value:m.id},m.name)))),c.createElement("nav",{"aria-label":"Main navigation"},[{name:"Overview",icon:Dy},{name:"Outcomes",icon:qn},{name:"Workstreams",icon:Tf},{name:"Inbox",icon:Oy},{name:"Decisions",icon:Sf},{name:"Connection",icon:Ry}].map(({name:m,icon:K})=>c.createElement("button",{key:m,className:U===m?"nav-item chosen":"nav-item",onClick:()=>O(m)},c.createElement(K,{size:18}),m,m==="Inbox"&&se.length>0&&c.createElement("span",{className:"count"},se.length)))),c.createElement("div",{className:"sidebar-bottom"},c.createElement("div",{className:"server-status"},c.createElement("span",{className:"live-dot "+(Ve?"":"offline")}),Ve?"Supervisor connected":"Reconnecting…"),c.createElement("p",null,"Workers keep moving.",c.createElement("br",null),"Your conversation stays open."),c.createElement("button",{className:"subtle",onClick:()=>{Ee(""),le("connect")}},c.createElement(ec,{size:16})," Connect a project"))),c.createElement("main",{className:"main"},c.createElement("header",{className:"topbar"},c.createElement("div",{className:"breadcrumb"},"Workspace ",c.createElement(bf,{size:14}),c.createElement("strong",null,(D==null?void 0:D.project.name)??"Getting started")),c.createElement("button",{className:"icon-button",title:"Open inbox","aria-label":"Open inbox",onClick:()=>O("Inbox")},c.createElement(Pu,{size:19}),_.length>0&&c.createElement("span",{className:"notification-dot"}))),!Ve&&c.createElement("div",{className:"connection-warning",role:"status"},"Cannot reach the supervisor. Retrying every two seconds. Check the instance token or run"," ",c.createElement("code",null,"node dist/cli.js start"),". Your saved work is retained."),c.createElement("div",{className:"content"},c.createElement("div",{className:"page-heading"},c.createElement("div",null,c.createElement("p",{className:"eyebrow"},"PROJECT CONTROL"),c.createElement("h1",null,U==="Overview"?"Keep the whole project in view.":U),c.createElement("p",{className:"muted"},U==="Overview"?"One lead. Independent workers. A shared direction.":U==="Outcomes"?"Observable outcomes, accountable delegation, and verified completion.":U==="Workstreams"?"Bounded assignments, clear ownership, visible progress.":U==="Inbox"?"Completion updates and questions, saved until you acknowledge them.":U==="Decisions"?"The choices that keep every agent working toward the same outcome.":"Explicit connections. No reliance on the focused terminal.")),D&&c.createElement("button",{className:"primary",disabled:!ne,onClick:()=>{Ee(""),le("assignment")}},c.createElement(ec,{size:17})," New assignment")),_e&&!H&&c.createElement("div",{className:"error",role:"alert"},_e,c.createElement("button",{"aria-label":"Dismiss error",onClick:()=>Ee("")},c.createElement(Hn,{size:16}))),D?c.createElement(c.Fragment,null,c.createElement("section",{className:"lead-strip"},c.createElement("div",{className:"lead-avatar"},c.createElement(zf,{size:19})),c.createElement("div",null,c.createElement("strong",null,((j=D.lead)==null?void 0:j.owner)??"No lead has control yet",(J=D.lead)!=null&&J.agent?` · ${D.lead.agent}`:""),c.createElement("p",null,ne?"This dashboard holds dispatch control.":D.lead?`Control version ${D.lead.epoch} · Workers continue during handover.`:"Acquire control before assigning work.")),c.createElement("div",{className:"lead-actions"},ne?c.createElement(c.Fragment,null,c.createElement("span",{className:"pill green"},"You have control"),c.createElement("button",{onClick:()=>le("handover")},"Hand over ",c.createElement(ql,{size:15}))):c.createElement("button",{onClick:()=>le("lead")},D.lead?"Take control":"Acquire control"," ",c.createElement(ql,{size:15})))),U==="Outcomes"&&c.createElement(xy,{data:D,projectId:M,canEdit:ne,pending:Je,onTask:Y,onAddTask:()=>le("assignment"),onAction:(m,K,G)=>Q(m,{...K,lease:x},G)}),U==="Overview"&&c.createElement(c.Fragment,null,c.createElement("div",{className:"metrics"},[{label:"In progress",value:D.tasks.filter(m=>jm.has(m.status)).length,icon:Ty,color:"blue"},{label:"Needs attention",value:D.tasks.filter(m=>By.has(m.status)).length,icon:Pu,color:"amber"},{label:"Verified complete",value:D.tasks.filter(m=>m.status==="completed").length,icon:qn,color:"green"},{label:"Workstreams",value:new Set(D.tasks.map(m=>m.workstream)).size,icon:Tf,color:"purple"}].map(({label:m,value:K,icon:G,color:xe})=>c.createElement("div",{className:"metric",key:m},c.createElement("span",null,m,c.createElement(G,{size:17,className:xe})),c.createElement("strong",null,K.toString().padStart(2,"0"))))),_.length>0&&c.createElement("section",{className:"attention-card"},c.createElement("div",null,c.createElement(Pu,{size:19}),c.createElement("strong",null,_.length," ",_.length===1?"question needs":"questions need"," your attention")),c.createElement("p",null,_[0].text),c.createElement("button",{onClick:()=>Y(_[0].taskId)},"Review question ",c.createElement(ql,{size:16})))),(U==="Overview"||U==="Workstreams")&&c.createElement("section",{className:"panel"},c.createElement("div",{className:"panel-heading"},c.createElement("div",null,c.createElement("h2",null,U==="Overview"?"Work in motion":"All assignments"),c.createElement("p",null,D.tasks.length," assignments across your project")),c.createElement("input",{className:"search","aria-label":"Filter assignments",placeholder:"Filter assignments…",value:ke,onChange:m=>p(m.target.value)})),D.tasks.length===0?c.createElement("div",{className:"empty-inline"},c.createElement(Tf,{size:28}),c.createElement("h3",null,"Give your first worker a direction"),c.createElement("p",null,"Describe an outcome, assign ownership, and define how completion will be checked."),c.createElement("button",{disabled:!ne,onClick:()=>le("assignment")},"Create an assignment ",c.createElement(ec,{size:15}))):c.createElement("div",{className:"task-table",role:"group","aria-label":"Assignments"},c.createElement("div",{className:"table-labels"},c.createElement("span",null,"ASSIGNMENT"),c.createElement("span",null,"AGENT"),c.createElement("span",null,"STATUS"),c.createElement("span",null,"ATTEMPT")),D.tasks.filter(m=>(m.title+" "+m.workstream+" "+m.status).toLowerCase().includes(ke.toLowerCase())).map(m=>c.createElement("button",{className:"task-row",key:m.id,onClick:()=>Y(m.id)},c.createElement("span",{className:"task-name"},c.createElement("span",{className:"task-symbol "+m.kind},c.createElement(qy,{size:17})),c.createElement("span",null,c.createElement("strong",null,m.title),c.createElement("small",null,m.workstream," ",c.createElement("span",null,"·")," ",Nf(m.id)))),c.createElement("span",{className:"agent-label"},m.kind==="agy"?"AGY":m.kind==="codex"?"Codex":"Claude"),c.createElement("span",null,c.createElement(Ym,{status:m.status})),c.createElement("span",{className:"attempt"},m.attempt," / ",m.maxAttempts,c.createElement(bf,{size:16})))))),U==="Overview"&&c.createElement("div",{className:"bottom-grid"},c.createElement("section",{className:"panel small-panel"},c.createElement("div",{className:"panel-heading"},c.createElement("h2",null,"Latest decisions"),c.createElement("button",{className:"text-button",onClick:()=>O("Decisions")},"View all ",c.createElement(ql,{size:15}))),D.decisions.length?D.decisions.slice(-3).reverse().map(m=>c.createElement("div",{className:"decision-preview",key:m.id},c.createElement(Sf,{size:16}),c.createElement("div",null,c.createElement("strong",null,m.text),c.createElement("small",null,m.owner)))):c.createElement("p",{className:"empty-copy"},"Decisions made by the lead will appear here and travel with every handover.")),c.createElement("section",{className:"panel small-panel handoff-card"},c.createElement("p",{className:"eyebrow"},"PICK UP WHERE YOU LEFT OFF"),c.createElement("h2",null,"Desktop or terminal.",c.createElement("br",null),"The same project state."),c.createElement("p",null,"Take a current briefing into Codex desktop or a lead agent inside Herdr."),c.createElement("button",{onClick:()=>Bm("marionette-briefing.json",D)},c.createElement(Ny,{size:16})," Export briefing"))),U==="Inbox"&&c.createElement("section",{className:"panel"},c.createElement("div",{className:"panel-heading"},c.createElement("h2",null,"Project inbox ",c.createElement("span",{className:"muted"},"(",se.length,")")),c.createElement("div",{className:"button-group"},c.createElement("button",{onClick:async()=>{if("Notification"in window){const m=await Notification.requestPermission();L(m==="granted"?"Desktop alerts enabled while the dashboard is open":"Use the persistent inbox for all updates")}}},c.createElement(Pu,{size:16})," Desktop alerts"),c.createElement("button",{disabled:!se.length,onClick:()=>{var m;return void Q("inbox.ack",{projectId:M,consumer:C,cursor:(m=se.at(-1))==null?void 0:m.id},"Events acknowledged").then(()=>Z([])).catch(()=>{})}},c.createElement(Ay,{size:16})," Mark read"))),c.createElement("p",{className:"inbox-note"},"Events remain available to other consumers. Desktop alerts require this dashboard to be open. MCP inbox updates do not wake an idle Codex conversation."),se.length?se.slice().reverse().map(m=>c.createElement("button",{className:"inbox-event",key:m.id,onClick:()=>m.taskId&&Y(m.taskId)},c.createElement("span",{className:"event-dot "+(m.type.includes("completed")?"green-bg":m.type.includes("question")?"amber-bg":"")}),c.createElement("span",null,c.createElement("strong",null,m.message),c.createElement("small",null,m.type," · ",new Date(m.createdAt).toLocaleString())),c.createElement(bf,{size:16}))):c.createElement("div",{className:"empty-inline"},c.createElement(qn,{size:28}),c.createElement("h3",null,"You’re all caught up"),c.createElement("p",null,"New updates will appear here as workers make progress."))),U==="Decisions"&&c.createElement("section",{className:"panel"},c.createElement("div",{className:"panel-heading"},c.createElement("h2",null,"Project decisions"),c.createElement("button",{disabled:!ne,onClick:()=>le("decision")},c.createElement(ec,{size:16})," Record decision")),D.decisions.length?D.decisions.slice().reverse().map(m=>c.createElement("article",{className:"decision",key:m.id},c.createElement("p",{className:"eyebrow"},m.owner," · ",new Date(m.createdAt).toLocaleDateString()),c.createElement("h3",null,m.text),c.createElement("p",null,m.rationale))):c.createElement("div",{className:"empty-inline"},c.createElement(Sf,{size:28}),c.createElement("h3",null,"A shared source of direction"),c.createElement("p",null,"Record design choices, architecture decisions, and priorities for every agent."))),U==="Connection"&&c.createElement("section",{className:"panel connection-panel"},c.createElement("h2",null,"Connected workspace"),c.createElement("dl",null,[["Project",D.project.name],["Root directory",D.project.root],["Herdr session",D.project.session],["Workspace",D.project.workspaceId],["Socket",D.project.socketPath]].map(([m,K])=>c.createElement("div",{key:m},c.createElement("dt",null,m),c.createElement("dd",null,c.createElement("code",null,K))))),c.createElement("button",{onClick:()=>void Q("project.inspect",{projectId:M},"Herdr workspace connection verified").catch(()=>{})},c.createElement(xm,{size:16})," Check connection"),c.createElement("hr",null),c.createElement("h3",null,"Continue in Herdr"),c.createElement("p",null,"Attach to this named session:"),c.createElement("pre",null,"herdr --session ",D.project.session),c.createElement("p",null,"Configure the Marionette MCP server for your terminal lead, then acquire control with a fresh briefing. A handover lease can also be supplied to the CLI."),c.createElement("p",{className:"muted"},"Marionette never closes an existing session or uses the UI-focused pane as an implicit target."))):c.createElement("section",{className:"empty-state"},c.createElement(My,{size:32}),c.createElement("h2",null,"Connect your first workspace"),c.createElement("p",null,"Choose a project folder, Herdr session, and workspace. Marionette will operate only within that explicit connection."),c.createElement("button",{className:"primary",onClick:()=>le("connect")},"Connect workspace ",c.createElement(ql,{size:17}))),c.createElement("footer",null,"MARIONETTE ",c.createElement("span",null,"Local orchestration · Durable project state")))),d&&c.createElement("div",{className:"drawer-backdrop",onClick:()=>Y(null)},c.createElement("aside",{className:"task-drawer",role:"dialog","aria-modal":"true","aria-label":"Task details",onClick:m=>m.stopPropagation()},c.createElement("header",null,c.createElement("p",{className:"eyebrow"},d.workstream," / ",Nf(d.id)),c.createElement("button",{className:"icon-button","aria-label":"Close task details",onClick:()=>Y(null)},c.createElement(Hn,{size:21}))),c.createElement("h2",null,d.title),c.createElement("div",{className:"detail-meta"},c.createElement(Ym,{status:d.status}),c.createElement("span",null,d.kind,d.model?` · ${d.model}`:" · Runtime default (exact model unreported)"," · Revision ",d.revision," · Attempt ",d.attempt)),d.error&&c.createElement("div",{className:"error"},d.error),d.waitReason&&c.createElement("p",{className:"inbox-note"},d.waitReason),c.createElement("div",{className:"task-controls"},c.createElement("button",{disabled:!ne||["completed","cancelled","failed","uncertain"].includes(d.status),onClick:()=>le("redirect")},c.createElement(Uy,{size:15})," Redirect"),c.createElement("button",{disabled:!ne||!(jm.has(d.status)||d.status==="queued"),onClick:()=>void me("pause").catch(()=>{})},c.createElement(Cy,{size:15})," Pause"),c.createElement("button",{disabled:!ne||!["blocked","paused"].includes(d.status),onClick:()=>le("reply")},c.createElement(_y,{size:15})," Continue"),c.createElement("button",{disabled:!ne||["completed","cancelled","failed","uncertain"].includes(d.status),onClick:()=>void me("cancel").catch(()=>{})},c.createElement(Hn,{size:15})," Cancel"),["failed","cancelled"].includes(d.status)&&c.createElement("button",{disabled:!ne||d.attempt>=d.maxAttempts,onClick:()=>void Q("task.retry",{lease:x,taskId:d.id,key:crypto.randomUUID()},"Retry queued").catch(()=>{})},c.createElement(xm,{size:15})," Retry"),d.status==="uncertain"&&c.createElement("button",{disabled:!ne,onClick:()=>le("reconcile")},"Reconcile delivery")),_.filter(m=>m.taskId===d.id).map(m=>c.createElement("section",{className:"question",key:m.id},c.createElement("p",{className:"eyebrow"},m.native?"AGENT INPUT REQUIRED":"PENDING QUESTION"),c.createElement("p",null,m.text),c.createElement("button",{disabled:!ne,onClick:()=>le(m.native?"keys":"reply")},m.native?"Send explicit keys":"Answer question"," ",c.createElement(ql,{size:15})),m.native&&c.createElement("button",{disabled:!ne,onClick:()=>le("reply")},"Continue after resolving in Herdr"))),c.createElement("section",null,c.createElement("h3",null,"Assignment"),c.createElement("p",{className:"preserve"},d.prompt),c.createElement("h4",null,"Execution"),c.createElement("p",null,((te=d.execution)==null?void 0:te.mode)==="worktree"?"Isolated Git worktree":"Shared working directory"),c.createElement("p",{className:"preserve"},d.cwd),d.worktree?c.createElement(c.Fragment,null,c.createElement("p",{className:"preserve"},"Branch: ",d.worktree.branch),c.createElement("p",{className:"preserve"},"Base commit: ",d.worktree.baseCommit),c.createElement("p",{className:"preserve"},"Worktree (",d.worktree.state,"): ",d.worktree.path),c.createElement("p",{className:"muted"},"Available for your review, merge, or pull request workflow.")):null,c.createElement("h4",null,"Ownership"),c.createElement("div",{className:"chips"},d.ownership.map(m=>c.createElement("code",{key:m},m))),d.dependencies.length>0&&c.createElement(c.Fragment,null,c.createElement("h4",null,"Dependencies"),d.dependencies.map(m=>{var K;return c.createElement("button",{key:m,className:"text-button",onClick:()=>Y(m)},((K=D==null?void 0:D.tasks.find(G=>G.id===m))==null?void 0:K.title)??Nf(m))}))),c.createElement("section",null,c.createElement("h3",null,"Worker output ",c.createElement("span",{className:"live-label"},"LIVE")),c.createElement("pre",{className:"terminal-output"},d.output||"Output will appear after the worker starts.")),c.createElement(jy,{key:d.id,taskId:d.id,canEdit:ne,pending:Je,onAction:(m,K)=>Q(m,{...K,lease:x},m==="cleanup.preview"?"Cleanup eligibility refreshed":"Cleanup state saved")}),d.receipt&&c.createElement("section",null,c.createElement("h3",null,"Completion report"),c.createElement("p",null,d.receipt.summary),c.createElement("h4",null,"Artifacts"),d.receipt.artifacts.map(m=>c.createElement("div",{className:"artifact",key:m},c.createElement(qn,{size:15}),c.createElement("code",null,m))),d.receipt.evidence.map((m,K)=>c.createElement("p",{key:K,className:"preserve"},m))),c.createElement("section",null,c.createElement("h3",null,"Verification"),(oe=d.verification)!=null&&oe.length?d.verification.map((m,K)=>c.createElement("div",{className:"verification "+(m.passed?"pass":"fail"),key:K},c.createElement("strong",null,m.passed?"Passed":"Failed"),c.createElement("pre",null,m.detail))):c.createElement(c.Fragment,null,c.createElement("p",{className:"muted"},"Completion requires a current worker report and independent checks."),c.createElement("pre",null,tc(d.checks)))))),H&&c.createElement("div",{className:"modal-backdrop"},c.createElement("section",{className:"modal",role:"dialog","aria-modal":"true","aria-labelledby":"modal-title"},c.createElement("header",null,c.createElement("h2",{id:"modal-title"},{connect:"Connect a project",lead:D!=null&&D.lead?"Take over control":"Acquire control",handover:"Hand over control",assignment:"New assignment",decision:"Record a decision",redirect:"Redirect this worker",reply:"Continue this assignment",keys:"Resolve agent input",reconcile:"Reconcile uncertain delivery"}[H]),c.createElement("button",{className:"icon-button","aria-label":"Close dialog",onClick:()=>{le(null),Ee("")}},c.createElement(Hn,{size:21}))),c.createElement("form",{onSubmit:o},H==="connect"&&c.createElement(c.Fragment,null,c.createElement("p",null,"Connect to an existing Herdr workspace. No sessions or agents will be closed."),c.createElement(dt,{label:"Project name",name:"name"}),c.createElement(dt,{label:"Absolute project directory",name:"root",placeholder:"/Users/you/Code/project"}),c.createElement(dt,{label:"Herdr session name",name:"session",placeholder:"project-work"}),c.createElement(dt,{label:"Absolute Herdr socket path",name:"socket",placeholder:"/Users/you/.config/herdr/sessions/project-work/herdr.sock"}),c.createElement("div",{className:"form-grid"},c.createElement(dt,{label:"Workspace ID",name:"workspace",placeholder:"w1"}),c.createElement(dt,{label:"Concurrent workers",name:"concurrency",type:"number",defaultValue:"3"}))),(H==="lead"||H==="handover")&&c.createElement(c.Fragment,null,c.createElement("p",null,H==="handover"?"The current lease will become invalid. A private lease file for the receiving lead will download with the handover.":D!=null&&D.lead?`This explicitly replaces ${D.lead.owner}. Their existing lease will stop authorizing dispatch. Workers continue running.`:"Choose an identity for the lead controlling this project."),c.createElement(dt,{label:H==="handover"?"Receiving lead identity":"Your lead identity",name:"owner",defaultValue:H==="lead"?"dashboard":"",placeholder:"terminal-lead"}),c.createElement("label",null,"Lead agent",c.createElement("select",{name:"leadAgent",defaultValue:((We=D==null?void 0:D.lead)==null?void 0:We.agent)??"codex-desktop"},c.createElement("option",{value:"codex-desktop"},"Codex desktop"),c.createElement("option",{value:"codex"},"Codex CLI"),c.createElement("option",{value:"claude"},"Claude Code"),c.createElement("option",{value:"agy"},"AGY"))),c.createElement(dt,{label:"Reason for this change",name:"reason"})),H==="assignment"&&c.createElement(c.Fragment,null,c.createElement(dt,{label:"Title",name:"title",placeholder:"Build the settings screen"}),c.createElement("label",null,"Outcome",c.createElement("select",{name:"outcomeId"},c.createElement("option",{value:""},"Create an outcome from this assignment's checks"),D.outcomes.map(m=>c.createElement("option",{key:m.id,value:m.id},m.objective.slice(0,120))))),c.createElement("label",null,"Responsible parent",c.createElement("select",{name:"parentId"},c.createElement("option",{value:""},"Root lead"),D.tasks.filter(m=>m.canDelegate).map(m=>c.createElement("option",{key:m.id,value:m.id},m.title)))),c.createElement("label",null,"Exact model profile",c.createElement("select",{name:"profileId"},c.createElement("option",{value:""},"Use selected runtime configuration"),D.profiles.map(m=>c.createElement("option",{key:m.id,value:m.id,disabled:m.availability!=="available"},m.name," · ",m.model," (",m.availability,")")))),c.createElement("label",{className:"checkbox"},c.createElement("input",{type:"checkbox",name:"canDelegate"})," Allow this worker to coordinate children within its scope and shared budget"),c.createElement("div",{className:"form-grid"},c.createElement(dt,{label:"Workstream",name:"workstream",defaultValue:"Product"}),c.createElement("label",null,"Specialist",c.createElement("select",{name:"kind"},c.createElement("option",{value:"codex"},"Codex"),c.createElement("option",{value:"claude"},"Claude"),c.createElement("option",{value:"agy"},"AGY")))),c.createElement("label",null,"Objective and acceptance criteria",c.createElement("textarea",{name:"prompt",required:!0,rows:5,placeholder:"Describe the outcome and constraints…"})),c.createElement(dt,{label:"Owned paths (comma-separated files or directories)",name:"ownership",placeholder:"src/settings, tests/settings"}),c.createElement(Gy,null),c.createElement("label",null,"Verification checks (JSON)",c.createElement("textarea",{className:"code-input",name:"checks",rows:5,required:!0,defaultValue:tc([{type:"file",path:"src/settings.ts"},{type:"command",command:"npm",args:["test"],timeoutMs:3e4}])})),D.tasks.length>0&&c.createElement("fieldset",null,c.createElement("legend",null,"Wait for these assignments"),D.tasks.map(m=>c.createElement("label",{className:"checkbox",key:m.id},c.createElement("input",{type:"checkbox",name:"dependency",value:m.id}),m.title))),c.createElement("p",{className:"muted"},"Submission returns immediately. Overlapping paths in a shared directory wait. Separate worktrees can edit the same repository files concurrently. Dependencies and the worker limit still apply.")),H==="decision"&&c.createElement(c.Fragment,null,c.createElement("label",null,"Decision",c.createElement("textarea",{name:"text",required:!0,rows:3})),c.createElement(dt,{label:"Rationale",name:"reason"})),(H==="redirect"||H==="reply")&&c.createElement(c.Fragment,null,c.createElement("p",null,H==="redirect"?"The worker will be interrupted. These instructions replace its objective and invalidate earlier completion reports. Existing verification checks are retained.":"Your answer will be saved and sent with the current assignment. The worker must submit a fresh report."),c.createElement("label",null,H==="redirect"?"Replacement objective":"Answer or continuation instructions",c.createElement("textarea",{name:"text",required:!0,rows:6,defaultValue:H==="redirect"?d==null?void 0:d.prompt:""}))),H==="keys"&&c.createElement(c.Fragment,null,c.createElement("p",null,"Inspect the worker output first. Enter only the keys needed for the specific visible prompt. This does not automatically approve future actions."),c.createElement(dt,{label:"Keys, separated by spaces",name:"keys",placeholder:"enter"})),H==="reconcile"&&c.createElement(c.Fragment,null,c.createElement("p",null,"Use this only after inspecting the original worker. An uncertain request is never automatically replayed."),c.createElement("label",null,"Observed delivery",c.createElement("select",{name:"resolution"},c.createElement("option",{value:"delivered"},"The instructions were delivered"),c.createElement("option",{value:"not-delivered"},"Not delivered; worker is stopped"))),c.createElement(dt,{label:"Evidence and reason",name:"reason"})),_e&&c.createElement("div",{className:"error",role:"alert"},_e),c.createElement("div",{className:"modal-actions"},c.createElement("button",{type:"button",onClick:()=>le(null)},"Cancel"),c.createElement("button",{className:"primary",disabled:Je},Je?"Saving…":H==="assignment"?"Queue assignment":H==="handover"?"Transfer and download lease":"Confirm",c.createElement(ql,{size:16})))))),Te&&c.createElement("div",{className:"toast",role:"status"},c.createElement(qn,{size:18}),c.createElement("span",null,Te),c.createElement("button",{"aria-label":"Dismiss notification",onClick:()=>L("")},c.createElement(Hn,{size:16})))):c.createElement("main",{className:"welcome"},c.createElement("div",{className:"brand-mark"},c.createElement(zf,{size:26})),c.createElement("p",{className:"eyebrow"},"MARIONETTE"),c.createElement("h1",null,"Your project,",c.createElement("br",null),"working together."),c.createElement("p",null,"Open the local access link printed by ",c.createElement("code",null,"node dist/cli.js dashboard"),", or enter your instance token below."),c.createElement("form",{onSubmit:m=>{m.preventDefault();const K=new FormData(m.currentTarget).get("token");sessionStorage.setItem("marionette-token",K),k(K)}},c.createElement("label",null,"Instance token",c.createElement("input",{type:"password",name:"token",required:!0,autoComplete:"off"})),c.createElement("button",{className:"primary"},"Connect ",c.createElement(ql,{size:16}))))}function Gy(){const[b,k]=P.useState("shared");return c.createElement(c.Fragment,null,c.createElement("label",null,"Working environment",c.createElement("select",{name:"execution",value:b,onChange:q=>k(q.target.value)},c.createElement("option",{value:"shared"},"Shared directory"),c.createElement("option",{value:"worktree"},"Isolated Git worktree"))),b==="worktree"?c.createElement(c.Fragment,null,c.createElement("label",null,"Base branch or commit (optional)",c.createElement("input",{name:"baseRef",placeholder:"HEAD"})),c.createElement("p",{className:"muted"},"Marionette creates a branch and worktree from committed history. Uncommitted source changes are not copied. The result remains available for review, merge, or a pull request.")):null)}function dt({label:b,...k}){return c.createElement("label",null,b,c.createElement("input",{required:!0,...k}))}function Ym({status:b}){return c.createElement("span",{className:"status status-"+b},c.createElement("span",null),b.replaceAll("_"," "))}py.createRoot(document.getElementById("root")).render(c.createElement(Yy,null));
|