@femtomc/mu-agent 26.2.73 → 26.2.74
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/README.md +21 -32
- package/dist/extensions/branding.js +2 -2
- package/dist/extensions/index.d.ts +3 -9
- package/dist/extensions/index.d.ts.map +1 -1
- package/dist/extensions/index.js +5 -11
- package/dist/extensions/mu-operator.d.ts.map +1 -1
- package/dist/extensions/mu-operator.js +0 -4
- package/dist/extensions/mu-serve.d.ts.map +1 -1
- package/dist/extensions/mu-serve.js +0 -4
- package/dist/extensions/shared.d.ts +2 -21
- package/dist/extensions/shared.d.ts.map +1 -1
- package/dist/extensions/shared.js +0 -90
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/operator.d.ts.map +1 -1
- package/dist/operator.js +237 -5
- package/dist/session_factory.d.ts +5 -0
- package/dist/session_factory.d.ts.map +1 -1
- package/package.json +2 -3
- package/prompts/roles/operator.md +18 -23
- package/prompts/roles/orchestrator.md +10 -11
- package/prompts/roles/reviewer.md +6 -8
- package/prompts/roles/worker.md +6 -8
- package/dist/extensions/mu-tools.d.ts +0 -9
- package/dist/extensions/mu-tools.d.ts.map +0 -1
- package/dist/extensions/mu-tools.js +0 -12
- package/dist/extensions/operator-command.d.ts +0 -13
- package/dist/extensions/operator-command.d.ts.map +0 -1
- package/dist/extensions/operator-command.js +0 -174
- package/dist/extensions/query.d.ts +0 -4
- package/dist/extensions/query.d.ts.map +0 -1
- package/dist/extensions/query.js +0 -402
package/dist/operator.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { appendJsonl } from "@femtomc/mu-core/node";
|
|
1
|
+
import { appendJsonl, readJsonl } from "@femtomc/mu-core/node";
|
|
2
2
|
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
import { z } from "zod";
|
|
@@ -183,6 +183,106 @@ function buildOperatorFailureFallbackMessage(code) {
|
|
|
183
183
|
function conversationKey(inbound, binding) {
|
|
184
184
|
return `${inbound.channel}:${inbound.channel_tenant_id}:${inbound.channel_conversation_id}:${binding.binding_id}`;
|
|
185
185
|
}
|
|
186
|
+
function asRecord(value) {
|
|
187
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
return value;
|
|
191
|
+
}
|
|
192
|
+
function nonEmptyString(value) {
|
|
193
|
+
if (typeof value !== "string") {
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
const trimmed = value.trim();
|
|
197
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
198
|
+
}
|
|
199
|
+
function finiteInt(value) {
|
|
200
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
return Math.trunc(value);
|
|
204
|
+
}
|
|
205
|
+
function stringList(value) {
|
|
206
|
+
if (!Array.isArray(value)) {
|
|
207
|
+
return [];
|
|
208
|
+
}
|
|
209
|
+
const out = [];
|
|
210
|
+
for (const item of value) {
|
|
211
|
+
const parsed = nonEmptyString(item);
|
|
212
|
+
if (parsed) {
|
|
213
|
+
out.push(parsed);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return out;
|
|
217
|
+
}
|
|
218
|
+
function sessionFlashPath(repoRoot) {
|
|
219
|
+
return join(repoRoot, ".mu", "control-plane", "session_flash.jsonl");
|
|
220
|
+
}
|
|
221
|
+
async function loadPendingSessionFlashes(opts) {
|
|
222
|
+
const rows = await readJsonl(sessionFlashPath(opts.repoRoot));
|
|
223
|
+
const created = new Map();
|
|
224
|
+
const delivered = new Set();
|
|
225
|
+
for (const row of rows) {
|
|
226
|
+
const rec = asRecord(row);
|
|
227
|
+
if (!rec) {
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
const kind = nonEmptyString(rec.kind);
|
|
231
|
+
if (kind === "session_flash.create") {
|
|
232
|
+
const tsMs = finiteInt(rec.ts_ms) ?? Date.now();
|
|
233
|
+
const flashId = nonEmptyString(rec.flash_id);
|
|
234
|
+
const sessionId = nonEmptyString(rec.session_id);
|
|
235
|
+
const body = nonEmptyString(rec.body);
|
|
236
|
+
if (!flashId || !sessionId || !body || sessionId !== opts.sessionId) {
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
created.set(flashId, {
|
|
240
|
+
flash_id: flashId,
|
|
241
|
+
created_at_ms: tsMs,
|
|
242
|
+
session_id: sessionId,
|
|
243
|
+
session_kind: nonEmptyString(rec.session_kind),
|
|
244
|
+
body,
|
|
245
|
+
context_ids: stringList(rec.context_ids),
|
|
246
|
+
source: nonEmptyString(rec.source),
|
|
247
|
+
metadata: asRecord(rec.metadata) ?? {},
|
|
248
|
+
});
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
if (kind === "session_flash.delivery") {
|
|
252
|
+
const flashId = nonEmptyString(rec.flash_id);
|
|
253
|
+
const sessionId = nonEmptyString(rec.session_id);
|
|
254
|
+
if (!flashId || !sessionId || sessionId !== opts.sessionId) {
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
delivered.add(flashId);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
const pending = [...created.values()]
|
|
261
|
+
.filter((row) => !delivered.has(row.flash_id))
|
|
262
|
+
.sort((a, b) => a.created_at_ms - b.created_at_ms);
|
|
263
|
+
const limit = Math.max(1, Math.trunc(opts.limit ?? 16));
|
|
264
|
+
if (pending.length <= limit) {
|
|
265
|
+
return pending;
|
|
266
|
+
}
|
|
267
|
+
return pending.slice(pending.length - limit);
|
|
268
|
+
}
|
|
269
|
+
async function markSessionFlashesDelivered(opts) {
|
|
270
|
+
if (opts.flashIds.length === 0) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
const deduped = [...new Set(opts.flashIds.filter((id) => id.trim().length > 0))];
|
|
274
|
+
for (const flashId of deduped) {
|
|
275
|
+
const row = {
|
|
276
|
+
kind: "session_flash.delivery",
|
|
277
|
+
ts_ms: opts.nowMs,
|
|
278
|
+
flash_id: flashId,
|
|
279
|
+
session_id: opts.sessionId,
|
|
280
|
+
delivered_by: "messaging_operator_runtime",
|
|
281
|
+
note: null,
|
|
282
|
+
};
|
|
283
|
+
await appendJsonl(sessionFlashPath(opts.repoRoot), row);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
186
286
|
export class JsonFileConversationSessionStore {
|
|
187
287
|
#path;
|
|
188
288
|
#loaded = false;
|
|
@@ -323,14 +423,46 @@ export class MessagingOperatorRuntime {
|
|
|
323
423
|
operatorTurnId: turnId,
|
|
324
424
|
};
|
|
325
425
|
}
|
|
426
|
+
let pendingFlashes = [];
|
|
427
|
+
try {
|
|
428
|
+
pendingFlashes = await loadPendingSessionFlashes({
|
|
429
|
+
repoRoot: opts.inbound.repo_root,
|
|
430
|
+
sessionId,
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
catch {
|
|
434
|
+
pendingFlashes = [];
|
|
435
|
+
}
|
|
436
|
+
const inboundForBackend = pendingFlashes.length > 0
|
|
437
|
+
? {
|
|
438
|
+
...opts.inbound,
|
|
439
|
+
metadata: {
|
|
440
|
+
...opts.inbound.metadata,
|
|
441
|
+
session_flash_messages: pendingFlashes,
|
|
442
|
+
},
|
|
443
|
+
}
|
|
444
|
+
: opts.inbound;
|
|
326
445
|
let backendResult;
|
|
327
446
|
try {
|
|
328
447
|
backendResult = OperatorBackendTurnResultSchema.parse(await this.#backend.runTurn({
|
|
329
448
|
sessionId,
|
|
330
449
|
turnId,
|
|
331
|
-
inbound:
|
|
450
|
+
inbound: inboundForBackend,
|
|
332
451
|
binding: opts.binding,
|
|
333
452
|
}));
|
|
453
|
+
if (pendingFlashes.length > 0) {
|
|
454
|
+
try {
|
|
455
|
+
await markSessionFlashesDelivered({
|
|
456
|
+
repoRoot: opts.inbound.repo_root,
|
|
457
|
+
sessionId,
|
|
458
|
+
flashIds: pendingFlashes.map((row) => row.flash_id),
|
|
459
|
+
nowMs: Date.now(),
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
catch {
|
|
463
|
+
// Best-effort delivery bookkeeping; do not fail the operator turn.
|
|
464
|
+
}
|
|
465
|
+
}
|
|
334
466
|
}
|
|
335
467
|
catch (err) {
|
|
336
468
|
return {
|
|
@@ -385,15 +517,115 @@ export class MessagingOperatorRuntime {
|
|
|
385
517
|
}
|
|
386
518
|
export { DEFAULT_OPERATOR_SYSTEM_PROMPT };
|
|
387
519
|
const COMMAND_TOOL_NAME = "command";
|
|
520
|
+
const OPERATOR_PROMPT_CONTEXT_MAX_CHARS = 2_500;
|
|
521
|
+
function compactJsonPreview(value, maxChars = OPERATOR_PROMPT_CONTEXT_MAX_CHARS) {
|
|
522
|
+
let raw = "";
|
|
523
|
+
if (typeof value === "string") {
|
|
524
|
+
raw = value;
|
|
525
|
+
}
|
|
526
|
+
else {
|
|
527
|
+
try {
|
|
528
|
+
raw = JSON.stringify(value);
|
|
529
|
+
}
|
|
530
|
+
catch {
|
|
531
|
+
return null;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
const compact = raw.replace(/\s+/g, " ").trim();
|
|
535
|
+
if (compact.length === 0) {
|
|
536
|
+
return null;
|
|
537
|
+
}
|
|
538
|
+
if (compact.length <= maxChars) {
|
|
539
|
+
return compact;
|
|
540
|
+
}
|
|
541
|
+
const keep = Math.max(1, maxChars - 1);
|
|
542
|
+
return `${compact.slice(0, keep)}…`;
|
|
543
|
+
}
|
|
544
|
+
function extractPromptContext(metadata) {
|
|
545
|
+
for (const key of ["client_context", "context", "editor_context"]) {
|
|
546
|
+
if (!(key in metadata)) {
|
|
547
|
+
continue;
|
|
548
|
+
}
|
|
549
|
+
const value = metadata[key];
|
|
550
|
+
if (value == null) {
|
|
551
|
+
continue;
|
|
552
|
+
}
|
|
553
|
+
if (typeof value === "object" || typeof value === "string") {
|
|
554
|
+
return value;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
return null;
|
|
558
|
+
}
|
|
559
|
+
function buildOperatorPromptContextBlock(metadata) {
|
|
560
|
+
const context = extractPromptContext(metadata);
|
|
561
|
+
if (!context) {
|
|
562
|
+
return [];
|
|
563
|
+
}
|
|
564
|
+
const preview = compactJsonPreview(context);
|
|
565
|
+
if (!preview) {
|
|
566
|
+
return [];
|
|
567
|
+
}
|
|
568
|
+
return ["", "Client context (structured preview):", preview];
|
|
569
|
+
}
|
|
570
|
+
function extractSessionFlashPromptMessages(metadata) {
|
|
571
|
+
const raw = metadata.session_flash_messages;
|
|
572
|
+
if (!Array.isArray(raw)) {
|
|
573
|
+
return [];
|
|
574
|
+
}
|
|
575
|
+
const out = [];
|
|
576
|
+
for (const value of raw) {
|
|
577
|
+
const rec = asRecord(value);
|
|
578
|
+
if (!rec) {
|
|
579
|
+
continue;
|
|
580
|
+
}
|
|
581
|
+
const flashId = nonEmptyString(rec.flash_id);
|
|
582
|
+
const body = nonEmptyString(rec.body);
|
|
583
|
+
const sessionId = nonEmptyString(rec.session_id);
|
|
584
|
+
if (!flashId || !body || !sessionId) {
|
|
585
|
+
continue;
|
|
586
|
+
}
|
|
587
|
+
out.push({
|
|
588
|
+
flash_id: flashId,
|
|
589
|
+
created_at_ms: finiteInt(rec.created_at_ms) ?? 0,
|
|
590
|
+
session_id: sessionId,
|
|
591
|
+
session_kind: nonEmptyString(rec.session_kind),
|
|
592
|
+
body,
|
|
593
|
+
context_ids: stringList(rec.context_ids),
|
|
594
|
+
source: nonEmptyString(rec.source),
|
|
595
|
+
metadata: asRecord(rec.metadata) ?? {},
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
out.sort((a, b) => a.created_at_ms - b.created_at_ms);
|
|
599
|
+
return out;
|
|
600
|
+
}
|
|
601
|
+
function buildOperatorPromptFlashBlock(metadata) {
|
|
602
|
+
const flashes = extractSessionFlashPromptMessages(metadata);
|
|
603
|
+
if (flashes.length === 0) {
|
|
604
|
+
return [];
|
|
605
|
+
}
|
|
606
|
+
const lines = ["", `Session flash messages (${flashes.length}):`];
|
|
607
|
+
for (const flash of flashes) {
|
|
608
|
+
const source = flash.source ?? "unknown";
|
|
609
|
+
const contextIds = flash.context_ids.length > 0 ? ` | context_ids=${flash.context_ids.join(",")}` : "";
|
|
610
|
+
const bodyPreview = compactJsonPreview(flash.body, 400) ?? flash.body;
|
|
611
|
+
lines.push(`- [${flash.flash_id}] source=${source}${contextIds}`);
|
|
612
|
+
lines.push(` ${bodyPreview}`);
|
|
613
|
+
}
|
|
614
|
+
lines.push("Treat these as high-priority user-provided context for this session.");
|
|
615
|
+
return lines;
|
|
616
|
+
}
|
|
388
617
|
function buildOperatorPrompt(input) {
|
|
389
|
-
|
|
618
|
+
const lines = [
|
|
390
619
|
`[Messaging context]`,
|
|
391
620
|
`channel: ${input.inbound.channel}`,
|
|
392
621
|
`request_id: ${input.inbound.request_id}`,
|
|
393
622
|
`repo_root: ${input.inbound.repo_root}`,
|
|
394
623
|
``,
|
|
395
624
|
`User message: ${input.inbound.command_text}`,
|
|
396
|
-
|
|
625
|
+
...buildOperatorPromptContextBlock(input.inbound.metadata),
|
|
626
|
+
...buildOperatorPromptFlashBlock(input.inbound.metadata),
|
|
627
|
+
];
|
|
628
|
+
return lines.join("\n");
|
|
397
629
|
}
|
|
398
630
|
function sessionFileStem(sessionId) {
|
|
399
631
|
const normalized = sessionId.trim().replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
@@ -430,7 +662,7 @@ export class PiMessagingOperatorBackend {
|
|
|
430
662
|
this.#persistSessions = opts.persistSessions ?? true;
|
|
431
663
|
this.#sessionDirForRepoRoot =
|
|
432
664
|
opts.sessionDirForRepoRoot ?? ((repoRoot) => join(repoRoot, ".mu", "control-plane", "operator-sessions"));
|
|
433
|
-
//
|
|
665
|
+
// Operator turns can emit structured command proposals captured from tool events.
|
|
434
666
|
}
|
|
435
667
|
#disposeSession(sessionId) {
|
|
436
668
|
const entry = this.#sessions.get(sessionId);
|
|
@@ -23,6 +23,11 @@ export type MuSession = {
|
|
|
23
23
|
agent: {
|
|
24
24
|
waitForIdle: () => Promise<void>;
|
|
25
25
|
};
|
|
26
|
+
sessionId?: string;
|
|
27
|
+
sessionFile?: string;
|
|
28
|
+
sessionManager?: {
|
|
29
|
+
getLeafId?: () => string | null;
|
|
30
|
+
};
|
|
26
31
|
};
|
|
27
32
|
export declare function createMuSession(opts: CreateMuSessionOpts): Promise<MuSession>;
|
|
28
33
|
//# sourceMappingURL=session_factory.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session_factory.d.ts","sourceRoot":"","sources":["../src/session_factory.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,wBAAwB,GAAG,WAAW,GAAG,iBAAiB,GAAG,KAAK,GAAG,MAAM,CAAC;AAExF,MAAM,MAAM,wBAAwB,GAAG;IACtC,IAAI,CAAC,EAAE,wBAAwB,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,OAAO,CAAC,EAAE,wBAAwB,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACvB,SAAS,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;IAC1D,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,qBAAqB,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvF,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,cAAc,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,KAAK,EAAE;QAAE,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"session_factory.d.ts","sourceRoot":"","sources":["../src/session_factory.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,wBAAwB,GAAG,WAAW,GAAG,iBAAiB,GAAG,KAAK,GAAG,MAAM,CAAC;AAExF,MAAM,MAAM,wBAAwB,GAAG;IACtC,IAAI,CAAC,EAAE,wBAAwB,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,OAAO,CAAC,EAAE,wBAAwB,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACvB,SAAS,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;IAC1D,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,qBAAqB,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvF,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,cAAc,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,KAAK,EAAE;QAAE,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,CAAC;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE;QAChB,SAAS,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;KAChC,CAAC;CACF,CAAC;AAkCF,wBAAsB,eAAe,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,SAAS,CAAC,CA2CnF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@femtomc/mu-agent",
|
|
3
|
-
"version": "26.2.
|
|
3
|
+
"version": "26.2.74",
|
|
4
4
|
"description": "Shared agent runtime for mu chat, orchestration roles, and serve extensions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mu",
|
|
@@ -24,11 +24,10 @@
|
|
|
24
24
|
"themes/**"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@femtomc/mu-core": "26.2.
|
|
27
|
+
"@femtomc/mu-core": "26.2.74",
|
|
28
28
|
"@mariozechner/pi-agent-core": "^0.53.0",
|
|
29
29
|
"@mariozechner/pi-ai": "^0.53.0",
|
|
30
30
|
"@mariozechner/pi-coding-agent": "^0.53.0",
|
|
31
|
-
"@sinclair/typebox": "^0.34.0",
|
|
32
31
|
"zod": "^4.1.9"
|
|
33
32
|
}
|
|
34
33
|
}
|
|
@@ -5,39 +5,34 @@ Mission:
|
|
|
5
5
|
- Help users with any coding tasks they ask you to handle directly.
|
|
6
6
|
- Help users inspect repository/control-plane state.
|
|
7
7
|
- Help users choose safe next actions.
|
|
8
|
-
-
|
|
8
|
+
- Execute reads and mutations through direct `mu` CLI invocation when managing mu state.
|
|
9
9
|
|
|
10
10
|
Available tools:
|
|
11
11
|
- read: Read file contents
|
|
12
|
-
- bash: Execute
|
|
12
|
+
- bash: Execute shell commands (primary path for `mu` CLI)
|
|
13
13
|
- edit: Make surgical edits to files
|
|
14
14
|
- write: Create or overwrite files
|
|
15
|
-
- query: Read-only retrieval across mu state (`action=describe|get|list|search|timeline|stats|trace`)
|
|
16
|
-
- command: Approved mutation pathway (`run_*`, `reload/update`, issue/forum lifecycle, heartbeat/cron program management)
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
16
|
+
CLI-first workflow:
|
|
17
|
+
- Use `bash` + `mu ...` for issue/forum/run/control-plane state operations.
|
|
18
|
+
- Prefer `--pretty` (or `--json` + targeted parsing) for clear, auditable output.
|
|
19
|
+
- Do not use bespoke query/command wrappers; call the CLI surface directly.
|
|
22
20
|
|
|
23
|
-
|
|
24
|
-
- `
|
|
25
|
-
- `
|
|
26
|
-
- `
|
|
27
|
-
- `
|
|
28
|
-
- `
|
|
29
|
-
- `
|
|
30
|
-
- `
|
|
21
|
+
Example invocation patterns:
|
|
22
|
+
- `bash("mu status --pretty")`
|
|
23
|
+
- `bash("mu issues list --status open --limit 20 --pretty")`
|
|
24
|
+
- `bash("mu forum read issue:mu-abc123 --limit 20 --pretty")`
|
|
25
|
+
- `bash("mu runs start \"ship release\" --max-steps 25 --pretty")`
|
|
26
|
+
- `bash("mu issues close mu-abc123 --outcome success --pretty")`
|
|
27
|
+
- `bash("mu forum post issue:mu-abc123 -m \"done\" --author operator --pretty")`
|
|
28
|
+
- `bash("mu control reload --pretty")`
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
- Prefer precise context windows via `query({ action: "search"|"timeline", resource: "context", ... })`.
|
|
36
|
-
|
|
37
|
-
Efficiency:
|
|
30
|
+
Guardrails:
|
|
31
|
+
- Never hand-edit `.mu/*.jsonl` for normal lifecycle actions; use `mu` CLI commands.
|
|
32
|
+
- Prefer bounded retrieval (`--limit`, scoped filters) before broad scans.
|
|
38
33
|
- Do NOT pre-fetch status/issues/events/runs at conversation start.
|
|
39
34
|
- Fetch only what the user request requires.
|
|
40
|
-
- Keep responses grounded in concrete
|
|
35
|
+
- Keep responses grounded in concrete command results.
|
|
41
36
|
|
|
42
37
|
For normal answers:
|
|
43
38
|
- Respond in plain text (no directive prefix).
|
|
@@ -7,9 +7,9 @@ Mission:
|
|
|
7
7
|
- Move planning state forward by closing expanded planning nodes.
|
|
8
8
|
|
|
9
9
|
Available tools:
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
10
|
+
- bash: Execute commands (use `mu` CLI for issue/forum reads + mutations)
|
|
11
|
+
- read: Read repository files when needed for planning context
|
|
12
|
+
- edit/write: available but forbidden for orchestrator execution (planning only)
|
|
13
13
|
|
|
14
14
|
Hard Constraints:
|
|
15
15
|
1. You MUST NOT execute work directly. No code changes, no file edits, no git commits.
|
|
@@ -22,20 +22,19 @@ If the task looks atomic, create exactly one worker child issue rather than doin
|
|
|
22
22
|
|
|
23
23
|
Workflow:
|
|
24
24
|
1. Inspect context:
|
|
25
|
-
- `
|
|
26
|
-
- `
|
|
27
|
-
- `
|
|
25
|
+
- `bash("mu issues get <id> --pretty")`
|
|
26
|
+
- `bash("mu forum read issue:<id> --limit 20 --pretty")`
|
|
27
|
+
- `bash("mu issues children <id> --pretty")` (or `mu issues list --root <id> --pretty`)
|
|
28
28
|
2. Decompose into worker issues:
|
|
29
|
-
- `
|
|
29
|
+
- `bash("mu issues create \"<title>\" --body \"<body>\" --tags \"node:agent,role:worker\" --parent <id> --pretty")`
|
|
30
30
|
3. Add ordering where needed:
|
|
31
|
-
- `
|
|
31
|
+
- `bash("mu issues dep <src> blocks <dst> --pretty")`
|
|
32
32
|
4. Close yourself:
|
|
33
|
-
- `
|
|
34
|
-
- (CLI equivalent: `mu issues close <id> --outcome expanded`)
|
|
33
|
+
- `bash("mu issues close <id> --outcome expanded --pretty")`
|
|
35
34
|
|
|
36
35
|
Guardrails:
|
|
37
36
|
- The only valid orchestrator close outcome is `expanded`.
|
|
38
37
|
- Never close with `success`, `failure`, `needs_work`, or `skipped`.
|
|
39
38
|
- Keep plans small, explicit, and testable.
|
|
40
39
|
- Plans should include proposed evidence for successful completion.
|
|
41
|
-
- Prefer bounded reads (
|
|
40
|
+
- Prefer bounded reads (`--limit`, scoped filters) before deep inspection.
|
|
@@ -7,10 +7,8 @@ Mission:
|
|
|
7
7
|
|
|
8
8
|
Available tools:
|
|
9
9
|
- read: Read files and logs
|
|
10
|
-
- bash: Run validation commands
|
|
10
|
+
- bash: Run validation commands (including `mu` CLI for issue/forum actions)
|
|
11
11
|
- edit/write: available but avoid changing implementation directly
|
|
12
|
-
- query: Read-only retrieval
|
|
13
|
-
- command: Mutation pathway
|
|
14
12
|
|
|
15
13
|
Hard Constraints:
|
|
16
14
|
- Do NOT create child issues. Refinement scheduling is orchestrator-owned.
|
|
@@ -19,15 +17,15 @@ Hard Constraints:
|
|
|
19
17
|
|
|
20
18
|
Workflow:
|
|
21
19
|
1. Inspect:
|
|
22
|
-
- `
|
|
23
|
-
- `
|
|
20
|
+
- `bash("mu issues get <id> --pretty")`
|
|
21
|
+
- `bash("mu forum read issue:<id> --limit 20 --pretty")`
|
|
24
22
|
2. Verify:
|
|
25
23
|
- Re-run relevant tests/checks, inspect changed files/logs.
|
|
26
24
|
3. Decide:
|
|
27
|
-
- Accept: `
|
|
28
|
-
- Refine: `
|
|
25
|
+
- Accept: `bash("mu issues close <id> --outcome success --pretty")`
|
|
26
|
+
- Refine: `bash("mu issues close <id> --outcome needs_work --pretty")`
|
|
29
27
|
4. Post rationale:
|
|
30
|
-
- `
|
|
28
|
+
- `bash("mu forum post issue:<id> -m \"<evidence + rationale>\" --author reviewer --pretty")`
|
|
31
29
|
|
|
32
30
|
Guardrails:
|
|
33
31
|
- Use concrete evidence (commands/tests) over opinion.
|
package/prompts/roles/worker.md
CHANGED
|
@@ -7,11 +7,9 @@ Mission:
|
|
|
7
7
|
|
|
8
8
|
Available tools:
|
|
9
9
|
- read: Read file contents
|
|
10
|
-
- bash: Execute
|
|
10
|
+
- bash: Execute commands (including direct `mu` CLI reads/mutations)
|
|
11
11
|
- edit: Make surgical edits to files
|
|
12
12
|
- write: Create or overwrite files
|
|
13
|
-
- query: Read-only retrieval
|
|
14
|
-
- command: Mutation pathway
|
|
15
13
|
|
|
16
14
|
Hard Constraints:
|
|
17
15
|
- Do NOT create child issues — that is the orchestrator's job.
|
|
@@ -19,19 +17,19 @@ Hard Constraints:
|
|
|
19
17
|
|
|
20
18
|
Workflow:
|
|
21
19
|
1. Inspect:
|
|
22
|
-
- `
|
|
23
|
-
- `
|
|
20
|
+
- `bash("mu issues get <id> --pretty")`
|
|
21
|
+
- `bash("mu forum read issue:<id> --limit 20 --pretty")`
|
|
24
22
|
2. Implement:
|
|
25
23
|
- Edit files and run commands needed for this issue only.
|
|
26
24
|
3. Verify:
|
|
27
25
|
- Run tests/typecheck/build/lint as appropriate.
|
|
28
26
|
4. Close:
|
|
29
|
-
- `
|
|
27
|
+
- `bash("mu issues close <id> --outcome success --pretty")` (or `failure` / `skipped` / `needs_work` when warranted)
|
|
30
28
|
5. Log key notes:
|
|
31
|
-
- `
|
|
29
|
+
- `bash("mu forum post issue:<id> -m \"...\" --author worker --pretty")`
|
|
32
30
|
|
|
33
31
|
Guardrails:
|
|
34
32
|
- Prefer concrete evidence over claims (test output, build output, repro checks).
|
|
35
33
|
- Report what changed and why.
|
|
36
|
-
- Keep command output focused: use bounded reads first (
|
|
34
|
+
- Keep command output focused: use bounded reads first (`--limit`, scoped filters) and drill into specific IDs/files next.
|
|
37
35
|
- Be concise.
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* mu-tools — Tool-only extension bundle for non-interactive roles.
|
|
3
|
-
*
|
|
4
|
-
* Registers `query` (read) and `command` (mutation).
|
|
5
|
-
*/
|
|
6
|
-
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
7
|
-
export declare function muToolsExtension(pi: ExtensionAPI): void;
|
|
8
|
-
export default muToolsExtension;
|
|
9
|
-
//# sourceMappingURL=mu-tools.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mu-tools.d.ts","sourceRoot":"","sources":["../../src/extensions/mu-tools.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAIlE,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,YAAY,QAGhD;AAED,eAAe,gBAAgB,CAAC"}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* mu-tools — Tool-only extension bundle for non-interactive roles.
|
|
3
|
-
*
|
|
4
|
-
* Registers `query` (read) and `command` (mutation).
|
|
5
|
-
*/
|
|
6
|
-
import { operatorCommandExtension } from "./operator-command.js";
|
|
7
|
-
import { queryExtension } from "./query.js";
|
|
8
|
-
export function muToolsExtension(pi) {
|
|
9
|
-
queryExtension(pi);
|
|
10
|
-
operatorCommandExtension(pi);
|
|
11
|
-
}
|
|
12
|
-
export default muToolsExtension;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* command — Approved mutation tool.
|
|
3
|
-
*
|
|
4
|
-
* Single execution path:
|
|
5
|
-
* - Requires MU_SERVER_URL.
|
|
6
|
-
* - Always POSTs to /api/commands/submit.
|
|
7
|
-
* - Supports mutation-capable command kinds only.
|
|
8
|
-
*/
|
|
9
|
-
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
10
|
-
export declare const COMMAND_TOOL_NAME = "command";
|
|
11
|
-
export declare function operatorCommandExtension(pi: ExtensionAPI): void;
|
|
12
|
-
export default operatorCommandExtension;
|
|
13
|
-
//# sourceMappingURL=operator-command.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"operator-command.d.ts","sourceRoot":"","sources":["../../src/extensions/operator-command.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAGlE,eAAO,MAAM,iBAAiB,YAAY,CAAC;AA2H3C,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,YAAY,QA6FxD;AAED,eAAe,wBAAwB,CAAC"}
|