@femtomc/mu-agent 26.2.70 → 26.2.71
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 +1 -2
- package/dist/backend.d.ts.map +1 -1
- package/dist/backend.js +1 -1
- package/dist/default_prompts.d.ts +1 -0
- package/dist/default_prompts.d.ts.map +1 -1
- package/dist/default_prompts.js +2 -0
- package/dist/extensions/messaging-setup/actions.d.ts +22 -0
- package/dist/extensions/messaging-setup/actions.d.ts.map +1 -0
- package/dist/extensions/messaging-setup/actions.js +229 -0
- package/dist/extensions/messaging-setup/adapters.d.ts +24 -0
- package/dist/extensions/messaging-setup/adapters.d.ts.map +1 -0
- package/dist/extensions/messaging-setup/adapters.js +170 -0
- package/dist/extensions/messaging-setup/index.d.ts +17 -0
- package/dist/extensions/messaging-setup/index.d.ts.map +1 -0
- package/dist/extensions/messaging-setup/index.js +261 -0
- package/dist/extensions/messaging-setup/parser.d.ts +33 -0
- package/dist/extensions/messaging-setup/parser.d.ts.map +1 -0
- package/dist/extensions/messaging-setup/parser.js +240 -0
- package/dist/extensions/messaging-setup/runtime.d.ts +16 -0
- package/dist/extensions/messaging-setup/runtime.d.ts.map +1 -0
- package/dist/extensions/messaging-setup/runtime.js +110 -0
- package/dist/extensions/messaging-setup/types.d.ts +157 -0
- package/dist/extensions/messaging-setup/types.d.ts.map +1 -0
- package/dist/extensions/messaging-setup/types.js +4 -0
- package/dist/extensions/messaging-setup/ui.d.ts +15 -0
- package/dist/extensions/messaging-setup/ui.d.ts.map +1 -0
- package/dist/extensions/messaging-setup/ui.js +173 -0
- package/dist/extensions/messaging-setup.d.ts +2 -14
- package/dist/extensions/messaging-setup.d.ts.map +1 -1
- package/dist/extensions/messaging-setup.js +2 -1190
- package/dist/mu_roles.d.ts +3 -3
- package/dist/mu_roles.d.ts.map +1 -1
- package/dist/mu_roles.js +11 -3
- package/package.json +2 -2
- package/prompts/roles/reviewer.md +34 -0
- package/prompts/roles/soul.md +3 -4
package/README.md
CHANGED
|
@@ -81,7 +81,7 @@ Default operator UI theme is `mu-gruvbox-dark`.
|
|
|
81
81
|
- `action`: `tail | query`
|
|
82
82
|
- `mu_messaging_setup({ action, adapter?, public_base_url? })`
|
|
83
83
|
- `action`: `check | preflight | guide | plan | apply | verify`
|
|
84
|
-
- `adapter`: `slack | discord | telegram
|
|
84
|
+
- `adapter`: `slack | discord | telegram`
|
|
85
85
|
|
|
86
86
|
### Query contract (context-safe by default)
|
|
87
87
|
|
|
@@ -104,6 +104,5 @@ kept compact to reduce context pollution.
|
|
|
104
104
|
|
|
105
105
|
- Runtime setup state comes from `GET /api/config` and `.mu/config.json`.
|
|
106
106
|
- `slack`, `discord`, `telegram` are currently modeled as available adapters.
|
|
107
|
-
- `gmail` is modeled as planned guidance (not mounted by runtime yet).
|
|
108
107
|
- `mu_messaging_setup(action=preflight)` is the quickest health check during
|
|
109
108
|
onboarding.
|
package/dist/backend.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAEjD,OAAO,EACN,WAAW,EAOX,qBAAqB,EAErB,eAAe,EACf,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAI5C,MAAM,MAAM,cAAc,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,WAAW,aAAa;IAC7B,GAAG,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC3C;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CA4BpD;AAGD;;;;;GAKG;AACH,wBAAgB,YAAY,CAC3B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,WAAW,EACxB,kBAAkB,CAAC,EAAE,MAAM,GACzB,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CA6BxB;AAED;;;;GAIG;AACH,qBAAa,UAAW,YAAW,aAAa;IACzC,GAAG,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAEjD,OAAO,EACN,WAAW,EAOX,qBAAqB,EAErB,eAAe,EACf,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAI5C,MAAM,MAAM,cAAc,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,WAAW,aAAa;IAC7B,GAAG,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC3C;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CA4BpD;AAGD;;;;;GAKG;AACH,wBAAgB,YAAY,CAC3B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,WAAW,EACxB,kBAAkB,CAAC,EAAE,MAAM,GACzB,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CA6BxB;AAED;;;;GAIG;AACH,qBAAa,UAAW,YAAW,aAAa;IACzC,GAAG,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC;CAoGhD;AAGD,MAAM,MAAM,0BAA0B,GAAG;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,wBAAwB,CAAC,EAAE,MAAM,EAAE,CAAC;IACpC,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;CAChC,CAAC;AAEF,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,0BAA0B,GAAG,qBAAqB,CA6B9F"}
|
package/dist/backend.js
CHANGED
|
@@ -78,7 +78,7 @@ export class SdkBackend {
|
|
|
78
78
|
throw new Error(`Model "${opts.model}" not found${scope} in pi-ai registry.`);
|
|
79
79
|
}
|
|
80
80
|
const settingsManager = SettingsManager.inMemory({ theme: MU_DEFAULT_THEME_NAME, quietStartup: true });
|
|
81
|
-
const roleExtensionPaths = opts.role === "
|
|
81
|
+
const roleExtensionPaths = opts.role === "orchestrator" ? orchestratorToolExtensionPaths : workerToolExtensionPaths;
|
|
82
82
|
const resourceLoader = createMuResourceLoader({
|
|
83
83
|
cwd: opts.cwd,
|
|
84
84
|
systemPrompt: opts.systemPrompt,
|
|
@@ -8,6 +8,7 @@ export declare function loadBundledPrompt(name: string): string;
|
|
|
8
8
|
export declare function appendSharedSoul(basePrompt: string, soulPrompt: string): string;
|
|
9
9
|
export declare const DEFAULT_SOUL_PROMPT: string;
|
|
10
10
|
export declare const DEFAULT_ORCHESTRATOR_PROMPT: string;
|
|
11
|
+
export declare const DEFAULT_REVIEWER_PROMPT: string;
|
|
11
12
|
export declare const DEFAULT_WORKER_PROMPT: string;
|
|
12
13
|
export declare const DEFAULT_OPERATOR_SYSTEM_PROMPT: string;
|
|
13
14
|
//# sourceMappingURL=default_prompts.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"default_prompts.d.ts","sourceRoot":"","sources":["../src/default_prompts.ts"],"names":[],"mappings":"AAUA;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAStD;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAO/E;AAED,eAAO,MAAM,mBAAmB,QAAqC,CAAC;
|
|
1
|
+
{"version":3,"file":"default_prompts.d.ts","sourceRoot":"","sources":["../src/default_prompts.ts"],"names":[],"mappings":"AAUA;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAStD;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAO/E;AAED,eAAO,MAAM,mBAAmB,QAAqC,CAAC;AAOtE,eAAO,MAAM,2BAA2B,QAAkE,CAAC;AAC3G,eAAO,MAAM,uBAAuB,QAA8D,CAAC;AACnG,eAAO,MAAM,qBAAqB,QAA4D,CAAC;AAC/F,eAAO,MAAM,8BAA8B,QAAqE,CAAC"}
|
package/dist/default_prompts.js
CHANGED
|
@@ -32,8 +32,10 @@ export function appendSharedSoul(basePrompt, soulPrompt) {
|
|
|
32
32
|
}
|
|
33
33
|
export const DEFAULT_SOUL_PROMPT = loadBundledPrompt("roles/soul.md");
|
|
34
34
|
const BASE_ORCHESTRATOR_PROMPT = loadBundledPrompt("roles/orchestrator.md");
|
|
35
|
+
const BASE_REVIEWER_PROMPT = loadBundledPrompt("roles/reviewer.md");
|
|
35
36
|
const BASE_WORKER_PROMPT = loadBundledPrompt("roles/worker.md");
|
|
36
37
|
const BASE_OPERATOR_SYSTEM_PROMPT = loadBundledPrompt("roles/operator.md");
|
|
37
38
|
export const DEFAULT_ORCHESTRATOR_PROMPT = appendSharedSoul(BASE_ORCHESTRATOR_PROMPT, DEFAULT_SOUL_PROMPT);
|
|
39
|
+
export const DEFAULT_REVIEWER_PROMPT = appendSharedSoul(BASE_REVIEWER_PROMPT, DEFAULT_SOUL_PROMPT);
|
|
38
40
|
export const DEFAULT_WORKER_PROMPT = appendSharedSoul(BASE_WORKER_PROMPT, DEFAULT_SOUL_PROMPT);
|
|
39
41
|
export const DEFAULT_OPERATOR_SYSTEM_PROMPT = appendSharedSoul(BASE_OPERATOR_SYSTEM_PROMPT, DEFAULT_SOUL_PROMPT);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config write/reload actions for mu-messaging-setup.
|
|
3
|
+
*/
|
|
4
|
+
import type { AdapterCheck, AdapterId, ApplyOutcome, ConfigPresence, ConfigWriteResponse, ControlPlaneReloadApiResponse, ControlPlaneReloadOutcome, VerifyOutcome } from "./types.js";
|
|
5
|
+
export declare function parseControlPlaneReloadApiResponse(raw: string): {
|
|
6
|
+
response: ControlPlaneReloadApiResponse | null;
|
|
7
|
+
error: string | null;
|
|
8
|
+
};
|
|
9
|
+
export declare function reloadControlPlaneInProcess(reason: string): Promise<ControlPlaneReloadOutcome>;
|
|
10
|
+
export declare function reloadOutcomeSummary(reload: ControlPlaneReloadOutcome): string;
|
|
11
|
+
export declare function patchForAdapterValues(adapterId: AdapterId, values: Record<string, string>): Record<string, unknown>;
|
|
12
|
+
export declare function writeConfigPatch(patch: Record<string, unknown>): Promise<ConfigWriteResponse>;
|
|
13
|
+
export declare function applyAdapterConfig(opts: {
|
|
14
|
+
adapterId: AdapterId;
|
|
15
|
+
overrides?: Record<string, string>;
|
|
16
|
+
presence: ConfigPresence;
|
|
17
|
+
}): Promise<ApplyOutcome>;
|
|
18
|
+
export declare function buildVerifyOutcome(checks: AdapterCheck[], opts: {
|
|
19
|
+
adapterId?: AdapterId;
|
|
20
|
+
publicBaseUrl?: string;
|
|
21
|
+
}): VerifyOutcome;
|
|
22
|
+
//# sourceMappingURL=actions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../../src/extensions/messaging-setup/actions.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EACX,YAAY,EACZ,SAAS,EACT,YAAY,EACZ,cAAc,EACd,mBAAmB,EAEnB,6BAA6B,EAE7B,yBAAyB,EACzB,aAAa,EACb,MAAM,YAAY,CAAC;AAsBpB,wBAAgB,kCAAkC,CAAC,GAAG,EAAE,MAAM,GAAG;IAChE,QAAQ,EAAE,6BAA6B,GAAG,IAAI,CAAC;IAC/C,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,CAmCA;AAED,wBAAsB,2BAA2B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAwDpG;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,yBAAyB,GAAG,MAAM,CAiB9E;AAED,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAmCnH;AAED,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAMnG;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE;IAC9C,SAAS,EAAE,SAAS,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,QAAQ,EAAE,cAAc,CAAC;CACzB,GAAG,OAAO,CAAC,YAAY,CAAC,CAiDxB;AAED,wBAAgB,kBAAkB,CACjC,MAAM,EAAE,YAAY,EAAE,EACtB,IAAI,EAAE;IAAE,SAAS,CAAC,EAAE,SAAS,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GACrD,aAAa,CASf"}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config write/reload actions for mu-messaging-setup.
|
|
3
|
+
*/
|
|
4
|
+
import { adapterById, missingRequiredFields, normalizePublicBaseUrl } from "./adapters.js";
|
|
5
|
+
import { resetChecksCache } from "./runtime.js";
|
|
6
|
+
import { fetchMuJson, muServerUrl } from "../shared.js";
|
|
7
|
+
function isRecord(value) {
|
|
8
|
+
return typeof value === "object" && value !== null;
|
|
9
|
+
}
|
|
10
|
+
function isControlPlaneGenerationIdentity(value) {
|
|
11
|
+
if (!isRecord(value))
|
|
12
|
+
return false;
|
|
13
|
+
return typeof value.generation_id === "string" && typeof value.generation_seq === "number";
|
|
14
|
+
}
|
|
15
|
+
function isControlPlaneReloadGenerationSummary(value) {
|
|
16
|
+
if (!isRecord(value))
|
|
17
|
+
return false;
|
|
18
|
+
if (typeof value.attempt_id !== "string")
|
|
19
|
+
return false;
|
|
20
|
+
if (typeof value.coalesced !== "boolean")
|
|
21
|
+
return false;
|
|
22
|
+
if (value.from_generation !== null && !isControlPlaneGenerationIdentity(value.from_generation))
|
|
23
|
+
return false;
|
|
24
|
+
if (!isControlPlaneGenerationIdentity(value.to_generation))
|
|
25
|
+
return false;
|
|
26
|
+
if (value.active_generation !== null && !isControlPlaneGenerationIdentity(value.active_generation))
|
|
27
|
+
return false;
|
|
28
|
+
return value.outcome === "success" || value.outcome === "failure";
|
|
29
|
+
}
|
|
30
|
+
export function parseControlPlaneReloadApiResponse(raw) {
|
|
31
|
+
let parsed;
|
|
32
|
+
try {
|
|
33
|
+
parsed = JSON.parse(raw);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return {
|
|
37
|
+
response: null,
|
|
38
|
+
error: "control-plane reload returned invalid JSON response",
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (!isRecord(parsed)) {
|
|
42
|
+
return {
|
|
43
|
+
response: null,
|
|
44
|
+
error: "control-plane reload returned non-object payload",
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
if (!isControlPlaneReloadGenerationSummary(parsed.generation)) {
|
|
48
|
+
return {
|
|
49
|
+
response: null,
|
|
50
|
+
error: "control-plane reload response missing generation metadata (expected generation-scoped contract)",
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const parsedRecord = parsed;
|
|
54
|
+
const response = {
|
|
55
|
+
...parsed,
|
|
56
|
+
telegram_generation: parsedRecord.telegram_generation ?? null,
|
|
57
|
+
};
|
|
58
|
+
return {
|
|
59
|
+
response,
|
|
60
|
+
error: null,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export async function reloadControlPlaneInProcess(reason) {
|
|
64
|
+
const base = muServerUrl();
|
|
65
|
+
if (!base) {
|
|
66
|
+
return {
|
|
67
|
+
ok: false,
|
|
68
|
+
response: null,
|
|
69
|
+
error: "MU_SERVER_URL not set",
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
const response = await fetch(`${base}/api/control-plane/reload`, {
|
|
74
|
+
method: "POST",
|
|
75
|
+
headers: { "Content-Type": "application/json" },
|
|
76
|
+
body: JSON.stringify({ reason }),
|
|
77
|
+
});
|
|
78
|
+
const raw = await response.text();
|
|
79
|
+
const parsedResult = parseControlPlaneReloadApiResponse(raw);
|
|
80
|
+
const parsed = parsedResult.response;
|
|
81
|
+
if (parsedResult.error) {
|
|
82
|
+
return {
|
|
83
|
+
ok: false,
|
|
84
|
+
response: null,
|
|
85
|
+
error: parsedResult.error,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
if (!parsed) {
|
|
89
|
+
return {
|
|
90
|
+
ok: false,
|
|
91
|
+
response: null,
|
|
92
|
+
error: "control-plane reload response missing payload",
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
if (!response.ok || !parsed.ok) {
|
|
96
|
+
return {
|
|
97
|
+
ok: false,
|
|
98
|
+
response: parsed,
|
|
99
|
+
error: parsed.error ?? `control-plane reload failed (${response.status})`,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
ok: true,
|
|
104
|
+
response: parsed,
|
|
105
|
+
error: null,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
return {
|
|
110
|
+
ok: false,
|
|
111
|
+
response: null,
|
|
112
|
+
error: err instanceof Error ? err.message : String(err),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
export function reloadOutcomeSummary(reload) {
|
|
117
|
+
if (!reload.ok) {
|
|
118
|
+
return `Control-plane reload failed: ${reload.error ?? "unknown error"}.`;
|
|
119
|
+
}
|
|
120
|
+
const response = reload.response;
|
|
121
|
+
if (!response) {
|
|
122
|
+
return "Control-plane reload failed: missing reload response payload.";
|
|
123
|
+
}
|
|
124
|
+
const adapters = response.control_plane?.adapters.join(", ") || "(none)";
|
|
125
|
+
const generationSummary = `${response.generation.outcome} (${response.generation.active_generation?.generation_id ?? response.generation.to_generation.generation_id})`;
|
|
126
|
+
const telegramRollbackTrigger = response.telegram_generation?.rollback.trigger;
|
|
127
|
+
const telegramNote = response.telegram_generation?.handled && telegramRollbackTrigger
|
|
128
|
+
? ` rollback_trigger=${telegramRollbackTrigger}`
|
|
129
|
+
: "";
|
|
130
|
+
return `Control-plane reloaded in-process. Active adapters: ${adapters}. Generation: ${generationSummary}.${telegramNote}`;
|
|
131
|
+
}
|
|
132
|
+
export function patchForAdapterValues(adapterId, values) {
|
|
133
|
+
switch (adapterId) {
|
|
134
|
+
case "slack":
|
|
135
|
+
return {
|
|
136
|
+
control_plane: {
|
|
137
|
+
adapters: {
|
|
138
|
+
slack: {
|
|
139
|
+
signing_secret: values.signing_secret ?? null,
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
case "discord":
|
|
145
|
+
return {
|
|
146
|
+
control_plane: {
|
|
147
|
+
adapters: {
|
|
148
|
+
discord: {
|
|
149
|
+
signing_secret: values.signing_secret ?? null,
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
case "telegram":
|
|
155
|
+
return {
|
|
156
|
+
control_plane: {
|
|
157
|
+
adapters: {
|
|
158
|
+
telegram: {
|
|
159
|
+
webhook_secret: values.webhook_secret ?? null,
|
|
160
|
+
bot_token: values.bot_token ?? null,
|
|
161
|
+
bot_username: values.bot_username ?? null,
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
export async function writeConfigPatch(patch) {
|
|
169
|
+
return await fetchMuJson("/api/config", {
|
|
170
|
+
method: "POST",
|
|
171
|
+
body: { patch },
|
|
172
|
+
timeoutMs: 6_000,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
export async function applyAdapterConfig(opts) {
|
|
176
|
+
const adapter = adapterById(opts.adapterId);
|
|
177
|
+
if (adapter.support === "planned") {
|
|
178
|
+
return {
|
|
179
|
+
ok: false,
|
|
180
|
+
adapter: adapter.id,
|
|
181
|
+
reason: "adapter_planned",
|
|
182
|
+
missing_required_fields: adapter.fields.filter((field) => field.required).map((field) => field.key),
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
const missingRequired = missingRequiredFields(adapter, opts.presence);
|
|
186
|
+
const overrides = opts.overrides ?? {};
|
|
187
|
+
const unresolved = missingRequired.filter((field) => !(field in overrides));
|
|
188
|
+
if (unresolved.length > 0) {
|
|
189
|
+
return {
|
|
190
|
+
ok: false,
|
|
191
|
+
adapter: adapter.id,
|
|
192
|
+
reason: "missing_required_fields",
|
|
193
|
+
missing_required_fields: unresolved,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
const patchValues = {};
|
|
197
|
+
for (const [key, value] of Object.entries(overrides)) {
|
|
198
|
+
const trimmed = value.trim();
|
|
199
|
+
if (trimmed.length > 0) {
|
|
200
|
+
patchValues[key] = trimmed;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
let configPath = null;
|
|
204
|
+
const updatedFields = Object.keys(patchValues);
|
|
205
|
+
if (updatedFields.length > 0) {
|
|
206
|
+
const patch = patchForAdapterValues(adapter.id, patchValues);
|
|
207
|
+
const writeResult = await writeConfigPatch(patch);
|
|
208
|
+
configPath = writeResult.config_path;
|
|
209
|
+
}
|
|
210
|
+
resetChecksCache();
|
|
211
|
+
const reload = await reloadControlPlaneInProcess(`mu_setup_apply_${adapter.id}`);
|
|
212
|
+
return {
|
|
213
|
+
ok: true,
|
|
214
|
+
adapter: adapter.id,
|
|
215
|
+
updated_fields: updatedFields,
|
|
216
|
+
config_path: configPath,
|
|
217
|
+
reload,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
export function buildVerifyOutcome(checks, opts) {
|
|
221
|
+
const targets = opts.adapterId ? checks.filter((check) => check.id === opts.adapterId) : checks;
|
|
222
|
+
const normalizedBase = normalizePublicBaseUrl(opts.publicBaseUrl);
|
|
223
|
+
const ok = targets.every((check) => check.state === "active");
|
|
224
|
+
return {
|
|
225
|
+
ok,
|
|
226
|
+
targets,
|
|
227
|
+
public_base_url: normalizedBase,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapter constants and lookup helpers for mu-messaging-setup.
|
|
3
|
+
*/
|
|
4
|
+
import type { AdapterCheck, AdapterConfig, AdapterId, ConfigPresence, SetupAction } from "./types.js";
|
|
5
|
+
export declare const ADAPTERS: AdapterConfig[];
|
|
6
|
+
export declare const SETUP_ACTIONS: readonly SetupAction[];
|
|
7
|
+
export declare function isSetupAction(value: string): value is SetupAction;
|
|
8
|
+
export declare function normalizeAdapterId(input: string): AdapterId | null;
|
|
9
|
+
export declare function defaultRouteForAdapter(id: AdapterId): string;
|
|
10
|
+
export declare function normalizePublicBaseUrl(input: string | undefined): string | null;
|
|
11
|
+
export declare function adapterById(id: AdapterId): AdapterConfig;
|
|
12
|
+
export declare function fieldPresent(presence: ConfigPresence, adapterId: AdapterId, key: string): boolean;
|
|
13
|
+
export declare function missingRequiredFields(adapter: AdapterConfig, presence: ConfigPresence | null): string[];
|
|
14
|
+
export declare function configured(adapter: AdapterConfig, presence: ConfigPresence | null): boolean;
|
|
15
|
+
export declare function deriveState(opts: {
|
|
16
|
+
adapter: AdapterConfig;
|
|
17
|
+
configured: boolean;
|
|
18
|
+
active: boolean;
|
|
19
|
+
}): AdapterCheck["state"];
|
|
20
|
+
export declare function nextStepForState(opts: {
|
|
21
|
+
state: AdapterCheck["state"];
|
|
22
|
+
missing: string[];
|
|
23
|
+
}): string;
|
|
24
|
+
//# sourceMappingURL=adapters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapters.d.ts","sourceRoot":"","sources":["../../../src/extensions/messaging-setup/adapters.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEtG,eAAO,MAAM,QAAQ,EAAE,aAAa,EAoEnC,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,SAAS,WAAW,EAOtC,CAAC;AAEX,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,WAAW,CAEjE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAUlE;AAED,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,SAAS,GAAG,MAAM,CAE5D;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAc/E;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,SAAS,GAAG,aAAa,CAMxD;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,cAAc,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAYjG;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,cAAc,GAAG,IAAI,GAAG,MAAM,EAAE,CAOvG;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,cAAc,GAAG,IAAI,GAAG,OAAO,CAE3F;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE;IACjC,OAAO,EAAE,aAAa,CAAC;IACvB,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;CAChB,GAAG,YAAY,CAAC,OAAO,CAAC,CAKxB;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IAAE,KAAK,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,MAAM,CAWlG"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapter constants and lookup helpers for mu-messaging-setup.
|
|
3
|
+
*/
|
|
4
|
+
export const ADAPTERS = [
|
|
5
|
+
{
|
|
6
|
+
id: "slack",
|
|
7
|
+
name: "Slack",
|
|
8
|
+
support: "available",
|
|
9
|
+
fields: [
|
|
10
|
+
{
|
|
11
|
+
key: "signing_secret",
|
|
12
|
+
required: true,
|
|
13
|
+
description: "Slack Signing Secret used to validate inbound webhook signatures.",
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
providerSetupSteps: [
|
|
17
|
+
"Create/open your Slack App (api.slack.com/apps).",
|
|
18
|
+
"Copy Signing Secret into .mu/config.json → control_plane.adapters.slack.signing_secret.",
|
|
19
|
+
"Create a Slash Command (e.g. /mu) with Request URL <public-base-url>/webhooks/slack.",
|
|
20
|
+
"Install/reinstall app after command changes.",
|
|
21
|
+
"Run /mu in Slack, then /mu setup verify slack.",
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: "discord",
|
|
26
|
+
name: "Discord",
|
|
27
|
+
support: "available",
|
|
28
|
+
fields: [
|
|
29
|
+
{
|
|
30
|
+
key: "signing_secret",
|
|
31
|
+
required: true,
|
|
32
|
+
description: "Discord interaction public key for signature verification.",
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
providerSetupSteps: [
|
|
36
|
+
"Create/open app in Discord Developer Portal.",
|
|
37
|
+
"Copy Interaction Public Key into .mu/config.json → control_plane.adapters.discord.signing_secret.",
|
|
38
|
+
"Set Interactions Endpoint URL to <public-base-url>/webhooks/discord.",
|
|
39
|
+
"Run a Discord command interaction, then /mu setup verify discord.",
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: "telegram",
|
|
44
|
+
name: "Telegram",
|
|
45
|
+
support: "available",
|
|
46
|
+
fields: [
|
|
47
|
+
{
|
|
48
|
+
key: "webhook_secret",
|
|
49
|
+
required: true,
|
|
50
|
+
description: "Telegram webhook secret token.",
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
key: "bot_token",
|
|
54
|
+
required: true,
|
|
55
|
+
description: "Telegram bot token used for outbound replies.",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
key: "bot_username",
|
|
59
|
+
required: false,
|
|
60
|
+
description: "Optional bot username used for mention normalization.",
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
providerSetupSteps: [
|
|
64
|
+
"Create bot with @BotFather and place token in control_plane.adapters.telegram.bot_token.",
|
|
65
|
+
"Set control_plane.adapters.telegram.webhook_secret to a random secret string.",
|
|
66
|
+
"Call Telegram setWebhook using URL <public-base-url>/webhooks/telegram and matching secret_token.",
|
|
67
|
+
"Link your Telegram identity to control-plane policy (mu control link --channel telegram --actor-id <telegram-user-id> --tenant-id telegram-bot --role <viewer|contributor|operator>).",
|
|
68
|
+
"Optionally set control_plane.adapters.telegram.bot_username.",
|
|
69
|
+
"Send /mu in Telegram chat, then /mu setup verify telegram.",
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
];
|
|
73
|
+
export const SETUP_ACTIONS = [
|
|
74
|
+
"check",
|
|
75
|
+
"preflight",
|
|
76
|
+
"guide",
|
|
77
|
+
"plan",
|
|
78
|
+
"apply",
|
|
79
|
+
"verify",
|
|
80
|
+
];
|
|
81
|
+
export function isSetupAction(value) {
|
|
82
|
+
return SETUP_ACTIONS.includes(value);
|
|
83
|
+
}
|
|
84
|
+
export function normalizeAdapterId(input) {
|
|
85
|
+
const normalized = input.trim().toLowerCase();
|
|
86
|
+
switch (normalized) {
|
|
87
|
+
case "slack":
|
|
88
|
+
case "discord":
|
|
89
|
+
case "telegram":
|
|
90
|
+
return normalized;
|
|
91
|
+
default:
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
export function defaultRouteForAdapter(id) {
|
|
96
|
+
return `/webhooks/${id}`;
|
|
97
|
+
}
|
|
98
|
+
export function normalizePublicBaseUrl(input) {
|
|
99
|
+
if (!input)
|
|
100
|
+
return null;
|
|
101
|
+
const trimmed = input.trim();
|
|
102
|
+
if (trimmed.length === 0)
|
|
103
|
+
return null;
|
|
104
|
+
try {
|
|
105
|
+
const url = new URL(trimmed);
|
|
106
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
const normalized = `${url.protocol}//${url.host}${url.pathname.replace(/\/$/, "")}`;
|
|
110
|
+
return normalized.endsWith("/") ? normalized.slice(0, -1) : normalized;
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
export function adapterById(id) {
|
|
117
|
+
const found = ADAPTERS.find((adapter) => adapter.id === id);
|
|
118
|
+
if (!found) {
|
|
119
|
+
throw new Error(`Unknown adapter id: ${id}`);
|
|
120
|
+
}
|
|
121
|
+
return found;
|
|
122
|
+
}
|
|
123
|
+
export function fieldPresent(presence, adapterId, key) {
|
|
124
|
+
switch (adapterId) {
|
|
125
|
+
case "slack":
|
|
126
|
+
return key === "signing_secret" ? presence.control_plane.adapters.slack.signing_secret : false;
|
|
127
|
+
case "discord":
|
|
128
|
+
return key === "signing_secret" ? presence.control_plane.adapters.discord.signing_secret : false;
|
|
129
|
+
case "telegram":
|
|
130
|
+
if (key === "webhook_secret")
|
|
131
|
+
return presence.control_plane.adapters.telegram.webhook_secret;
|
|
132
|
+
if (key === "bot_token")
|
|
133
|
+
return presence.control_plane.adapters.telegram.bot_token;
|
|
134
|
+
if (key === "bot_username")
|
|
135
|
+
return presence.control_plane.adapters.telegram.bot_username;
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
export function missingRequiredFields(adapter, presence) {
|
|
140
|
+
if (!presence) {
|
|
141
|
+
return adapter.fields.filter((field) => field.required).map((field) => field.key);
|
|
142
|
+
}
|
|
143
|
+
return adapter.fields
|
|
144
|
+
.filter((field) => field.required && !fieldPresent(presence, adapter.id, field.key))
|
|
145
|
+
.map((field) => field.key);
|
|
146
|
+
}
|
|
147
|
+
export function configured(adapter, presence) {
|
|
148
|
+
return missingRequiredFields(adapter, presence).length === 0;
|
|
149
|
+
}
|
|
150
|
+
export function deriveState(opts) {
|
|
151
|
+
if (opts.adapter.support === "planned")
|
|
152
|
+
return "planned";
|
|
153
|
+
if (opts.active)
|
|
154
|
+
return "active";
|
|
155
|
+
if (opts.configured)
|
|
156
|
+
return "configured_not_active";
|
|
157
|
+
return "missing_config";
|
|
158
|
+
}
|
|
159
|
+
export function nextStepForState(opts) {
|
|
160
|
+
switch (opts.state) {
|
|
161
|
+
case "active":
|
|
162
|
+
return "No action needed. Adapter is mounted and receiving webhooks.";
|
|
163
|
+
case "configured_not_active":
|
|
164
|
+
return "Run `/mu setup apply <adapter>` to trigger in-process control-plane reload.";
|
|
165
|
+
case "missing_config":
|
|
166
|
+
return `Set required config fields: ${opts.missing.join(", ")}.`;
|
|
167
|
+
case "planned":
|
|
168
|
+
return "Adapter is planned. Track implementation work before expecting runtime activation.";
|
|
169
|
+
}
|
|
170
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mu-messaging-setup — Adapter configuration diagnostics + guided setup.
|
|
3
|
+
*
|
|
4
|
+
* Goals:
|
|
5
|
+
* - Make `/mu setup <adapter>` hand setup context to the active mu agent.
|
|
6
|
+
* - Keep configuration in `.mu/config.json` (no process.env mutations).
|
|
7
|
+
* - Support plan/apply/verify workflow with in-process control-plane reload.
|
|
8
|
+
*/
|
|
9
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
10
|
+
export type { AdapterId, AdapterCheck, AdapterPlan, RuntimeState, SetupAction } from "./types.js";
|
|
11
|
+
export type { ParsedSetupCommand } from "./parser.js";
|
|
12
|
+
export type MessagingSetupExtensionOpts = {
|
|
13
|
+
allowApply?: boolean;
|
|
14
|
+
};
|
|
15
|
+
export declare function messagingSetupExtension(pi: ExtensionAPI, opts?: MessagingSetupExtensionOpts): void;
|
|
16
|
+
export default messagingSetupExtension;
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/extensions/messaging-setup/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAiBlE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAClG,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD,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"}
|