@rubytech/create-maxy 1.0.892 → 1.0.894

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 (45) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/oauth-llm/dist/index.d.ts +2 -2
  3. package/payload/platform/lib/oauth-llm/dist/index.js +1 -1
  4. package/payload/platform/lib/oauth-llm/src/index.ts +2 -2
  5. package/payload/platform/plugins/admin/PLUGIN.md +1 -2
  6. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-load-required-inputs.test.d.ts +2 -0
  7. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-load-required-inputs.test.d.ts.map +1 -0
  8. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-load-required-inputs.test.js +141 -0
  9. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-load-required-inputs.test.js.map +1 -0
  10. package/payload/platform/plugins/admin/mcp/dist/index.js +19 -59
  11. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  12. package/payload/platform/plugins/admin/mcp/dist/skill-resolution.d.ts +1 -0
  13. package/payload/platform/plugins/admin/mcp/dist/skill-resolution.d.ts.map +1 -1
  14. package/payload/platform/plugins/admin/mcp/dist/skill-resolution.js +48 -0
  15. package/payload/platform/plugins/admin/mcp/dist/skill-resolution.js.map +1 -1
  16. package/payload/platform/plugins/docs/references/troubleshooting.md +2 -0
  17. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js +1 -1
  18. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js.map +1 -1
  19. package/payload/platform/templates/agents/admin/IDENTITY.md +4 -2
  20. package/payload/premium-plugins/real-agency/plugins/brochures/skills/make-brochure/SKILL.md +3 -0
  21. package/payload/premium-plugins/real-agency/plugins/brochures/skills/property-brochure/SKILL.md +2 -0
  22. package/payload/server/chunk-4S22HQC6.js +9440 -0
  23. package/payload/server/chunk-FSJLLIEA.js +3570 -0
  24. package/payload/server/client-pool-XM2AWBV5.js +34 -0
  25. package/payload/server/maxy-edge.js +2 -2
  26. package/payload/server/public/assets/{Checkbox-CeujDRv0.js → Checkbox-C6ZCsPvl.js} +1 -1
  27. package/payload/server/public/assets/{admin-BM3orGyK.js → admin-BGhZNd6Q.js} +6 -6
  28. package/payload/server/public/assets/data-CWQQl_ZG.js +1 -0
  29. package/payload/server/public/assets/graph-CRSLozxc.js +1 -0
  30. package/payload/server/public/assets/{graph-labels-Co03qEv5.js → graph-labels-CQyZQ0u6.js} +1 -1
  31. package/payload/server/public/assets/jsx-runtime-DvanDPKm.css +1 -0
  32. package/payload/server/public/assets/{page-C4E0CWHe.js → page-DOA9eA6p.js} +1 -1
  33. package/payload/server/public/assets/{page-DGLz4ozf.js → page-TARBO-Yr.js} +1 -1
  34. package/payload/server/public/assets/{public-rILg7e8-.js → public-9hQfbymC.js} +1 -1
  35. package/payload/server/public/assets/{useVoiceRecorder-D3Upd7Q3.js → useVoiceRecorder-C3xcgryC.js} +1 -1
  36. package/payload/server/public/data.html +5 -5
  37. package/payload/server/public/graph.html +6 -6
  38. package/payload/server/public/index.html +8 -8
  39. package/payload/server/public/public.html +5 -5
  40. package/payload/server/server.js +91 -118
  41. package/payload/platform/plugins/docs/references/adherence.md +0 -98
  42. package/payload/server/public/assets/data-LYciLZK9.js +0 -1
  43. package/payload/server/public/assets/graph-C-SKAbGX.js +0 -1
  44. package/payload/server/public/assets/jsx-runtime-BcZkJOEw.css +0 -1
  45. /package/payload/server/public/assets/{jsx-runtime-BWYXu1CT.js → jsx-runtime-vPsBTwUp.js} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-maxy",
3
- "version": "1.0.892",
3
+ "version": "1.0.894",
4
4
  "description": "Install Maxy — AI for Productive People",
