@rubytech/create-maxy-code 0.1.212 → 0.1.216
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/package.json +1 -1
- package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/admin/PLUGIN.md +5 -1
- package/payload/platform/plugins/admin/hooks/__tests__/hook-emit.test.sh +75 -0
- package/payload/platform/plugins/admin/hooks/__tests__/post-tool-use-agent.test.sh +173 -0
- package/payload/platform/plugins/admin/hooks/__tests__/pre-tool-use-admin-tool-gate.test.sh +107 -40
- package/payload/platform/plugins/admin/hooks/__tests__/pre-tool-use-base64-guard.test.sh +4 -4
- package/payload/platform/plugins/admin/hooks/lib/hook-emit.sh +114 -0
- package/payload/platform/plugins/admin/hooks/post-tool-use-agent.sh +136 -0
- package/payload/platform/plugins/admin/hooks/pre-tool-use.sh +127 -68
- package/payload/platform/plugins/admin/mcp/dist/__tests__/capabilities-here.test.d.ts +2 -0
- package/payload/platform/plugins/admin/mcp/dist/__tests__/capabilities-here.test.d.ts.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/__tests__/capabilities-here.test.js +130 -0
- package/payload/platform/plugins/admin/mcp/dist/__tests__/capabilities-here.test.js.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/index.js +63 -0
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/lib/catalogue-census.d.ts +14 -0
- package/payload/platform/plugins/admin/mcp/dist/lib/catalogue-census.d.ts.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/lib/catalogue-census.js +50 -0
- package/payload/platform/plugins/admin/mcp/dist/lib/catalogue-census.js.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/capabilities-here.d.ts +28 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/capabilities-here.d.ts.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/capabilities-here.js +68 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/capabilities-here.js.map +1 -0
- package/payload/platform/plugins/admin/skills/capabilities-here/SKILL.md +31 -0
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +30 -14
- package/payload/platform/plugins/docs/references/platform.md +19 -9
- package/payload/platform/plugins/docs/references/plugins-guide.md +2 -0
- package/payload/platform/scripts/check-architecture-skill-no-drift.mjs +89 -42
- package/payload/platform/scripts/check-roles-doc-completeness.mjs +96 -0
- package/payload/platform/scripts/check-specialist-tool-surface.mjs +1 -1
- package/payload/platform/scripts/setup-account.sh +6 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +1 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +77 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.js +30 -0
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/jsonl-tail.d.ts +18 -0
- package/payload/platform/services/claude-session-manager/dist/jsonl-tail.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/jsonl-tail.js +63 -0
- package/payload/platform/services/claude-session-manager/dist/jsonl-tail.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts +5 -0
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +29 -0
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-script-spawn.d.ts +80 -0
- package/payload/platform/services/claude-session-manager/dist/rc-script-spawn.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/rc-script-spawn.js +306 -0
- package/payload/platform/services/claude-session-manager/dist/rc-script-spawn.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/specialist-drift.d.ts +9 -0
- package/payload/platform/services/claude-session-manager/dist/specialist-drift.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/specialist-drift.js +6 -2
- package/payload/platform/services/claude-session-manager/dist/specialist-drift.js.map +1 -1
- package/payload/platform/templates/agents/admin/IDENTITY.md +3 -1
- package/payload/platform/templates/specialists/agents/content-producer.md +1 -1
- package/payload/server/public/assets/AdminShell-CPWbJ_I8.js +1 -0
- package/payload/server/public/assets/{admin-DMo5DWKH.js → admin-DjGGOx2K.js} +1 -1
- package/payload/server/public/assets/{data-D6IQdm0R.js → data-WBEvtRV-.js} +1 -1
- package/payload/server/public/assets/{graph-PkZKVkWD.js → graph-DsOLsIPf.js} +1 -1
- package/payload/server/public/data.html +2 -2
- package/payload/server/public/graph.html +2 -2
- package/payload/server/public/index.html +2 -2
- package/payload/server/server.js +6 -0
- package/payload/server/public/assets/AdminShell-BcxEZnpu.js +0 -1
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
2
|
+
import { resolve, join } from "node:path";
|
|
3
|
+
function listSpecialists(dir) {
|
|
4
|
+
if (!existsSync(dir))
|
|
5
|
+
return [];
|
|
6
|
+
const out = [];
|
|
7
|
+
for (const entry of readdirSync(dir)) {
|
|
8
|
+
const full = join(dir, entry);
|
|
9
|
+
const st = statSync(full);
|
|
10
|
+
if (st.isFile() && entry.endsWith(".md"))
|
|
11
|
+
out.push(entry.replace(/\.md$/, ""));
|
|
12
|
+
else if (st.isDirectory() && existsSync(join(full, "IDENTITY.md")))
|
|
13
|
+
out.push(entry);
|
|
14
|
+
}
|
|
15
|
+
return out;
|
|
16
|
+
}
|
|
17
|
+
function slugify(s) {
|
|
18
|
+
return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
19
|
+
}
|
|
20
|
+
export function runCatalogueCensus(input) {
|
|
21
|
+
const platformSpecs = listSpecialists(resolve(input.platformRoot, "templates", "specialists", "agents"));
|
|
22
|
+
const premiumSpecs = [];
|
|
23
|
+
for (const bundle of input.enabledBundles) {
|
|
24
|
+
const dir = resolve(input.premiumPluginsRoot, bundle, "agents");
|
|
25
|
+
premiumSpecs.push(...listSpecialists(dir));
|
|
26
|
+
}
|
|
27
|
+
const disk = [...platformSpecs, ...premiumSpecs];
|
|
28
|
+
const body = existsSync(input.shippedSkillPath)
|
|
29
|
+
? readFileSync(input.shippedSkillPath, "utf8")
|
|
30
|
+
: "";
|
|
31
|
+
const bodySlugs = new Set();
|
|
32
|
+
for (const match of body.matchAll(/^\|\s*([^|]+)\s*\|/gm)) {
|
|
33
|
+
const cell = match[1].trim();
|
|
34
|
+
if (!cell || cell.startsWith("---") || cell === "Role" || cell === "Plugin")
|
|
35
|
+
continue;
|
|
36
|
+
bodySlugs.add(slugify(cell));
|
|
37
|
+
}
|
|
38
|
+
const missing = disk.filter((s) => !bodySlugs.has(slugify(s)));
|
|
39
|
+
// Stale signal arrives via the per-brand drift gate and the
|
|
40
|
+
// check-roles-doc-completeness gate; this census closes the F5 leak —
|
|
41
|
+
// disk-but-undocumented — which the drift gates cannot see.
|
|
42
|
+
const stale = [];
|
|
43
|
+
return {
|
|
44
|
+
diskCount: disk.length,
|
|
45
|
+
documentedCount: bodySlugs.size,
|
|
46
|
+
missing,
|
|
47
|
+
stale,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=catalogue-census.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalogue-census.js","sourceRoot":"","sources":["../../src/lib/catalogue-census.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface CapabilitiesHereInput {
|
|
2
|
+
accountId: string;
|
|
3
|
+
accountConfigPath: string;
|
|
4
|
+
brandConfigPath: string;
|
|
5
|
+
platformRoot: string;
|
|
6
|
+
premiumPluginsRoot: string;
|
|
7
|
+
claudeConfigDir: string;
|
|
8
|
+
}
|
|
9
|
+
export interface CapabilitiesHereResult {
|
|
10
|
+
accountId: string;
|
|
11
|
+
tier: string | null;
|
|
12
|
+
adminModel: string | null;
|
|
13
|
+
publicModel: string | null;
|
|
14
|
+
enabledPlugins: string[];
|
|
15
|
+
installedPlatformSpecialists: string[];
|
|
16
|
+
installedPremiumSpecialists: Array<{
|
|
17
|
+
bundle: string;
|
|
18
|
+
name: string;
|
|
19
|
+
}>;
|
|
20
|
+
registeredAgentTypes: string[];
|
|
21
|
+
brand: {
|
|
22
|
+
productName: string | null;
|
|
23
|
+
shipsPremiumBundles: string[];
|
|
24
|
+
};
|
|
25
|
+
capturedAt: string;
|
|
26
|
+
}
|
|
27
|
+
export declare function resolveCapabilitiesHere(input: CapabilitiesHereInput, nowIso: string): Promise<CapabilitiesHereResult>;
|
|
28
|
+
//# sourceMappingURL=capabilities-here.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities-here.d.ts","sourceRoot":"","sources":["../../src/tools/capabilities-here.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,4BAA4B,EAAE,MAAM,EAAE,CAAC;IACvC,2BAA2B,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrE,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,KAAK,EAAE;QACL,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,mBAAmB,EAAE,MAAM,EAAE,CAAC;KAC/B,CAAC;IACF,UAAU,EAAE,MAAM,CAAC;CACpB;AA0BD,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,qBAAqB,EAC5B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,sBAAsB,CAAC,CAgDjC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
3
|
+
import { resolve, join } from "node:path";
|
|
4
|
+
function listSpecialistFiles(dir) {
|
|
5
|
+
if (!existsSync(dir))
|
|
6
|
+
return [];
|
|
7
|
+
const out = [];
|
|
8
|
+
for (const entry of readdirSync(dir)) {
|
|
9
|
+
const full = join(dir, entry);
|
|
10
|
+
const st = statSync(full);
|
|
11
|
+
if (st.isFile() && entry.endsWith(".md")) {
|
|
12
|
+
out.push(entry.replace(/\.md$/, ""));
|
|
13
|
+
}
|
|
14
|
+
else if (st.isDirectory() && existsSync(join(full, "IDENTITY.md"))) {
|
|
15
|
+
out.push(entry);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return out.sort();
|
|
19
|
+
}
|
|
20
|
+
function listAgentRegistry(dir) {
|
|
21
|
+
if (!existsSync(dir))
|
|
22
|
+
return [];
|
|
23
|
+
const out = [];
|
|
24
|
+
for (const entry of readdirSync(dir)) {
|
|
25
|
+
if (entry.endsWith(".md"))
|
|
26
|
+
out.push(entry.replace(/\.md$/, ""));
|
|
27
|
+
}
|
|
28
|
+
return out.sort();
|
|
29
|
+
}
|
|
30
|
+
export async function resolveCapabilitiesHere(input, nowIso) {
|
|
31
|
+
const accountRaw = await readFile(input.accountConfigPath, "utf-8");
|
|
32
|
+
const account = JSON.parse(accountRaw);
|
|
33
|
+
const brandRaw = await readFile(input.brandConfigPath, "utf-8");
|
|
34
|
+
const brand = JSON.parse(brandRaw);
|
|
35
|
+
const enabledPlugins = Array.isArray(account.enabledPlugins)
|
|
36
|
+
? account.enabledPlugins.slice().sort()
|
|
37
|
+
: [];
|
|
38
|
+
const tier = typeof account.tier === "string" ? account.tier : null;
|
|
39
|
+
const adminModel = typeof account.adminModel === "string" ? account.adminModel : null;
|
|
40
|
+
const publicModel = typeof account.publicModel === "string" ? account.publicModel : null;
|
|
41
|
+
const productName = typeof brand.productName === "string" ? brand.productName : null;
|
|
42
|
+
const shipsPremiumBundles = Array.isArray(brand.shipsPremiumBundles)
|
|
43
|
+
? brand.shipsPremiumBundles.slice().sort()
|
|
44
|
+
: [];
|
|
45
|
+
const platformSpecialistsDir = resolve(input.platformRoot, "templates", "specialists", "agents");
|
|
46
|
+
const installedPlatformSpecialists = listSpecialistFiles(platformSpecialistsDir);
|
|
47
|
+
const installedPremiumSpecialists = [];
|
|
48
|
+
for (const bundle of shipsPremiumBundles) {
|
|
49
|
+
const bundleAgentsDir = resolve(input.premiumPluginsRoot, bundle, "agents");
|
|
50
|
+
const names = listSpecialistFiles(bundleAgentsDir);
|
|
51
|
+
for (const name of names)
|
|
52
|
+
installedPremiumSpecialists.push({ bundle, name });
|
|
53
|
+
}
|
|
54
|
+
const registeredAgentTypes = listAgentRegistry(resolve(input.claudeConfigDir, "agents"));
|
|
55
|
+
return {
|
|
56
|
+
accountId: input.accountId,
|
|
57
|
+
tier,
|
|
58
|
+
adminModel,
|
|
59
|
+
publicModel,
|
|
60
|
+
enabledPlugins,
|
|
61
|
+
installedPlatformSpecialists,
|
|
62
|
+
installedPremiumSpecialists,
|
|
63
|
+
registeredAgentTypes,
|
|
64
|
+
brand: { productName, shipsPremiumBundles },
|
|
65
|
+
capturedAt: nowIso,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=capabilities-here.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities-here.js","sourceRoot":"","sources":["../../src/tools/capabilities-here.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: capabilities-here
|
|
3
|
+
description: Use when grounding any claim about what is installed on the current account — enabled plugins, available specialists, registered Claude Code agent types, brand, tier, models. Call the `capabilities-here` tool; the JSON it returns is the authoritative install snapshot. Never infer install state from the platform-architecture skill (that skill is the install catalogue, not evidence of what is enabled here).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# capabilities-here
|
|
7
|
+
|
|
8
|
+
The `capabilities-here` admin MCP tool returns a single JSON object describing the live install state on the current account. Call it whenever you are about to:
|
|
9
|
+
|
|
10
|
+
- Tell the operator what you can or cannot do here.
|
|
11
|
+
- Decide whether a specialist exists before dispatching it.
|
|
12
|
+
- Say which plugins are available on this account.
|
|
13
|
+
- Compare the install against a catalogue claim from `platform-architecture`.
|
|
14
|
+
|
|
15
|
+
## How to use
|
|
16
|
+
|
|
17
|
+
Call `mcp__plugin_admin_admin__capabilities-here` with no arguments. The tool reads:
|
|
18
|
+
|
|
19
|
+
- `account.json` for `enabledPlugins`, `tier`, `adminModel`, `publicModel`.
|
|
20
|
+
- `brand.json` for `productName` and `shipsPremiumBundles`.
|
|
21
|
+
- `platform/templates/specialists/agents/` for `installedPlatformSpecialists`.
|
|
22
|
+
- Each enabled premium bundle's `agents/` for `installedPremiumSpecialists`.
|
|
23
|
+
- `$CLAUDE_CONFIG_DIR/agents/` for `registeredAgentTypes` (the same registry the Agent tool resolves against).
|
|
24
|
+
|
|
25
|
+
Returns one JSON object with those fields plus `accountId`, `capturedAt`, and the `brand` block. No LLM in the resolution path; pure disk + JSON reads.
|
|
26
|
+
|
|
27
|
+
## Boundary against `platform-architecture`
|
|
28
|
+
|
|
29
|
+
`platform-architecture` is the install catalogue — every plugin, skill, and specialist the platform can ship. It is not evidence that any of them is enabled here. For documented surface (how a plugin works, what a role is for) cite `platform-architecture` with the `Source:` URL. For what is actually installed on this account, cite `capabilities-here`.
|
|
30
|
+
|
|
31
|
+
When the operator asks "what can you do" or "what plugins are enabled" or "do you have X", the answer comes from `capabilities-here`, not from this skill or from `platform-architecture`.
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: platform-architecture
|
|
3
|
-
description: Use when grounding any claim about what Maxy
|
|
4
|
-
content-hash: sha256:
|
|
3
|
+
description: Use when grounding any documented-surface claim about what Maxy ships — plugins, skills, specialists, install/deploy flows, internals. This is the install catalogue, not evidence of what is enabled on the current account. For install state on this account, call `capabilities-here`; for documented surface, cite the `Source:` URL inline.
|
|
4
|
+
content-hash: sha256:b26da3e924270e5b1492f4c822c2e45e681b29f535c021c2cecb97ed2eabcda6
|
|
5
|
+
brand: maxy-code
|
|
6
|
+
product-name: Maxy
|
|
5
7
|
---
|
|
6
8
|
|
|
7
|
-
#
|
|
9
|
+
# Maxy platform architecture (catalogue)
|
|
8
10
|
|
|
9
|
-
This skill is
|
|
11
|
+
This skill is the install catalogue — every surface the platform can ship. It is not evidence of what is installed on the current account. Cite for documented surface. For 'what is installed here' / 'what can you do', call `capabilities-here` and read `account-manage`; do not infer install state from this body.
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
This skill is generated. Its body is the concatenated source markdown for every public Maxy docs page, emitted by `docs/scripts/copy-docs.mjs` as `docs/public/llms-full.maxy-code.txt` and assembled here by `maxy-code/scripts/assemble-architecture-skill.mjs`. Do not hand-edit — the drift gate in `platform/scripts/check-architecture-skill-no-drift.mjs` will fail CI.
|
|
14
|
+
|
|
15
|
+
When you load this skill to ground a factual claim, cite the `Source:` URL printed above the block you drew from. The URL is the canonical public docs page (https://docs.getmaxy.com); relay it as a markdown link in your reply. Training-data recall is not a permitted source — the body below is.
|
|
12
16
|
|
|
13
17
|
---
|
|
14
18
|
# Maxy Documentation — full corpus
|
|
@@ -145,18 +149,26 @@ Plugins are installed and managed through conversation. You can add marketplace
|
|
|
145
149
|
|
|
146
150
|
## Roles
|
|
147
151
|
|
|
148
|
-
Maxy
|
|
152
|
+
Maxy ships twelve roles it can dispatch for specific tasks — like members of your team. You don't need to configure or manage them — Maxy decides when to use each role and handles everything automatically. You may see activity like "Dispatching personal-assistant..." in the chat timeline when this happens.
|
|
153
|
+
|
|
154
|
+
The catalogue below is what the platform ships. It is not evidence of what is installed on the current account. For the live install set on this account, ask Maxy to call `capabilities-here`.
|
|
149
155
|
|
|
150
156
|
| Role | What it does |
|
|
151
157
|
|------|-------------|
|
|
152
|
-
|
|
|
153
|
-
|
|
|
154
|
-
|
|
|
155
|
-
|
|
|
156
|
-
|
|
|
157
|
-
| Database Operator |
|
|
158
|
-
|
|
159
|
-
|
|
158
|
+
| Archive Ingest Operator | Ingests bulk external archives — Obsidian, ICS, X, Notion — and surfaces schema-mapping ambiguity rather than catching all unmapped relations as :MENTIONS. |
|
|
159
|
+
| Citation Auditor | Audits :TimelineEvent rows for missing citations and writes either citations directly or a CitationProposal stub. |
|
|
160
|
+
| Coding Assistant | Runs shell commands, drives git repositories, and reads or edits code on your behalf — the specialist you reach for when the work belongs in a developer terminal. |
|
|
161
|
+
| Compiled Truth Rewriter | Recomputes a node's compiledTruth (and public twin where applicable) from its 90-day timeline plus optional operator hints. |
|
|
162
|
+
| Content Producer | Produces visual output from your graph: generates images, renders pages to PDF, and hosts static websites you upload as a zip. |
|
|
163
|
+
| Database Operator | Executes graph writes on admin's behalf when delegated via the Task tool — admin names each write, the specialist runs it. |
|
|
164
|
+
| Librarian | Owns foreground ingest of documents, conversation transcripts, and external archives into the memory graph. |
|
|
165
|
+
| Personal Assistant | Handles the operational tasks you'd give a personal assistant: scheduling meetings, managing your platform settings, connecting messaging channels, and completing browser-based tasks on your behalf. |
|
|
166
|
+
| Project Manager | Manages your tasks, projects, sessions, and workflows: linking work to people and goals, and keeping everything organised. |
|
|
167
|
+
| Public Session Reviewer | Reads a gated public-agent transcript and dispatches database-operator for each per-visitor memory write. |
|
|
168
|
+
| Research Assistant | Researches topics online, manages your knowledge graph, and produces supporting visuals. |
|
|
169
|
+
| Typed Edge Classifier | Reads recently-written prose nodes and writes typed edges from a closed allowlist. |
|
|
170
|
+
|
|
171
|
+
Roles are installed during setup and listed when Maxy introduces itself. Some premium bundles add their own specialists (e.g. the `real-agent` bundle adds a listing curator, negotiator, valuer, compliance officer, and buyer-enquiry public agent). Roles installed mid-session become active from the next session.
|
|
160
172
|
|
|
161
173
|
## Memory
|
|
162
174
|
|
|
@@ -230,6 +242,8 @@ Each session row also carries a small muted timestamp crumb under the name showi
|
|
|
230
242
|
|
|
231
243
|
`verified=true` requires `master-fd=closed` AND `fdDelta>=1` AND `trackerRemoved=true`. `master-fd=close-failed` is logged at error level (`[rc-spawn-error]` prefix) — never swallowed; the next post-archive sweep is the catch-net.
|
|
232
244
|
|
|
245
|
+
**Cross-arm `[rc-life]` schema (Task 562).** Both rc-spawn arms (the legacy node-pty one above and a new isolated `script-scope` arm exposed via the dashboard A/B toggle next to "New session") plus the rc-daemon emit a shared log shape so the populations can be compared from `server.log` alone. One spawn's full lifeline is `grep <unitToken>`; one arm's signature is `grep 'source=<arm>'`. The new `script-scope` arm spawns via the daemon's mechanism — `systemdSpawn` + the same `script(1)` wrap — and the manager holds zero fds. Capture files are retained at `~/.<brand>/logs/spawn-<unitToken>.log` for post-mortem. Full schema and operator runbook in [`.docs/rc-life-observability.md`](../../../.docs/rc-life-observability.md).
|
|
246
|
+
|
|
233
247
|
**Post-archive fd sweep (Task 558).** Independent of spawn/archive request traffic, the manager runs a 60 s sweep that walks both directions of the master-fd invariant:
|
|
234
248
|
|
|
235
249
|
- `[fd-audit] op=orphan-master sessionId=<8> pid=<n> archivedAt=<ms> heldSinceArchiveMs=<n> fd=<n|unknown>` — fires per tracker whose row is archived (the leak).
|
|
@@ -305,6 +319,8 @@ A plugin extends what Maxy can do. Each plugin adds a focused capability — con
|
|
|
305
319
|
|
|
306
320
|
Maxy's own capabilities are plugins too. Marketplace plugins (like Stripe) work the same way — Maxy manages all of them through conversation.
|
|
307
321
|
|
|
322
|
+
The tables below are the install catalogue — every plugin the platform can ship. They are not evidence of what is enabled on the current account. For the live install set, ask Maxy to call `capabilities-here`.
|
|
323
|
+
|
|
308
324
|
## Plugin Groups
|
|
309
325
|
|
|
310
326
|
### Core (always active)
|
|
@@ -37,18 +37,26 @@ Plugins are installed and managed through conversation. You can add marketplace
|
|
|
37
37
|
|
|
38
38
|
## Roles
|
|
39
39
|
|
|
40
|
-
{{productName}}
|
|
40
|
+
{{productName}} ships twelve roles it can dispatch for specific tasks — like members of your team. You don't need to configure or manage them — {{productName}} decides when to use each role and handles everything automatically. You may see activity like "Dispatching personal-assistant..." in the chat timeline when this happens.
|
|
41
|
+
|
|
42
|
+
The catalogue below is what the platform ships. It is not evidence of what is installed on the current account. For the live install set on this account, ask {{productName}} to call `capabilities-here`.
|
|
41
43
|
|
|
42
44
|
| Role | What it does |
|
|
43
45
|
|------|-------------|
|
|
44
|
-
|
|
|
45
|
-
|
|
|
46
|
-
|
|
|
47
|
-
|
|
|
48
|
-
|
|
|
49
|
-
| Database Operator |
|
|
50
|
-
|
|
51
|
-
|
|
46
|
+
| Archive Ingest Operator | Ingests bulk external archives — Obsidian, ICS, X, Notion — and surfaces schema-mapping ambiguity rather than catching all unmapped relations as :MENTIONS. |
|
|
47
|
+
| Citation Auditor | Audits :TimelineEvent rows for missing citations and writes either citations directly or a CitationProposal stub. |
|
|
48
|
+
| Coding Assistant | Runs shell commands, drives git repositories, and reads or edits code on your behalf — the specialist you reach for when the work belongs in a developer terminal. |
|
|
49
|
+
| Compiled Truth Rewriter | Recomputes a node's compiledTruth (and public twin where applicable) from its 90-day timeline plus optional operator hints. |
|
|
50
|
+
| Content Producer | Produces visual output from your graph: generates images, renders pages to PDF, and hosts static websites you upload as a zip. |
|
|
51
|
+
| Database Operator | Executes graph writes on admin's behalf when delegated via the Task tool — admin names each write, the specialist runs it. |
|
|
52
|
+
| Librarian | Owns foreground ingest of documents, conversation transcripts, and external archives into the memory graph. |
|
|
53
|
+
| Personal Assistant | Handles the operational tasks you'd give a personal assistant: scheduling meetings, managing your platform settings, connecting messaging channels, and completing browser-based tasks on your behalf. |
|
|
54
|
+
| Project Manager | Manages your tasks, projects, sessions, and workflows: linking work to people and goals, and keeping everything organised. |
|
|
55
|
+
| Public Session Reviewer | Reads a gated public-agent transcript and dispatches database-operator for each per-visitor memory write. |
|
|
56
|
+
| Research Assistant | Researches topics online, manages your knowledge graph, and produces supporting visuals. |
|
|
57
|
+
| Typed Edge Classifier | Reads recently-written prose nodes and writes typed edges from a closed allowlist. |
|
|
58
|
+
|
|
59
|
+
Roles are installed during setup and listed when {{productName}} introduces itself. Some premium bundles add their own specialists (e.g. the `real-agent` bundle adds a listing curator, negotiator, valuer, compliance officer, and buyer-enquiry public agent). Roles installed mid-session become active from the next session.
|
|
52
60
|
|
|
53
61
|
## Memory
|
|
54
62
|
|
|
@@ -122,6 +130,8 @@ Each session row also carries a small muted timestamp crumb under the name showi
|
|
|
122
130
|
|
|
123
131
|
`verified=true` requires `master-fd=closed` AND `fdDelta>=1` AND `trackerRemoved=true`. `master-fd=close-failed` is logged at error level (`[rc-spawn-error]` prefix) — never swallowed; the next post-archive sweep is the catch-net.
|
|
124
132
|
|
|
133
|
+
**Cross-arm `[rc-life]` schema (Task 562).** Both rc-spawn arms (the legacy node-pty one above and a new isolated `script-scope` arm exposed via the dashboard A/B toggle next to "New session") plus the rc-daemon emit a shared log shape so the populations can be compared from `server.log` alone. One spawn's full lifeline is `grep <unitToken>`; one arm's signature is `grep 'source=<arm>'`. The new `script-scope` arm spawns via the daemon's mechanism — `systemdSpawn` + the same `script(1)` wrap — and the manager holds zero fds. Capture files are retained at `~/.<brand>/logs/spawn-<unitToken>.log` for post-mortem. Full schema and operator runbook in [`.docs/rc-life-observability.md`](../../../.docs/rc-life-observability.md).
|
|
134
|
+
|
|
125
135
|
**Post-archive fd sweep (Task 558).** Independent of spawn/archive request traffic, the manager runs a 60 s sweep that walks both directions of the master-fd invariant:
|
|
126
136
|
|
|
127
137
|
- `[fd-audit] op=orphan-master sessionId=<8> pid=<n> archivedAt=<ms> heldSinceArchiveMs=<n> fd=<n|unknown>` — fires per tracker whose row is archived (the leak).
|
|
@@ -6,6 +6,8 @@ A plugin extends what {{productName}} can do. Each plugin adds a focused capabil
|
|
|
6
6
|
|
|
7
7
|
{{productName}}'s own capabilities are plugins too. Marketplace plugins (like Stripe) work the same way — {{productName}} manages all of them through conversation.
|
|
8
8
|
|
|
9
|
+
The tables below are the install catalogue — every plugin the platform can ship. They are not evidence of what is enabled on the current account. For the live install set, ask {{productName}} to call `capabilities-here`.
|
|
10
|
+
|
|
9
11
|
## Plugin Groups
|
|
10
12
|
|
|
11
13
|
### Core (always active)
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
2
|
+
// check-architecture-skill-no-drift.mjs — prepublishOnly gate.
|
|
3
|
+
//
|
|
4
|
+
// The per-brand platform-architecture skill body is a generated artefact.
|
|
5
|
+
// Source: docs/public/llms-full.<brand>.txt (emitted by copy-docs.mjs).
|
|
6
|
+
// Generator: maxy-code/scripts/assemble-architecture-skill.mjs --brand <brand>.
|
|
7
|
+
//
|
|
8
|
+
// For brand=maxy-code, the gate also asserts byte-equality with the
|
|
9
|
+
// checked-in skill source at platform/plugins/admin/skills/platform-architecture/SKILL.md
|
|
10
|
+
// (back-compat with the existing release flow).
|
|
11
|
+
//
|
|
12
|
+
// For other brands, the gate asserts the assembled cache body exists and
|
|
13
|
+
// contains the brand product name + the catalogue-boundary sentence.
|
|
14
|
+
//
|
|
15
|
+
// Usage:
|
|
16
|
+
// node platform/scripts/check-architecture-skill-no-drift.mjs # all brands
|
|
17
|
+
// node platform/scripts/check-architecture-skill-no-drift.mjs --brand maxy-code
|
|
18
|
+
// node platform/scripts/check-architecture-skill-no-drift.mjs --brand realagent-code
|
|
18
19
|
|
|
19
20
|
import { readFileSync, existsSync } from 'node:fs';
|
|
20
21
|
import { dirname, resolve } from 'node:path';
|
|
@@ -25,43 +26,89 @@ import { assemble } from '../../scripts/assemble-architecture-skill.mjs';
|
|
|
25
26
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
26
27
|
const MAXY_CODE_ROOT = resolve(__dirname, '..', '..');
|
|
27
28
|
const REPO_ROOT = resolve(MAXY_CODE_ROOT, '..');
|
|
28
|
-
const LLMS_FULL = resolve(REPO_ROOT, 'docs/public/llms-full.txt');
|
|
29
29
|
const COPY_DOCS = resolve(REPO_ROOT, 'docs/scripts/copy-docs.mjs');
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
|
|
31
|
+
const args = process.argv.slice(2);
|
|
32
|
+
const brandIdx = args.indexOf('--brand');
|
|
33
|
+
const REQUESTED_BRAND = brandIdx === -1 ? null : args[brandIdx + 1];
|
|
34
|
+
|
|
35
|
+
const CATALOGUE_BOUNDARY_SUBSTRING = 'not evidence of what is installed on the current account';
|
|
36
|
+
|
|
37
|
+
const BRANDS = [
|
|
38
|
+
{
|
|
39
|
+
key: 'maxy-code',
|
|
40
|
+
productName: 'Maxy',
|
|
41
|
+
docsUrl: 'https://docs.getmaxy.com',
|
|
42
|
+
sourceSkillPath: resolve(
|
|
43
|
+
MAXY_CODE_ROOT,
|
|
44
|
+
'platform/plugins/admin/skills/platform-architecture/SKILL.md',
|
|
45
|
+
),
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
key: 'realagent-code',
|
|
49
|
+
productName: 'Real Agent',
|
|
50
|
+
docsUrl: 'https://docs.realagent.network',
|
|
51
|
+
sourceSkillPath: null,
|
|
52
|
+
},
|
|
53
|
+
];
|
|
34
54
|
|
|
35
55
|
function fail(msg) {
|
|
36
56
|
console.error(`[check-architecture-skill-no-drift] ERROR: ${msg}`);
|
|
37
57
|
process.exit(1);
|
|
38
58
|
}
|
|
39
59
|
|
|
40
|
-
if (!existsSync(COPY_DOCS)) {
|
|
41
|
-
fail(`docs mirror script missing: ${COPY_DOCS}`);
|
|
42
|
-
}
|
|
60
|
+
if (!existsSync(COPY_DOCS)) fail(`docs mirror script missing: ${COPY_DOCS}`);
|
|
43
61
|
|
|
44
|
-
// Regenerate the docs corpus so the comparison runs against current sources.
|
|
45
62
|
execFileSync('node', [COPY_DOCS], { stdio: 'pipe' });
|
|
46
63
|
|
|
47
|
-
|
|
48
|
-
fail(`expected ${LLMS_FULL} after running copy-docs.mjs`);
|
|
49
|
-
}
|
|
50
|
-
if (!existsSync(SKILL_PATH)) {
|
|
51
|
-
fail(`expected ${SKILL_PATH} (run scripts/assemble-architecture-skill.mjs)`);
|
|
52
|
-
}
|
|
64
|
+
const ASSEMBLER = resolve(MAXY_CODE_ROOT, 'scripts/assemble-architecture-skill.mjs');
|
|
53
65
|
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
66
|
+
const brandsToCheck = REQUESTED_BRAND
|
|
67
|
+
? BRANDS.filter((b) => b.key === REQUESTED_BRAND)
|
|
68
|
+
: BRANDS;
|
|
57
69
|
|
|
58
|
-
if (
|
|
59
|
-
fail(
|
|
60
|
-
`${SKILL_PATH} is out of sync with docs/public/llms-full.txt. ` +
|
|
61
|
-
`Run \`node maxy-code/scripts/assemble-architecture-skill.mjs\` and commit the result.`,
|
|
62
|
-
);
|
|
70
|
+
if (REQUESTED_BRAND && brandsToCheck.length === 0) {
|
|
71
|
+
fail(`unknown brand: ${REQUESTED_BRAND}`);
|
|
63
72
|
}
|
|
64
73
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
);
|
|
74
|
+
for (const brand of brandsToCheck) {
|
|
75
|
+
const corpus = resolve(REPO_ROOT, `docs/public/llms-full.${brand.key}.txt`);
|
|
76
|
+
if (!existsSync(corpus)) fail(`expected ${corpus} after running copy-docs.mjs`);
|
|
77
|
+
|
|
78
|
+
// Re-run assembler for this brand. The assembler writes the cache file;
|
|
79
|
+
// we then compare its body to a fresh in-process assemble() call to catch
|
|
80
|
+
// drift between the assembler module and the cache write.
|
|
81
|
+
execFileSync('node', [ASSEMBLER, '--brand', brand.key], { stdio: 'pipe' });
|
|
82
|
+
|
|
83
|
+
const body = readFileSync(corpus, 'utf8');
|
|
84
|
+
const expected = assemble(body, {
|
|
85
|
+
productName: brand.productName,
|
|
86
|
+
brand: brand.key,
|
|
87
|
+
docsUrl: brand.docsUrl,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
if (!expected.includes(CATALOGUE_BOUNDARY_SUBSTRING)) {
|
|
91
|
+
fail(`brand=${brand.key}: assembled body missing catalogue-boundary sentence`);
|
|
92
|
+
}
|
|
93
|
+
if (!expected.includes(brand.productName)) {
|
|
94
|
+
fail(`brand=${brand.key}: assembled body missing product name ${brand.productName}`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (brand.sourceSkillPath) {
|
|
98
|
+
if (!existsSync(brand.sourceSkillPath)) {
|
|
99
|
+
fail(
|
|
100
|
+
`brand=${brand.key}: source skill missing at ${brand.sourceSkillPath}; ` +
|
|
101
|
+
`run \`node maxy-code/scripts/assemble-architecture-skill.mjs\``,
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
const actual = readFileSync(brand.sourceSkillPath, 'utf8');
|
|
105
|
+
if (expected !== actual) {
|
|
106
|
+
fail(
|
|
107
|
+
`brand=${brand.key}: ${brand.sourceSkillPath} out of sync. ` +
|
|
108
|
+
`Run \`node maxy-code/scripts/assemble-architecture-skill.mjs\` and commit.`,
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
console.log(`[check-architecture-skill-no-drift] ok brand=${brand.key} (${expected.length} bytes)`);
|
|
114
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// check-roles-doc-completeness.mjs
|
|
3
|
+
// Asserts every specialist on disk has a row in the authoritative roles doc.
|
|
4
|
+
// Brands: --brand maxy (default) | --brand real-agent
|
|
5
|
+
import { readFileSync, readdirSync, statSync, existsSync } from 'node:fs';
|
|
6
|
+
import { resolve, join, dirname } from 'node:path';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
|
|
9
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const maxyCodeRoot = resolve(here, '..', '..');
|
|
11
|
+
|
|
12
|
+
const args = process.argv.slice(2);
|
|
13
|
+
const brandIdx = args.indexOf('--brand');
|
|
14
|
+
const brand = brandIdx === -1 ? 'maxy' : args[brandIdx + 1];
|
|
15
|
+
|
|
16
|
+
const config = {
|
|
17
|
+
maxy: {
|
|
18
|
+
diskDir: resolve(maxyCodeRoot, 'platform/templates/specialists/agents'),
|
|
19
|
+
docPath: resolve(maxyCodeRoot, 'platform/plugins/docs/references/platform.md'),
|
|
20
|
+
},
|
|
21
|
+
'real-agent': {
|
|
22
|
+
diskDir: resolve(maxyCodeRoot, 'premium-plugins/real-agent/agents'),
|
|
23
|
+
docPath: resolve(maxyCodeRoot, 'premium-plugins/real-agent/docs/references/real-agent-roles.md'),
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
if (!config[brand]) {
|
|
28
|
+
console.error(`[check-roles-doc] unknown brand: ${brand}`);
|
|
29
|
+
process.exit(2);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const { diskDir, docPath } = config[brand];
|
|
33
|
+
const TABLE_HEADER = '| Role | What it does |';
|
|
34
|
+
|
|
35
|
+
if (!existsSync(diskDir)) {
|
|
36
|
+
console.error(`[check-roles-doc] disk dir missing: ${diskDir}`);
|
|
37
|
+
process.exit(2);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function listSpecialists(dir) {
|
|
41
|
+
const out = [];
|
|
42
|
+
for (const entry of readdirSync(dir)) {
|
|
43
|
+
const full = join(dir, entry);
|
|
44
|
+
const st = statSync(full);
|
|
45
|
+
if (st.isFile() && entry.endsWith('.md')) {
|
|
46
|
+
out.push(entry.replace(/\.md$/, ''));
|
|
47
|
+
} else if (st.isDirectory()) {
|
|
48
|
+
if (existsSync(join(full, 'IDENTITY.md'))) out.push(entry);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return out.sort();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const diskSpecialists = listSpecialists(diskDir);
|
|
55
|
+
|
|
56
|
+
if (!existsSync(docPath)) {
|
|
57
|
+
console.error(`[check-roles-doc] doc missing: ${docPath}`);
|
|
58
|
+
console.error(`[check-roles-doc] disk specialists (${diskSpecialists.length}): ${diskSpecialists.join(', ')}`);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const docBody = readFileSync(docPath, 'utf8');
|
|
63
|
+
|
|
64
|
+
function extractRoleRows(body, header) {
|
|
65
|
+
const lines = body.split(/\r?\n/);
|
|
66
|
+
const start = lines.findIndex((l) => l.trim() === header.trim());
|
|
67
|
+
if (start === -1) return [];
|
|
68
|
+
const rows = [];
|
|
69
|
+
for (let i = start + 2; i < lines.length; i++) {
|
|
70
|
+
const ln = lines[i];
|
|
71
|
+
if (!ln.startsWith('|')) break;
|
|
72
|
+
const cells = ln.split('|').map((c) => c.trim()).filter(Boolean);
|
|
73
|
+
if (cells.length >= 2) rows.push(cells[0]);
|
|
74
|
+
}
|
|
75
|
+
return rows;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const rowLabels = extractRoleRows(docBody, TABLE_HEADER);
|
|
79
|
+
|
|
80
|
+
const slugify = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
|
|
81
|
+
const rowSlugs = new Set(rowLabels.map(slugify));
|
|
82
|
+
|
|
83
|
+
const missing = diskSpecialists.filter((s) => !rowSlugs.has(slugify(s)));
|
|
84
|
+
const stale = rowLabels.filter((r) => !diskSpecialists.some((s) => slugify(s) === slugify(r)));
|
|
85
|
+
|
|
86
|
+
if (missing.length === 0 && stale.length === 0) {
|
|
87
|
+
console.log(`[check-roles-doc] brand=${brand} ok — ${diskSpecialists.length} specialists documented`);
|
|
88
|
+
process.exit(0);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
console.error(`[check-roles-doc] brand=${brand} FAIL`);
|
|
92
|
+
console.error(` disk specialists (${diskSpecialists.length}): ${diskSpecialists.join(', ')}`);
|
|
93
|
+
console.error(` doc rows (${rowLabels.length}): ${rowLabels.join(', ')}`);
|
|
94
|
+
if (missing.length) console.error(` MISSING from doc: ${missing.join(', ')}`);
|
|
95
|
+
if (stale.length) console.error(` STALE in doc (no template): ${stale.join(', ')}`);
|
|
96
|
+
process.exit(1);
|
|
@@ -50,7 +50,7 @@ function rootsFor(maxyCodeRoot) {
|
|
|
50
50
|
// Mirrors CC_NATIVE_TOOLS in specialist-drift.ts. Listed exhaustively so a
|
|
51
51
|
// new CC-native tool forces an explicit ledger update in both surfaces.
|
|
52
52
|
const CC_NATIVE_TOOLS = new Set([
|
|
53
|
-
'Read', 'Write', 'Edit', 'Glob', 'Grep', 'Bash', 'BashOutput', 'KillShell',
|
|
53
|
+
'Read', 'Write', 'Edit', 'MultiEdit', 'Glob', 'Grep', 'Bash', 'BashOutput', 'KillShell',
|
|
54
54
|
'Skill', 'WebSearch', 'WebFetch', 'Task', 'TodoWrite', 'NotebookEdit',
|
|
55
55
|
'NotebookRead', 'AskUserQuestion',
|
|
56
56
|
]);
|
|
@@ -121,6 +121,12 @@ cat > "$ACCOUNT_SETTINGS" << SETTINGS_EOF
|
|
|
121
121
|
}
|
|
122
122
|
],
|
|
123
123
|
"PostToolUse": [
|
|
124
|
+
{
|
|
125
|
+
"matcher": "Agent",
|
|
126
|
+
"hooks": [
|
|
127
|
+
{ "type": "command", "command": "bash $HOOKS_PATH/post-tool-use-agent.sh" }
|
|
128
|
+
]
|
|
129
|
+
},
|
|
124
130
|
{
|
|
125
131
|
"matcher": "mcp__.*__.*-(export|import)-parse$",
|
|
126
132
|
"hooks": [
|