@cohortapp/agent-sdk 2.3.2 → 2.4.0

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 (148) hide show
  1. package/framework-features.json +30 -0
  2. package/lib/backlog.mjs +136 -0
  3. package/lib/cadences.mjs +63 -2
  4. package/lib/cadences.test.mjs +105 -0
  5. package/lib/capability/inventory.mjs +542 -0
  6. package/lib/capability/inventory.test.mjs +232 -0
  7. package/lib/capability/probe.mjs +255 -0
  8. package/lib/channels/contract.mjs +37 -1
  9. package/lib/channels/contract.test.mjs +25 -1
  10. package/lib/claude-bin.mjs +37 -3
  11. package/lib/claude-bin.test.mjs +42 -8
  12. package/lib/execution/disposition.mjs +501 -0
  13. package/lib/execution/disposition.test.mjs +482 -0
  14. package/lib/execution/drive.mjs +352 -0
  15. package/lib/execution/drive.test.mjs +270 -0
  16. package/lib/execution/effects.mjs +340 -0
  17. package/lib/execution/effects.test.mjs +193 -0
  18. package/lib/execution/index.mjs +152 -0
  19. package/lib/execution/intake.mjs +581 -0
  20. package/lib/execution/intake.test.mjs +343 -0
  21. package/lib/execution/journal.mjs +374 -0
  22. package/lib/execution/journal.test.mjs +261 -0
  23. package/lib/execution/match.mjs +331 -0
  24. package/lib/execution/match.test.mjs +235 -0
  25. package/lib/execution/pipeline.mjs +341 -0
  26. package/lib/execution/pipeline.test.mjs +389 -0
  27. package/lib/execution/route.mjs +332 -0
  28. package/lib/execution/route.test.mjs +186 -0
  29. package/lib/execution/surface-policy.mjs +446 -0
  30. package/lib/execution/surface-policy.test.mjs +162 -0
  31. package/lib/goals/admission.mjs +209 -0
  32. package/lib/goals/admission.test.mjs +139 -0
  33. package/lib/goals/classify.mjs +206 -0
  34. package/lib/goals/classify.test.mjs +109 -0
  35. package/lib/goals/collaborate.mjs +415 -0
  36. package/lib/goals/collaborate.test.mjs +324 -0
  37. package/lib/goals/gaps.mjs +111 -0
  38. package/lib/goals/gaps.test.mjs +284 -0
  39. package/lib/goals/loop.mjs +537 -0
  40. package/lib/goals/loop.test.mjs +719 -0
  41. package/lib/identity/persona.mjs +247 -0
  42. package/lib/identity/persona.test.mjs +117 -0
  43. package/lib/kpi.mjs +469 -0
  44. package/lib/kpi.test.mjs +244 -0
  45. package/lib/mandate/audit.mjs +168 -0
  46. package/lib/mandate/audit.test.mjs +195 -0
  47. package/lib/mandate/cache.mjs +162 -0
  48. package/lib/mandate/derive.mjs +317 -0
  49. package/lib/mandate/derive.test.mjs +224 -0
  50. package/lib/mandate/model.mjs +352 -0
  51. package/lib/mandate/model.test.mjs +145 -0
  52. package/lib/mandate/refresh.mjs +187 -0
  53. package/lib/mandate/refresh.test.mjs +293 -0
  54. package/lib/mcp/server.test.mjs +4 -4
  55. package/lib/org/approvals.mjs +14 -2
  56. package/lib/org/client.mjs +58 -22
  57. package/lib/org/client.test.mjs +3 -1
  58. package/lib/org/inbound/directedness.mjs +720 -0
  59. package/lib/org/inbound/directedness.test.mjs +543 -0
  60. package/lib/org/inbound/facts.mjs +501 -0
  61. package/lib/org/inbound/facts.test.mjs +375 -0
  62. package/lib/org/inbound/hydrate.mjs +535 -0
  63. package/lib/org/inbound/hydrate.test.mjs +326 -0
  64. package/lib/org/inbound/index.mjs +233 -0
  65. package/lib/org/inbound/index.test.mjs +324 -0
  66. package/lib/org/inbound/io.mjs +141 -0
  67. package/lib/org/inbound/project.mjs +201 -0
  68. package/lib/org/inbound/project.test.mjs +287 -0
  69. package/lib/org/inbound/surfaces.mjs +257 -0
  70. package/lib/org/knowledge.mjs +10 -1
  71. package/lib/org/knowledge.test.mjs +8 -1
  72. package/lib/org/leases.mjs +5 -0
  73. package/lib/org/mesh.mjs +17 -2
  74. package/lib/org/messaging.mjs +40 -4
  75. package/lib/org/messaging.test.mjs +40 -0
  76. package/lib/org/param-contract.mjs +694 -0
  77. package/lib/org/param-contract.test.mjs +451 -0
  78. package/lib/org/protocol.checksum +1 -1
  79. package/lib/org/protocol.mjs +8 -0
  80. package/lib/org/protocol.test.mjs +5 -1
  81. package/lib/org/push.mjs +1025 -0
  82. package/lib/org/push.test.mjs +690 -0
  83. package/lib/org/tool-surface.mjs +138 -38
  84. package/lib/org/tool-surface.test.mjs +13 -8
  85. package/lib/org/typing.mjs +341 -0
  86. package/lib/org/typing.test.mjs +291 -0
  87. package/lib/plan/compile.mjs +510 -0
  88. package/lib/plan/compile.test.mjs +286 -0
  89. package/lib/plan/emit.mjs +256 -0
  90. package/lib/plan/emit.test.mjs +246 -0
  91. package/lib/plan/explain.mjs +226 -0
  92. package/lib/plan/explain.test.mjs +188 -0
  93. package/lib/plan/schema.mjs +140 -0
  94. package/lib/resource-governor.mjs +47 -1
  95. package/lib/resource-governor.test.mjs +21 -1
  96. package/lib/setup/enroll-from-cohort.mjs +84 -16
  97. package/lib/setup/enroll-from-cohort.test.mjs +43 -1
  98. package/lib/setup/sections/identity.mjs +15 -4
  99. package/lib/setup/sections/identity.test.mjs +94 -0
  100. package/lib/setup/sections/inventory.mjs +178 -0
  101. package/lib/setup/sections/inventory.test.mjs +198 -0
  102. package/lib/setup/sections/mandate.mjs +392 -0
  103. package/lib/setup/sections/mandate.test.mjs +373 -0
  104. package/lib/setup/sections/subagents.mjs +427 -0
  105. package/lib/setup/sections/subagents.test.mjs +429 -0
  106. package/lib/setup/sections/verify.mjs +121 -0
  107. package/lib/setup/sections/verify.test.mjs +175 -0
  108. package/lib/setup/sot.mjs +2 -0
  109. package/lib/subagents/cli.mjs +463 -0
  110. package/lib/subagents/cli.test.mjs +389 -0
  111. package/lib/subagents/client.mjs +373 -0
  112. package/lib/subagents/client.test.mjs +309 -0
  113. package/lib/subagents/gap.mjs +268 -0
  114. package/lib/subagents/gap.test.mjs +234 -0
  115. package/lib/subagents/lock.mjs +296 -0
  116. package/lib/subagents/lock.test.mjs +248 -0
  117. package/lib/subagents/manifest.mjs +224 -0
  118. package/lib/subagents/manifest.test.mjs +175 -0
  119. package/lib/subagents/refs.mjs +274 -0
  120. package/lib/subagents/refs.test.mjs +204 -0
  121. package/lib/subagents/resolve.mjs +455 -0
  122. package/lib/subagents/resolve.test.mjs +422 -0
  123. package/lib/subagents/schema.mjs +467 -0
  124. package/lib/subagents/schema.test.mjs +306 -0
  125. package/package.json +8 -3
  126. package/plugins/maestro-skills/.claude-plugin/marketplace.json +16 -0
  127. package/policies/ai-disclosure.yaml +42 -2
  128. package/scaffold/CLAUDE.md +16 -2
  129. package/schedules/triggers/goal-steward.md +79 -0
  130. package/scripts/ci/conformance-org-api.mjs +792 -0
  131. package/scripts/ci/conformance-org-api.test.mjs +417 -0
  132. package/scripts/daemon/agent-daemon.mjs +36 -4
  133. package/scripts/daemon/cadence-handlers.mjs +145 -1
  134. package/scripts/daemon/goal-steward-cadence.test.mjs +243 -0
  135. package/scripts/daemon/inbox-deferral.mjs +45 -2
  136. package/scripts/daemon/inbox-deferral.test.mjs +56 -0
  137. package/scripts/daemon/inbox-wake.mjs +282 -0
  138. package/scripts/daemon/inbox-wake.test.mjs +199 -0
  139. package/scripts/daemon/prompt-builder.mjs +41 -1
  140. package/scripts/daemon/typing-registry.mjs +55 -2
  141. package/scripts/daemon/typing-registry.test.mjs +25 -0
  142. package/scripts/local-triggers/generate-plists.test.mjs +5 -5
  143. package/scripts/setup/gen-subagent-manifest.mjs +95 -0
  144. package/scripts/setup/gen-subagent-manifest.test.mjs +124 -0
  145. package/scripts/setup/generate-plan.mjs +108 -0
  146. package/scripts/setup/init-capability-manifest.mjs +70 -0
  147. package/scripts/setup/init-skill-marketplace.mjs +155 -0
  148. package/scripts/setup/init-skill-marketplace.test.mjs +193 -0
