@femtomc/mu-agent 26.2.69 → 26.2.70

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.
Files changed (52) hide show
  1. package/README.md +20 -1
  2. package/dist/backend.d.ts +1 -0
  3. package/dist/backend.d.ts.map +1 -1
  4. package/dist/backend.js +11 -2
  5. package/dist/extensions/activities.d.ts +4 -1
  6. package/dist/extensions/activities.d.ts.map +1 -1
  7. package/dist/extensions/activities.js +127 -16
  8. package/dist/extensions/branding.d.ts +2 -3
  9. package/dist/extensions/branding.d.ts.map +1 -1
  10. package/dist/extensions/branding.js +73 -58
  11. package/dist/extensions/cron.d.ts +4 -1
  12. package/dist/extensions/cron.d.ts.map +1 -1
  13. package/dist/extensions/cron.js +74 -14
  14. package/dist/extensions/heartbeats.d.ts +4 -1
  15. package/dist/extensions/heartbeats.d.ts.map +1 -1
  16. package/dist/extensions/heartbeats.js +60 -17
  17. package/dist/extensions/index.d.ts +13 -3
  18. package/dist/extensions/index.d.ts.map +1 -1
  19. package/dist/extensions/index.js +13 -3
  20. package/dist/extensions/messaging-setup.d.ts +4 -1
  21. package/dist/extensions/messaging-setup.d.ts.map +1 -1
  22. package/dist/extensions/messaging-setup.js +47 -10
  23. package/dist/extensions/mu-full-tools.d.ts +10 -0
  24. package/dist/extensions/mu-full-tools.d.ts.map +1 -0
  25. package/dist/extensions/mu-full-tools.js +25 -0
  26. package/dist/extensions/mu-operator.d.ts.map +1 -1
  27. package/dist/extensions/mu-operator.js +2 -6
  28. package/dist/extensions/mu-query-tools.d.ts +10 -0
  29. package/dist/extensions/mu-query-tools.d.ts.map +1 -0
  30. package/dist/extensions/mu-query-tools.js +11 -0
  31. package/dist/extensions/operator-command.d.ts.map +1 -1
  32. package/dist/extensions/operator-command.js +106 -6
  33. package/dist/extensions/orchestration-runs-readonly.d.ts.map +1 -1
  34. package/dist/extensions/orchestration-runs-readonly.js +180 -10
  35. package/dist/extensions/orchestration-runs.d.ts.map +1 -1
  36. package/dist/extensions/orchestration-runs.js +206 -14
  37. package/dist/extensions/server-tools.d.ts +10 -0
  38. package/dist/extensions/server-tools.d.ts.map +1 -1
  39. package/dist/extensions/server-tools.js +688 -290
  40. package/dist/extensions/shared.d.ts +11 -0
  41. package/dist/extensions/shared.d.ts.map +1 -1
  42. package/dist/extensions/shared.js +81 -0
  43. package/dist/session_factory.d.ts.map +1 -1
  44. package/dist/session_factory.js +3 -1
  45. package/dist/ui_defaults.d.ts +4 -0
  46. package/dist/ui_defaults.d.ts.map +1 -0
  47. package/dist/ui_defaults.js +18 -0
  48. package/package.json +4 -3
  49. package/prompts/roles/operator.md +5 -0
  50. package/prompts/roles/orchestrator.md +1 -0
  51. package/prompts/roles/worker.md +10 -4
  52. package/themes/mu-gruvbox-dark.json +90 -0
@@ -1,6 +1,6 @@
1
1
  import { StringEnum } from "@mariozechner/pi-ai";
2
2
  import { Type } from "@sinclair/typebox";
3
- import { clampInt, fetchMuJson, textResult, toJsonText } from "./shared.js";
3
+ import { asArray, asNumber, asRecord, asString, clampInt, fetchMuJson, parseFieldPaths, previewText, selectFields, textResult, toJsonText, } from "./shared.js";
4
4
  function trimOrNull(value) {
5
5
  if (value == null)
6
6
  return null;
@@ -13,9 +13,40 @@ function normalizedNumber(value) {
13
13
  }
14
14
  return Math.trunc(value);
15
15
  }