5
5
  "bin": {
6
6
  "create-maxy": "./dist/index.js"
@@ -2,7 +2,7 @@
2
2
  * OAuth-bearer LLM calls for admin-side classifiers (Task 740).
3
3
  *
4
4
  * Every admin-side classifier (memory-classify, memory-rank, commitment,
5
- * adherence, inbound-gateway, query classifier, summarisation, email
5
+ * inbound-gateway, query classifier, summarisation, email
6
6
  * screening) uses Claude Code OAuth credentials — never the Anthropic
7
7
  * API key. The API-key path is reserved for the public agent.
8
8
  *
@@ -46,7 +46,7 @@ export interface CallOauthLlmParams {
46
46
  /**
47
47
  * Hard timeout in ms for the model call. Default 60_000.
48
48
  *
49
- * 60s fits short admin classifiers (commitment, adherence, query,
49
+ * 60s fits short admin classifiers (commitment, query,
50
50
  * inbound-gateway, screening, summary — all <2K input, <500 output).
51
51
  * Long-output callers MUST override per-call: `memory-classify` runs at
52
52
  * 8K maxTokens against documents up to 20K chars and has been observed
@@ -3,7 +3,7 @@
3
3
  * OAuth-bearer LLM calls for admin-side classifiers (Task 740).
4
4
  *
5
5
  * Every admin-side classifier (memory-classify, memory-rank, commitment,
6
- * adherence, inbound-gateway, query classifier, summarisation, email
6
+ * inbound-gateway, query classifier, summarisation, email
7
7
  * screening) uses Claude Code OAuth credentials — never the Anthropic
8
8
  * API key. The API-key path is reserved for the public agent.
9
9
  *
@@ -2,7 +2,7 @@
2
2
  * OAuth-bearer LLM calls for admin-side classifiers (Task 740).
3
3
  *
4
4
  * Every admin-side classifier (memory-classify, memory-rank, commitment,
5
- * adherence, inbound-gateway, query classifier, summarisation, email
5
+ * inbound-gateway, query classifier, summarisation, email
6
6
  * screening) uses Claude Code OAuth credentials — never the Anthropic
7
7
  * API key. The API-key path is reserved for the public agent.
8
8
  *
@@ -86,7 +86,7 @@ export interface CallOauthLlmParams {
86
86
  /**
87
87
  * Hard timeout in ms for the model call. Default 60_000.
88
88
  *
89
- * 60s fits short admin classifiers (commitment, adherence, query,
89
+ * 60s fits short admin classifiers (commitment, query,
90
90
  * inbound-gateway, screening, summary — all <2K input, <500 output).
91
91
  * Long-output callers MUST override per-call: `memory-classify` runs at
92
92
  * 8K maxTokens against documents up to 20K chars and has been observed
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: admin
3
- description: "Platform administration plugin. Provides system-status, public-hostname (deterministic Cloudflare public-URL resolver — single call returning the operator's canonical hostname so agents never guess property names on :CloudflareHostname nodes), brand-settings, account-manage, account-update, admin-add, admin-remove, admin-list, admin-update-pin, agent-list, agent-config-read, logs-read, plugin-read, skill-load (one-call resolve+read for SKILL.md by skill name — the canonical primitive for loading a named skill; plugin-read remains the reader for references/* and PLUGIN.md), store-skill (deterministic write counterpart to plugin-read; persists operator-authored skills as plugin files under the active account), render-component, session-reset, session-resume, file-attach, wifi, adherence-read (attention-weighted adherence ledger), and action-approval tools (action-pending, action-approve, action-reject, action-edit) for managing the Maxy platform."
3
+ description: "Platform administration plugin. Provides system-status, public-hostname (deterministic Cloudflare public-URL resolver — single call returning the operator's canonical hostname so agents never guess property names on :CloudflareHostname nodes), brand-settings, account-manage, account-update, admin-add, admin-remove, admin-list, admin-update-pin, agent-list, agent-config-read, logs-read, plugin-read, skill-load (one-call resolve+read for SKILL.md by skill name — the canonical primitive for loading a named skill; plugin-read remains the reader for references/* and PLUGIN.md), store-skill (deterministic write counterpart to plugin-read; persists operator-authored skills as plugin files under the active account), render-component, session-reset, session-resume, file-attach, wifi, and action-approval tools (action-pending, action-approve, action-reject, action-edit) for managing the Maxy platform."
4
4
  tools:
5
5
  - system-status
6
6
  - public-hostname
@@ -21,7 +21,6 @@ tools:
21
21
  - session-reset
22
22
  - session-resume
23
23
  - file-attach
24
- - adherence-read
25
24
  - action-pending
26
25
  - action-approve
27
26
  - action-reject
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=skill-load-required-inputs.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-load-required-inputs.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/skill-load-required-inputs.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,141 @@
1
+ // Task 1021 — skill-load surfaces `requiredInputs` to the agent.
2
+ //
3
+ // Tests the frontmatter parser (`parseRequiredInputs`) and the
4
+ // integration contract: when a SKILL.md declares `requiredInputs:`, the
5
+ // body the skill-load handler returns to the agent must carry a
6
+ // `<!-- skill-input-contract requiredInputs=... -->` marker that
7
+ // `parseClaudeStream` can grep without re-parsing YAML. This pair is the
8
+ // writer; the stream-parser is the reader.
9
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
10
+ import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
11
+ import { tmpdir } from "node:os";
12
+ import { join } from "node:path";
13
+ import { loadSkill, parseRequiredInputs } from "../skill-resolution.js";
14
+ let root;
15
+ beforeEach(() => {
16
+ root = mkdtempSync(join(tmpdir(), "skill-load-required-inputs-"));
17
+ });
18
+ afterEach(() => {
19
+ rmSync(root, { recursive: true, force: false });
20
+ });
21
+ function seedSkill(plugin, skill, body) {
22
+ const dir = join(root, "plugins", plugin, "skills", skill);
23
+ mkdirSync(dir, { recursive: true });
24
+ writeFileSync(join(dir, "SKILL.md"), body);
25
+ }
26
+ describe("parseRequiredInputs", () => {
27
+ it("property-brochure-shaped frontmatter parses one slot with two alternatives", () => {
28
+ const body = [
29
+ "---",
30
+ "name: property-brochure",
31
+ "description: Create A4 brochures",
32
+ "requiredInputs:",
33
+ " - propertyAssetsDir | listingURL",
34
+ "---",
35
+ "",
36
+ "# Property Brochure",
37
+ ].join("\n");
38
+ expect(parseRequiredInputs(body)).toEqual([["propertyAssetsDir", "listingURL"]]);
39
+ });
40
+ it("make-brochure-shaped frontmatter parses two slots, each with two alternatives", () => {
41
+ const body = [
42
+ "---",
43
+ "name: make-brochure",
44
+ "description: end-to-end brochure",
45
+ "allowed-tools:",
46
+ " - Bash",
47
+ " - Read",
48
+ "requiredInputs:",
49
+ " - agentURL | brandPackDir",
50
+ " - listingURL | propertyAssetsDir",
51
+ "---",
52
+ "",
53
+ "# make-brochure",
54
+ ].join("\n");
55
+ expect(parseRequiredInputs(body)).toEqual([
56
+ ["agentURL", "brandPackDir"],
57
+ ["listingURL", "propertyAssetsDir"],
58
+ ]);
59
+ });
60
+ it("returns undefined when frontmatter has no requiredInputs key", () => {
61
+ const body = [
62
+ "---",
63
+ "name: plainly",
64
+ "description: Strip AI tells",
65
+ "---",
66
+ "",
67
+ "# Plainly",
68
+ ].join("\n");
69
+ expect(parseRequiredInputs(body)).toBeUndefined();
70
+ });
71
+ it("returns undefined when body has no frontmatter at all", () => {
72
+ expect(parseRequiredInputs("# Just a title\n\nNo frontmatter here.\n")).toBeUndefined();
73
+ });
74
+ it("stops scanning at the next column-0 key (no cross-talk into siblings)", () => {
75
+ const body = [
76
+ "---",
77
+ "name: example",
78
+ "requiredInputs:",
79
+ " - x | y",
80
+ "allowed-tools:",
81
+ " - Bash",
82
+ " - Read",
83
+ "---",
84
+ "",
85
+ ].join("\n");
86
+ expect(parseRequiredInputs(body)).toEqual([["x", "y"]]);
87
+ });
88
+ });
89
+ describe("loadSkill + parseRequiredInputs integration", () => {
90
+ it("loadSkill returns body verbatim; parseRequiredInputs extracts the declared slots", async () => {
91
+ seedSkill("brochures", "property-brochure", [
92
+ "---",
93
+ "name: property-brochure",
94
+ "description: Create A4 brochures",
95
+ "requiredInputs:",
96
+ " - propertyAssetsDir | listingURL",
97
+ "---",
98
+ "",
99
+ "# Property Brochure",
100
+ ].join("\n"));
101
+ const outcome = await loadSkill(root, "property-brochure");
102
+ expect(outcome.status).toBe("unique");
103
+ if (outcome.status !== "unique")
104
+ return;
105
+ expect(parseRequiredInputs(outcome.body)).toEqual([
106
+ ["propertyAssetsDir", "listingURL"],
107
+ ]);
108
+ });
109
+ it("loadSkill on a skill without requiredInputs leaves parser at undefined", async () => {
110
+ seedSkill("admin", "plainly", "---\nname: plainly\ndescription: Strip AI tells\n---\n\n# Plainly\n");
111
+ const outcome = await loadSkill(root, "plainly");
112
+ expect(outcome.status).toBe("unique");
113
+ if (outcome.status !== "unique")
114
+ return;
115
+ expect(parseRequiredInputs(outcome.body)).toBeUndefined();
116
+ });
117
+ });
118
+ describe("skill-input-contract marker shape (writer/reader contract)", () => {
119
+ it("the marker the handler prepends survives JSON round-trip and matches the stream-parser regex", () => {
120
+ // Mirror the regex literal in
121
+ // platform/ui/app/lib/claude-agent/stream-parser.ts (Task 1021).
122
+ const RE = /<!-- skill-input-contract requiredInputs=(\[[^]+?\]) -->/;
123
+ const slots = [["propertyAssetsDir", "listingURL"]];
124
+ const marker = `<!-- skill-input-contract requiredInputs=${JSON.stringify(slots)} -->`;
125
+ const m = marker.match(RE);
126
+ expect(m).not.toBeNull();
127
+ expect(JSON.parse(m[1])).toEqual(slots);
128
+ });
129
+ it("the make-brochure two-slot case also round-trips through the regex", () => {
130
+ const RE = /<!-- skill-input-contract requiredInputs=(\[[^]+?\]) -->/;
131
+ const slots = [
132
+ ["agentURL", "brandPackDir"],
133
+ ["listingURL", "propertyAssetsDir"],
134
+ ];
135
+ const marker = `<!-- skill-input-contract requiredInputs=${JSON.stringify(slots)} -->`;
136
+ const m = marker.match(RE);
137
+ expect(m).not.toBeNull();
138
+ expect(JSON.parse(m[1])).toEqual(slots);
139
+ });
140
+ });
141
+ //# sourceMappingURL=skill-load-required-inputs.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-load-required-inputs.test.js","sourceRoot":"","sources":["../../src/__tests__/skill-load-required-inputs.test.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,EAAE;AACF,+DAA+D;AAC/D,wEAAwE;AACxE,gEAAgE;AAChE,iEAAiE;AACjE,yEAAyE;AACzE,2CAA2C;AAC3C,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACxE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAExE,IAAI,IAAY,CAAC;AAEjB,UAAU,CAAC,GAAG,EAAE;IACd,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,6BAA6B,CAAC,CAAC,CAAC;AACpE,CAAC,CAAC,CAAC;AAEH,SAAS,CAAC,GAAG,EAAE;IACb,MAAM,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;AAClD,CAAC,CAAC,CAAC;AAEH,SAAS,SAAS,CAAC,MAAc,EAAE,KAAa,EAAE,IAAY;IAC5D,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC3D,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpC,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,IAAI,CAAC,CAAC;AAC7C,CAAC;AAED,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,EAAE,CAAC,4EAA4E,EAAE,GAAG,EAAE;QACpF,MAAM,IAAI,GAAG;YACX,KAAK;YACL,yBAAyB;YACzB,kCAAkC;YAClC,iBAAiB;YACjB,oCAAoC;YACpC,KAAK;YACL,EAAE;YACF,qBAAqB;SACtB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEb,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;IACnF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+EAA+E,EAAE,GAAG,EAAE;QACvF,MAAM,IAAI,GAAG;YACX,KAAK;YACL,qBAAqB;YACrB,kCAAkC;YAClC,gBAAgB;YAChB,UAAU;YACV,UAAU;YACV,iBAAiB;YACjB,6BAA6B;YAC7B,oCAAoC;YACpC,KAAK;YACL,EAAE;YACF,iBAAiB;SAClB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEb,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;YACxC,CAAC,UAAU,EAAE,cAAc,CAAC;YAC5B,CAAC,YAAY,EAAE,mBAAmB,CAAC;SACpC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;QACtE,MAAM,IAAI,GAAG;YACX,KAAK;YACL,eAAe;YACf,6BAA6B;YAC7B,KAAK;YACL,EAAE;YACF,WAAW;SACZ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEb,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,CAAC,mBAAmB,CAAC,0CAA0C,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;IAC1F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uEAAuE,EAAE,GAAG,EAAE;QAC/E,MAAM,IAAI,GAAG;YACX,KAAK;YACL,eAAe;YACf,iBAAiB;YACjB,WAAW;YACX,gBAAgB;YAChB,UAAU;YACV,UAAU;YACV,KAAK;YACL,EAAE;SACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEb,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,6CAA6C,EAAE,GAAG,EAAE;IAC3D,EAAE,CAAC,kFAAkF,EAAE,KAAK,IAAI,EAAE;QAChG,SAAS,CACP,WAAW,EACX,mBAAmB,EACnB;YACE,KAAK;YACL,yBAAyB;YACzB,kCAAkC;YAClC,iBAAiB;YACjB,oCAAoC;YACpC,KAAK;YACL,EAAE;YACF,qBAAqB;SACtB,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;QAEF,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC;QAC3D,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtC,IAAI,OAAO,CAAC,MAAM,KAAK,QAAQ;YAAE,OAAO;QAExC,MAAM,CAAC,mBAAmB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;YAChD,CAAC,mBAAmB,EAAE,YAAY,CAAC;SACpC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wEAAwE,EAAE,KAAK,IAAI,EAAE;QACtF,SAAS,CACP,OAAO,EACP,SAAS,EACT,qEAAqE,CACtE,CAAC;QAEF,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACjD,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtC,IAAI,OAAO,CAAC,MAAM,KAAK,QAAQ;YAAE,OAAO;QAExC,MAAM,CAAC,mBAAmB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;IAC5D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,4DAA4D,EAAE,GAAG,EAAE;IAC1E,EAAE,CAAC,8FAA8F,EAAE,GAAG,EAAE;QACtG,8BAA8B;QAC9B,iEAAiE;QACjE,MAAM,EAAE,GAAG,0DAA0D,CAAC;QACtE,MAAM,KAAK,GAAe,CAAC,CAAC,mBAAmB,EAAE,YAAY,CAAC,CAAC,CAAC;QAChE,MAAM,MAAM,GAAG,4CAA4C,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC;QACvF,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC3B,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QACzB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;QAC5E,MAAM,EAAE,GAAG,0DAA0D,CAAC;QACtE,MAAM,KAAK,GAAe;YACxB,CAAC,UAAU,EAAE,cAAc,CAAC;YAC5B,CAAC,YAAY,EAAE,mBAAmB,CAAC;SACpC,CAAC;QACF,MAAM,MAAM,GAAG,4CAA4C,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC;QACvF,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC3B,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QACzB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -20,7 +20,7 @@ import { homedir, hostname as osHostname } from "node:os";
20
20
  import QRCode from "qrcode";
21
21
  import { getSession, closeDriver } from "./lib/neo4j.js";
22
22
  import { getOnboardingState, completeOnboardingStep } from "./lib/onboarding.js";
23
- import { findSkillOwners, computePluginReadHint, loadSkill } from "./skill-resolution.js";
23
+ import { findSkillOwners, computePluginReadHint, loadSkill, parseRequiredInputs } from "./skill-resolution.js";
24
24
  import { resolvePublicHostname } from "./lib/public-hostname.js";
25
25
  const server = new McpServer({
26
26
  name: "admin",
@@ -1740,9 +1740,25 @@ eagerTool(server, "skill-load", "Load a plugin skill's SKILL.md body by skill na
1740
1740
  };
1741
1741
  }
1742
1742
  const content = substituteBrandPlaceholders(outcome.body, outcome.absolutePath);
1743
+ // Task 1021 — prepend a skill-input-contract notice when the skill's
1744
+ // frontmatter declares `requiredInputs:`. The notice tells the agent
1745
+ // to route missing inputs through AskUserQuestion (per IDENTITY.md
1746
+ // "Skill-input resolution"); the embedded `<!-- skill-input-contract
1747
+ // requiredInputs=... -->` marker is the per-turn keying signal that
1748
+ // parseClaudeStream uses to fire [skill-input-resolution] /
1749
+ // [skill-input-missing] observability lines.
1750
+ const requiredInputs = parseRequiredInputs(outcome.body);
1751
+ let bodyOut = content;
1752
+ if (requiredInputs) {
1753
+ const slotLabels = requiredInputs.map(s => s.join(" | ")).join(", ");
1754
+ const marker = JSON.stringify(requiredInputs);
1755
+ const notice = `<!-- skill-input-contract requiredInputs=${marker} -->\nREQUIRED INPUTS: ${slotLabels}\nIf the operator has not supplied each of these inputs, your next tool call MUST be AskUserQuestion. Do not use memory-search, conversation-search, graph-read, or task-get to guess the missing input.\n<!-- /skill-input-contract -->\n\n`;
1756
+ bodyOut = notice + content;
1757
+ }
1743
1758
  const ms = Date.now() - start;
1744
- console.log(`[skill-load] skillName=${skillName} result=unique pluginName=${outcome.pluginName} file=${outcome.file} bodyBytes=${content.length} ms=${ms}`);
1745
- return { content: [{ type: "text", text: content }] };
1759
+ const reqLog = requiredInputs ? ` requiredInputs=${JSON.stringify(requiredInputs)}` : "";
1760
+ console.log(`[skill-load] skillName=${skillName} result=unique pluginName=${outcome.pluginName} file=${outcome.file} bodyBytes=${bodyOut.length}${reqLog} ms=${ms}`);
1761
+ return { content: [{ type: "text", text: bodyOut }] };
1746
1762
  }
1747
1763
  catch (err) {
1748
1764
  const ms = Date.now() - start;
@@ -3467,62 +3483,6 @@ eagerTool(server, "action-edit", "Edit a pending action's input and then execute
3467
3483
  };
3468
3484
  }
3469
3485
  });
3470
- // ---------------------------------------------------------------------------
3471
- // Adherence ledger read (Task 594) — file-backed query of the per-agent
3472
- // adherence-ledger.json. Reads from disk on every call, never from cache,
3473
- // so the returned score matches the on-disk state byte-for-byte. File-only
3474
- // access keeps the answer authoritative even if the Hono server is down.
3475
- // ---------------------------------------------------------------------------
3476
- eagerTool(server, "adherence-read", "Read the attention-weighted adherence ledger for an agent in this account. Returns the ledger JSON (rules with counts, rolling_7d, samples, streaks) and the score. Reads the file on every call — the value is authoritative and matches `{accountDir}/agents/<agent>/adherence-ledger.json` on disk. Use to answer 'what is my adherence score' or to surface the top offenders. Defaults to the admin agent when no name is supplied.", {
3477
- agent: z.string().optional().describe("Agent name to query. Defaults to 'admin'."),
3478
- }, async ({ agent }) => {
3479
- const TAG = "[adherence-read]";
3480
- const agentName = agent ?? "admin";
3481
- const ledgerPath = resolve(getAccountDir(), "agents", agentName, "adherence-ledger.json");
3482
- try {
3483
- if (!existsSync(ledgerPath)) {
3484
- const emptyBody = JSON.stringify({
3485
- agent_id: agentName,
3486
- account_id: ACCOUNT_ID,
3487
- rules: [],
3488
- score: 100,
3489
- note: "No ledger file yet — the agent has not run long enough to record data.",
3490
- }, null, 2);
3491
- console.error(`${TAG} agent=${agentName} status=empty-no-file`);
3492
- return { content: [{ type: "text", text: emptyBody }] };
3493
- }
3494
- const raw = readFileSync(ledgerPath, "utf-8");
3495
- const data = JSON.parse(raw);
3496
- const rules = Array.isArray(data?.rules) ? data.rules : [];
3497
- const total = rules.length;
3498
- let violating = 0;
3499
- const sevenDaysMs = 7 * 24 * 60 * 60 * 1000;
3500
- const cutoff = Date.now() - sevenDaysMs;
3501
- for (const r of rules) {
3502
- const violations = Array.isArray(r?.violations) ? r.violations : [];
3503
- const inWindow = violations.filter((ts) => {
3504
- if (typeof ts !== "string")
3505
- return false;
3506
- const t = Date.parse(ts);
3507
- return Number.isFinite(t) && t >= cutoff;
3508
- }).length;
3509
- if (inWindow > 0)
3510
- violating += 1;
3511
- }
3512
- const score = total > 0 ? Math.round(100 * (1 - violating / total)) : 100;
3513
- const out = { ...data, score };
3514
- console.error(`${TAG} agent=${agentName} score=${score} n_rules=${total}`);
3515
- return { content: [{ type: "text", text: JSON.stringify(out, null, 2) }] };
3516
- }
3517
- catch (err) {
3518
- const errMsg = err instanceof Error ? err.message : String(err);
3519
- console.error(`${TAG} failed agent=${agentName} err=${errMsg}`);
3520
- return {
3521
- content: [{ type: "text", text: `Failed to read adherence ledger for agent=${agentName}: ${errMsg}` }],
3522
- isError: true,
3523
- };
3524
- }
3525
- });
3526
3486
  // Cleanup on exit (SIGTERM for systemd service stops on Pi)
3527
3487
  const cleanup = async () => {
3528
3488
  await closeDriver();