@@ -38,6 +38,7 @@ import {
38
38
  okFrame,
39
39
  errFrame,
40
40
  } from "./protocol.mjs";
41
+ import { normalizeParams, logReportOnce, toRegisterParams } from "./param-contract.mjs";
41
42
  import { applyBrandEnvCompat } from "../env-compat.mjs";
42
43
 
43
44
  // SDK self-bridge: agent instances import this module directly from their own
@@ -268,9 +269,18 @@ export async function pairRequest(o = {}) {
268
269
  * posts the params object, and returns the parsed res frame. Fail-open: a
269
270
  * transport error yields an INTERNAL error frame rather than throwing.
270
271
  *
272
+ * THE WIRE-CONTRACT CHOKEPOINT. Every plane reaches hq through this one function
273
+ * — the 2 090 `ui-parity.mjs` wrappers, the curated `tool-surface.mjs` table, the
274
+ * `org_rpc` escape hatch, and every hand-written helper in `lib/org/*.mjs` — so
275
+ * `normalizeParams` (lib/org/param-contract.mjs) runs HERE. That is what makes
276
+ * param-name drift a class of bug this SDK cannot ship again: a call site cannot
277
+ * opt out, and a newly added wrapper inherits the contract for free. The rewrite
278
+ * is reported once per distinct (method, rewrite) per process — fail-open, but
279
+ * NEVER silent (silent fail-open is what hid all 18 drift rows).
280
+ *
271
281
  * @param {string} method full dotted method name (e.g. "board.claim")
272
282
  * @param {object} params the params object (request body)
273
- * @param {object} o - { base, token, orgId?, idempotencyKey?, fetchImpl? }
283
+ * @param {object} o - { base, token, orgId?, idempotencyKey?, fetchImpl?, logImpl? }
274
284
  * @returns {Promise<object>} res frame
275
285
  */
276
286
  export async function call(method, params, o = {}) {
@@ -279,15 +289,45 @@ export async function call(method, params, o = {}) {
279
289
  const def = methodDef(method);
280
290
  if (!def) return errFrame("NOT_FOUND", `unknown method ${method}`);
281
291
 
292
+ // Project the caller's params onto the names hq's zod schemas actually read.
293
+ // Pure + total; a method with no contract entry passes through unchanged.
294
+ let wire = params || {};
295
+ try {
296
+ const report = normalizeParams(method, wire);
297
+ wire = report.params;
298
+ logReportOnce(method, report, o.logImpl);
299
+ } catch (err) {
300
+ // Fail-open, but NEVER SILENT. Every production bug in this system has been
301
+ // a quiet catch: the org mesh 401'd for hours without a line, the daemon
302
+ // read the wrong config file and logged "not configured", the inbound filter
303
+ // dropped six DMs saying nothing. If the param contract throws, the call
304
+ // still goes out with the RAW params — which is very likely the drift this
305
+ // module exists to correct — so the operator has to be told, or they debug a
306
+ // BAD_REQUEST with no idea the normaliser bailed.
307
+ try {
308
+ const log = typeof o.logImpl === "function" ? o.logImpl : console.warn;
309
+ log(
310
+ `[org] param contract failed for ${method} (${err && err.message}) — ` +
311
+ `sending RAW params; wire-name drift will NOT be corrected for this call`,
312
+ );
313
+ } catch { /* never throw from logging */ }
314
+ }
315
+
282
316
  const headers = baseHeaders(def.auth === false ? "" : token, def.auth === false ? "" : orgId);
283
317
  if (def.sideEffecting) {
284
- const key = o.idempotencyKey || (def.idempotent ? defaultIdempotencyKey(method, params) : "");
318
+ // Key off the ORIGINAL params too: the contract may have renamed the id the
319
+ // legacy key derivation reads.
320
+ const key =
321
+ o.idempotencyKey ||
322
+ (def.idempotent
323
+ ? defaultIdempotencyKey(method, wire) || defaultIdempotencyKey(method, params)
324
+ : "");
285
325
  if (key) headers["x-idempotency-key"] = String(key);
286
326
  }
287
327
  const r = await httpRequest(o.fetchImpl, v1Url(base, method), {
288
328
  method: "POST",
289
329
  headers,
290
- body: JSON.stringify(params || {}),
330
+ body: JSON.stringify(wire),
291
331
  });
292
332
  return asResFrame(r);
293
333
  }
@@ -571,6 +611,13 @@ export async function fetchHierarchy(o = {}) {
571
611
 
572
612
  /**
573
613
  * register self with the org (registry.register). Idempotent.
614
+ *
615
+ * Accepts EITHER a rich maestro self-entry (assembleSelfEntry shape) or an
616
+ * already-projected registerSchema params object: `call()` runs the wire contract
617
+ * (`toRegisterParams`) and hq's `.strict()` schema sees only
618
+ * {displayName, archetype, humanSponsor, card}. Passing the raw entry used to
619
+ * 400 on every boot while the caller logged success.
620
+ *
574
621
  * @param {object} entry directory entry (id, displayName, role, focus, pubkey…)
575
622
  * @param {object} o - { base, token, idempotencyKey?, fetchImpl? }
576
623
  */
@@ -1577,28 +1624,17 @@ export function brandingRestoreFoundation(params, o = {}) {
1577
1624
  * models { displayName, archetype:string, humanSponsor, card } — so we MUST trim
1578
1625
  * here or a rich entry 400s (BAD_REQUEST). Everything the server doesn't model is
1579
1626
  * preserved REDACTION-SAFE under `card` (the handler records only a `hasCard`
1580
- * boolean on the chain, never the blob). Pure; never throws.
1627
+ * boolean on the chain, never the blob).
1628
+ *
1629
+ * THE projection now lives in lib/org/param-contract (`toRegisterParams`) — the
1630
+ * same table `call()` applies — so `client.register(rawEntry)` and
1631
+ * `publishEntry({entry})` can no longer disagree about the shape. Re-exported
1632
+ * under the historical name for the callers that already import it.
1581
1633
  * @param {object} entry
1582
1634
  * @returns {object} registerSchema-shaped params
1583
1635
  */
1584
- function entryToRegisterParams(entry) {
1585
- const e = entry || {};
1586
- const displayName = e.fullName || e.name || e.displayName || String(e.id || "");
1587
- // archetype is an object in the maestro entry ({function,altitude,label}); the
1588
- // server wants a single string. Prefer the human label, then the function.
1589
- const arch = e.archetype;
1590
- const archetype =
1591
- typeof arch === "string"
1592
- ? arch
1593
- : (arch && (arch.label || arch.function || arch.altitude)) || "";
1594
- const humanSponsor =
1595
- (e.principal && (e.principal.fullName || e.principal.title)) || e.humanSponsor || "";
1596
- const params = { card: e };
1597
- if (displayName) params.displayName = String(displayName).slice(0, 200);
1598
- if (archetype) params.archetype = String(archetype).slice(0, 120);
1599
- if (humanSponsor) params.humanSponsor = String(humanSponsor).slice(0, 200);
1600
- return params;
1601
- }
1636
+ const entryToRegisterParams = toRegisterParams;
1637
+ export { entryToRegisterParams };
1602
1638
 
1603
1639
  /**
1604
1640
  * Publish (upsert) this agent's directory entry — now via the /v1 binding
@@ -875,7 +875,9 @@ test("knowledgeSearch: side-effecting (POST), Bearer set, posts the query body",
875
875
  assert.equal(f.calls[0].init.method, "POST");
876
876
  assert.equal(f.calls[0].url, `${BASE}/api/v1/knowledge.search`);
877
877
  assert.equal(f.calls[0].headers.authorization, `Bearer ${TOKEN}`);
878
- assert.deepEqual(JSON.parse(f.calls[0].init.body), { query: "q", group: "org", limit: 5 });
878
+ // The wire contract canonicalises `query`→`q` (hq reads `p.q ?? p.query`) and
879
+ // keeps the legacy name alongside for an older server.
880
+ assert.deepEqual(JSON.parse(f.calls[0].init.body), { query: "q", q: "q", group: "org", limit: 5 });
879
881
  assert.deepEqual(frame.result.returned_ids, ["k-1"]);
880
882
  });
881
883