16
- export function cronExtension(pi) {
16
+ function summarizeCronProgram(program) {
17
+ const target = asRecord(program.target);
18
+ const schedule = asRecord(program.schedule);
19
+ return {
20
+ program_id: asString(program.program_id),
21
+ title: previewText(program.title, 120),
22
+ enabled: program.enabled ?? null,
23
+ target_kind: target ? asString(target.kind) : asString(program.target_kind),
24
+ target_job_id: target ? asString(target.job_id) : asString(program.run_job_id),
25
+ target_root_issue_id: target ? asString(target.root_issue_id) : asString(program.run_root_issue_id),
26
+ target_activity_id: target ? asString(target.activity_id) : asString(program.activity_id),
27
+ schedule_kind: schedule ? asString(schedule.kind) : asString(program.schedule_kind),
28
+ schedule_preview: previewText(schedule ?? program, 180),
29
+ reason: asString(program.reason),
30
+ wake_mode: asString(program.wake_mode),
31
+ last_result: asString(program.last_result),
32
+ updated_at_ms: asNumber(program.updated_at_ms),
33
+ };
34
+ }
35
+ function summarizeCronMutation(payload) {
36
+ const program = asRecord(payload.program);
37
+ return {
38
+ ok: payload.ok ?? null,
39
+ reason: asString(payload.reason),
40
+ program: program ? summarizeCronProgram(program) : null,
41
+ };
42
+ }
43
+ export function cronExtension(pi, opts = {}) {
44
+ const allowMutations = opts.allowMutations ?? true;
45
+ const cronActions = allowMutations
46
+ ? ["status", "list", "get", "create", "update", "delete", "trigger", "enable", "disable"]
47
+ : ["status", "list", "get"];
17
48
  const Params = Type.Object({
18
- action: StringEnum(["status", "list", "get", "create", "update", "delete", "trigger", "enable", "disable"]),
49
+ action: StringEnum(cronActions),
19
50
  program_id: Type.Optional(Type.String({ description: "Cron program ID" })),
20
51
  title: Type.Optional(Type.String({ description: "Program title" })),
21
52
  target_kind: Type.Optional(Type.String({ description: "Target kind (run|activity)" })),
@@ -32,18 +63,34 @@ export function cronExtension(pi) {
32
63
  reason: Type.Optional(Type.String({ description: "Execution reason" })),
33
64
  enabled: Type.Optional(Type.Boolean({ description: "Enabled state" })),
34
65
  schedule_filter: Type.Optional(Type.String({ description: "Filter list by schedule kind" })),
35
- limit: Type.Optional(Type.Number({ description: "Max returned items for list" })),
66
+ fields: Type.Optional(Type.String({ description: "Comma-separated fields for get selection" })),
67
+ limit: Type.Optional(Type.Number({ description: "Max returned items for list (default: 20)" })),
36
68
  });
37
69
  pi.registerTool({
38
70
  name: "mu_cron",
39
71
  label: "Cron",
40
- description: "Manage persistent cron programs. Actions: status, list, get, create, update, delete, trigger, enable, disable.",
72
+ description: allowMutations
73
+ ? "Manage persistent cron programs. Actions: status, list, get, create, update, delete, trigger, enable, disable. Summary-first output; use fields for precise retrieval."
74
+ : "Read cron programs. Actions: status, list, get. Query-only mode excludes mutations.",
41
75
  parameters: Params,
42
76
  async execute(_toolCallId, params) {
43
77
  switch (params.action) {
44
78
  case "status": {
45
79
  const payload = await fetchMuJson("/api/cron/status");
46
- return textResult(toJsonText(payload), { action: "status" });
80
+ const status = {
81
+ count: asNumber(payload.count) ?? 0,
82
+ enabled_count: asNumber(payload.enabled_count),
83
+ armed_count: asNumber(payload.armed_count),
84
+ running_count: asNumber(payload.running_count) ?? asNumber(payload.count_running) ?? null,
85
+ armed: asArray(payload.armed)
86
+ .map((entry) => asRecord(entry))
87
+ .filter((entry) => entry != null)
88
+ .map((entry) => ({
89
+ program_id: asString(entry.program_id),
90
+ due_at_ms: asNumber(entry.due_at_ms),
91
+ })),
92
+ };
93
+ return textResult(toJsonText(status), { action: "status", payload });
47
94
  }
48
95
  case "list": {
49
96
  const query = new URLSearchParams();
@@ -58,13 +105,20 @@ export function cronExtension(pi) {
58
105
  if (scheduleFilter) {
59
106
  query.set("schedule_kind", scheduleFilter);
60
107
  }
61
- query.set("limit", String(clampInt(params.limit, 50, 1, 500)));
108
+ const limit = clampInt(params.limit, 20, 1, 500);
109
+ query.set("limit", String(limit));
62
110
  const payload = await fetchMuJson(`/api/cron?${query.toString()}`);
63
- return textResult(toJsonText(payload), {
111
+ const programs = asArray(payload.programs)
112
+ .map((program) => asRecord(program))
113
+ .filter((program) => program != null)
114
+ .map((program) => summarizeCronProgram(program));
115
+ return textResult(toJsonText({ count: programs.length, programs }), {
64
116
  action: "list",
65
117
  targetKind,
66
118
  enabled: params.enabled,
67
119
  scheduleFilter,
120
+ limit,
121
+ payload,
68
122
  });
69
123
  }
70
124
  case "get": {
@@ -72,7 +126,11 @@ export function cronExtension(pi) {
72
126
  if (!programId)
73
127
  return textResult("get requires program_id");
74
128
  const payload = await fetchMuJson(`/api/cron/${encodeURIComponent(programId)}`);
75
- return textResult(toJsonText(payload), { action: "get", programId });
129
+ const fields = parseFieldPaths(trimOrNull(params.fields) ?? undefined);
130
+ const content = fields.length > 0
131
+ ? { program_id: programId, selected: selectFields(payload, fields) }
132
+ : { program: summarizeCronProgram(payload) };
133
+ return textResult(toJsonText(content), { action: "get", programId, fields, payload });
76
134
  }
77
135
  case "create": {
78
136
  const title = trimOrNull(params.title);
@@ -103,11 +161,12 @@ export function cronExtension(pi) {
103
161
  enabled: typeof params.enabled === "boolean" ? params.enabled : undefined,
104
162
  },
105
163
  });
106
- return textResult(toJsonText(payload), {
164
+ return textResult(toJsonText(summarizeCronMutation(payload)), {
107
165
  action: "create",
108
166
  title,
109
167
  targetKind,
110
168
  scheduleKind,
169
+ payload,
111
170
  });
112
171
  }
113
172
  case "update": {
@@ -134,7 +193,7 @@ export function cronExtension(pi) {
134
193
  enabled: typeof params.enabled === "boolean" ? params.enabled : undefined,
135
194
  },
136
195
  });
137
- return textResult(toJsonText(payload), { action: "update", programId });
196
+ return textResult(toJsonText(summarizeCronMutation(payload)), { action: "update", programId, payload });
138
197
  }
139
198
  case "delete": {
140
199
  const programId = trimOrNull(params.program_id);
@@ -146,7 +205,7 @@ export function cronExtension(pi) {
146
205
  program_id: programId,
147
206
  },
148
207
  });
149
- return textResult(toJsonText(payload), { action: "delete", programId });
208
+ return textResult(toJsonText(summarizeCronMutation(payload)), { action: "delete", programId, payload });
150
209
  }
151
210
  case "trigger": {
152
211
  const programId = trimOrNull(params.program_id);
@@ -159,7 +218,7 @@ export function cronExtension(pi) {
159
218
  reason: trimOrNull(params.reason),
160
219
  },
161
220
  });
162
- return textResult(toJsonText(payload), { action: "trigger", programId });
221
+ return textResult(toJsonText(summarizeCronMutation(payload)), { action: "trigger", programId, payload });
163
222
  }
164
223
  case "enable":
165
224
  case "disable": {
@@ -173,9 +232,10 @@ export function cronExtension(pi) {
173
232
  enabled: params.action === "enable",
174
233
  },
175
234
  });
176
- return textResult(toJsonText(payload), {
235
+ return textResult(toJsonText(summarizeCronMutation(payload)), {
177
236
  action: params.action,
178
237
  programId,
238
+ payload,
179
239
  });
180
240
  }
181
241
  default:
@@ -1,4 +1,7 @@
1
1
  import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
2
- export declare function heartbeatsExtension(pi: ExtensionAPI): void;
2
+ export type HeartbeatsExtensionOpts = {
3
+ allowMutations?: boolean;
4
+ };
5
+ export declare function heartbeatsExtension(pi: ExtensionAPI, opts?: HeartbeatsExtensionOpts): void;
3
6
  export default heartbeatsExtension;
4
7
  //# sourceMappingURL=heartbeats.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"heartbeats.d.ts","sourceRoot":"","sources":["../../src/extensions/heartbeats.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAUlE,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,YAAY,QAyInD;AAED,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"heartbeats.d.ts","sourceRoot":"","sources":["../../src/extensions/heartbeats.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAiDlE,MAAM,MAAM,uBAAuB,GAAG;IACrC,cAAc,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,GAAE,uBAA4B,QA8JvF;AAED,eAAe,mBAAmB,CAAC"}
@@ -1,15 +1,44 @@
1
1
  import { StringEnum } from "@mariozechner/pi-ai";
2
2
  import { Type } from "@sinclair/typebox";
3
- import { clampInt, fetchMuJson, textResult, toJsonText } from "./shared.js";
3
+ import { asArray, asNumber, asRecord, asString, clampInt, fetchMuJson, parseFieldPaths, previewText, selectFields, textResult, toJsonText, } from "./shared.js";
4
4
  function trimOrNull(value) {
5
5
  if (value == null)
6
6
  return null;
7
7
  const trimmed = value.trim();
8
8
  return trimmed.length > 0 ? trimmed : null;
9
9
  }
10
- export function heartbeatsExtension(pi) {
10
+ function summarizeHeartbeatProgram(program) {
11
+ const target = asRecord(program.target);
12
+ return {
13
+ program_id: asString(program.program_id),
14
+ title: previewText(program.title, 120),
15
+ enabled: program.enabled ?? null,
16
+ every_ms: asNumber(program.every_ms),
17
+ reason: asString(program.reason),
18
+ wake_mode: asString(program.wake_mode),
19
+ target_kind: target ? asString(target.kind) : asString(program.target_kind),
20
+ target_job_id: target ? asString(target.job_id) : asString(program.run_job_id),
21
+ target_root_issue_id: target ? asString(target.root_issue_id) : asString(program.run_root_issue_id),
22
+ target_activity_id: target ? asString(target.activity_id) : asString(program.activity_id),
23
+ last_result: asString(program.last_result),
24
+ updated_at_ms: asNumber(program.updated_at_ms),
25
+ };
26
+ }
27
+ function summarizeHeartbeatMutation(payload) {
28
+ const program = asRecord(payload.program);
29
+ return {
30
+ ok: payload.ok ?? null,
31
+ reason: asString(payload.reason),
32
+ program: program ? summarizeHeartbeatProgram(program) : null,
33
+ };
34
+ }
35
+ export function heartbeatsExtension(pi, opts = {}) {
36
+ const allowMutations = opts.allowMutations ?? true;
37
+ const heartbeatActions = allowMutations
38
+ ? ["list", "get", "create", "update", "delete", "trigger", "enable", "disable"]
39
+ : ["list", "get"];
11
40
  const Params = Type.Object({
12
- action: StringEnum(["list", "get", "create", "update", "delete", "trigger", "enable", "disable"]),
41
+ action: StringEnum(heartbeatActions),
13
42
  program_id: Type.Optional(Type.String({ description: "Heartbeat program ID" })),
14
43
  title: Type.Optional(Type.String({ description: "Program title" })),
15
44
  target_kind: Type.Optional(Type.String({ description: "Target kind (run|activity)" })),
@@ -19,12 +48,15 @@ export function heartbeatsExtension(pi) {
19
48
  every_ms: Type.Optional(Type.Number({ description: "Heartbeat interval in ms" })),
20
49
  reason: Type.Optional(Type.String({ description: "Heartbeat reason" })),
21
50
  enabled: Type.Optional(Type.Boolean({ description: "Enabled state" })),
22
- limit: Type.Optional(Type.Number({ description: "Max returned items for list" })),
51
+ fields: Type.Optional(Type.String({ description: "Comma-separated fields for get selection" })),
52
+ limit: Type.Optional(Type.Number({ description: "Max returned items for list (default: 20)" })),
23
53
  });
24
54
  pi.registerTool({
25
55
  name: "mu_heartbeats",
26
56
  label: "Heartbeats",
27
- description: "Program and manage persistent heartbeat schedules. Actions: list, get, create, update, delete, trigger, enable, disable.",
57
+ description: allowMutations
58
+ ? "Program and manage persistent heartbeat schedules. Actions: list, get, create, update, delete, trigger, enable, disable. Summary-first output; use fields for precise retrieval."
59
+ : "Read heartbeat programs. Actions: list, get. Query-only mode excludes mutations.",
28
60
  parameters: Params,
29
61
  async execute(_toolCallId, params) {
30
62
  switch (params.action) {
@@ -37,20 +69,25 @@ export function heartbeatsExtension(pi) {
37
69
  if (typeof params.enabled === "boolean") {
38
70
  query.set("enabled", params.enabled ? "true" : "false");
39
71
  }
40
- query.set("limit", String(clampInt(params.limit, 50, 1, 500)));
72
+ const limit = clampInt(params.limit, 20, 1, 500);
73
+ query.set("limit", String(limit));
41
74
  const payload = await fetchMuJson(`/api/heartbeats?${query.toString()}`);
42
- return textResult(toJsonText(payload), {
43
- action: "list",
44
- targetKind,
45
- enabled: params.enabled,
46
- });
75
+ const programs = asArray(payload.programs)
76
+ .map((program) => asRecord(program))
77
+ .filter((program) => program != null)
78
+ .map((program) => summarizeHeartbeatProgram(program));
79
+ return textResult(toJsonText({ count: programs.length, programs }), { action: "list", targetKind, enabled: params.enabled, limit, payload });
47
80
  }
48
81
  case "get": {
49
82
  const programId = trimOrNull(params.program_id);
50
83
  if (!programId)
51
84
  return textResult("get requires program_id");
52
85
  const payload = await fetchMuJson(`/api/heartbeats/${encodeURIComponent(programId)}`);
53
- return textResult(toJsonText(payload), { action: "get", programId });
86
+ const fields = parseFieldPaths(trimOrNull(params.fields) ?? undefined);
87
+ const content = fields.length > 0
88
+ ? { program_id: programId, selected: selectFields(payload, fields) }
89
+ : { program: summarizeHeartbeatProgram(payload) };
90
+ return textResult(toJsonText(content), { action: "get", programId, fields, payload });
54
91
  }
55
92
  case "create": {
56
93
  const title = trimOrNull(params.title);
@@ -74,7 +111,12 @@ export function heartbeatsExtension(pi) {
74
111
  enabled: typeof params.enabled === "boolean" ? params.enabled : undefined,
75
112
  },
76
113
  });
77
- return textResult(toJsonText(payload), { action: "create", title, targetKind });
114
+ return textResult(toJsonText(summarizeHeartbeatMutation(payload)), {
115
+ action: "create",
116
+ title,
117
+ targetKind,
118
+ payload,
119
+ });
78
120
  }
79
121
  case "update": {
80
122
  const programId = trimOrNull(params.program_id);
@@ -96,7 +138,7 @@ export function heartbeatsExtension(pi) {
96
138
  enabled: typeof params.enabled === "boolean" ? params.enabled : undefined,
97
139
  },
98
140
  });
99
- return textResult(toJsonText(payload), { action: "update", programId });
141
+ return textResult(toJsonText(summarizeHeartbeatMutation(payload)), { action: "update", programId, payload });
100
142
  }
101
143
  case "delete": {
102
144
  const programId = trimOrNull(params.program_id);
@@ -108,7 +150,7 @@ export function heartbeatsExtension(pi) {
108
150
  program_id: programId,
109
151
  },
110
152
  });
111
- return textResult(toJsonText(payload), { action: "delete", programId });
153
+ return textResult(toJsonText(summarizeHeartbeatMutation(payload)), { action: "delete", programId, payload });
112
154
  }
113
155
  case "trigger": {
114
156
  const programId = trimOrNull(params.program_id);
@@ -121,7 +163,7 @@ export function heartbeatsExtension(pi) {
121
163
  reason: trimOrNull(params.reason),
122
164
  },
123
165
  });
124
- return textResult(toJsonText(payload), { action: "trigger", programId });
166
+ return textResult(toJsonText(summarizeHeartbeatMutation(payload)), { action: "trigger", programId, payload });
125
167
  }
126
168
  case "enable":
127
169
  case "disable": {
@@ -135,9 +177,10 @@ export function heartbeatsExtension(pi) {
135
177
  enabled: params.action === "enable",
136
178
  },
137
179
  });
138
- return textResult(toJsonText(payload), {
180
+ return textResult(toJsonText(summarizeHeartbeatMutation(payload)), {
139
181
  action: params.action,
140
182
  programId,
183
+ payload,
141
184
  });
142
185
  }
143
186
  default:
@@ -4,20 +4,30 @@ export { cronExtension } from "./cron.js";
4
4
  export { eventLogExtension } from "./event-log.js";
5
5
  export { heartbeatsExtension } from "./heartbeats.js";
6
6
  export { messagingSetupExtension } from "./messaging-setup.js";
7
+ export { muFullToolsExtension } from "./mu-full-tools.js";
7
8
  export { muOperatorExtension } from "./mu-operator.js";
9
+ export { muQueryToolsExtension } from "./mu-query-tools.js";
8
10
  export { muServeExtension } from "./mu-serve.js";
9
11
  export { operatorCommandExtension } from "./operator-command.js";
10
12
  export { orchestrationRunsExtension } from "./orchestration-runs.js";
11
13
  export { orchestrationRunsReadOnlyExtension } from "./orchestration-runs-readonly.js";
12
- export { serverToolsExtension, serverToolsReadOnlyExtension } from "./server-tools.js";
14
+ export { serverToolsExtension, serverToolsIssueForumExtension, serverToolsReadOnlyExtension } from "./server-tools.js";
13
15
  export { serverToolsReadonlyExtension } from "./server-tools-readonly.js";
14
16
  /**
15
17
  * Serve-mode extension — single facade that bundles all serve extensions.
16
18
  */
17
19
  export declare const serveExtensionPaths: string[];
18
20
  /**
19
- * Operator-mode extension — single facade that bundles all operator
20
- * extensions (read-only tools, approved `/mu` command flow).
21
+ * Operator-mode extension — single facade that bundles operator UI +
22
+ * full mu tools + approved `/mu` command flow.
21
23
  */
22
24
  export declare const operatorExtensionPaths: string[];
25
+ /**
26
+ * Tool-only extension bundle for orchestrator sessions (full tool surface).
27
+ */
28
+ export declare const orchestratorToolExtensionPaths: string[];
29
+ /**
30
+ * Tool-only extension bundle for worker sessions (issue/forum coordination only).
31
+ */
32
+ export declare const workerToolExtensionPaths: string[];
23
33
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/extensions/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,kCAAkC,EAAE,MAAM,kCAAkC,CAAC;AACtF,OAAO,EAAE,oBAAoB,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAC;AACvF,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAQ1E;;GAEG;AACH,eAAO,MAAM,mBAAmB,UAA4C,CAAC;AAE7E;;;GAGG;AACH,eAAO,MAAM,sBAAsB,UAA+C,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/extensions/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,kCAAkC,EAAE,MAAM,kCAAkC,CAAC;AACtF,OAAO,EAAE,oBAAoB,EAAE,8BAA8B,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAC;AACvH,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAQ1E;;GAEG;AACH,eAAO,MAAM,mBAAmB,UAA4C,CAAC;AAE7E;;;GAGG;AACH,eAAO,MAAM,sBAAsB,UAA+C,CAAC;AAEnF;;GAEG;AACH,eAAO,MAAM,8BAA8B,UAAiD,CAAC;AAE7F;;GAEG;AACH,eAAO,MAAM,wBAAwB,UAAkD,CAAC"}
@@ -4,12 +4,14 @@ export { cronExtension } from "./cron.js";
4
4
  export { eventLogExtension } from "./event-log.js";
5
5
  export { heartbeatsExtension } from "./heartbeats.js";
6
6
  export { messagingSetupExtension } from "./messaging-setup.js";
7
+ export { muFullToolsExtension } from "./mu-full-tools.js";
7
8
  export { muOperatorExtension } from "./mu-operator.js";
9
+ export { muQueryToolsExtension } from "./mu-query-tools.js";
8
10
  export { muServeExtension } from "./mu-serve.js";
9
11
  export { operatorCommandExtension } from "./operator-command.js";
10
12
  export { orchestrationRunsExtension } from "./orchestration-runs.js";
11
13
  export { orchestrationRunsReadOnlyExtension } from "./orchestration-runs-readonly.js";
12
- export { serverToolsExtension, serverToolsReadOnlyExtension } from "./server-tools.js";
14
+ export { serverToolsExtension, serverToolsIssueForumExtension, serverToolsReadOnlyExtension } from "./server-tools.js";
13
15
  export { serverToolsReadonlyExtension } from "./server-tools-readonly.js";
14
16
  const RUNTIME_EXTENSION = import.meta.url.endsWith(".ts") ? "ts" : "js";
15
17
  function resolveBundledExtensionPath(moduleBasename) {
@@ -20,7 +22,15 @@ function resolveBundledExtensionPath(moduleBasename) {
20
22
  */
21
23
  export const serveExtensionPaths = [resolveBundledExtensionPath("mu-serve")];
22
24
  /**
23
- * Operator-mode extension — single facade that bundles all operator
24
- * extensions (read-only tools, approved `/mu` command flow).
25
+ * Operator-mode extension — single facade that bundles operator UI +
26
+ * full mu tools + approved `/mu` command flow.
25
27
  */
26
28
  export const operatorExtensionPaths = [resolveBundledExtensionPath("mu-operator")];
29
+ /**
30
+ * Tool-only extension bundle for orchestrator sessions (full tool surface).
31
+ */
32
+ export const orchestratorToolExtensionPaths = [resolveBundledExtensionPath("mu-full-tools")];
33
+ /**
34
+ * Tool-only extension bundle for worker sessions (issue/forum coordination only).
35
+ */
36
+ export const workerToolExtensionPaths = [resolveBundledExtensionPath("mu-query-tools")];
@@ -7,6 +7,9 @@
7
7
  * - Support plan/apply/verify workflow with in-process control-plane reload.
8
8
  */
9
9
  import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
10
- export declare function messagingSetupExtension(pi: ExtensionAPI): void;
10
+ export type MessagingSetupExtensionOpts = {
11
+ allowApply?: boolean;
12
+ };
13
+ export declare function messagingSetupExtension(pi: ExtensionAPI, opts?: MessagingSetupExtensionOpts): void;
11
14
  export default messagingSetupExtension;
12
15
  //# sourceMappingURL=messaging-setup.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"messaging-setup.d.ts","sourceRoot":"","sources":["../../src/extensions/messaging-setup.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,YAAY,EAA6C,MAAM,+BAA+B,CAAC;AAypC7G,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,YAAY,QAyPvD;AAED,eAAe,uBAAuB,CAAC"}
1
+ {"version":3,"file":"messaging-setup.d.ts","sourceRoot":"","sources":["../../src/extensions/messaging-setup.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,YAAY,EAA6C,MAAM,+BAA+B,CAAC;AAoqC7G,MAAM,MAAM,2BAA2B,GAAG;IACzC,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,GAAE,2BAAgC,QAsR/F;AAED,eAAe,uBAAuB,CAAC"}
@@ -334,6 +334,9 @@ function summarizeChecks(checks) {
334
334
  }
335
335
  function preflightSummary(checks, runtime) {
336
336
  const lines = ["Messaging adapter preflight:", ""];
337
+ if (checks.length === 0) {
338
+ lines.push("(no matching adapters)");
339
+ }
337
340
  for (const check of checks) {
338
341
  const route = check.route ? ` · route ${check.route}` : "";
339
342
  const missing = check.missing.length > 0 ? ` · missing ${check.missing.join(", ")}` : "";
@@ -867,6 +870,13 @@ function dispatchSetupPromptToAgent(pi, ctx, prompt) {
867
870
  function findCheckByAdapter(checks, adapterId) {
868
871
  return checks.find((check) => check.id === adapterId) ?? null;
869
872
  }
873
+ function checksForAdapter(checks, adapterId) {
874
+ if (!adapterId) {
875
+ return checks;
876
+ }
877
+ const match = checks.find((check) => check.id === adapterId);
878
+ return match ? [match] : [];
879
+ }
870
880
  async function maybeDispatchAgentSetupBrief(opts) {
871
881
  if (!opts.parsed.adapterId)
872
882
  return false;
@@ -934,7 +944,8 @@ async function runInteractiveApply(ctx, adapterId) {
934
944
  ];
935
945
  return lines.join("\n");
936
946
  }
937
- export function messagingSetupExtension(pi) {
947
+ export function messagingSetupExtension(pi, opts = {}) {
948
+ const allowApply = opts.allowApply ?? true;
938
949
  pi.on("before_agent_start", async (event) => {
939
950
  const { checks } = await collectChecksCached();
940
951
  const summary = summarizeChecks(checks);
@@ -942,7 +953,9 @@ export function messagingSetupExtension(pi) {
942
953
  "",
943
954
  "[MU MESSAGING]",
944
955
  summary.length > 0 ? summary : "no adapter status available",
945
- "Use mu_messaging_setup(action=preflight|plan|apply|verify|guide) for operator workflow.",
956
+ allowApply
957
+ ? "Use mu_messaging_setup(action=preflight|plan|apply|verify|guide) for operator workflow."
958
+ : "Use mu_messaging_setup(action=preflight|plan|verify|guide) for query workflow.",
946
959
  ];
947
960
  return {
948
961
  systemPrompt: `${event.systemPrompt}${lines.join("\n")}`,
@@ -951,8 +964,11 @@ export function messagingSetupExtension(pi) {
951
964
  pi.on("session_start", async (_event, ctx) => {
952
965
  await refreshMessagingStatus(ctx);
953
966
  });
967
+ const setupActions = allowApply
968
+ ? ["check", "preflight", "guide", "plan", "apply", "verify"]
969
+ : ["check", "preflight", "guide", "plan", "verify"];
954
970
  const SetupParams = Type.Object({
955
- action: StringEnum(["check", "preflight", "guide", "plan", "apply", "verify"]),
971
+ action: StringEnum(setupActions),
956
972
  adapter: Type.Optional(Type.String({ description: "Adapter name: slack, discord, telegram, gmail" })),
957
973
  public_base_url: Type.Optional(Type.String({
958
974
  description: "Optional public base URL used to compute expected webhook endpoints (e.g. https://example.ngrok.app)",
@@ -964,9 +980,11 @@ export function messagingSetupExtension(pi) {
964
980
  pi.registerTool({
965
981
  name: "mu_messaging_setup",
966
982
  label: "Messaging Setup",
967
- description: "Messaging setup workflow. Actions: check/preflight/guide/plan/apply/verify. For apply, pass field values via the fields parameter (e.g. fields={bot_token:'...', webhook_secret:'...'}).",
983
+ description: allowApply
984
+ ? "Messaging setup workflow. Actions: check/preflight/guide/plan/apply/verify. For apply, pass field values via the fields parameter (e.g. fields={bot_token:'...', webhook_secret:'...'})."
985
+ : "Messaging setup query workflow. Actions: check/preflight/guide/plan/verify. Apply is disabled in query-only mode.",
968
986
  parameters: SetupParams,
969
- async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
987
+ async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
970
988
  const adapterId = params.adapter ? normalizeAdapterId(params.adapter) : null;
971
989
  if (params.adapter && !adapterId) {
972
990
  return textResult(`Unknown adapter: ${params.adapter}. Available: ${ADAPTERS.map((adapter) => adapter.id).join(", ")}`);
@@ -974,17 +992,24 @@ export function messagingSetupExtension(pi) {
974
992
  switch (params.action) {
975
993
  case "check": {
976
994
  const { checks, runtime } = await collectChecksCached();
995
+ const filteredChecks = checksForAdapter(checks, adapterId);
977
996
  return textResult(toJsonText({
978
- checks,
997
+ checks: filteredChecks,
979
998
  runtime: { ...runtime, routesByAdapter: Object.fromEntries(runtime.routesByAdapter) },
980
999
  }), {
981
- checks,
1000
+ checks: filteredChecks,
982
1001
  runtime,
1002
+ adapter: adapterId,
983
1003
  });
984
1004
  }
985
1005
  case "preflight": {
986
1006
  const { checks, runtime } = await collectChecksCached();
987
- return textResult(preflightSummary(checks, runtime), { checks, runtime });
1007
+ const filteredChecks = checksForAdapter(checks, adapterId);
1008
+ return textResult(preflightSummary(filteredChecks, runtime), {
1009
+ checks: filteredChecks,
1010
+ runtime,
1011
+ adapter: adapterId,
1012
+ });
988
1013
  }
989
1014
  case "guide":
990
1015
  case "plan": {
@@ -1010,6 +1035,12 @@ export function messagingSetupExtension(pi) {
1010
1035
  return textResult(planSummary(plans), { plans, runtime, adapter: null });
1011
1036
  }
1012
1037
  case "apply": {
1038
+ if (!allowApply) {
1039
+ return textResult("apply is disabled in query-only mode. Use plan/guide/verify actions.", {
1040
+ blocked: true,
1041
+ reason: "messaging_setup_query_only_mode",
1042
+ });
1043
+ }
1013
1044
  if (!adapterId) {
1014
1045
  return textResult("apply requires adapter (slack|discord|telegram)");
1015
1046
  }
@@ -1071,8 +1102,9 @@ export function messagingSetupExtension(pi) {
1071
1102
  switch (parsed.action) {
1072
1103
  case "check": {
1073
1104
  const { checks, runtime } = await collectChecksCached(0);
1105
+ const filteredChecks = checksForAdapter(checks, parsed.adapterId);
1074
1106
  ctx.ui.notify(toJsonText({
1075
- checks,
1107
+ checks: filteredChecks,
1076
1108
  runtime: { ...runtime, routesByAdapter: Object.fromEntries(runtime.routesByAdapter) },
1077
1109
  }), "info");
1078
1110
  await refreshMessagingStatus(ctx);
@@ -1087,7 +1119,8 @@ export function messagingSetupExtension(pi) {
1087
1119
  await refreshMessagingStatus(ctx);
1088
1120
  return;
1089
1121
  }
1090
- ctx.ui.notify(preflightSummary(checks, runtime), "info");
1122
+ const filteredChecks = checksForAdapter(checks, parsed.adapterId);
1123
+ ctx.ui.notify(preflightSummary(filteredChecks, runtime), "info");
1091
1124
  await refreshMessagingStatus(ctx);
1092
1125
  return;
1093
1126
  }
@@ -1123,6 +1156,10 @@ export function messagingSetupExtension(pi) {
1123
1156
  return;
1124
1157
  }
1125
1158
  case "apply": {
1159
+ if (!allowApply) {
1160
+ ctx.ui.notify("apply is disabled in query-only mode. Use /mu setup plan and /mu setup verify.", "warning");
1161
+ return;
1162
+ }
1126
1163
  if (!parsed.adapterId) {
1127
1164
  ctx.ui.notify("apply requires adapter. Example: /mu setup apply slack", "error");
1128
1165
  return;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * mu-full-tools — Tool-only extension bundle with full mu tool surface.
3
+ *
4
+ * Intended for orchestrator/operator contexts that should have the complete
5
+ * server-backed tool set (including mutation-capable tool actions).
6
+ */
7
+ import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
8
+ export declare function muFullToolsExtension(pi: ExtensionAPI): void;
9
+ export default muFullToolsExtension;
10
+ //# sourceMappingURL=mu-full-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mu-full-tools.d.ts","sourceRoot":"","sources":["../../src/extensions/mu-full-tools.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAQlE,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,YAAY,QAYpD;AAED,eAAe,oBAAoB,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * mu-full-tools — Tool-only extension bundle with full mu tool surface.
3
+ *
4
+ * Intended for orchestrator/operator contexts that should have the complete
5
+ * server-backed tool set (including mutation-capable tool actions).
6
+ */
7
+ import { activitiesExtension } from "./activities.js";
8
+ import { cronExtension } from "./cron.js";
9
+ import { heartbeatsExtension } from "./heartbeats.js";
10
+ import { messagingSetupExtension } from "./messaging-setup.js";
11
+ import { orchestrationRunsExtension } from "./orchestration-runs.js";
12
+ import { serverToolsExtension } from "./server-tools.js";
13
+ export function muFullToolsExtension(pi) {
14
+ serverToolsExtension(pi, {
15
+ allowForumPost: true,
16
+ allowIdentityMutations: true,
17
+ toolIntroLine: "Tools: mu_status, mu_control_plane, mu_issues, mu_forum, mu_events, mu_runs, mu_activities, mu_heartbeats, mu_cron, mu_messaging_setup, mu_identity.",
18
+ });
19
+ messagingSetupExtension(pi, { allowApply: true });
20
+ orchestrationRunsExtension(pi);
21
+ activitiesExtension(pi, { allowMutations: true });
22
+ heartbeatsExtension(pi, { allowMutations: true });
23
+ cronExtension(pi, { allowMutations: true });
24
+ }
25
+ export default muFullToolsExtension;
@@ -1 +1 @@
1
- {"version":3,"file":"mu-operator.d.ts","sourceRoot":"","sources":["../../src/extensions/mu-operator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAQlE,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,YAAY,QAOnD;AAED,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"mu-operator.d.ts","sourceRoot":"","sources":["../../src/extensions/mu-operator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAMlE,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,YAAY,QAKnD;AAED,eAAe,mBAAmB,CAAC"}