@femtomc/mu-agent 26.2.102 → 26.2.103
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 +4 -3
- package/dist/operator.d.ts.map +1 -1
- package/dist/operator.js +2 -169
- package/dist/session_factory.d.ts.map +1 -1
- package/dist/session_factory.js +21 -8
- package/dist/session_turn.d.ts.map +1 -1
- package/dist/session_turn.js +71 -16
- package/package.json +5 -5
- package/prompts/roles/operator.md +1 -0
- package/prompts/skills/memory/SKILL.md +0 -3
- package/prompts/skills/mu/SKILL.md +87 -18
- package/prompts/skills/setup-telegram/SKILL.md +5 -19
- package/prompts/skills/writing/SKILL.md +179 -0
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@ These are loaded by runtime code and are the single source of truth for default
|
|
|
22
22
|
## Bundled starter skills
|
|
23
23
|
|
|
24
24
|
Bundled starter skills live under `packages/agent/prompts/skills/` and are bootstrapped
|
|
25
|
-
into `~/.mu/skills/` (or `$MU_HOME/skills/`)
|
|
25
|
+
into `~/.mu/skills/` (or `$MU_HOME/skills/`) by the CLI store-initialization path:
|
|
26
26
|
|
|
27
27
|
- `mu`
|
|
28
28
|
- `memory`
|
|
@@ -36,9 +36,10 @@ into `~/.mu/skills/` (or `$MU_HOME/skills/`) when missing:
|
|
|
36
36
|
- `setup-discord`
|
|
37
37
|
- `setup-telegram`
|
|
38
38
|
- `setup-neovim`
|
|
39
|
+
- `writing`
|
|
39
40
|
|
|
40
|
-
Starter skills are version-synced by
|
|
41
|
-
|
|
41
|
+
Starter skills are version-synced by CLI bootstrap. Initial bootstrap seeds missing
|
|
42
|
+
skills; bundled-version changes refresh installed starter skill files.
|
|
42
43
|
|
|
43
44
|
## Install
|
|
44
45
|
|
package/dist/operator.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"operator.d.ts","sourceRoot":"","sources":["../src/operator.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"operator.d.ts","sourceRoot":"","sources":["../src/operator.ts"],"names":[],"mappings":"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"}
|
package/dist/operator.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { HudDocSchema, normalizeHudDocs } from "@femtomc/mu-core";
|
|
2
|
-
import { appendJsonl, getStorePaths
|
|
2
|
+
import { appendJsonl, getStorePaths } from "@femtomc/mu-core/node";
|
|
3
3
|
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
4
4
|
import { dirname, join } from "node:path";
|
|
5
5
|
import { z } from "zod";
|
|
@@ -292,93 +292,6 @@ function collectHudDocsFromToolExecutionEvent(event) {
|
|
|
292
292
|
}
|
|
293
293
|
return extractHudDocsFromToolResult(rec.result);
|
|
294
294
|
}
|
|
295
|
-
function finiteInt(value) {
|
|
296
|
-
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
297
|
-
return null;
|
|
298
|
-
}
|
|
299
|
-
return Math.trunc(value);
|
|
300
|
-
}
|
|
301
|
-
function stringList(value) {
|
|
302
|
-
if (!Array.isArray(value)) {
|
|
303
|
-
return [];
|
|
304
|
-
}
|
|
305
|
-
const out = [];
|
|
306
|
-
for (const item of value) {
|
|
307
|
-
const parsed = nonEmptyString(item);
|
|
308
|
-
if (parsed) {
|
|
309
|
-
out.push(parsed);
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
return out;
|
|
313
|
-
}
|
|
314
|
-
function sessionFlashPath(repoRoot) {
|
|
315
|
-
return join(getStorePaths(repoRoot).storeDir, "control-plane", "session_flash.jsonl");
|
|
316
|
-
}
|
|
317
|
-
async function loadPendingSessionFlashes(opts) {
|
|
318
|
-
const rows = await readJsonl(sessionFlashPath(opts.repoRoot));
|
|
319
|
-
const created = new Map();
|
|
320
|
-
const delivered = new Set();
|
|
321
|
-
for (const row of rows) {
|
|
322
|
-
const rec = asRecord(row);
|
|
323
|
-
if (!rec) {
|
|
324
|
-
continue;
|
|
325
|
-
}
|
|
326
|
-
const kind = nonEmptyString(rec.kind);
|
|
327
|
-
if (kind === "session_flash.create") {
|
|
328
|
-
const tsMs = finiteInt(rec.ts_ms) ?? Date.now();
|
|
329
|
-
const flashId = nonEmptyString(rec.flash_id);
|
|
330
|
-
const sessionId = nonEmptyString(rec.session_id);
|
|
331
|
-
const body = nonEmptyString(rec.body);
|
|
332
|
-
if (!flashId || !sessionId || !body || sessionId !== opts.sessionId) {
|
|
333
|
-
continue;
|
|
334
|
-
}
|
|
335
|
-
created.set(flashId, {
|
|
336
|
-
flash_id: flashId,
|
|
337
|
-
created_at_ms: tsMs,
|
|
338
|
-
session_id: sessionId,
|
|
339
|
-
session_kind: nonEmptyString(rec.session_kind),
|
|
340
|
-
body,
|
|
341
|
-
context_ids: stringList(rec.context_ids),
|
|
342
|
-
source: nonEmptyString(rec.source),
|
|
343
|
-
metadata: asRecord(rec.metadata) ?? {},
|
|
344
|
-
});
|
|
345
|
-
continue;
|
|
346
|
-
}
|
|
347
|
-
if (kind === "session_flash.delivery") {
|
|
348
|
-
const flashId = nonEmptyString(rec.flash_id);
|
|
349
|
-
const sessionId = nonEmptyString(rec.session_id);
|
|
350
|
-
if (!flashId || !sessionId || sessionId !== opts.sessionId) {
|
|
351
|
-
continue;
|
|
352
|
-
}
|
|
353
|
-
delivered.add(flashId);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
const pending = [...created.values()]
|
|
357
|
-
.filter((row) => !delivered.has(row.flash_id))
|
|
358
|
-
.sort((a, b) => a.created_at_ms - b.created_at_ms);
|
|
359
|
-
const limit = Math.max(1, Math.trunc(opts.limit ?? 16));
|
|
360
|
-
if (pending.length <= limit) {
|
|
361
|
-
return pending;
|
|
362
|
-
}
|
|
363
|
-
return pending.slice(pending.length - limit);
|
|
364
|
-
}
|
|
365
|
-
async function markSessionFlashesDelivered(opts) {
|
|
366
|
-
if (opts.flashIds.length === 0) {
|
|
367
|
-
return;
|
|
368
|
-
}
|
|
369
|
-
const deduped = [...new Set(opts.flashIds.filter((id) => id.trim().length > 0))];
|
|
370
|
-
for (const flashId of deduped) {
|
|
371
|
-
const row = {
|
|
372
|
-
kind: "session_flash.delivery",
|
|
373
|
-
ts_ms: opts.nowMs,
|
|
374
|
-
flash_id: flashId,
|
|
375
|
-
session_id: opts.sessionId,
|
|
376
|
-
delivered_by: "messaging_operator_runtime",
|
|
377
|
-
note: null,
|
|
378
|
-
};
|
|
379
|
-
await appendJsonl(sessionFlashPath(opts.repoRoot), row);
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
295
|
export class JsonFileConversationSessionStore {
|
|
383
296
|
#path;
|
|
384
297
|
#loaded = false;
|
|
@@ -551,46 +464,14 @@ export class MessagingOperatorRuntime {
|
|
|
551
464
|
operatorTurnId: turnId,
|
|
552
465
|
};
|
|
553
466
|
}
|
|
554
|
-
let pendingFlashes = [];
|
|
555
|
-
try {
|
|
556
|
-
pendingFlashes = await loadPendingSessionFlashes({
|
|
557
|
-
repoRoot: opts.inbound.repo_root,
|
|
558
|
-
sessionId,
|
|
559
|
-
});
|
|
560
|
-
}
|
|
561
|
-
catch {
|
|
562
|
-
pendingFlashes = [];
|
|
563
|
-
}
|
|
564
|
-
const inboundForBackend = pendingFlashes.length > 0
|
|
565
|
-
? {
|
|
566
|
-
...opts.inbound,
|
|
567
|
-
metadata: {
|
|
568
|
-
...opts.inbound.metadata,
|
|
569
|
-
session_flash_messages: pendingFlashes,
|
|
570
|
-
},
|
|
571
|
-
}
|
|
572
|
-
: opts.inbound;
|
|
573
467
|
let backendResult;
|
|
574
468
|
try {
|
|
575
469
|
backendResult = OperatorBackendTurnResultSchema.parse(await this.#backend.runTurn({
|
|
576
470
|
sessionId,
|
|
577
471
|
turnId,
|
|
578
|
-
inbound:
|
|
472
|
+
inbound: opts.inbound,
|
|
579
473
|
binding: opts.binding,
|
|
580
474
|
}));
|
|
581
|
-
if (pendingFlashes.length > 0) {
|
|
582
|
-
try {
|
|
583
|
-
await markSessionFlashesDelivered({
|
|
584
|
-
repoRoot: opts.inbound.repo_root,
|
|
585
|
-
sessionId,
|
|
586
|
-
flashIds: pendingFlashes.map((row) => row.flash_id),
|
|
587
|
-
nowMs: Date.now(),
|
|
588
|
-
});
|
|
589
|
-
}
|
|
590
|
-
catch {
|
|
591
|
-
// Best-effort delivery bookkeeping; do not fail the operator turn.
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
475
|
}
|
|
595
476
|
catch (err) {
|
|
596
477
|
const failureCode = classifyBackendFailureCode(err);
|
|
@@ -707,53 +588,6 @@ function buildOperatorPromptContextBlock(metadata) {
|
|
|
707
588
|
}
|
|
708
589
|
return ["", "Client context (structured preview):", preview];
|
|
709
590
|
}
|
|
710
|
-
function extractSessionFlashPromptMessages(metadata) {
|
|
711
|
-
const raw = metadata.session_flash_messages;
|
|
712
|
-
if (!Array.isArray(raw)) {
|
|
713
|
-
return [];
|
|
714
|
-
}
|
|
715
|
-
const out = [];
|
|
716
|
-
for (const value of raw) {
|
|
717
|
-
const rec = asRecord(value);
|
|
718
|
-
if (!rec) {
|
|
719
|
-
continue;
|
|
720
|
-
}
|
|
721
|
-
const flashId = nonEmptyString(rec.flash_id);
|
|
722
|
-
const body = nonEmptyString(rec.body);
|
|
723
|
-
const sessionId = nonEmptyString(rec.session_id);
|
|
724
|
-
if (!flashId || !body || !sessionId) {
|
|
725
|
-
continue;
|
|
726
|
-
}
|
|
727
|
-
out.push({
|
|
728
|
-
flash_id: flashId,
|
|
729
|
-
created_at_ms: finiteInt(rec.created_at_ms) ?? 0,
|
|
730
|
-
session_id: sessionId,
|
|
731
|
-
session_kind: nonEmptyString(rec.session_kind),
|
|
732
|
-
body,
|
|
733
|
-
context_ids: stringList(rec.context_ids),
|
|
734
|
-
source: nonEmptyString(rec.source),
|
|
735
|
-
metadata: asRecord(rec.metadata) ?? {},
|
|
736
|
-
});
|
|
737
|
-
}
|
|
738
|
-
out.sort((a, b) => a.created_at_ms - b.created_at_ms);
|
|
739
|
-
return out;
|
|
740
|
-
}
|
|
741
|
-
function buildOperatorPromptFlashBlock(metadata) {
|
|
742
|
-
const flashes = extractSessionFlashPromptMessages(metadata);
|
|
743
|
-
if (flashes.length === 0) {
|
|
744
|
-
return [];
|
|
745
|
-
}
|
|
746
|
-
const lines = ["", `Session flash messages (${flashes.length}):`];
|
|
747
|
-
for (const flash of flashes) {
|
|
748
|
-
const source = flash.source ?? "unknown";
|
|
749
|
-
const contextIds = flash.context_ids.length > 0 ? ` | context_ids=${flash.context_ids.join(",")}` : "";
|
|
750
|
-
const bodyPreview = compactJsonPreview(flash.body, 400) ?? flash.body;
|
|
751
|
-
lines.push(`- [${flash.flash_id}] source=${source}${contextIds}`);
|
|
752
|
-
lines.push(` ${bodyPreview}`);
|
|
753
|
-
}
|
|
754
|
-
lines.push("Treat these as high-priority user-provided context for this session.");
|
|
755
|
-
return lines;
|
|
756
|
-
}
|
|
757
591
|
function buildOperatorPrompt(input) {
|
|
758
592
|
const lines = [
|
|
759
593
|
`[Messaging context]`,
|
|
@@ -763,7 +597,6 @@ function buildOperatorPrompt(input) {
|
|
|
763
597
|
``,
|
|
764
598
|
`User message: ${input.inbound.command_text}`,
|
|
765
599
|
...buildOperatorPromptContextBlock(input.inbound.metadata),
|
|
766
|
-
...buildOperatorPromptFlashBlock(input.inbound.metadata),
|
|
767
600
|
];
|
|
768
601
|
return lines.join("\n");
|
|
769
602
|
}
|
|
@@ -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,KAAK,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,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;
|
|
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,KAAK,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,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;AAsCF,wBAAsB,eAAe,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,SAAS,CAAC,CAuDnF"}
|
package/dist/session_factory.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { createBashTool, createEditTool, createReadTool, createWriteTool } from "@mariozechner/pi-coding-agent";
|
|
2
2
|
import { createMuResourceLoader, resolveModel } from "./backend.js";
|
|
3
3
|
import { MU_DEFAULT_THEME_NAME, MU_DEFAULT_THEME_PATH } from "./ui_defaults.js";
|
|
4
|
+
function resolveSessionPersistenceMode(sessionOpts) {
|
|
5
|
+
return sessionOpts?.mode ?? (sessionOpts?.sessionFile ? "open" : "continue-recent");
|
|
6
|
+
}
|
|
4
7
|
function createSessionManager(SessionManager, cwd, sessionOpts) {
|
|
5
|
-
const mode =
|
|
8
|
+
const mode = resolveSessionPersistenceMode(sessionOpts);
|
|
6
9
|
const sessionDir = sessionOpts?.sessionDir;
|
|
7
10
|
switch (mode) {
|
|
8
11
|
case "continue-recent":
|
|
@@ -23,10 +26,13 @@ function createSessionManager(SessionManager, cwd, sessionOpts) {
|
|
|
23
26
|
export async function createMuSession(opts) {
|
|
24
27
|
const { AuthStorage, createAgentSession, SessionManager, SettingsManager } = await import("@mariozechner/pi-coding-agent");
|
|
25
28
|
const authStorage = AuthStorage.create();
|
|
29
|
+
const sessionMode = resolveSessionPersistenceMode(opts.session);
|
|
30
|
+
const shouldRestoreSessionConfig = sessionMode === "open" && !opts.provider && !opts.model;
|
|
26
31
|
const defaultModel = "gpt-5.3-codex";
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
|
|
32
|
+
const requestedModelId = opts.model?.trim();
|
|
33
|
+
const modelId = requestedModelId && requestedModelId.length > 0 ? requestedModelId : shouldRestoreSessionConfig ? null : defaultModel;
|
|
34
|
+
const model = modelId ? resolveModel(modelId, authStorage, opts.provider) : undefined;
|
|
35
|
+
if (modelId && !model) {
|
|
30
36
|
const scope = opts.provider ? ` in provider "${opts.provider}"` : "";
|
|
31
37
|
throw new Error(`Model "${modelId}" not found${scope} in pi-ai registry.`);
|
|
32
38
|
}
|
|
@@ -45,15 +51,22 @@ export async function createMuSession(opts) {
|
|
|
45
51
|
createWriteTool(opts.cwd),
|
|
46
52
|
createEditTool(opts.cwd),
|
|
47
53
|
];
|
|
48
|
-
const
|
|
54
|
+
const requestedThinking = opts.thinking?.trim();
|
|
55
|
+
const thinkingLevel = requestedThinking && requestedThinking.length > 0
|
|
56
|
+
? requestedThinking
|
|
57
|
+
: shouldRestoreSessionConfig
|
|
58
|
+
? undefined
|
|
59
|
+
: "minimal";
|
|
60
|
+
const createOpts = {
|
|
49
61
|
cwd: opts.cwd,
|
|
50
|
-
model,
|
|
62
|
+
...(model ? { model } : {}),
|
|
51
63
|
tools,
|
|
52
|
-
thinkingLevel:
|
|
64
|
+
...(thinkingLevel ? { thinkingLevel: thinkingLevel } : {}),
|
|
53
65
|
sessionManager: createSessionManager(SessionManager, opts.cwd, opts.session),
|
|
54
66
|
settingsManager,
|
|
55
67
|
resourceLoader,
|
|
56
68
|
authStorage,
|
|
57
|
-
}
|
|
69
|
+
};
|
|
70
|
+
const { session } = await createAgentSession(createOpts);
|
|
58
71
|
return session;
|
|
59
72
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session_turn.d.ts","sourceRoot":"","sources":["../src/session_turn.ts"],"names":[],"mappings":"AAKA,OAAO,EAAmB,KAAK,mBAAmB,EAAE,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjG,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,aAAa,CAAC;AACrD,MAAM,MAAM,uBAAuB,GAAG,UAAU,GAAG,MAAM,CAAC;AAE1D,MAAM,MAAM,kBAAkB,GAAG;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,WAAW,GAAG,IAAI,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,iBAAiB,EAAE,uBAAuB,GAAG,IAAI,CAAC;CAClD,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,WAAW,GAAG,IAAI,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,qBAAa,gBAAiB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEL,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAIlD;
|
|
1
|
+
{"version":3,"file":"session_turn.d.ts","sourceRoot":"","sources":["../src/session_turn.ts"],"names":[],"mappings":"AAKA,OAAO,EAAmB,KAAK,mBAAmB,EAAE,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjG,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,aAAa,CAAC;AACrD,MAAM,MAAM,uBAAuB,GAAG,UAAU,GAAG,MAAM,CAAC;AAE1D,MAAM,MAAM,kBAAkB,GAAG;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,WAAW,GAAG,IAAI,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,iBAAiB,EAAE,uBAAuB,GAAG,IAAI,CAAC;CAClD,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,WAAW,GAAG,IAAI,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,qBAAa,gBAAiB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEL,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAIlD;AAuUD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IACvE,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACnC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,CAyCA;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,kBAAkB,CAAC;IAC5B,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,mBAAmB,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACnE,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;CACrB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAgG7B"}
|
package/dist/session_turn.js
CHANGED
|
@@ -65,6 +65,29 @@ function defaultSessionDirForKind(repoRoot, sessionKind) {
|
|
|
65
65
|
return join(storeDir, "control-plane", "operator-sessions");
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
|
+
function normalizePathForPrefixMatch(path) {
|
|
69
|
+
return resolve(path).replaceAll("\\", "/");
|
|
70
|
+
}
|
|
71
|
+
function inferSessionKindFromSessionDir(repoRoot, sessionDir) {
|
|
72
|
+
const storeDir = getStorePaths(repoRoot).storeDir;
|
|
73
|
+
const normalizedSessionDir = normalizePathForPrefixMatch(sessionDir);
|
|
74
|
+
const operatorDir = normalizePathForPrefixMatch(join(storeDir, "operator", "sessions"));
|
|
75
|
+
if (normalizedSessionDir === operatorDir || normalizedSessionDir.startsWith(`${operatorDir}/`)) {
|
|
76
|
+
return "operator";
|
|
77
|
+
}
|
|
78
|
+
const cpOperatorDir = normalizePathForPrefixMatch(join(storeDir, "control-plane", "operator-sessions"));
|
|
79
|
+
if (normalizedSessionDir === cpOperatorDir || normalizedSessionDir.startsWith(`${cpOperatorDir}/`)) {
|
|
80
|
+
return "cp_operator";
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
function defaultSessionLookupTargets(repoRoot) {
|
|
85
|
+
const storeDir = getStorePaths(repoRoot).storeDir;
|
|
86
|
+
return [
|
|
87
|
+
{ sessionKind: "operator", sessionDir: join(storeDir, "operator", "sessions") },
|
|
88
|
+
{ sessionKind: "cp_operator", sessionDir: join(storeDir, "control-plane", "operator-sessions") },
|
|
89
|
+
];
|
|
90
|
+
}
|
|
68
91
|
async function pathExists(path) {
|
|
69
92
|
try {
|
|
70
93
|
await stat(path);
|
|
@@ -208,9 +231,7 @@ function safeSessionFile(session) {
|
|
|
208
231
|
return typeof value === "string" && value.trim().length > 0 ? value : null;
|
|
209
232
|
}
|
|
210
233
|
async function resolveSessionTarget(opts) {
|
|
211
|
-
const
|
|
212
|
-
? resolveRepoPath(opts.repoRoot, opts.request.session_dir)
|
|
213
|
-
: defaultSessionDirForKind(opts.repoRoot, opts.normalizedSessionKind);
|
|
234
|
+
const explicitSessionDir = opts.request.session_dir ? resolveRepoPath(opts.repoRoot, opts.request.session_dir) : null;
|
|
214
235
|
if (opts.request.session_file) {
|
|
215
236
|
const sessionFile = resolveRepoPath(opts.repoRoot, opts.request.session_file);
|
|
216
237
|
if (!(await pathExists(sessionFile))) {
|
|
@@ -223,22 +244,55 @@ async function resolveSessionTarget(opts) {
|
|
|
223
244
|
if (headerId !== opts.request.session_id) {
|
|
224
245
|
throw new SessionTurnError(409, `session_file header id mismatch (expected ${opts.request.session_id}, found ${headerId})`);
|
|
225
246
|
}
|
|
247
|
+
const sessionDir = explicitSessionDir ?? dirname(sessionFile);
|
|
248
|
+
return {
|
|
249
|
+
sessionFile,
|
|
250
|
+
sessionDir,
|
|
251
|
+
sessionKind: opts.normalizedSessionKind ?? inferSessionKindFromSessionDir(opts.repoRoot, sessionDir),
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
if (explicitSessionDir || opts.normalizedSessionKind) {
|
|
255
|
+
const sessionDir = explicitSessionDir ?? defaultSessionDirForKind(opts.repoRoot, opts.normalizedSessionKind);
|
|
256
|
+
if (!(await directoryExists(sessionDir))) {
|
|
257
|
+
throw new SessionTurnError(404, `session directory not found: ${sessionDir}`);
|
|
258
|
+
}
|
|
259
|
+
const sessionFile = await resolveSessionFileById({
|
|
260
|
+
sessionDir,
|
|
261
|
+
sessionId: opts.request.session_id,
|
|
262
|
+
});
|
|
263
|
+
if (!sessionFile) {
|
|
264
|
+
throw new SessionTurnError(404, `session_id not found in ${sessionDir}: ${opts.request.session_id}`);
|
|
265
|
+
}
|
|
226
266
|
return {
|
|
227
267
|
sessionFile,
|
|
228
|
-
sessionDir
|
|
268
|
+
sessionDir,
|
|
269
|
+
sessionKind: opts.normalizedSessionKind ?? inferSessionKindFromSessionDir(opts.repoRoot, sessionDir),
|
|
229
270
|
};
|
|
230
271
|
}
|
|
231
|
-
|
|
232
|
-
|
|
272
|
+
const matches = [];
|
|
273
|
+
for (const target of defaultSessionLookupTargets(opts.repoRoot)) {
|
|
274
|
+
if (!(await directoryExists(target.sessionDir))) {
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
const sessionFile = await resolveSessionFileById({
|
|
278
|
+
sessionDir: target.sessionDir,
|
|
279
|
+
sessionId: opts.request.session_id,
|
|
280
|
+
});
|
|
281
|
+
if (sessionFile) {
|
|
282
|
+
matches.push({
|
|
283
|
+
sessionFile,
|
|
284
|
+
sessionDir: target.sessionDir,
|
|
285
|
+
sessionKind: target.sessionKind,
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
if (matches.length === 1) {
|
|
290
|
+
return matches[0];
|
|
233
291
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
sessionId: opts.request.session_id,
|
|
237
|
-
});
|
|
238
|
-
if (!sessionFile) {
|
|
239
|
-
throw new SessionTurnError(404, `session_id not found in ${sessionDir}: ${opts.request.session_id}`);
|
|
292
|
+
if (matches.length > 1) {
|
|
293
|
+
throw new SessionTurnError(409, `session_id is ambiguous across operator/cp_operator stores: ${opts.request.session_id} (pass --session-kind or --session-dir)`);
|
|
240
294
|
}
|
|
241
|
-
|
|
295
|
+
throw new SessionTurnError(404, `session_id not found in operator/cp_operator stores: ${opts.request.session_id}`);
|
|
242
296
|
}
|
|
243
297
|
export function parseSessionTurnRequest(body) {
|
|
244
298
|
const sessionId = nonEmptyString(body.session_id);
|
|
@@ -289,18 +343,19 @@ export async function executeSessionTurn(opts) {
|
|
|
289
343
|
request: opts.request,
|
|
290
344
|
normalizedSessionKind,
|
|
291
345
|
});
|
|
346
|
+
const effectiveSessionKind = target.sessionKind ?? normalizedSessionKind;
|
|
292
347
|
const sessionFactory = opts.sessionFactory ?? createMuSession;
|
|
293
348
|
const session = await sessionFactory({
|
|
294
349
|
cwd: opts.repoRoot,
|
|
295
350
|
systemPrompt: systemPromptForTurn({
|
|
296
|
-
sessionKind:
|
|
351
|
+
sessionKind: effectiveSessionKind,
|
|
297
352
|
extensionProfile,
|
|
298
353
|
}),
|
|
299
354
|
provider: opts.request.provider ?? undefined,
|
|
300
355
|
model: opts.request.model ?? undefined,
|
|
301
356
|
thinking: opts.request.thinking ?? undefined,
|
|
302
357
|
extensionPaths: extensionPathsForTurn({
|
|
303
|
-
sessionKind:
|
|
358
|
+
sessionKind: effectiveSessionKind,
|
|
304
359
|
extensionProfile,
|
|
305
360
|
}),
|
|
306
361
|
session: {
|
|
@@ -365,7 +420,7 @@ export async function executeSessionTurn(opts) {
|
|
|
365
420
|
}
|
|
366
421
|
return {
|
|
367
422
|
session_id: resolvedSessionId ?? opts.request.session_id,
|
|
368
|
-
session_kind:
|
|
423
|
+
session_kind: effectiveSessionKind,
|
|
369
424
|
session_file: resolvedSessionFile ?? target.sessionFile,
|
|
370
425
|
context_entry_id: contextEntryId,
|
|
371
426
|
reply,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@femtomc/mu-agent",
|
|
3
|
-
"version": "26.2.
|
|
3
|
+
"version": "26.2.103",
|
|
4
4
|
"description": "Shared operator runtime for mu assistant sessions and serve extensions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mu",
|
|
@@ -24,10 +24,10 @@
|
|
|
24
24
|
"themes/**"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@femtomc/mu-core": "26.2.
|
|
28
|
-
"@mariozechner/pi-agent-core": "^0.
|
|
29
|
-
"@mariozechner/pi-ai": "^0.
|
|
30
|
-
"@mariozechner/pi-coding-agent": "^0.
|
|
27
|
+
"@femtomc/mu-core": "26.2.103",
|
|
28
|
+
"@mariozechner/pi-agent-core": "^0.54.2",
|
|
29
|
+
"@mariozechner/pi-ai": "^0.54.2",
|
|
30
|
+
"@mariozechner/pi-coding-agent": "^0.54.2",
|
|
31
31
|
"zod": "^4.1.9"
|
|
32
32
|
}
|
|
33
33
|
}
|
|
@@ -19,5 +19,6 @@ Using `mu`:
|
|
|
19
19
|
- The `mu` CLI is self-explanatory: poke around with `mu --help` to understand.
|
|
20
20
|
- Use `mu memory search|timeline|stats` to access contextual memory from past interactions.
|
|
21
21
|
- Use `mu memory index status|rebuild` to inspect/refresh local memory index health when needed.
|
|
22
|
+
- Use `mu control harness [provider] --json --pretty` to inspect harness adapter/provider/model configuration and model capability vectors.
|
|
22
23
|
- Use `mu heartbeats` and `mu cron` to access persistent scheduled processes that broadcast to the user.
|
|
23
24
|
|
|
@@ -136,9 +136,6 @@ mu memory stats --pretty
|
|
|
136
136
|
- adjust anchors (`issue_id`, `run_id`, `session_id`, `topic`, channel metadata)
|
|
137
137
|
- rebuild selected sources only
|
|
138
138
|
|
|
139
|
-
Compatibility note:
|
|
140
|
-
- `mu context ...` remains an alias to `mu memory ...`.
|
|
141
|
-
|
|
142
139
|
## Evaluation scenarios
|
|
143
140
|
|
|
144
141
|
1. **Issue-scoped context retrieval**
|
|
@@ -11,9 +11,10 @@ run focused execution loops, and hand off to specialized skills when needed.
|
|
|
11
11
|
## Contents
|
|
12
12
|
|
|
13
13
|
- [Core contract](#core-contract)
|
|
14
|
+
- [CLI capability map](#cli-capability-map)
|
|
14
15
|
- [Default bounded investigation loop](#default-bounded-investigation-loop)
|
|
15
|
-
- [Common mutation patterns](#common-mutation-patterns)
|
|
16
|
-
- [Session and
|
|
16
|
+
- [Common mutation and diagnostics patterns](#common-mutation-and-diagnostics-patterns)
|
|
17
|
+
- [Session, serve, and one-shot surfaces](#session-serve-and-one-shot-surfaces)
|
|
17
18
|
- [Durable automation handoff](#durable-automation-handoff)
|
|
18
19
|
- [Evaluation scenarios](#evaluation-scenarios)
|
|
19
20
|
- [Escalation map](#escalation-map)
|
|
@@ -25,25 +26,66 @@ run focused execution loops, and hand off to specialized skills when needed.
|
|
|
25
26
|
- Start with bounded queries (`--limit`, scoped filters), then drill into specific entities.
|
|
26
27
|
|
|
27
28
|
2. **CLI-first state operations**
|
|
28
|
-
-
|
|
29
|
+
- Use `mu` command surfaces for state reads/writes (`issues`, `forum`, `memory`, `events`, `control`, `store`, `session`).
|
|
29
30
|
- Avoid hand-editing JSONL runtime journals for normal operations.
|
|
30
31
|
|
|
31
32
|
3. **Read -> act -> verify loop**
|
|
32
33
|
- Before writes: inspect relevant current state.
|
|
33
34
|
- After writes: re-read to confirm effect.
|
|
34
35
|
|
|
35
|
-
4. **
|
|
36
|
+
4. **Prefer self-discovery when uncertain**
|
|
37
|
+
- Run `mu --help` and `mu <command> --help` instead of guessing flags/subcommands.
|
|
38
|
+
- Use `mu guide` for the canonical in-CLI workflow map.
|
|
39
|
+
|
|
40
|
+
5. **Keep work reversible and explicit**
|
|
36
41
|
- Prefer small, composable steps.
|
|
37
42
|
- State assumptions and blockers clearly.
|
|
38
43
|
|
|
44
|
+
## CLI capability map
|
|
45
|
+
|
|
46
|
+
Use these command groups as the source of truth for current capabilities:
|
|
47
|
+
|
|
48
|
+
- Orientation + summaries:
|
|
49
|
+
- `mu --help`
|
|
50
|
+
- `mu guide`
|
|
51
|
+
- `mu status --pretty`
|
|
52
|
+
- Work graph + coordination:
|
|
53
|
+
- `mu issues <subcmd>`
|
|
54
|
+
- `mu forum <subcmd>`
|
|
55
|
+
- Context retrieval + traces:
|
|
56
|
+
- `mu memory <search|timeline|stats|index ...>`
|
|
57
|
+
- `mu events <list|trace ...>`
|
|
58
|
+
- Control-plane + operator config:
|
|
59
|
+
- `mu control status`
|
|
60
|
+
- `mu control harness`
|
|
61
|
+
- `mu control identities`
|
|
62
|
+
- `mu control operator <...>`
|
|
63
|
+
- `mu control config <get|set|unset ...>`
|
|
64
|
+
- `mu control reload`
|
|
65
|
+
- `mu control diagnose-operator`
|
|
66
|
+
- Session/runtime surfaces:
|
|
67
|
+
- `mu serve`, `mu stop`
|
|
68
|
+
- `mu session [list|config|<id>]`
|
|
69
|
+
- `mu turn ...`
|
|
70
|
+
- `mu exec ...`
|
|
71
|
+
- Durable automation:
|
|
72
|
+
- `mu heartbeats <...>`
|
|
73
|
+
- `mu cron <...>`
|
|
74
|
+
- Store forensics + replay:
|
|
75
|
+
- `mu store <paths|ls|tail ...>`
|
|
76
|
+
- `mu replay <id|path>`
|
|
77
|
+
- Provider auth:
|
|
78
|
+
- `mu login [<provider>] [--list] [--logout]`
|
|
79
|
+
|
|
39
80
|
## Default bounded investigation loop
|
|
40
81
|
|
|
41
82
|
```bash
|
|
42
83
|
mu status --pretty
|
|
43
84
|
mu issues list --status open --limit 20 --pretty
|
|
44
85
|
mu issues ready --limit 20 --pretty
|
|
45
|
-
mu forum
|
|
86
|
+
mu forum topics --prefix issue: --limit 20 --pretty
|
|
46
87
|
mu memory search --query "<topic>" --limit 20
|
|
88
|
+
mu events list --limit 20 --pretty
|
|
47
89
|
mu store tail events --limit 20 --pretty
|
|
48
90
|
```
|
|
49
91
|
|
|
@@ -52,37 +94,54 @@ Then inspect concrete targets:
|
|
|
52
94
|
```bash
|
|
53
95
|
mu issues get <id> --pretty
|
|
54
96
|
mu forum read issue:<id> --limit 20 --pretty
|
|
97
|
+
mu memory timeline --issue-id <id> --order desc --limit 40 --pretty
|
|
55
98
|
```
|
|
56
99
|
|
|
57
|
-
## Common mutation patterns
|
|
100
|
+
## Common mutation and diagnostics patterns
|
|
58
101
|
|
|
59
102
|
Issue/forum lifecycle:
|
|
60
103
|
|
|
61
104
|
```bash
|
|
105
|
+
mu issues claim <id> --pretty
|
|
62
106
|
mu issues update <id> --status in_progress --pretty
|
|
63
107
|
mu forum post issue:<id> -m "START: <plan>" --author operator
|
|
64
108
|
mu forum post issue:<id> -m "RESULT: <summary>" --author operator
|
|
65
109
|
mu issues close <id> --outcome success --pretty
|
|
66
110
|
```
|
|
67
111
|
|
|
68
|
-
Control-plane lifecycle:
|
|
112
|
+
Control-plane lifecycle and config:
|
|
69
113
|
|
|
70
114
|
```bash
|
|
71
115
|
mu control status --pretty
|
|
116
|
+
mu control harness --pretty
|
|
72
117
|
mu control identities --all --pretty
|
|
118
|
+
mu control config get --pretty
|
|
119
|
+
mu control operator get --pretty
|
|
73
120
|
mu control reload
|
|
74
121
|
```
|
|
75
122
|
|
|
76
|
-
|
|
123
|
+
Targeted config/operator updates:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
mu control config set control_plane.operator.enabled false
|
|
127
|
+
mu control config set control_plane.memory_index.every_ms 120000
|
|
128
|
+
mu control operator set openai-codex gpt-5.3-codex high
|
|
129
|
+
mu control diagnose-operator --limit 40 --pretty
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Store forensics and run replay:
|
|
77
133
|
|
|
78
134
|
```bash
|
|
135
|
+
mu store paths --pretty
|
|
79
136
|
mu store ls --pretty
|
|
80
137
|
mu store tail cp_commands --limit 20 --pretty
|
|
81
138
|
mu store tail cp_outbox --limit 20 --pretty
|
|
82
139
|
mu store tail cp_adapter_audit --limit 20 --pretty
|
|
140
|
+
mu store tail cp_operator_turns --limit 20 --pretty
|
|
141
|
+
mu replay <issue-id-or-log-path>
|
|
83
142
|
```
|
|
84
143
|
|
|
85
|
-
## Session and
|
|
144
|
+
## Session, serve, and one-shot surfaces
|
|
86
145
|
|
|
87
146
|
Primary interactive surface:
|
|
88
147
|
|
|
@@ -93,9 +152,17 @@ mu serve
|
|
|
93
152
|
Session follow-ups/handoffs:
|
|
94
153
|
|
|
95
154
|
```bash
|
|
96
|
-
mu session list --json --pretty
|
|
155
|
+
mu session list --kind all --all-workspaces --limit 50 --json --pretty
|
|
97
156
|
mu session <session-id>
|
|
98
157
|
mu turn --session-kind operator --session-id <session-id> --body "<follow-up>"
|
|
158
|
+
mu session config get --session-id <session-id>
|
|
159
|
+
mu session config set-thinking --session-id <session-id> --thinking minimal
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
One-shot prompt (no durable session):
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
mu exec --message "<task>" --json
|
|
99
166
|
```
|
|
100
167
|
|
|
101
168
|
In attached terminal operator chat, `/mu` helpers are available (`/mu events`, `/mu hud ...`, `/mu help`).
|
|
@@ -110,8 +177,8 @@ mu cron --help
|
|
|
110
177
|
```
|
|
111
178
|
|
|
112
179
|
When work is multi-step and issue-graph driven, use `planning` to shape the DAG,
|
|
113
|
-
then `hierarchical-work-protocol` to keep DAG
|
|
114
|
-
`subagents` for durable execution.
|
|
180
|
+
then `hud` for canonical HUD behavior, then `hierarchical-work-protocol` to keep DAG
|
|
181
|
+
semantics consistent, then `subagents` for durable execution.
|
|
115
182
|
For recurring bounded automation loops, use `heartbeats`.
|
|
116
183
|
For wall-clock schedules (one-shot, interval, cron-expression), use `crons`.
|
|
117
184
|
|
|
@@ -119,20 +186,21 @@ For wall-clock schedules (one-shot, interval, cron-expression), use `crons`.
|
|
|
119
186
|
|
|
120
187
|
1. **Bounded investigation before mutation**
|
|
121
188
|
- Prompt: user asks for status + targeted change.
|
|
122
|
-
- Expected:
|
|
189
|
+
- Expected: gather scoped evidence first (`mu status`, `issues`, `forum`, `memory`/`events`), then perform minimal write and verify post-state.
|
|
123
190
|
|
|
124
191
|
2. **Control-plane diagnostics loop**
|
|
125
|
-
- Prompt:
|
|
126
|
-
- Expected:
|
|
192
|
+
- Prompt: messaging channel stopped responding.
|
|
193
|
+
- Expected: inspect `mu control status`, `harness`, identities, adapter audit/outbox logs; then apply smallest reversible fix (`config set`, relink, `reload`) and verify.
|
|
127
194
|
|
|
128
|
-
3. **Session
|
|
129
|
-
- Prompt:
|
|
130
|
-
- Expected:
|
|
195
|
+
3. **Session continuity + scope-safe config**
|
|
196
|
+
- Prompt: continue prior operator thread with model/thinking tweaks.
|
|
197
|
+
- Expected: use `mu session list` + `mu session <id>`/`mu turn`; when needed, apply `mu session config ...` (session-scoped) instead of mutating global defaults.
|
|
131
198
|
|
|
132
199
|
## Escalation map
|
|
133
200
|
|
|
134
201
|
- Historical context retrieval and index maintenance: **`memory`**
|
|
135
202
|
- Planning/decomposition and DAG review: **`planning`**
|
|
203
|
+
- HUD contract/state updates across surfaces: **`hud`**
|
|
136
204
|
- Shared DAG semantics for planning + execution: **`hierarchical-work-protocol`**
|
|
137
205
|
- Durable multi-agent orchestration: **`subagents`**
|
|
138
206
|
- Recurring bounded automation scheduling: **`heartbeats`**
|
|
@@ -142,3 +210,4 @@ For wall-clock schedules (one-shot, interval, cron-expression), use `crons`.
|
|
|
142
210
|
- **`setup-discord`**
|
|
143
211
|
- **`setup-telegram`**
|
|
144
212
|
- **`setup-neovim`**
|
|
213
|
+
- Technical writing/docs polish: **`writing`**
|
|
@@ -21,8 +21,6 @@ Goal: get Telegram bot ingress and reply delivery working with minimal user-side
|
|
|
21
21
|
- Public webhook base URL reachable by Telegram (for example `https://mu.example.com`)
|
|
22
22
|
- Telegram bot token (from BotFather)
|
|
23
23
|
|
|
24
|
-
Optional (agent can usually discover):
|
|
25
|
-
- Bot username
|
|
26
24
|
|
|
27
25
|
## Agent-first workflow
|
|
28
26
|
|
|
@@ -47,18 +45,10 @@ mu control identities --all --pretty
|
|
|
47
45
|
|
|
48
46
|
If no running server is available, ask user to start `mu serve` in another terminal before reload/route checks.
|
|
49
47
|
|
|
50
|
-
### 2) Generate webhook secret
|
|
48
|
+
### 2) Generate webhook secret
|
|
51
49
|
|
|
52
50
|
Generate a strong webhook secret (do not expose it in final summaries).
|
|
53
51
|
|
|
54
|
-
If outbound network is available, discover bot username:
|
|
55
|
-
|
|
56
|
-
```bash
|
|
57
|
-
curl -sS "https://api.telegram.org/bot<bot-token>/getMe"
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
Extract `result.username` when present.
|
|
61
|
-
|
|
62
52
|
### 3) Configure Telegram webhook (agent does this when possible)
|
|
63
53
|
|
|
64
54
|
Set webhook to `https://<public-base>/webhooks/telegram` with secret token:
|
|
@@ -78,7 +68,6 @@ Use this canonical patch snippet (preserves unrelated keys):
|
|
|
78
68
|
```bash
|
|
79
69
|
export MU_TELEGRAM_WEBHOOK_SECRET='<TELEGRAM_WEBHOOK_SECRET>'
|
|
80
70
|
export MU_TELEGRAM_BOT_TOKEN='<TELEGRAM_BOT_TOKEN>'
|
|
81
|
-
export MU_TELEGRAM_BOT_USERNAME='<TELEGRAM_BOT_USERNAME_OR_EMPTY>'
|
|
82
71
|
config_path="$(mu control status --json | python3 -c 'import json,sys; print(json.load(sys.stdin)["config_path"])')"
|
|
83
72
|
|
|
84
73
|
python3 - "$config_path" <<'PY'
|
|
@@ -98,8 +87,6 @@ adapters = cp.setdefault("adapters", {})
|
|
|
98
87
|
telegram = adapters.setdefault("telegram", {})
|
|
99
88
|
telegram["webhook_secret"] = os.environ["MU_TELEGRAM_WEBHOOK_SECRET"]
|
|
100
89
|
telegram["bot_token"] = os.environ["MU_TELEGRAM_BOT_TOKEN"]
|
|
101
|
-
username = os.environ.get("MU_TELEGRAM_BOT_USERNAME", "").strip()
|
|
102
|
-
telegram["bot_username"] = username or None
|
|
103
90
|
|
|
104
91
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
105
92
|
path.write_text(json.dumps(data, indent=2) + "\n")
|
|
@@ -107,8 +94,7 @@ PY
|
|
|
107
94
|
```
|
|
108
95
|
|
|
109
96
|
Replace placeholder values with secrets from the user.
|
|
110
|
-
|
|
111
|
-
Then `unset MU_TELEGRAM_WEBHOOK_SECRET MU_TELEGRAM_BOT_TOKEN MU_TELEGRAM_BOT_USERNAME` after patching.
|
|
97
|
+
Then `unset MU_TELEGRAM_WEBHOOK_SECRET MU_TELEGRAM_BOT_TOKEN` after patching.
|
|
112
98
|
|
|
113
99
|
### 5) Reload and verify
|
|
114
100
|
|
|
@@ -160,9 +146,9 @@ Ask user to send `/mu status` (or plain status text) and verify response deliver
|
|
|
160
146
|
- Inputs: agent cannot reach `api.telegram.org`.
|
|
161
147
|
- Expected: skill hands user exact `setWebhook` command, resumes after confirmation, and still completes local config/reload verification.
|
|
162
148
|
|
|
163
|
-
3. **
|
|
164
|
-
- Inputs:
|
|
165
|
-
- Expected:
|
|
149
|
+
3. **Token+secret only configuration**
|
|
150
|
+
- Inputs: valid bot token + webhook secret, no username discovery step.
|
|
151
|
+
- Expected: adapter activates and identity link can proceed from audit chat id.
|
|
166
152
|
|
|
167
153
|
## Safety requirements
|
|
168
154
|
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: writing
|
|
3
|
+
description: "Crafts clear, precise technical documentation. Use when writing or reviewing docs, PR descriptions, error messages, READMEs, API references, or any technical prose."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# writing
|
|
7
|
+
|
|
8
|
+
Use this skill when asked to write, edit, or review technical prose. This includes documentation, READMEs, PR descriptions, error messages, comments, API references, and commit messages.
|
|
9
|
+
|
|
10
|
+
## Contents
|
|
11
|
+
|
|
12
|
+
- [Core contract](#core-contract)
|
|
13
|
+
- [Writing workflows](#writing-workflows)
|
|
14
|
+
- [Common patterns by document type](#common-patterns-by-document-type)
|
|
15
|
+
- [Editing and review workflow](#editing-and-review-workflow)
|
|
16
|
+
- [Evaluation scenarios](#evaluation-scenarios)
|
|
17
|
+
|
|
18
|
+
## Core contract
|
|
19
|
+
|
|
20
|
+
1. **Audience first**
|
|
21
|
+
- Identify the reader's baseline knowledge before writing.
|
|
22
|
+
- Write for the busiest reader who needs this information.
|
|
23
|
+
- Honor their time: front-load the essential information.
|
|
24
|
+
|
|
25
|
+
2. **Clarity over style**
|
|
26
|
+
- One idea per sentence. Complex concepts deserve their own space.
|
|
27
|
+
- Active voice: "The system returns an error" not "An error is returned by the system."
|
|
28
|
+
- Precise terminology: use the same word for the same concept throughout.
|
|
29
|
+
- Concrete over abstract: "200ms latency" beats "fast performance."
|
|
30
|
+
|
|
31
|
+
3. **Structure for scanability**
|
|
32
|
+
- Headings should communicate the document structure without reading prose.
|
|
33
|
+
- Lists for parallel items (bullets for unordered, numbers for sequences).
|
|
34
|
+
- Code blocks and tables over prose descriptions.
|
|
35
|
+
- Inverted pyramid: conclusion, supporting details, background.
|
|
36
|
+
|
|
37
|
+
4. **Actionability**
|
|
38
|
+
- Imperative for procedures: "Run the migration" not "The migration should be run."
|
|
39
|
+
- Explicit consequences: state what happens if the user does X.
|
|
40
|
+
- Anticipate failure modes in troubleshooting sections.
|
|
41
|
+
|
|
42
|
+
5. **Accessibility**
|
|
43
|
+
- Plain language: avoid Latin abbreviations, buzzwords, metaphor-heavy descriptions.
|
|
44
|
+
- Sentence length: average 15-20 words. Vary rhythm but never confuse length with sophistication.
|
|
45
|
+
- Context for jargon: define domain-specific terms on first use or link to definitions.
|
|
46
|
+
|
|
47
|
+
6. **Verify by reading aloud**
|
|
48
|
+
- Awkward phrasing surfaces when spoken.
|
|
49
|
+
- Test instructions by following them exactly as written.
|
|
50
|
+
- Delete mercilessly: if a sentence doesn't inform or direct, cut it.
|
|
51
|
+
|
|
52
|
+
## Writing workflows
|
|
53
|
+
|
|
54
|
+
### A) Documentation from scratch
|
|
55
|
+
|
|
56
|
+
1. **Identify the audience and goal**
|
|
57
|
+
- Who will read this? What do they know? What must they do after reading?
|
|
58
|
+
|
|
59
|
+
2. **Outline the structure**
|
|
60
|
+
- Opening paragraph: what this document covers and why it matters.
|
|
61
|
+
- Body: group related concepts, sequence procedures in order of execution.
|
|
62
|
+
- Closing: next steps, related resources, or troubleshooting.
|
|
63
|
+
|
|
64
|
+
3. **Draft with constraints**
|
|
65
|
+
- Maximum 25 words per sentence on average.
|
|
66
|
+
- Active voice for all instructions.
|
|
67
|
+
- Code examples for any behavior described.
|
|
68
|
+
|
|
69
|
+
4. **Review against the contract**
|
|
70
|
+
- Scan test: can a reader grasp structure from headings alone?
|
|
71
|
+
- Action test: can a reader execute procedures without asking questions?
|
|
72
|
+
- Deletion pass: remove sentences that don't inform or direct.
|
|
73
|
+
|
|
74
|
+
### B) PR/commit description
|
|
75
|
+
|
|
76
|
+
1. **What changed** (imperative, present tense)
|
|
77
|
+
2. **Why it changed** (context, motivation)
|
|
78
|
+
3. **How to verify** (testing steps, expected outcomes)
|
|
79
|
+
4. **Breaking changes** (if any, with migration path)
|
|
80
|
+
|
|
81
|
+
Keep under 80 characters per line in the summary. Body wraps at 72 characters.
|
|
82
|
+
|
|
83
|
+
### C) Error messages
|
|
84
|
+
|
|
85
|
+
1. **State what happened** (not what didn't)
|
|
86
|
+
2. **Explain why** (the root cause, if known)
|
|
87
|
+
3. **Provide the fix** (concrete next step, not generic advice)
|
|
88
|
+
4. **Include identifiers** (error codes, relevant IDs, log locations)
|
|
89
|
+
|
|
90
|
+
Example:
|
|
91
|
+
```
|
|
92
|
+
Error: Connection refused to database 'prod-db' on port 5432.
|
|
93
|
+
Cause: The database service is not running or firewall blocks port 5432.
|
|
94
|
+
Fix: Start the service with 'sudo systemctl start postgresql' or verify firewall rules.
|
|
95
|
+
Log: See /var/log/postgresql/postgresql-14-main.log for details.
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Common patterns by document type
|
|
99
|
+
|
|
100
|
+
### README.md
|
|
101
|
+
|
|
102
|
+
Structure:
|
|
103
|
+
1. One-line description of what this is
|
|
104
|
+
2. Installation/usage (minimal working example)
|
|
105
|
+
3. Key features (bullet list)
|
|
106
|
+
4. Configuration/options
|
|
107
|
+
5. Contributing/troubleshooting links
|
|
108
|
+
|
|
109
|
+
### API documentation
|
|
110
|
+
|
|
111
|
+
Per endpoint:
|
|
112
|
+
- Purpose (one sentence)
|
|
113
|
+
- HTTP method and path
|
|
114
|
+
- Parameters (name, type, required, description)
|
|
115
|
+
- Request/response examples
|
|
116
|
+
- Error codes and meanings
|
|
117
|
+
|
|
118
|
+
### Inline code comments
|
|
119
|
+
|
|
120
|
+
- **Why**, not what: explain intent, not obvious behavior.
|
|
121
|
+
- Non-obvious side effects or assumptions.
|
|
122
|
+
- TODO/FIXME with issue references, not vague notes.
|
|
123
|
+
- Public APIs: docstrings with parameters, returns, raises.
|
|
124
|
+
|
|
125
|
+
### Configuration docs
|
|
126
|
+
|
|
127
|
+
- Default values explicitly stated.
|
|
128
|
+
- Units for all numeric values (ms, bytes, percent).
|
|
129
|
+
- Validation constraints (min/max, allowed values).
|
|
130
|
+
- Impact of changing the value (what breaks, what improves).
|
|
131
|
+
|
|
132
|
+
## Editing and review workflow
|
|
133
|
+
|
|
134
|
+
When reviewing existing prose:
|
|
135
|
+
|
|
136
|
+
1. **Structural audit**
|
|
137
|
+
- Does the outline serve the reader's goal?
|
|
138
|
+
- Are headings descriptive? Is sequencing logical?
|
|
139
|
+
|
|
140
|
+
2. **Sentence-level edits**
|
|
141
|
+
- Convert passive to active voice.
|
|
142
|
+
- Replace vague quantifiers ("some", "many") with specifics.
|
|
143
|
+
- Break long sentences (\> 25 words) into two.
|
|
144
|
+
|
|
145
|
+
3. **Accuracy check**
|
|
146
|
+
- Verify all code examples execute as written.
|
|
147
|
+
- Confirm version numbers, paths, and URLs are current.
|
|
148
|
+
- Check that error messages match actual output.
|
|
149
|
+
|
|
150
|
+
4. **Final polish**
|
|
151
|
+
- Read aloud for awkward rhythm.
|
|
152
|
+
- Consistent formatting (punctuation in lists, code fences with languages).
|
|
153
|
+
- Spelling and grammar (but prioritize clarity over grammatical perfection).
|
|
154
|
+
|
|
155
|
+
## Evaluation scenarios
|
|
156
|
+
|
|
157
|
+
1. **Drafting documentation for a new feature**
|
|
158
|
+
- Prompt: user asks for docs for a feature they've implemented.
|
|
159
|
+
- Expected: skill identifies audience, structures around user goals not implementation details, includes working examples, and ends with verification steps.
|
|
160
|
+
|
|
161
|
+
2. **Reviewing a PR description**
|
|
162
|
+
- Prompt: user shares a draft PR description for feedback.
|
|
163
|
+
- Expected: skill checks for imperative summary line, clear what/why/how structure, and explicit breaking change notice if applicable.
|
|
164
|
+
|
|
165
|
+
3. **Improving error messages**
|
|
166
|
+
- Prompt: user shares error handling code or current error text.
|
|
167
|
+
- Expected: skill transforms vague messages into specific what/why/fix format with actionable next steps and relevant identifiers.
|
|
168
|
+
|
|
169
|
+
4. **Editing README for clarity**
|
|
170
|
+
- Prompt: user asks for help with a project's README.
|
|
171
|
+
- Expected: skill restructures for inverted pyramid, adds minimal working example, replaces feature paragraphs with scannable lists, and ensures installation steps are complete and ordered.
|
|
172
|
+
|
|
173
|
+
## Quality bar
|
|
174
|
+
|
|
175
|
+
- Every sentence earns its place: informs or directs.
|
|
176
|
+
- No sentence requires a second reading to understand.
|
|
177
|
+
- A reader can act on instructions without asking clarifying questions.
|
|
178
|
+
- Code examples execute without modification.
|
|
179
|
+
- A skim reader grasps the document's purpose and structure.
|