@primitive.ai/prim 0.1.0-alpha.90 → 0.1.0-alpha.91

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/README.md +20 -12
  2. package/SKILL.md +6 -6
  3. package/dist/{chunk-LMRYZL3D.js → chunk-5AFRMOPX.js} +1 -1
  4. package/dist/{chunk-RO3F6JYV.js → chunk-5GYQ4J3D.js} +2 -2
  5. package/dist/{chunk-3EEFL6NJ.js → chunk-67VNLLBN.js} +261 -1
  6. package/dist/{chunk-LEMX3IOG.js → chunk-BTNNEH2W.js} +1 -1
  7. package/dist/chunk-EWZMDD44.js +1474 -0
  8. package/dist/{chunk-YWO7O6QG.js → chunk-FBAYCS3X.js} +2 -2
  9. package/dist/{chunk-R26A7TWY.js → chunk-FKXFUUWJ.js} +1 -1
  10. package/dist/{chunk-C7T7B45R.js → chunk-FOLKHXLJ.js} +150 -21
  11. package/dist/chunk-H4UNYFUC.js +196 -0
  12. package/dist/chunk-HU4PW6I6.js +264 -0
  13. package/dist/{chunk-CUE2LKLR.js → chunk-KFXF2V5G.js} +1 -1
  14. package/dist/{chunk-6IWNH776.js → chunk-LFFLHSQO.js} +4 -3
  15. package/dist/{chunk-MAZWKJGL.js → chunk-M6RIJVRE.js} +42 -232
  16. package/dist/{chunk-2JRX7ZR4.js → chunk-NAHHFSLH.js} +16 -5
  17. package/dist/{chunk-FI3LIRCB.js → chunk-OAAP2MY6.js} +2 -2
  18. package/dist/{chunk-Z7YPFWAZ.js → chunk-PCVGBE5B.js} +10 -268
  19. package/dist/{chunk-UZPBB7V4.js → chunk-VW3FDYRT.js} +60 -48
  20. package/dist/chunk-WX52U7Z2.js +112 -0
  21. package/dist/{chunk-PPQYQEIR.js → chunk-ZB4F75SZ.js} +28 -0
  22. package/dist/daemon/server.js +20 -20
  23. package/dist/hook-runtime/daemon/server.js +20 -20
  24. package/dist/hook-runtime/hooks/post-commit.js +20 -20
  25. package/dist/hook-runtime/hooks/post-rewrite.js +20 -20
  26. package/dist/hook-runtime/hooks/post-tool-use.js +651 -132
  27. package/dist/hook-runtime/hooks/pre-tool-use.js +644 -96
  28. package/dist/hook-runtime/hooks/prim-hook.js +612 -96
  29. package/dist/hook-runtime/hooks/session-end.js +610 -27
  30. package/dist/hook-runtime/hooks/session-start.js +1132 -533
  31. package/dist/hook-runtime/index.js +735 -264
  32. package/dist/hook-runtime/statusline-main.js +48 -4
  33. package/dist/hooks/post-commit.js +11 -9
  34. package/dist/hooks/post-rewrite.js +11 -9
  35. package/dist/hooks/post-tool-use.js +73 -48
  36. package/dist/hooks/pre-commit.js +4 -4
  37. package/dist/hooks/pre-tool-use.js +46 -44
  38. package/dist/hooks/prim-hook.js +47 -25
  39. package/dist/hooks/session-end.js +15 -26
  40. package/dist/hooks/session-start.js +59 -32
  41. package/dist/index.js +558 -1436
  42. package/dist/statusline-main.js +48 -4
  43. package/package.json +1 -1
  44. package/dist/chunk-PMRDE2DA.js +0 -310
  45. package/dist/chunk-WB7AUZ4C.js +0 -52
@@ -52,8 +52,8 @@ var require_ucs2length = __commonJS({
52
52
  });
53
53
 
54
54
  // src/hooks/post-tool-use.ts
55
- import { readFileSync as readFileSync11 } from "fs";
56
- import { dirname as dirname9, join as join13 } from "path";
55
+ import { readFileSync as readFileSync14 } from "fs";
56
+ import { dirname as dirname11, join as join16 } from "path";
57
57
  import { fileURLToPath as fileURLToPath2 } from "url";
58
58
 
59
59
  // src/binding.ts
@@ -636,7 +636,7 @@ var PRIM_REPO_SYNC_REPOSITORY_KEY = "prim.repoSyncRepository";
636
636
  var PRIM_REPO_BINDING_STATE_KEY = "prim.repoBindingState";
637
637
  var GIT_TIMEOUT_MS2 = 1e3;
638
638
  var REPO_SYNC_ID_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/;
639
- var PROJECT_INSTALL_FILES = [".claude/settings.json", ".codex/hooks.json"];
639
+ var PROJECT_INSTALL_FILES = [".claude/settings.json", ".codex/hooks.json", ".cursor/hooks.json"];
640
640
  var PRIM_HOOK_BINS = ["prim-hook", "prim-pre-tool-use", "prim-post-tool-use"];
641
641
  function repoActiveFlag(cwd) {
642
642
  try {
@@ -893,14 +893,14 @@ function throwIfAborted(signal) {
893
893
  }
894
894
  async function defaultSleep(ms, signal) {
895
895
  if (!signal) {
896
- await new Promise((resolve4) => setTimeout(resolve4, ms));
896
+ await new Promise((resolve6) => setTimeout(resolve6, ms));
897
897
  return;
898
898
  }
899
899
  throwIfAborted(signal);
900
- await new Promise((resolve4, reject) => {
900
+ await new Promise((resolve6, reject) => {
901
901
  const timer = setTimeout(() => {
902
902
  signal.removeEventListener("abort", onAbort);
903
- resolve4();
903
+ resolve6();
904
904
  }, ms);
905
905
  const onAbort = () => {
906
906
  clearTimeout(timer);
@@ -2257,7 +2257,7 @@ function validate23(data, { instancePath = "", parentData, parentDataProperty, r
2257
2257
  }
2258
2258
  validate23.evaluated = { "props": true, "dynamicProps": false, "dynamicItems": false };
2259
2259
  var isDecisionCollectScopeResponse = validate24;
2260
- var schema39 = { "type": "object", "properties": { "policy": { "anyOf": [{ "type": "object", "properties": { "repositories": { "type": "array", "items": { "type": "string" } }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } }, "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "users": { "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 } }, "required": ["kind", "userId"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } }, "updatedAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 } }, "required": ["updatedAt"], "additionalProperties": {} }, { "type": "null" }] }, "collectScopeVersion": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "callerIncluded": { "type": "boolean" } }, "required": ["policy", "collectScopeVersion", "callerIncluded"], "additionalProperties": {} };
2260
+ var schema39 = { "type": "object", "properties": { "policy": { "anyOf": [{ "type": "object", "properties": { "repositories": { "type": "array", "items": { "type": "string" } }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } }, "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "users": { "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 } }, "required": ["kind", "userId"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "cursor", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } }, "updatedAt": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 } }, "required": ["updatedAt"], "additionalProperties": {} }, { "type": "null" }] }, "collectScopeVersion": { "type": "integer", "minimum": 0, "maximum": 9007199254740991 }, "callerIncluded": { "type": "boolean" } }, "required": ["policy", "collectScopeVersion", "callerIncluded"], "additionalProperties": {} };
2261
2261
  function validate24(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
2262
2262
  ;
2263
2263
  let vErrors = null;
@@ -2808,7 +2808,7 @@ function validate24(data, { instancePath = "", parentData, parentDataProperty, r
2808
2808
  }
2809
2809
  errors++;
2810
2810
  }
2811
- if (!(data18 === "claude_code" || data18 === "codex" || data18 === "hermes")) {
2811
+ if (!(data18 === "claude_code" || data18 === "codex" || data18 === "cursor" || data18 === "hermes")) {
2812
2812
  const err34 = { instancePath: instancePath + "/policy/users/" + i4 + "/agent", schemaPath: "https://api.getprimitive.ai/contracts/cli-http-v1.schema.json#/$defs/DecisionCollectScopeResponse/properties/policy/anyOf/0/properties/users/items/oneOf/2/properties/agent/enum", keyword: "enum", params: { allowedValues: schema39.properties.policy.anyOf[0].properties.users.items.oneOf[2].properties.agent.enum }, message: "must be equal to one of the allowed values" };
2813
2813
  if (vErrors === null) {
2814
2814
  vErrors = [err34];
@@ -3577,7 +3577,7 @@ function validate26(data, { instancePath = "", parentData, parentDataProperty, r
3577
3577
  return errors === 0;
3578
3578
  }
3579
3579
  validate26.evaluated = { "dynamicProps": true, "dynamicItems": false };
3580
- var schema45 = { "type": "object", "properties": { "intent": { "type": "string", "minLength": 1, "maxLength": 500 }, "attribution": { "type": "string", "enum": ["user", "agent", "unknown"] }, "kind": { "type": "string", "enum": ["change", "exploration", "task_execution", "unclear"] }, "rationale": { "type": "string" }, "area": { "type": "string" }, "decided": { "type": "array", "items": { "type": "string" } }, "alternatives": { "type": "array", "items": { "type": "string" } }, "confidence": { "type": "string", "enum": ["high", "medium", "low"] }, "reversibility": { "type": "string", "enum": ["high", "low"] }, "files": { "type": "array", "items": { "type": "string" } }, "protocolVersion": { "type": "number", "const": 3 }, "repoSyncId": { "type": "string" }, "scope": { "default": {}, "type": "object", "properties": { "location": { "default": {}, "type": "object", "properties": { "repository": { "type": "boolean" }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } } }, "additionalProperties": {} }, "time": { "default": {}, "type": "object", "properties": { "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "additionalProperties": {} }, "users": { "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 } }, "required": ["kind", "userId"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } } }, "additionalProperties": {} }, "stageOverride": { "type": "string", "enum": ["candidate", "draft", "adopted"] } }, "required": ["intent"], "additionalProperties": {}, "x-primitive-runtime-refinements": ["degrade_invalid_rollout_fields", "degrade_invalid_location_scope", "degrade_invalid_time_scope"] };
3580
+ var schema45 = { "type": "object", "properties": { "intent": { "type": "string", "minLength": 1, "maxLength": 500 }, "attribution": { "type": "string", "enum": ["user", "agent", "unknown"] }, "kind": { "type": "string", "enum": ["change", "exploration", "task_execution", "unclear"] }, "rationale": { "type": "string" }, "area": { "type": "string" }, "decided": { "type": "array", "items": { "type": "string" } }, "alternatives": { "type": "array", "items": { "type": "string" } }, "confidence": { "type": "string", "enum": ["high", "medium", "low"] }, "reversibility": { "type": "string", "enum": ["high", "low"] }, "files": { "type": "array", "items": { "type": "string" } }, "protocolVersion": { "type": "number", "const": 3 }, "repoSyncId": { "type": "string" }, "scope": { "default": {}, "type": "object", "properties": { "location": { "default": {}, "type": "object", "properties": { "repository": { "type": "boolean" }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } } }, "additionalProperties": {} }, "time": { "default": {}, "type": "object", "properties": { "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "additionalProperties": {} }, "users": { "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 } }, "required": ["kind", "userId"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "cursor", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } } }, "additionalProperties": {} }, "stageOverride": { "type": "string", "enum": ["candidate", "draft", "adopted"] } }, "required": ["intent"], "additionalProperties": {}, "x-primitive-runtime-refinements": ["degrade_invalid_rollout_fields", "degrade_invalid_location_scope", "degrade_invalid_time_scope"] };
3581
3581
  function validate27(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
3582
3582
  ;
3583
3583
  let vErrors = null;
@@ -4281,7 +4281,7 @@ function validate27(data, { instancePath = "", parentData, parentDataProperty, r
4281
4281
  }
4282
4282
  errors++;
4283
4283
  }
4284
- if (!(data34 === "claude_code" || data34 === "codex" || data34 === "hermes")) {
4284
+ if (!(data34 === "claude_code" || data34 === "codex" || data34 === "cursor" || data34 === "hermes")) {
4285
4285
  const err19 = { instancePath: instancePath + "/scope/users/" + i6 + "/agent", schemaPath: "https://api.getprimitive.ai/contracts/cli-http-v1.schema.json#/$defs/DecisionCreateRequest/properties/scope/properties/users/items/oneOf/2/properties/agent/enum", keyword: "enum", params: { allowedValues: schema45.properties.scope.properties.users.items.oneOf[2].properties.agent.enum }, message: "must be equal to one of the allowed values" };
4286
4286
  if (vErrors === null) {
4287
4287
  vErrors = [err19];
@@ -4509,7 +4509,7 @@ function validate27(data, { instancePath = "", parentData, parentDataProperty, r
4509
4509
  return errors === 0;
4510
4510
  }
4511
4511
  validate27.evaluated = { "props": true, "dynamicProps": false, "dynamicItems": false };
4512
- var schema47 = { "type": "object", "properties": { "decisionId": { "type": "string", "minLength": 1 }, "shortId": { "type": "string" }, "createdAt": { "type": "number" }, "scope": { "type": "object", "properties": { "location": { "type": "object", "properties": { "repository": { "type": "boolean" }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } } }, "required": ["repository", "directories", "globs", "branches"], "additionalProperties": {} }, "time": { "type": "object", "properties": { "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "additionalProperties": {} }, "users": { "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 } }, "required": ["kind", "userId"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } } }, "required": ["location", "time", "users"], "additionalProperties": {} }, "scopeWarnings": { "type": "array", "items": { "type": "string" } } }, "required": ["decisionId", "shortId", "createdAt"], "additionalProperties": {} };
4512
+ var schema47 = { "type": "object", "properties": { "decisionId": { "type": "string", "minLength": 1 }, "shortId": { "type": "string" }, "createdAt": { "type": "number" }, "scope": { "type": "object", "properties": { "location": { "type": "object", "properties": { "repository": { "type": "boolean" }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } } }, "required": ["repository", "directories", "globs", "branches"], "additionalProperties": {} }, "time": { "type": "object", "properties": { "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "additionalProperties": {} }, "users": { "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 } }, "required": ["kind", "userId"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "cursor", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } } }, "required": ["location", "time", "users"], "additionalProperties": {} }, "scopeWarnings": { "type": "array", "items": { "type": "string" } } }, "required": ["decisionId", "shortId", "createdAt"], "additionalProperties": {} };
4513
4513
  function validate28(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
4514
4514
  ;
4515
4515
  let vErrors = null;
@@ -5045,7 +5045,7 @@ function validate28(data, { instancePath = "", parentData, parentDataProperty, r
5045
5045
  }
5046
5046
  errors++;
5047
5047
  }
5048
- if (!(data22 === "claude_code" || data22 === "codex" || data22 === "hermes")) {
5048
+ if (!(data22 === "claude_code" || data22 === "codex" || data22 === "cursor" || data22 === "hermes")) {
5049
5049
  const err19 = { instancePath: instancePath + "/scope/users/" + i3 + "/agent", schemaPath: "https://api.getprimitive.ai/contracts/cli-http-v1.schema.json#/$defs/DecisionCreateResponse/properties/scope/properties/users/items/oneOf/2/properties/agent/enum", keyword: "enum", params: { allowedValues: schema47.properties.scope.properties.users.items.oneOf[2].properties.agent.enum }, message: "must be equal to one of the allowed values" };
5050
5050
  if (vErrors === null) {
5051
5051
  vErrors = [err19];
@@ -5277,7 +5277,7 @@ function validate28(data, { instancePath = "", parentData, parentDataProperty, r
5277
5277
  return errors === 0;
5278
5278
  }
5279
5279
  validate28.evaluated = { "props": true, "dynamicProps": false, "dynamicItems": false };
5280
- var schema49 = { "type": "object", "properties": { "decision": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1 }, "shortId": { "type": "string" }, "intent": { "type": "string" }, "intentKind": { "type": "string", "enum": ["change", "exploration", "task_execution", "unclear"] }, "rationale": { "type": "string" }, "decided": { "type": "array", "items": { "type": "string" } }, "alternatives": { "type": "array", "items": { "type": "string" } }, "area": { "type": "string" }, "producerKind": { "type": "string" }, "stage": { "type": "string", "enum": ["draft", "provisional", "adopted", "superseded", "abandoned"] }, "status": { "type": "string", "enum": ["active", "superseded", "under_review"] }, "supersededBy": { "anyOf": [{ "type": "string", "minLength": 1 }, { "type": "null" }] }, "confidence": { "type": "string", "enum": ["high", "medium", "low"] }, "reversibility": { "type": "string", "enum": ["high", "low"] }, "confirmed": { "type": "boolean" }, "respondedAt": { "type": "number" }, "fanOut": { "type": "number" }, "classifiedAt": { "type": "number" }, "authorName": { "type": "string" } }, "required": ["id", "intent", "intentKind", "alternatives", "stage", "status", "supersededBy", "confidence", "classifiedAt", "authorName"], "additionalProperties": {} }, "files": { "type": "array", "items": { "type": "string" } }, "flags": { "type": "array", "items": { "type": "object", "properties": { "type": { "type": "string", "enum": ["file_edit", "supersession", "invalidation", "confirmation_request"] }, "file": { "type": "string" }, "flaggedAt": { "type": "number" }, "acknowledgedAt": { "type": "number" }, "gateVerdict": { "type": "string" }, "reason": { "type": "string" } }, "required": ["type", "flaggedAt"], "additionalProperties": {} } }, "dependsOn": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1 }, "shortId": { "type": "string" }, "intent": { "type": "string" }, "area": { "type": "string" }, "authorName": { "type": "string" }, "classifiedAt": { "type": "number" }, "status": { "type": "string", "enum": ["active", "superseded", "under_review"] } }, "required": ["id", "intent", "authorName", "classifiedAt", "status"], "additionalProperties": {} } }, "dependents": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1 }, "shortId": { "type": "string" }, "intent": { "type": "string" }, "area": { "type": "string" }, "authorName": { "type": "string" }, "classifiedAt": { "type": "number" }, "status": { "type": "string", "enum": ["active", "superseded", "under_review"] } }, "required": ["id", "intent", "authorName", "classifiedAt", "status"], "additionalProperties": {} } }, "scope": { "type": "object", "properties": { "location": { "type": "object", "properties": { "repository": { "type": "boolean" }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } } }, "required": ["repository", "directories", "globs", "branches"], "additionalProperties": {} }, "time": { "type": "object", "properties": { "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "additionalProperties": {} }, "users": { "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 }, "displayName": { "type": "string" } }, "required": ["kind", "userId", "displayName"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } } }, "required": ["location", "time", "users"], "additionalProperties": {} }, "truncated": { "type": "boolean" } }, "required": ["decision", "files", "flags", "dependsOn", "dependents", "scope", "truncated"], "additionalProperties": {} };
5280
+ var schema49 = { "type": "object", "properties": { "decision": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1 }, "shortId": { "type": "string" }, "intent": { "type": "string" }, "intentKind": { "type": "string", "enum": ["change", "exploration", "task_execution", "unclear"] }, "rationale": { "type": "string" }, "decided": { "type": "array", "items": { "type": "string" } }, "alternatives": { "type": "array", "items": { "type": "string" } }, "area": { "type": "string" }, "producerKind": { "type": "string" }, "stage": { "type": "string", "enum": ["draft", "provisional", "adopted", "superseded", "abandoned"] }, "status": { "type": "string", "enum": ["active", "superseded", "under_review"] }, "supersededBy": { "anyOf": [{ "type": "string", "minLength": 1 }, { "type": "null" }] }, "confidence": { "type": "string", "enum": ["high", "medium", "low"] }, "reversibility": { "type": "string", "enum": ["high", "low"] }, "confirmed": { "type": "boolean" }, "respondedAt": { "type": "number" }, "fanOut": { "type": "number" }, "classifiedAt": { "type": "number" }, "authorName": { "type": "string" } }, "required": ["id", "intent", "intentKind", "alternatives", "stage", "status", "supersededBy", "confidence", "classifiedAt", "authorName"], "additionalProperties": {} }, "files": { "type": "array", "items": { "type": "string" } }, "flags": { "type": "array", "items": { "type": "object", "properties": { "type": { "type": "string", "enum": ["file_edit", "supersession", "invalidation", "confirmation_request"] }, "file": { "type": "string" }, "flaggedAt": { "type": "number" }, "acknowledgedAt": { "type": "number" }, "gateVerdict": { "type": "string" }, "reason": { "type": "string" } }, "required": ["type", "flaggedAt"], "additionalProperties": {} } }, "dependsOn": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1 }, "shortId": { "type": "string" }, "intent": { "type": "string" }, "area": { "type": "string" }, "authorName": { "type": "string" }, "classifiedAt": { "type": "number" }, "status": { "type": "string", "enum": ["active", "superseded", "under_review"] } }, "required": ["id", "intent", "authorName", "classifiedAt", "status"], "additionalProperties": {} } }, "dependents": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1 }, "shortId": { "type": "string" }, "intent": { "type": "string" }, "area": { "type": "string" }, "authorName": { "type": "string" }, "classifiedAt": { "type": "number" }, "status": { "type": "string", "enum": ["active", "superseded", "under_review"] } }, "required": ["id", "intent", "authorName", "classifiedAt", "status"], "additionalProperties": {} } }, "scope": { "type": "object", "properties": { "location": { "type": "object", "properties": { "repository": { "type": "boolean" }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } } }, "required": ["repository", "directories", "globs", "branches"], "additionalProperties": {} }, "time": { "type": "object", "properties": { "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "additionalProperties": {} }, "users": { "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 }, "displayName": { "type": "string" } }, "required": ["kind", "userId", "displayName"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "cursor", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } } }, "required": ["location", "time", "users"], "additionalProperties": {} }, "truncated": { "type": "boolean" } }, "required": ["decision", "files", "flags", "dependsOn", "dependents", "scope", "truncated"], "additionalProperties": {} };
5281
5281
  function validate29(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
5282
5282
  ;
5283
5283
  let vErrors = null;
@@ -6571,7 +6571,7 @@ function validate29(data, { instancePath = "", parentData, parentDataProperty, r
6571
6571
  }
6572
6572
  errors++;
6573
6573
  }
6574
- if (!(data70 === "claude_code" || data70 === "codex" || data70 === "hermes")) {
6574
+ if (!(data70 === "claude_code" || data70 === "codex" || data70 === "cursor" || data70 === "hermes")) {
6575
6575
  const err24 = { instancePath: instancePath + "/scope/users/" + i9 + "/agent", schemaPath: "https://api.getprimitive.ai/contracts/cli-http-v1.schema.json#/$defs/DecisionDetailResponse/properties/scope/properties/users/items/oneOf/2/properties/agent/enum", keyword: "enum", params: { allowedValues: schema49.properties.scope.properties.users.items.oneOf[2].properties.agent.enum }, message: "must be equal to one of the allowed values" };
6576
6576
  if (vErrors === null) {
6577
6577
  vErrors = [err24];
@@ -7132,7 +7132,7 @@ function validate33(data, { instancePath = "", parentData, parentDataProperty, r
7132
7132
  return errors === 0;
7133
7133
  }
7134
7134
  validate33.evaluated = { "props": true, "dynamicProps": false, "dynamicItems": false };
7135
- var schema59 = { "type": "object", "properties": { "id": { "type": "string" }, "location": { "anyOf": [{ "default": {}, "type": "object", "properties": { "repository": { "type": "boolean" }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } } }, "additionalProperties": {} }, { "type": "null" }] }, "time": { "anyOf": [{ "default": {}, "type": "object", "properties": { "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "additionalProperties": {} }, { "type": "null" }] }, "users": { "anyOf": [{ "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 } }, "required": ["kind", "userId"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } }, { "type": "null" }] } }, "required": ["id"], "additionalProperties": {} };
7135
+ var schema59 = { "type": "object", "properties": { "id": { "type": "string" }, "location": { "anyOf": [{ "default": {}, "type": "object", "properties": { "repository": { "type": "boolean" }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } } }, "additionalProperties": {} }, { "type": "null" }] }, "time": { "anyOf": [{ "default": {}, "type": "object", "properties": { "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "additionalProperties": {} }, { "type": "null" }] }, "users": { "anyOf": [{ "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 } }, "required": ["kind", "userId"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "cursor", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } }, { "type": "null" }] } }, "required": ["id"], "additionalProperties": {} };
7136
7136
  function validate34(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
7137
7137
  ;
7138
7138
  let vErrors = null;
@@ -7773,7 +7773,7 @@ function validate34(data, { instancePath = "", parentData, parentDataProperty, r
7773
7773
  }
7774
7774
  errors++;
7775
7775
  }
7776
- if (!(data19 === "claude_code" || data19 === "codex" || data19 === "hermes")) {
7776
+ if (!(data19 === "claude_code" || data19 === "codex" || data19 === "cursor" || data19 === "hermes")) {
7777
7777
  const err38 = { instancePath: instancePath + "/users/" + i3 + "/agent", schemaPath: "https://api.getprimitive.ai/contracts/cli-http-v1.schema.json#/$defs/DecisionRescopeRequest/properties/users/anyOf/0/items/oneOf/2/properties/agent/enum", keyword: "enum", params: { allowedValues: schema59.properties.users.anyOf[0].items.oneOf[2].properties.agent.enum }, message: "must be equal to one of the allowed values" };
7778
7778
  if (vErrors === null) {
7779
7779
  vErrors = [err38];
@@ -8001,7 +8001,7 @@ function validate34(data, { instancePath = "", parentData, parentDataProperty, r
8001
8001
  return errors === 0;
8002
8002
  }
8003
8003
  validate34.evaluated = { "props": true, "dynamicProps": false, "dynamicItems": false };
8004
- var schema61 = { "anyOf": [{ "type": "object", "properties": { "outcome": { "type": "string", "const": "no_op" }, "stage": { "type": "string", "enum": ["draft", "provisional", "adopted", "superseded", "abandoned"] }, "scope": { "type": "object", "properties": { "location": { "type": "object", "properties": { "repository": { "type": "boolean" }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } } }, "required": ["repository", "directories", "globs", "branches"], "additionalProperties": {} }, "time": { "type": "object", "properties": { "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "additionalProperties": {} }, "users": { "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 } }, "required": ["kind", "userId"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } } }, "required": ["location", "time", "users"], "additionalProperties": {} }, "scopeWarnings": { "type": "array", "items": { "type": "string" } } }, "required": ["outcome", "stage", "scope"], "additionalProperties": {} }, { "type": "object", "properties": { "outcome": { "type": "string", "const": "ok" }, "decisionId": { "type": "string", "minLength": 1 }, "shortId": { "type": "string" }, "stage": { "type": "string", "enum": ["draft", "provisional", "adopted", "superseded", "abandoned"] }, "scope": { "type": "object", "properties": { "location": { "type": "object", "properties": { "repository": { "type": "boolean" }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } } }, "required": ["repository", "directories", "globs", "branches"], "additionalProperties": {} }, "time": { "type": "object", "properties": { "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "additionalProperties": {} }, "users": { "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 } }, "required": ["kind", "userId"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } } }, "required": ["location", "time", "users"], "additionalProperties": {} }, "scopeWarnings": { "type": "array", "items": { "type": "string" } } }, "required": ["outcome", "decisionId", "stage", "scope"], "additionalProperties": {} }] };
8004
+ var schema61 = { "anyOf": [{ "type": "object", "properties": { "outcome": { "type": "string", "const": "no_op" }, "stage": { "type": "string", "enum": ["draft", "provisional", "adopted", "superseded", "abandoned"] }, "scope": { "type": "object", "properties": { "location": { "type": "object", "properties": { "repository": { "type": "boolean" }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } } }, "required": ["repository", "directories", "globs", "branches"], "additionalProperties": {} }, "time": { "type": "object", "properties": { "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "additionalProperties": {} }, "users": { "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 } }, "required": ["kind", "userId"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "cursor", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } } }, "required": ["location", "time", "users"], "additionalProperties": {} }, "scopeWarnings": { "type": "array", "items": { "type": "string" } } }, "required": ["outcome", "stage", "scope"], "additionalProperties": {} }, { "type": "object", "properties": { "outcome": { "type": "string", "const": "ok" }, "decisionId": { "type": "string", "minLength": 1 }, "shortId": { "type": "string" }, "stage": { "type": "string", "enum": ["draft", "provisional", "adopted", "superseded", "abandoned"] }, "scope": { "type": "object", "properties": { "location": { "type": "object", "properties": { "repository": { "type": "boolean" }, "directories": { "type": "array", "items": { "type": "string" } }, "globs": { "type": "array", "items": { "type": "string" } }, "branches": { "type": "array", "items": { "type": "string" } } }, "required": ["repository", "directories", "globs", "branches"], "additionalProperties": {} }, "time": { "type": "object", "properties": { "effectiveFrom": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 }, "effectiveUntil": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991 } }, "additionalProperties": {} }, "users": { "type": "array", "items": { "oneOf": [{ "type": "object", "properties": { "kind": { "type": "string", "const": "user" }, "userId": { "type": "string", "minLength": 1 } }, "required": ["kind", "userId"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "role" }, "role": { "type": "string", "enum": ["owner", "admin", "member"] } }, "required": ["kind", "role"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "agent" }, "agent": { "type": "string", "enum": ["claude_code", "codex", "cursor", "hermes"] } }, "required": ["kind", "agent"], "additionalProperties": false }, { "type": "object", "properties": { "kind": { "type": "string", "const": "credential" }, "credential": { "type": "string", "enum": ["workos_jwt", "workos_api_key", "service_token"] } }, "required": ["kind", "credential"], "additionalProperties": false }] } } }, "required": ["location", "time", "users"], "additionalProperties": {} }, "scopeWarnings": { "type": "array", "items": { "type": "string" } } }, "required": ["outcome", "decisionId", "stage", "scope"], "additionalProperties": {} }] };
8005
8005
  function validate35(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
8006
8006
  ;
8007
8007
  let vErrors = null;
@@ -8639,7 +8639,7 @@ function validate35(data, { instancePath = "", parentData, parentDataProperty, r
8639
8639
  }
8640
8640
  errors++;
8641
8641
  }
8642
- if (!(data21 === "claude_code" || data21 === "codex" || data21 === "hermes")) {
8642
+ if (!(data21 === "claude_code" || data21 === "codex" || data21 === "cursor" || data21 === "hermes")) {
8643
8643
  const err41 = { instancePath: instancePath + "/scope/users/" + i3 + "/agent", schemaPath: "https://api.getprimitive.ai/contracts/cli-http-v1.schema.json#/$defs/DecisionRescopeResponse/anyOf/0/properties/scope/properties/users/items/oneOf/2/properties/agent/enum", keyword: "enum", params: { allowedValues: schema61.anyOf[0].properties.scope.properties.users.items.oneOf[2].properties.agent.enum }, message: "must be equal to one of the allowed values" };
8644
8644
  if (vErrors === null) {
8645
8645
  vErrors = [err41];
@@ -9563,7 +9563,7 @@ function validate35(data, { instancePath = "", parentData, parentDataProperty, r
9563
9563
  }
9564
9564
  errors++;
9565
9565
  }
9566
- if (!(data49 === "claude_code" || data49 === "codex" || data49 === "hermes")) {
9566
+ if (!(data49 === "claude_code" || data49 === "codex" || data49 === "cursor" || data49 === "hermes")) {
9567
9567
  const err100 = { instancePath: instancePath + "/scope/users/" + i8 + "/agent", schemaPath: "https://api.getprimitive.ai/contracts/cli-http-v1.schema.json#/$defs/DecisionRescopeResponse/anyOf/1/properties/scope/properties/users/items/oneOf/2/properties/agent/enum", keyword: "enum", params: { allowedValues: schema61.anyOf[1].properties.scope.properties.users.items.oneOf[2].properties.agent.enum }, message: "must be equal to one of the allowed values" };
9568
9568
  if (vErrors === null) {
9569
9569
  vErrors = [err100];
@@ -15209,7 +15209,7 @@ function validate50(data, { instancePath = "", parentData, parentDataProperty, r
15209
15209
  return errors === 0;
15210
15210
  }
15211
15211
  validate50.evaluated = { "dynamicProps": true, "dynamicItems": false };
15212
- var schema93 = { "type": "object", "properties": { "batch": { "type": "array", "items": { "anyOf": [{ "type": "object", "properties": { "moveId": { "type": "string" }, "capturedAt": { "type": "number" }, "sessionId": { "type": "string" }, "invocationId": { "type": "string" }, "eventType": { "type": "string" }, "payload": {}, "env": {}, "capturedOrganizationId": { "type": "string", "minLength": 1, "maxLength": 128, "pattern": "^[A-Za-z0-9_-]+$" }, "captureAuthorityKind": { "type": "string", "enum": ["workos", "service_token"] }, "decisionLifecycleProtocolVersion": { "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "producer": { "type": "string", "enum": ["claude_code", "codex", "hermes"] }, "toolOutcome": { "type": "string", "enum": ["succeeded", "returned", "failed", "interrupted", "prevented", "unknown"] }, "envelopeVersion": { "type": "number", "const": 4 } }, "required": ["moveId", "capturedAt", "sessionId", "eventType", "capturedOrganizationId", "captureAuthorityKind", "decisionLifecycleProtocolVersion", "envelopeVersion"], "additionalProperties": {} }, { "type": "object", "properties": { "moveId": { "type": "string" }, "capturedAt": { "type": "number" }, "sessionId": { "type": "string" }, "invocationId": { "type": "string" }, "eventType": { "type": "string" }, "payload": {}, "env": {}, "capturedOrganizationId": { "type": "string", "minLength": 1, "maxLength": 128, "pattern": "^[A-Za-z0-9_-]+$" }, "captureAuthorityKind": { "type": "string", "enum": ["workos", "service_token"] }, "decisionLifecycleProtocolVersion": { "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "producer": { "type": "string", "enum": ["claude_code", "codex", "hermes"] }, "toolOutcome": { "type": "string", "enum": ["succeeded", "returned", "failed", "interrupted", "prevented", "unknown"] }, "envelopeVersion": { "type": "number", "exclusiveMaximum": 4 } }, "required": ["moveId", "capturedAt", "sessionId", "eventType"], "additionalProperties": {} }] } } }, "required": ["batch"], "additionalProperties": {} };
15212
+ var schema93 = { "type": "object", "properties": { "batch": { "type": "array", "items": { "anyOf": [{ "type": "object", "properties": { "moveId": { "type": "string" }, "capturedAt": { "type": "number" }, "sessionId": { "type": "string" }, "invocationId": { "type": "string" }, "eventType": { "type": "string" }, "payload": {}, "env": {}, "capturedOrganizationId": { "type": "string", "minLength": 1, "maxLength": 128, "pattern": "^[A-Za-z0-9_-]+$" }, "captureAuthorityKind": { "type": "string", "enum": ["workos", "service_token"] }, "decisionLifecycleProtocolVersion": { "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "producer": { "type": "string", "enum": ["claude_code", "codex", "cursor", "hermes"] }, "toolOutcome": { "type": "string", "enum": ["succeeded", "returned", "failed", "interrupted", "prevented", "unknown"] }, "envelopeVersion": { "type": "number", "const": 4 } }, "required": ["moveId", "capturedAt", "sessionId", "eventType", "capturedOrganizationId", "captureAuthorityKind", "decisionLifecycleProtocolVersion", "envelopeVersion"], "additionalProperties": {} }, { "type": "object", "properties": { "moveId": { "type": "string" }, "capturedAt": { "type": "number" }, "sessionId": { "type": "string" }, "invocationId": { "type": "string" }, "eventType": { "type": "string" }, "payload": {}, "env": {}, "capturedOrganizationId": { "type": "string", "minLength": 1, "maxLength": 128, "pattern": "^[A-Za-z0-9_-]+$" }, "captureAuthorityKind": { "type": "string", "enum": ["workos", "service_token"] }, "decisionLifecycleProtocolVersion": { "type": "integer", "minimum": 1, "maximum": 9007199254740991 }, "producer": { "type": "string", "enum": ["claude_code", "codex", "cursor", "hermes"] }, "toolOutcome": { "type": "string", "enum": ["succeeded", "returned", "failed", "interrupted", "prevented", "unknown"] }, "envelopeVersion": { "type": "number", "exclusiveMaximum": 4 } }, "required": ["moveId", "capturedAt", "sessionId", "eventType"], "additionalProperties": {} }] } } }, "required": ["batch"], "additionalProperties": {} };
15213
15213
  var pattern8 = new RegExp("^[A-Za-z0-9_-]+$", "u");
15214
15214
  function validate51(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
15215
15215
  ;
@@ -15463,7 +15463,7 @@ function validate51(data, { instancePath = "", parentData, parentDataProperty, r
15463
15463
  }
15464
15464
  errors++;
15465
15465
  }
15466
- if (!(data10 === "claude_code" || data10 === "codex" || data10 === "hermes")) {
15466
+ if (!(data10 === "claude_code" || data10 === "codex" || data10 === "cursor" || data10 === "hermes")) {
15467
15467
  const err16 = { instancePath: instancePath + "/batch/" + i0 + "/producer", schemaPath: "https://api.getprimitive.ai/contracts/cli-http-v1.schema.json#/$defs/MoveIngestRequest/properties/batch/items/anyOf/0/properties/producer/enum", keyword: "enum", params: { allowedValues: schema93.properties.batch.items.anyOf[0].properties.producer.enum }, message: "must be equal to one of the allowed values" };
15468
15468
  if (vErrors === null) {
15469
15469
  vErrors = [err16];
@@ -15775,7 +15775,7 @@ function validate51(data, { instancePath = "", parentData, parentDataProperty, r
15775
15775
  }
15776
15776
  errors++;
15777
15777
  }
15778
- if (!(data21 === "claude_code" || data21 === "codex" || data21 === "hermes")) {
15778
+ if (!(data21 === "claude_code" || data21 === "codex" || data21 === "cursor" || data21 === "hermes")) {
15779
15779
  const err38 = { instancePath: instancePath + "/batch/" + i0 + "/producer", schemaPath: "https://api.getprimitive.ai/contracts/cli-http-v1.schema.json#/$defs/MoveIngestRequest/properties/batch/items/anyOf/1/properties/producer/enum", keyword: "enum", params: { allowedValues: schema93.properties.batch.items.anyOf[1].properties.producer.enum }, message: "must be equal to one of the allowed values" };
15780
15780
  if (vErrors === null) {
15781
15781
  vErrors = [err38];
@@ -15912,7 +15912,7 @@ function validate51(data, { instancePath = "", parentData, parentDataProperty, r
15912
15912
  return errors === 0;
15913
15913
  }
15914
15914
  validate51.evaluated = { "props": true, "dynamicProps": false, "dynamicItems": false };
15915
- var schema95 = { "type": "object", "properties": { "protocolVersion": { "type": "number", "const": 3 }, "agent": { "type": "string", "enum": ["claude_code", "codex", "hermes"] }, "sessionId": { "type": "string", "pattern": "^[A-Za-z0-9._:-]{1,128}$" }, "invocationId": { "type": "string", "pattern": "^[A-Za-z0-9._:-]{1,128}$" }, "repoSyncId": { "type": "string", "pattern": "^[A-Za-z0-9]{1,64}$" }, "paths": { "maxItems": 32, "type": "array", "items": { "type": "string" } }, "coverage": { "type": "string", "enum": ["complete", "unverified"] }, "branch": { "type": "string", "maxLength": 255, "pattern": "^(?!@?$)(?!\\/)(?!.*\\/$)(?!.*\\/\\/)(?!.*(?:^|\\/)\\.{1,2}(?:\\/|$))(?!.*(?:^|\\/)[^/]*\\.lock(?:\\/|$))(?!.*\\.\\.)(?!.*@\\{)(?!.*[~^:?*\\\\]).+$" }, "clientMode": { "type": "string", "enum": ["block", "warn"] }, "clientVersion": { "type": "string", "maxLength": 32, "pattern": "^[A-Za-z0-9][A-Za-z0-9._+-]*$" }, "proposal": { "type": "string" } }, "required": ["protocolVersion", "agent", "sessionId", "invocationId", "repoSyncId", "paths", "coverage", "proposal"], "additionalProperties": false, "x-primitive-runtime-refinements": ["canonical_repository_paths", "unique_repository_paths", "complete_coverage_requires_path", "proposal_utf8_max_6144", "degrade_invalid_rollout_fields", "degrade_invalid_branch"] };
15915
+ var schema95 = { "type": "object", "properties": { "protocolVersion": { "type": "number", "const": 3 }, "agent": { "type": "string", "enum": ["claude_code", "codex", "cursor", "hermes"] }, "sessionId": { "type": "string", "pattern": "^[A-Za-z0-9._:-]{1,128}$" }, "invocationId": { "type": "string", "pattern": "^[A-Za-z0-9._:-]{1,128}$" }, "repoSyncId": { "type": "string", "pattern": "^[A-Za-z0-9]{1,64}$" }, "paths": { "maxItems": 32, "type": "array", "items": { "type": "string" } }, "coverage": { "type": "string", "enum": ["complete", "unverified"] }, "branch": { "type": "string", "maxLength": 255, "pattern": "^(?!@?$)(?!\\/)(?!.*\\/$)(?!.*\\/\\/)(?!.*(?:^|\\/)\\.{1,2}(?:\\/|$))(?!.*(?:^|\\/)[^/]*\\.lock(?:\\/|$))(?!.*\\.\\.)(?!.*@\\{)(?!.*[~^:?*\\\\]).+$" }, "clientMode": { "type": "string", "enum": ["block", "warn"] }, "clientVersion": { "type": "string", "maxLength": 32, "pattern": "^[A-Za-z0-9][A-Za-z0-9._+-]*$" }, "proposal": { "type": "string" } }, "required": ["protocolVersion", "agent", "sessionId", "invocationId", "repoSyncId", "paths", "coverage", "proposal"], "additionalProperties": false, "x-primitive-runtime-refinements": ["canonical_repository_paths", "unique_repository_paths", "complete_coverage_requires_path", "proposal_utf8_max_6144", "degrade_invalid_rollout_fields", "degrade_invalid_branch"] };
15916
15916
  var pattern10 = new RegExp("^[A-Za-z0-9._:-]{1,128}$", "u");
15917
15917
  var pattern12 = new RegExp("^[A-Za-z0-9]{1,64}$", "u");
15918
15918
  var pattern13 = new RegExp("^(?!@?$)(?!\\/)(?!.*\\/$)(?!.*\\/\\/)(?!.*(?:^|\\/)\\.{1,2}(?:\\/|$))(?!.*(?:^|\\/)[^/]*\\.lock(?:\\/|$))(?!.*\\.\\.)(?!.*@\\{)(?!.*[~^:?*\\\\]).+$", "u");
@@ -15968,7 +15968,7 @@ function validate52(data, { instancePath = "", parentData, parentDataProperty, r
15968
15968
  validate52.errors = [{ instancePath: instancePath + "/agent", schemaPath: "https://api.getprimitive.ai/contracts/cli-http-v1.schema.json#/$defs/PreflightRequestV3/properties/agent/type", keyword: "type", params: { type: "string" }, message: "must be string" }];
15969
15969
  return false;
15970
15970
  }
15971
- if (!(data1 === "claude_code" || data1 === "codex" || data1 === "hermes")) {
15971
+ if (!(data1 === "claude_code" || data1 === "codex" || data1 === "cursor" || data1 === "hermes")) {
15972
15972
  validate52.errors = [{ instancePath: instancePath + "/agent", schemaPath: "https://api.getprimitive.ai/contracts/cli-http-v1.schema.json#/$defs/PreflightRequestV3/properties/agent/enum", keyword: "enum", params: { allowedValues: schema95.properties.agent.enum }, message: "must be equal to one of the allowed values" }];
15973
15973
  return false;
15974
15974
  }
@@ -19350,7 +19350,7 @@ function optionalUserScopeMembers(record) {
19350
19350
  members.push({ kind: "role", role: candidate.role });
19351
19351
  continue;
19352
19352
  }
19353
- if (candidate.kind === "agent" && (candidate.agent === "claude_code" || candidate.agent === "codex" || candidate.agent === "hermes")) {
19353
+ if (candidate.kind === "agent" && (candidate.agent === "claude_code" || candidate.agent === "codex" || candidate.agent === "cursor" || candidate.agent === "hermes")) {
19354
19354
  members.push({ kind: "agent", agent: candidate.agent });
19355
19355
  continue;
19356
19356
  }
@@ -19782,7 +19782,7 @@ function errorCode(error) {
19782
19782
  function parseAgent(argv) {
19783
19783
  const i = argv.indexOf("--agent");
19784
19784
  const value = i !== -1 ? argv[i + 1] : void 0;
19785
- if (value === "codex" || value === "hermes") {
19785
+ if (value === "codex" || value === "cursor" || value === "hermes") {
19786
19786
  return value;
19787
19787
  }
19788
19788
  return "claude_code";
@@ -19869,7 +19869,7 @@ function daemonRequest(method, params = {}, opts = {}) {
19869
19869
  ...caller ? { caller } : {}
19870
19870
  };
19871
19871
  const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
19872
- return new Promise((resolve4) => {
19872
+ return new Promise((resolve6) => {
19873
19873
  let settled = false;
19874
19874
  let socket;
19875
19875
  let buffer = Buffer.alloc(0);
@@ -19884,7 +19884,7 @@ function daemonRequest(method, params = {}, opts = {}) {
19884
19884
  } catch {
19885
19885
  }
19886
19886
  }
19887
- resolve4(value);
19887
+ resolve6(value);
19888
19888
  };
19889
19889
  const timer = setTimeout(() => settle(null), timeoutMs);
19890
19890
  timer.unref();
@@ -19962,6 +19962,7 @@ import { dirname as dirname7, isAbsolute as isAbsolute4, join as join9 } from "p
19962
19962
  import { fileURLToPath } from "url";
19963
19963
  var PKG_NAME = "@primitive.ai/prim";
19964
19964
  var ROOT_WALK_LIMIT = 6;
19965
+ var STABLE_HOOK_LAUNCHER_NAME = "prim-hook-launcher-v1";
19965
19966
  var resolvedRoot;
19966
19967
  function locateRoot() {
19967
19968
  if (resolvedRoot !== void 0) {
@@ -19992,6 +19993,34 @@ function locateRoot() {
19992
19993
  function packageVersion() {
19993
19994
  return locateRoot()?.version ?? null;
19994
19995
  }
19996
+ function shellQuote(value) {
19997
+ return `'${value.replaceAll("'", `'"'"'`)}'`;
19998
+ }
19999
+ var STABLE_HOOK_ARGUMENTS_RE = /^[-A-Za-z0-9_ ]*$/u;
20000
+ var STABLE_HOOK_BIN_RE = /^[A-Za-z0-9][A-Za-z0-9-]*$/u;
20001
+ function stableHookCommand(bin, args = "") {
20002
+ if (!STABLE_HOOK_BIN_RE.test(bin) || !STABLE_HOOK_ARGUMENTS_RE.test(args)) {
20003
+ throw new Error("invalid stable hook command");
20004
+ }
20005
+ const resolver = [
20006
+ // #242 and earlier identify managed commands by this package marker. Keep
20007
+ // it as inert data during the rolling window so an older uninstall or
20008
+ // reinstall can remove the stable entry without invoking npm or PATH.
20009
+ `prim_legacy_reader='-p ${PKG_NAME}@stable prim-shim.sh ${bin} '; `,
20010
+ 'prim_absolute() { case "$1" in [/]* ) ;; *) return 1 ;; esac; case "$1" in [[:space:]]*|*[[:space:]]|*[/][/]*|*[/].[/]*|*[/]..[/]*|*[/].|*[/]..|?*[/]) return 1 ;; esac; }; ',
20011
+ 'prim_config=${PRIM_CONFIG_DIR:-}; if ! prim_absolute "$prim_config"; then prim_config=${XDG_CONFIG_HOME:-}; if prim_absolute "$prim_config"; then ',
20012
+ 'case "$prim_config" in /) prim_config=/prim ;; *) prim_config="$prim_config/prim" ;; esac; ',
20013
+ 'else prim_home=${HOME:-}; prim_absolute "$prim_home" || exit 78; case "$prim_home" in /) prim_config=/.config/prim ;; *) prim_config="$prim_home/.config/prim" ;; esac; ',
20014
+ "fi; fi; ",
20015
+ `case "$prim_config" in /) prim_launcher=/${STABLE_HOOK_LAUNCHER_NAME} ;; *) prim_launcher="$prim_config/${STABLE_HOOK_LAUNCHER_NAME}" ;; esac; `,
20016
+ 'exec "$prim_launcher" "$@"'
20017
+ ].join("");
20018
+ const suffix = args ? ` ${args}` : "";
20019
+ return `/bin/sh -c ${shellQuote(resolver)} ${STABLE_HOOK_LAUNCHER_NAME} ${bin}${suffix}`;
20020
+ }
20021
+ function detachedHookShimCommand(bin, args = "") {
20022
+ return `payload=$(cat); { trap '' HUP; printf '%s' "$payload" | { ${stableHookCommand(bin, args)}; }; } </dev/null >/dev/null 2>&1 &`;
20023
+ }
19995
20024
 
19996
20025
  // src/lib/presence.ts
19997
20026
  var DECISION_ORIGIN = "https://app.getprimitive.ai";
@@ -20106,9 +20135,7 @@ var CODEX_DRAFT_DIGEST_MAX_SEEN_IDS = 4096;
20106
20135
  var CODEX_DIGEST_STATE_RETENTION_MS = 7 * 24 * 60 * 60 * 1e3;
20107
20136
  var CODEX_DIGEST_STATE_MAX_FILES = 256;
20108
20137
  var STATE_VERSION = 1;
20109
- var STATE_DIRECTORY = ["codex", "decision-digests"];
20110
20138
  var DRAFT_STATE_VERSION = 2;
20111
- var DRAFT_STATE_DIRECTORY = ["codex", "decision-draft-deliveries"];
20112
20139
  var NO_CURSOR = -1;
20113
20140
  function appendContext(existing, context) {
20114
20141
  return existing ? `${existing}
@@ -20133,11 +20160,11 @@ function appendCodexContext(output, context) {
20133
20160
  }
20134
20161
  return next;
20135
20162
  }
20136
- function stateRoot() {
20137
- return join10(primConfigDirectory(), ...STATE_DIRECTORY);
20163
+ function stateRoot(namespace) {
20164
+ return join10(primConfigDirectory(), namespace, "decision-digests");
20138
20165
  }
20139
- function draftStateRoot() {
20140
- return join10(primConfigDirectory(), ...DRAFT_STATE_DIRECTORY);
20166
+ function draftStateRoot(namespace) {
20167
+ return join10(primConfigDirectory(), namespace, "decision-draft-deliveries");
20141
20168
  }
20142
20169
  function workspaceFor(cwd) {
20143
20170
  try {
@@ -20149,12 +20176,12 @@ function workspaceFor(cwd) {
20149
20176
  function statePath(args) {
20150
20177
  const identity = `${args.siteUrl}\0${workspaceFor(args.cwd)}\0${args.sessionId}`;
20151
20178
  const key = createHash5("sha256").update(identity).digest("hex");
20152
- return join10(stateRoot(), `${key}.json`);
20179
+ return join10(stateRoot(args.namespace), `${key}.json`);
20153
20180
  }
20154
20181
  function draftStatePath(args) {
20155
20182
  const identity = `${args.siteUrl}\0${workspaceFor(args.cwd)}\0${args.sessionId}\0${args.principalId}\0${args.organizationId}\0${args.credentialFingerprint}`;
20156
20183
  const key = createHash5("sha256").update(identity).digest("hex");
20157
- return join10(draftStateRoot(), `${key}.json`);
20184
+ return join10(draftStateRoot(args.namespace), `${key}.json`);
20158
20185
  }
20159
20186
  function parseState(value) {
20160
20187
  if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
@@ -20345,14 +20372,14 @@ function mergeState(latest, args) {
20345
20372
  updatedAt: args.now
20346
20373
  };
20347
20374
  }
20348
- async function commitState(path, args) {
20375
+ async function commitState(path, args, namespace) {
20349
20376
  try {
20350
20377
  await withFileLock(
20351
20378
  `${path}.lock`,
20352
20379
  () => {
20353
20380
  const latest = readState(path);
20354
- writeStateFile(path, stateRoot(), mergeState(latest, args));
20355
- cleanupStateFiles(stateRoot(), args.now);
20381
+ writeStateFile(path, stateRoot(namespace), mergeState(latest, args));
20382
+ cleanupStateFiles(stateRoot(namespace), args.now);
20356
20383
  },
20357
20384
  { timeoutMs: 50, pollMs: 10 }
20358
20385
  );
@@ -20374,7 +20401,7 @@ function mergeDraftState(latest, args) {
20374
20401
  updatedAt: args.now
20375
20402
  };
20376
20403
  }
20377
- async function commitDraftState(path, args) {
20404
+ async function commitDraftState(path, args, namespace) {
20378
20405
  try {
20379
20406
  let next;
20380
20407
  await withFileLock(
@@ -20382,8 +20409,8 @@ async function commitDraftState(path, args) {
20382
20409
  () => {
20383
20410
  const latest = readDraftState(path);
20384
20411
  next = mergeDraftState(latest, args);
20385
- writeStateFile(path, draftStateRoot(), next);
20386
- cleanupStateFiles(draftStateRoot(), args.now);
20412
+ writeStateFile(path, draftStateRoot(namespace), next);
20413
+ cleanupStateFiles(draftStateRoot(namespace), args.now);
20387
20414
  },
20388
20415
  { timeoutMs: 50, pollMs: 10 }
20389
20416
  );
@@ -20393,9 +20420,10 @@ async function commitDraftState(path, args) {
20393
20420
  }
20394
20421
  }
20395
20422
  async function prepareCodexContext(options) {
20423
+ const namespace = options.namespace ?? "codex";
20396
20424
  const siteUrl = getSiteUrl();
20397
20425
  const workspace = workspaceFor(options.cwd);
20398
- const path = statePath({ cwd: options.cwd, sessionId: options.sessionId, siteUrl });
20426
+ const path = statePath({ cwd: options.cwd, sessionId: options.sessionId, siteUrl, namespace });
20399
20427
  const previous = readState(path);
20400
20428
  const principal = resolveDaemonPrincipal();
20401
20429
  const privatePath = principal ? draftStatePath({
@@ -20404,7 +20432,8 @@ async function prepareCodexContext(options) {
20404
20432
  siteUrl,
20405
20433
  principalId: principal.principalId,
20406
20434
  organizationId: principal.organizationId,
20407
- credentialFingerprint: principal.credentialFingerprint
20435
+ credentialFingerprint: principal.credentialFingerprint,
20436
+ namespace
20408
20437
  }) : void 0;
20409
20438
  const previousDraft = privatePath ? readDraftState(privatePath) : void 0;
20410
20439
  const startup = options.startup === true;
@@ -20494,32 +20523,40 @@ async function prepareCodexContext(options) {
20494
20523
  acknowledge: async (handedOff) => {
20495
20524
  if (!handedOff || acknowledged) return;
20496
20525
  acknowledged = true;
20497
- await commitState(path, {
20498
- sessionId: options.sessionId,
20499
- siteUrl,
20500
- workspace,
20501
- startedAt,
20502
- watermarkMs: pageWatermark,
20503
- seenIds: freshRows.map((row) => row.id),
20504
- report,
20505
- feedAvailable,
20506
- now: Date.now()
20507
- });
20526
+ await commitState(
20527
+ path,
20528
+ {
20529
+ sessionId: options.sessionId,
20530
+ siteUrl,
20531
+ workspace,
20532
+ startedAt,
20533
+ watermarkMs: pageWatermark,
20534
+ seenIds: freshRows.map((row) => row.id),
20535
+ report,
20536
+ feedAvailable,
20537
+ now: Date.now()
20538
+ },
20539
+ namespace
20540
+ );
20508
20541
  if (privatePath === void 0 || principal === void 0 || draftPageToken === void 0) {
20509
20542
  return;
20510
20543
  }
20511
20544
  let persistedDraft = previousDraft;
20512
20545
  if (draftDigest?.deliveredIds.length) {
20513
- persistedDraft = await commitDraftState(privatePath, {
20514
- sessionId: options.sessionId,
20515
- siteUrl,
20516
- workspace,
20517
- principalId: principal.principalId,
20518
- organizationId: principal.organizationId,
20519
- credentialFingerprint: principal.credentialFingerprint,
20520
- deliveredIds: draftDigest.deliveredIds,
20521
- now: Date.now()
20522
- });
20546
+ persistedDraft = await commitDraftState(
20547
+ privatePath,
20548
+ {
20549
+ sessionId: options.sessionId,
20550
+ siteUrl,
20551
+ workspace,
20552
+ principalId: principal.principalId,
20553
+ organizationId: principal.organizationId,
20554
+ credentialFingerprint: principal.credentialFingerprint,
20555
+ deliveredIds: draftDigest.deliveredIds,
20556
+ now: Date.now()
20557
+ },
20558
+ namespace
20559
+ );
20523
20560
  }
20524
20561
  const seenDrafts = new Set(persistedDraft?.seenDraftIds ?? []);
20525
20562
  const deliveredOnThisPage = draftPageActionableIds.filter((id) => seenDrafts.has(id));
@@ -20536,8 +20573,292 @@ async function prepareCodexContext(options) {
20536
20573
  };
20537
20574
  }
20538
20575
 
20576
+ // src/commands/cursor-install.ts
20577
+ import { existsSync as existsSync9, readFileSync as readFileSync11 } from "fs";
20578
+ import { homedir as homedir4 } from "os";
20579
+ import { isAbsolute as isAbsolute6, join as join13 } from "path";
20580
+
20581
+ // src/lib/hook-runtime.ts
20582
+ import { createHash as createHash6, randomBytes as randomBytes4 } from "crypto";
20583
+ import {
20584
+ constants as constants3,
20585
+ accessSync,
20586
+ chmodSync as chmodSync4,
20587
+ copyFileSync,
20588
+ existsSync as existsSync7,
20589
+ lstatSync as lstatSync3,
20590
+ mkdirSync as mkdirSync6,
20591
+ mkdtempSync,
20592
+ readFileSync as readFileSync9,
20593
+ readdirSync as readdirSync2,
20594
+ realpathSync as realpathSync2,
20595
+ renameSync as renameSync3,
20596
+ rmSync as rmSync5,
20597
+ statSync as statSync4,
20598
+ utimesSync,
20599
+ writeFileSync as writeFileSync5
20600
+ } from "fs";
20601
+ import { dirname as dirname8, isAbsolute as isAbsolute5, join as join11, resolve as resolve4 } from "path";
20602
+ var RELEASE_PREFIX = "release-";
20603
+ var MAX_MANIFEST_BYTES = 64 * 1024;
20604
+ var RELEASE_GRACE_MS = 10 * 60 * 1e3;
20605
+ var HOOK_RUNTIME_ENTRIES = {
20606
+ // SessionStart self-healing resolves this exact CLI entry to run
20607
+ // `daemon ensure`; it must travel with the immutable hook release.
20608
+ prim: "dist/index.js",
20609
+ "prim-hook": "dist/hooks/prim-hook.js",
20610
+ "prim-pre-commit": "dist/hooks/pre-commit.js",
20611
+ "prim-post-commit": "dist/hooks/post-commit.js",
20612
+ "prim-post-rewrite": "dist/hooks/post-rewrite.js",
20613
+ "prim-pre-tool-use": "dist/hooks/pre-tool-use.js",
20614
+ "prim-post-tool-use": "dist/hooks/post-tool-use.js",
20615
+ "prim-session-start": "dist/hooks/session-start.js",
20616
+ "prim-session-end": "dist/hooks/session-end.js",
20617
+ "prim-daemon-server": "dist/daemon/server.js",
20618
+ "prim-statusline": "dist/statusline-main.js"
20619
+ };
20620
+ var SOURCE_ENTRIES = Object.fromEntries(
20621
+ Object.entries(HOOK_RUNTIME_ENTRIES).map(([bin, target]) => [
20622
+ bin,
20623
+ target.replace(/^dist\//u, "")
20624
+ ])
20625
+ );
20626
+ var STABLE_HOOK_LAUNCHER_CONTENT = `#!/bin/sh
20627
+ set -eu
20628
+ case "$0" in */*) prim_launcher_dir=\${0%/*} ;; *) exit 78 ;; esac
20629
+ IFS= read -r prim_release_name < "$prim_launcher_dir/hook-runtime/current" || exit 69
20630
+ case "$prim_release_name" in ${RELEASE_PREFIX}*) ;; *) exit 69 ;; esac
20631
+ prim_release_id=\${prim_release_name#${RELEASE_PREFIX}}
20632
+ case "$prim_release_id" in *[!0-9a-f]*|"") exit 69 ;; esac
20633
+ [ "\${#prim_release_id}" -eq 64 ] || exit 69
20634
+ prim_release="$prim_launcher_dir/hook-runtime/releases/$prim_release_name"
20635
+ case "\${1-}" in
20636
+ ${Object.entries(HOOK_RUNTIME_ENTRIES).map(([bin, entry]) => ` ${bin}) prim_entry="$prim_release/${entry}" ;;`).join("\n")}
20637
+ *) exit 64 ;;
20638
+ esac
20639
+ shift
20640
+ IFS= read -r prim_node < "$prim_release/node" || exit 69
20641
+ case "$prim_node" in /*) ;; *) exit 69 ;; esac
20642
+ [ -x "$prim_node" ] && [ -f "$prim_entry" ] || exit 69
20643
+ exec "$prim_node" "$prim_entry" "$@"
20644
+ `;
20645
+
20646
+ // src/commands/claude-install.ts
20647
+ import { existsSync as existsSync8, readFileSync as readFileSync10 } from "fs";
20648
+ import { homedir as homedir3 } from "os";
20649
+ import { join as join12 } from "path";
20650
+ var CAPTURE_BIN = "prim-hook";
20651
+ var GATE_BIN = "prim-pre-tool-use";
20652
+ var POST_TOOL_USE_BIN = "prim-post-tool-use";
20653
+ var SESSION_START_BIN = "prim-session-start";
20654
+ var SESSION_END_BIN = "prim-session-end";
20655
+ var STATUSLINE_BIN = "prim-statusline";
20656
+ var STATUSLINE_ARGS = "";
20657
+ var STATUSLINE_COMMAND = stableHookCommand(STATUSLINE_BIN, STATUSLINE_ARGS);
20658
+ var USER_SCOPE_PATH = join12(homedir3(), ".claude", "settings.json");
20659
+ function projectRoot() {
20660
+ return gitToplevel() ?? process.cwd();
20661
+ }
20662
+ var CAPTURE_EVENTS = [
20663
+ "SessionStart",
20664
+ "UserPromptSubmit",
20665
+ "PreToolUse",
20666
+ "PostToolUse",
20667
+ "PostToolUseFailure",
20668
+ "Stop",
20669
+ "SessionEnd",
20670
+ "SubagentStop"
20671
+ ];
20672
+ function makeRegistration(event, matcher, bin, args = "") {
20673
+ return {
20674
+ event,
20675
+ matcher,
20676
+ bin,
20677
+ command: stableHookCommand(bin, args)
20678
+ };
20679
+ }
20680
+ function makeDetachedRegistration(event, matcher, bin, args = "") {
20681
+ return { event, matcher, bin, command: detachedHookShimCommand(bin, args) };
20682
+ }
20683
+ var REGISTRATIONS = [
20684
+ ...CAPTURE_EVENTS.map(
20685
+ (event) => event === "SessionEnd" ? makeDetachedRegistration(event, "*", CAPTURE_BIN) : makeRegistration(event, "*", CAPTURE_BIN)
20686
+ ),
20687
+ makeRegistration("PreToolUse", "Edit|Write|MultiEdit|NotebookEdit|Bash", GATE_BIN),
20688
+ makeRegistration("PostToolUse", "Edit|Write|MultiEdit|NotebookEdit|Bash", POST_TOOL_USE_BIN),
20689
+ makeRegistration(
20690
+ "PostToolUseFailure",
20691
+ "Edit|Write|MultiEdit|NotebookEdit|Bash",
20692
+ POST_TOOL_USE_BIN
20693
+ ),
20694
+ makeRegistration("SessionStart", "*", SESSION_START_BIN),
20695
+ makeDetachedRegistration("SessionEnd", "*", SESSION_END_BIN)
20696
+ ];
20697
+ var PRIM_PERMISSION_RULE = "Bash(npx --yes @primitive.ai/prim*)";
20698
+ var LEGACY_PRIM_PERMISSION_RULES = [
20699
+ "Bash(npx --yes @primitive.ai/prim@latest:*)",
20700
+ "Bash(npx --yes @primitive.ai/prim:*)"
20701
+ ];
20702
+ var ALL_PRIM_PERMISSION_RULES = /* @__PURE__ */ new Set([
20703
+ PRIM_PERMISSION_RULE,
20704
+ ...LEGACY_PRIM_PERMISSION_RULES
20705
+ ]);
20706
+
20707
+ // src/commands/cursor-install.ts
20708
+ var CAPTURE_BIN2 = "prim-hook";
20709
+ var GATE_BIN2 = "prim-pre-tool-use";
20710
+ var POST_TOOL_BIN = "prim-post-tool-use";
20711
+ var SESSION_START_BIN2 = "prim-session-start";
20712
+ var SESSION_END_BIN2 = "prim-session-end";
20713
+ var STATUSLINE_BIN2 = "prim-statusline";
20714
+ var CURSOR_EVENTS = [
20715
+ "sessionStart",
20716
+ "beforeSubmitPrompt",
20717
+ "preToolUse",
20718
+ "postToolUse",
20719
+ "postToolUseFailure",
20720
+ "afterAgentResponse",
20721
+ "subagentStop",
20722
+ "stop",
20723
+ "sessionEnd"
20724
+ ];
20725
+ var REGISTRATIONS2 = [
20726
+ ...CURSOR_EVENTS.map((event) => ({ event, bin: CAPTURE_BIN2 })),
20727
+ { event: "preToolUse", bin: GATE_BIN2, matcher: "Write|Delete|Shell", timeout: 10 },
20728
+ { event: "postToolUse", bin: POST_TOOL_BIN },
20729
+ { event: "postToolUseFailure", bin: POST_TOOL_BIN },
20730
+ { event: "sessionStart", bin: SESSION_START_BIN2 },
20731
+ { event: "sessionEnd", bin: SESSION_END_BIN2 }
20732
+ ];
20733
+ function cursorConfigDirectory(env = process.env, home = homedir4(), platform2 = process.platform) {
20734
+ const explicit = env.CURSOR_CONFIG_DIR?.trim();
20735
+ if (explicit && isAbsolute6(explicit)) return explicit;
20736
+ const xdg = env.XDG_CONFIG_HOME?.trim();
20737
+ if (platform2 !== "darwin" && xdg && isAbsolute6(xdg)) return join13(xdg, "cursor");
20738
+ return join13(home, ".cursor");
20739
+ }
20740
+ function cursorHooksPath(scope, root = projectRoot()) {
20741
+ return scope === "user" ? join13(cursorConfigDirectory(), "hooks.json") : join13(root, ".cursor", "hooks.json");
20742
+ }
20743
+ function plainObject(value) {
20744
+ return typeof value === "object" && value !== null && !Array.isArray(value);
20745
+ }
20746
+ function readCursorHooks(path) {
20747
+ if (!existsSync9(path)) return {};
20748
+ let parsed;
20749
+ try {
20750
+ parsed = JSON.parse(readFileSync11(path, "utf8"));
20751
+ } catch {
20752
+ throw new Error(`invalid Cursor hooks JSON at ${path}`);
20753
+ }
20754
+ if (!plainObject(parsed)) throw new Error(`Cursor hooks config must be an object: ${path}`);
20755
+ if (parsed.version !== void 0 && parsed.version !== 1) {
20756
+ throw new Error(`unsupported Cursor hooks version at ${path} (expected version 1)`);
20757
+ }
20758
+ if (parsed.hooks !== void 0) {
20759
+ if (!plainObject(parsed.hooks)) throw new Error(`Cursor hooks must be an object: ${path}`);
20760
+ for (const [event, entries] of Object.entries(parsed.hooks)) {
20761
+ if (!Array.isArray(entries) || !entries.every(plainObject)) {
20762
+ throw new Error(`Cursor hook list must contain objects: ${event} in ${path}`);
20763
+ }
20764
+ }
20765
+ }
20766
+ return parsed;
20767
+ }
20768
+ function commandFor(registration, scope) {
20769
+ return stableHookCommand(
20770
+ registration.bin,
20771
+ `--agent cursor --event ${registration.event} --scope ${scope}`
20772
+ );
20773
+ }
20774
+ var OWNED_COMMANDS = new Set(
20775
+ ["project", "user"].flatMap(
20776
+ (scope) => REGISTRATIONS2.map((registration) => commandFor(registration, scope))
20777
+ )
20778
+ );
20779
+ function jsoncUnsafeCommand(command) {
20780
+ return command.replace('case "$1" in [/]* ', 'case "$1" in /*').replace("*[/][/]*", "*//*").replace("*[/].[/]*", "*/./*").replace("*[/]..[/]*", "*/../*").replace("*[/].", "*/.").replace("*[/]..", "*/..").replace("?*[/]", "?*/");
20781
+ }
20782
+ var JSONC_UNSAFE_OWNED_COMMANDS = new Set([...OWNED_COMMANDS].map(jsoncUnsafeCommand));
20783
+ function hookFor(registration, scope) {
20784
+ return {
20785
+ command: commandFor(registration, scope),
20786
+ ...registration.matcher ? { matcher: registration.matcher } : {},
20787
+ ...registration.timeout ? { timeout: registration.timeout } : {}
20788
+ };
20789
+ }
20790
+ function exactHook(entry, registration, scope) {
20791
+ return JSON.stringify(entry) === JSON.stringify(hookFor(registration, scope));
20792
+ }
20793
+ function hasExactCursorHandler(settings, event, bin, scope) {
20794
+ const registration = REGISTRATIONS2.find(
20795
+ (candidate) => candidate.event === event && candidate.bin === bin
20796
+ );
20797
+ return registration ? (settings.hooks?.[event] ?? []).some((entry) => exactHook(entry, registration, scope)) : false;
20798
+ }
20799
+ var FOOTER = {
20800
+ type: "command",
20801
+ command: stableHookCommand(STATUSLINE_BIN2),
20802
+ updateIntervalMs: 1e3,
20803
+ timeoutMs: 2e3
20804
+ };
20805
+ var JSONC_UNSAFE_FOOTER = {
20806
+ ...FOOTER,
20807
+ command: jsoncUnsafeCommand(FOOTER.command)
20808
+ };
20809
+
20810
+ // src/hooks/cursor-coexistence.ts
20811
+ var CURSOR_EVENTS2 = /* @__PURE__ */ new Set([
20812
+ "sessionStart",
20813
+ "beforeSubmitPrompt",
20814
+ "preToolUse",
20815
+ "postToolUse",
20816
+ "postToolUseFailure",
20817
+ "afterAgentResponse",
20818
+ "subagentStop",
20819
+ "stop",
20820
+ "sessionEnd"
20821
+ ]);
20822
+ function cursorEvidence(parsed) {
20823
+ return typeof parsed.cursor_version === "string" && parsed.cursor_version.length > 0 && typeof parsed.conversation_id === "string" && parsed.conversation_id.length > 0 && typeof parsed.generation_id === "string" && parsed.generation_id.length > 0 && Array.isArray(parsed.workspace_roots) && typeof parsed.hook_event_name === "string" && CURSOR_EVENTS2.has(parsed.hook_event_name);
20824
+ }
20825
+ function uniqueProjectRoot(parsed) {
20826
+ if (!Array.isArray(parsed.workspace_roots)) return;
20827
+ const roots = new Set(
20828
+ parsed.workspace_roots.filter((value) => typeof value === "string" && value.length > 0).map((value) => resolveRepositoryContext(value)?.repoRoot).filter((value) => !!value)
20829
+ );
20830
+ return roots.size === 1 ? [...roots][0] : void 0;
20831
+ }
20832
+ function shouldSuppressImportedCursorHandler(parsed, bin) {
20833
+ if (!cursorEvidence(parsed)) return false;
20834
+ const project = uniqueProjectRoot(parsed);
20835
+ if (project) {
20836
+ try {
20837
+ if (hasExactCursorHandler(
20838
+ readCursorHooks(cursorHooksPath("project", project)),
20839
+ parsed.hook_event_name,
20840
+ bin,
20841
+ "project"
20842
+ )) {
20843
+ return true;
20844
+ }
20845
+ } catch {
20846
+ }
20847
+ }
20848
+ try {
20849
+ return hasExactCursorHandler(
20850
+ readCursorHooks(cursorHooksPath("user")),
20851
+ parsed.hook_event_name,
20852
+ bin,
20853
+ "user"
20854
+ );
20855
+ } catch {
20856
+ return false;
20857
+ }
20858
+ }
20859
+
20539
20860
  // src/hooks/pre-tool-use-scoring.ts
20540
- import { isAbsolute as isAbsolute5, relative as relative2, sep as sep2 } from "path";
20861
+ import { isAbsolute as isAbsolute7, relative as relative2, sep as sep2 } from "path";
20541
20862
  var SUPPORTED_TOOLS = /* @__PURE__ */ new Set(["Edit", "Write", "MultiEdit", "NotebookEdit"]);
20542
20863
  var APPLY_PATCH_FILE_RE = /^\*\*\* (?:Update|Add|Delete) File: (?<path>.+)$/;
20543
20864
  var MOVE_FILE_RE = /^\*\*\* Move File:\s*(?<src>.+?)\s*->\s*(?<dst>.+?)\s*$/;
@@ -20608,10 +20929,25 @@ function extractHermesFileTargets(toolName, toolInput) {
20608
20929
  const mode = input.mode;
20609
20930
  return { paths, complete: paths.length > 0 && (mode === void 0 || mode === "replace") };
20610
20931
  }
20932
+ function extractCursorFileTargets(toolName, toolInput) {
20933
+ if (toolName !== "Write" && toolName !== "Delete") return null;
20934
+ if (!toolInput || typeof toolInput !== "object" || Array.isArray(toolInput)) {
20935
+ return { paths: [], complete: false };
20936
+ }
20937
+ const input = toolInput;
20938
+ const candidates = [input.file_path, input.path].filter(
20939
+ (value) => typeof value === "string" && value.length > 0
20940
+ );
20941
+ const paths = [...new Set(candidates)];
20942
+ return { paths, complete: paths.length === 1 };
20943
+ }
20611
20944
  function extractFileTargets(toolName, toolInput, agent = "claude_code") {
20612
20945
  if (agent === "codex") {
20613
20946
  return extractCodexFileTargets(toolName, toolInput);
20614
20947
  }
20948
+ if (agent === "cursor") {
20949
+ return extractCursorFileTargets(toolName, toolInput);
20950
+ }
20615
20951
  if (agent === "hermes") {
20616
20952
  return extractHermesFileTargets(toolName, toolInput);
20617
20953
  }
@@ -25078,7 +25414,8 @@ function preserveHookFileMetadata(payload, resolution) {
25078
25414
  return { ...payload, primitive };
25079
25415
  }
25080
25416
  function resolveHookFileRefs(args) {
25081
- const command = (args.agent === "claude_code" || args.agent === "codex") && args.toolName === "Bash" ? typeof args.toolInput === "string" ? args.toolInput : args.toolInput && typeof args.toolInput === "object" && typeof args.toolInput.command === "string" ? args.toolInput.command : void 0 : void 0;
25417
+ const isShellTool = (args.agent === "claude_code" || args.agent === "codex") && args.toolName === "Bash" || args.agent === "cursor" && args.toolName === "Shell";
25418
+ const command = isShellTool ? typeof args.toolInput === "string" ? args.toolInput : args.toolInput && typeof args.toolInput === "object" && typeof args.toolInput.command === "string" ? args.toolInput.command : void 0 : void 0;
25082
25419
  const shell = command === void 0 ? void 0 : analyzeShellTargets(command);
25083
25420
  const shellMutation = shell?.mutation === "none" ? "none" : shell?.coverage === "complete" ? "resolved" : shell ? "unresolved" : void 0;
25084
25421
  const readPath = args.agent === "claude_code" && args.toolName === "Read" && args.toolInput && typeof args.toolInput === "object" && typeof args.toolInput.file_path === "string" ? [args.toolInput.file_path] : void 0;
@@ -25123,8 +25460,41 @@ function enrichHookPayloadWithFileRefs(args) {
25123
25460
  };
25124
25461
  }
25125
25462
 
25463
+ // src/hooks/hook-stdin.ts
25464
+ var DEFAULT_MAX_BYTES = 1024 * 1024;
25465
+ function readHookStdin(timeoutMs = 1e3, maxBytes = DEFAULT_MAX_BYTES) {
25466
+ return new Promise((resolve6, reject) => {
25467
+ const chunks = [];
25468
+ let bytes = 0;
25469
+ let settled = false;
25470
+ const finish2 = (error) => {
25471
+ if (settled) return;
25472
+ settled = true;
25473
+ clearTimeout(timer);
25474
+ process.stdin.removeAllListeners("data");
25475
+ process.stdin.removeAllListeners("end");
25476
+ process.stdin.removeAllListeners("error");
25477
+ if (error) reject(error);
25478
+ else resolve6(Buffer.concat(chunks, bytes).toString("utf-8"));
25479
+ };
25480
+ const timer = setTimeout(() => finish2(new Error("stdin read timeout")), timeoutMs);
25481
+ process.stdin.on("data", (chunk) => {
25482
+ bytes += chunk.length;
25483
+ if (bytes > maxBytes) {
25484
+ finish2(new Error("stdin envelope exceeds size limit"));
25485
+ return;
25486
+ }
25487
+ chunks.push(chunk);
25488
+ });
25489
+ process.stdin.on("end", () => finish2());
25490
+ process.stdin.on("error", (error) => finish2(error));
25491
+ });
25492
+ }
25493
+
25126
25494
  // src/hooks/normalize.ts
25127
- import { createHash as createHash6 } from "crypto";
25495
+ import { createHash as createHash7 } from "crypto";
25496
+ import { realpathSync as realpathSync3 } from "fs";
25497
+ import { isAbsolute as isAbsolute8, resolve as resolve5 } from "path";
25128
25498
  var HERMES_EVENT_MAP = {
25129
25499
  on_session_start: "SessionStart",
25130
25500
  on_session_end: "SessionEnd",
@@ -25134,7 +25504,125 @@ var HERMES_EVENT_MAP = {
25134
25504
  post_tool_call: "PostToolUse",
25135
25505
  subagent_stop: "SubagentStop"
25136
25506
  };
25507
+ var CURSOR_EVENT_MAP = {
25508
+ sessionStart: "SessionStart",
25509
+ beforeSubmitPrompt: "UserPromptSubmit",
25510
+ preToolUse: "PreToolUse",
25511
+ postToolUse: "PostToolUse",
25512
+ postToolUseFailure: "PostToolUseFailure",
25513
+ afterAgentResponse: "AssistantResponse",
25514
+ subagentStop: "SubagentStop",
25515
+ stop: "Stop",
25516
+ sessionEnd: "SessionEnd"
25517
+ };
25518
+ var CURSOR_TOOL_EVENTS = /* @__PURE__ */ new Set(["PreToolUse", "PostToolUse", "PostToolUseFailure"]);
25519
+ var SAFE_CORRELATION_ID_RE = /^[A-Za-z0-9._:-]{1,128}$/u;
25520
+ var CURSOR_LOCAL_ONLY_FIELDS = /* @__PURE__ */ new Set([
25521
+ "conversation_id",
25522
+ "generation_id",
25523
+ "user_email",
25524
+ "account_email",
25525
+ "transcript_path",
25526
+ "transcript",
25527
+ "thought",
25528
+ "thoughts",
25529
+ "thinking",
25530
+ "tool_output"
25531
+ ]);
25532
+ function requiredId(value, field) {
25533
+ if (typeof value !== "string" || value.length === 0) {
25534
+ throw new TypeError(`Cursor hook envelope is missing ${field}`);
25535
+ }
25536
+ return value;
25537
+ }
25538
+ function cursorToolUseId(value) {
25539
+ if (SAFE_CORRELATION_ID_RE.test(value)) return value;
25540
+ return `cursor:tool:v1:${createHash7("sha256").update(value).digest("hex")}`;
25541
+ }
25542
+ function workspaceCandidates(value) {
25543
+ if (!Array.isArray(value)) return [];
25544
+ const roots = value.filter((item) => typeof item === "string" && item.length > 0);
25545
+ if (roots.some((root) => !isAbsolute8(root))) {
25546
+ throw new TypeError("Cursor workspace roots must be absolute");
25547
+ }
25548
+ return roots;
25549
+ }
25550
+ function pathIdentity(path) {
25551
+ try {
25552
+ return realpathSync3.native(path);
25553
+ } catch {
25554
+ return resolve5(path);
25555
+ }
25556
+ }
25557
+ function resolveCursorCwd(parsed) {
25558
+ const roots = workspaceCandidates(parsed.workspace_roots).map(pathIdentity);
25559
+ const rootRepositories = roots.map((root) => resolveRepositoryContext(root)?.repoRoot);
25560
+ const repositoryRoots = new Set(rootRepositories.filter((root) => !!root));
25561
+ if (repositoryRoots.size > 1) {
25562
+ throw new TypeError("Cursor hook envelope spans multiple repositories");
25563
+ }
25564
+ if (roots.length > 1 && rootRepositories.some((root) => root === void 0)) {
25565
+ throw new TypeError("Cursor hook envelope has ambiguous workspace roots");
25566
+ }
25567
+ const expectedRepo = [...repositoryRoots][0];
25568
+ const rawCwd = typeof parsed.cwd === "string" && parsed.cwd.length > 0 ? parsed.cwd : void 0;
25569
+ if (rawCwd && !isAbsolute8(rawCwd)) {
25570
+ throw new TypeError("Cursor hook cwd must be absolute");
25571
+ }
25572
+ const envelopeCwd = rawCwd ? pathIdentity(rawCwd) : void 0;
25573
+ const input = typeof parsed.tool_input === "object" && parsed.tool_input !== null && !Array.isArray(parsed.tool_input) ? parsed.tool_input : void 0;
25574
+ const rawToolCwd = parsed.tool_name === "Shell" && typeof input?.working_directory === "string" ? input.working_directory : void 0;
25575
+ const base = envelopeCwd ?? (roots.length === 1 ? roots[0] : expectedRepo);
25576
+ if (rawToolCwd && !isAbsolute8(rawToolCwd) && !base) {
25577
+ throw new TypeError("relative Cursor tool cwd has no workspace base");
25578
+ }
25579
+ const toolCwd = rawToolCwd ? pathIdentity(isAbsolute8(rawToolCwd) ? rawToolCwd : resolve5(base, rawToolCwd)) : void 0;
25580
+ const selected = toolCwd ?? envelopeCwd ?? (roots.length === 1 ? roots[0] : expectedRepo);
25581
+ if (!selected) {
25582
+ throw new TypeError("Cursor hook envelope has no unambiguous workspace");
25583
+ }
25584
+ const selectedRepo = resolveRepositoryContext(selected)?.repoRoot;
25585
+ if (expectedRepo && selectedRepo !== expectedRepo) {
25586
+ throw new TypeError("Cursor hook cwd conflicts with workspace repository");
25587
+ }
25588
+ return selected;
25589
+ }
25590
+ function normalizeCursorEnvelope(parsed) {
25591
+ const rawEvent = requiredId(parsed.hook_event_name, "hook_event_name");
25592
+ const event = CURSOR_EVENT_MAP[rawEvent];
25593
+ if (!event) throw new TypeError(`unsupported Cursor hook event: ${rawEvent}`);
25594
+ const sessionId = requiredId(parsed.conversation_id, "conversation_id");
25595
+ const turnId = requiredId(parsed.generation_id, "generation_id");
25596
+ if (parsed.session_id !== void 0 && parsed.session_id !== sessionId) {
25597
+ throw new TypeError("Cursor conversation_id conflicts with session_id");
25598
+ }
25599
+ if (parsed.turn_id !== void 0 && parsed.turn_id !== turnId) {
25600
+ throw new TypeError("Cursor generation_id conflicts with turn_id");
25601
+ }
25602
+ const rawToolUseId = CURSOR_TOOL_EVENTS.has(event) ? requiredId(parsed.tool_use_id, "tool_use_id") : void 0;
25603
+ const normalized = {
25604
+ ...Object.fromEntries(
25605
+ Object.entries(parsed).filter(([key]) => !CURSOR_LOCAL_ONLY_FIELDS.has(key))
25606
+ ),
25607
+ hook_event_name: event,
25608
+ session_id: sessionId,
25609
+ turn_id: turnId,
25610
+ cwd: resolveCursorCwd(parsed),
25611
+ ...rawToolUseId === void 0 ? {} : { tool_use_id: cursorToolUseId(rawToolUseId) }
25612
+ };
25613
+ if (typeof parsed.tool_output === "string") {
25614
+ try {
25615
+ normalized.tool_response = JSON.parse(parsed.tool_output);
25616
+ } catch {
25617
+ normalized.tool_response = parsed.tool_output;
25618
+ }
25619
+ }
25620
+ return normalized;
25621
+ }
25137
25622
  function normalizeEnvelope(parsed, agent) {
25623
+ if (agent === "cursor") {
25624
+ return normalizeCursorEnvelope(parsed);
25625
+ }
25138
25626
  if (agent === "codex") {
25139
25627
  const event = parsed.hook_event_name;
25140
25628
  if ((event === "PreToolUse" || event === "PostToolUse") && (typeof parsed.tool_use_id !== "string" || parsed.tool_use_id.length === 0)) {
@@ -25146,7 +25634,7 @@ function normalizeEnvelope(parsed, agent) {
25146
25634
  ]);
25147
25635
  return {
25148
25636
  ...parsed,
25149
- tool_use_id: `codex:fallback:v1:${createHash6("sha256").update(stableToolIdentity).digest("hex")}`
25637
+ tool_use_id: `codex:fallback:v1:${createHash7("sha256").update(stableToolIdentity).digest("hex")}`
25150
25638
  };
25151
25639
  }
25152
25640
  return parsed;
@@ -25194,17 +25682,17 @@ function requireDurableIngestAcknowledgement(value, expected, cwd = process.cwd(
25194
25682
  import {
25195
25683
  appendFileSync,
25196
25684
  closeSync as closeSync3,
25197
- existsSync as existsSync7,
25685
+ existsSync as existsSync10,
25198
25686
  fstatSync,
25199
- mkdirSync as mkdirSync6,
25687
+ mkdirSync as mkdirSync7,
25200
25688
  openSync as openSync3,
25201
25689
  opendirSync,
25202
- readFileSync as readFileSync9,
25690
+ readFileSync as readFileSync12,
25203
25691
  readSync,
25204
- readdirSync as readdirSync2
25692
+ readdirSync as readdirSync3
25205
25693
  } from "fs";
25206
- import { dirname as dirname8, join as join11 } from "path";
25207
- var JOURNAL_DIR = join11(primConfigDirectory(), "moves");
25694
+ import { dirname as dirname10, join as join14 } from "path";
25695
+ var JOURNAL_DIR = join14(primConfigDirectory(), "moves");
25208
25696
  var UNBOUND_BUCKET = "_unbound";
25209
25697
  var JOURNAL_BASENAME = "journal.ndjson";
25210
25698
  var JOURNAL_STATS_SAMPLE_BYTES = 64 * 1024;
@@ -25216,26 +25704,26 @@ function envSlug(apiUrl) {
25216
25704
  return slug;
25217
25705
  }
25218
25706
  function currentEnvDir() {
25219
- return join11(JOURNAL_DIR, envSlug(getSiteUrl()));
25707
+ return join14(JOURNAL_DIR, envSlug(getSiteUrl()));
25220
25708
  }
25221
25709
  var DIR_MODE = 448;
25222
25710
  var FILE_MODE2 = 384;
25223
25711
  var SAFE_BUCKET = /^[A-Za-z0-9_-]+$/;
25224
25712
  var RESERVED_BUCKETS = /* @__PURE__ */ new Set([UNBOUND_BUCKET, "_legacy"]);
25225
25713
  function appendMoveToPath(path, move) {
25226
- const dir = dirname8(path);
25227
- if (!existsSync7(dir)) {
25228
- mkdirSync6(dir, { recursive: true, mode: DIR_MODE });
25714
+ const dir = dirname10(path);
25715
+ if (!existsSync10(dir)) {
25716
+ mkdirSync7(dir, { recursive: true, mode: DIR_MODE });
25229
25717
  }
25230
25718
  appendFileSync(path, `${JSON.stringify(move)}
25231
25719
  `, { mode: FILE_MODE2 });
25232
25720
  }
25233
25721
  function bucketDir(orgId) {
25234
25722
  const safe = orgId !== void 0 && SAFE_BUCKET.test(orgId) && !RESERVED_BUCKETS.has(orgId);
25235
- return join11(currentEnvDir(), safe ? orgId : UNBOUND_BUCKET);
25723
+ return join14(currentEnvDir(), safe ? orgId : UNBOUND_BUCKET);
25236
25724
  }
25237
25725
  function journalPath(orgId) {
25238
- return join11(bucketDir(orgId), JOURNAL_BASENAME);
25726
+ return join14(bucketDir(orgId), JOURNAL_BASENAME);
25239
25727
  }
25240
25728
  function appendMove(move, orgId) {
25241
25729
  appendMoveToPath(journalPath(orgId), move);
@@ -25255,15 +25743,15 @@ async function deliverPostToolMove(move, orgId) {
25255
25743
  }
25256
25744
 
25257
25745
  // src/hooks/prim-hook-core.ts
25258
- import { createHash as createHash7, randomUUID as randomUUID3 } from "crypto";
25746
+ import { createHash as createHash8, randomUUID as randomUUID3 } from "crypto";
25259
25747
  import { platform } from "os";
25260
25748
 
25261
25749
  // src/protocol/move.ts
25262
25750
  var AGENT_ENVELOPE_VERSION = 3;
25263
25751
 
25264
25752
  // src/hooks/redact.ts
25265
- import { existsSync as existsSync8, readFileSync as readFileSync10, statSync as statSync4 } from "fs";
25266
- import { join as join12 } from "path";
25753
+ import { existsSync as existsSync11, readFileSync as readFileSync13, statSync as statSync5 } from "fs";
25754
+ import { join as join15 } from "path";
25267
25755
  import { Worker } from "worker_threads";
25268
25756
 
25269
25757
  // src/lib/ansi.ts
@@ -25381,15 +25869,15 @@ function normalizedWorkspaceFlags(value) {
25381
25869
  return [...new Set(`g${requested}`)].sort().join("");
25382
25870
  }
25383
25871
  function loadWorkspaceRules(cwd) {
25384
- const path = join12(cwd, WORKSPACE_FILE2);
25385
- if (!existsSync8(path)) return [];
25872
+ const path = join15(cwd, WORKSPACE_FILE2);
25873
+ if (!existsSync11(path)) return [];
25386
25874
  let cfg;
25387
25875
  try {
25388
- if (statSync4(path).size > MAX_WORKSPACE_CONFIG_BYTES) {
25876
+ if (statSync5(path).size > MAX_WORKSPACE_CONFIG_BYTES) {
25389
25877
  debugRedaction(`ignoring oversized ${WORKSPACE_FILE2}`);
25390
25878
  return [];
25391
25879
  }
25392
- cfg = JSON.parse(readFileSync10(path, "utf-8"));
25880
+ cfg = JSON.parse(readFileSync13(path, "utf-8"));
25393
25881
  } catch {
25394
25882
  debugRedaction(`ignoring unparseable ${WORKSPACE_FILE2}`);
25395
25883
  return [];
@@ -25508,7 +25996,7 @@ function applyWorkspaceRules(value, rules) {
25508
25996
  flags: pattern.flags,
25509
25997
  reason
25510
25998
  }));
25511
- return new Promise((resolve4) => {
25999
+ return new Promise((resolve6) => {
25512
26000
  let worker;
25513
26001
  try {
25514
26002
  worker = new Worker(WORKSPACE_REDACTION_WORKER, {
@@ -25516,20 +26004,20 @@ function applyWorkspaceRules(value, rules) {
25516
26004
  workerData: { value, rules: serialized }
25517
26005
  });
25518
26006
  } catch {
25519
- resolve4(redactEveryString(value, "workspace-rule-failed"));
26007
+ resolve6(redactEveryString(value, "workspace-rule-failed"));
25520
26008
  return;
25521
26009
  }
25522
26010
  let settled = false;
25523
- const finish = (result) => {
26011
+ const finish2 = (result) => {
25524
26012
  if (settled) return;
25525
26013
  settled = true;
25526
26014
  clearTimeout(timer);
25527
26015
  void worker.terminate();
25528
- resolve4(result);
26016
+ resolve6(result);
25529
26017
  };
25530
- const failClosed = () => finish(redactEveryString(value, "workspace-rule-failed"));
26018
+ const failClosed = () => finish2(redactEveryString(value, "workspace-rule-failed"));
25531
26019
  const timer = setTimeout(failClosed, WORKSPACE_RULE_TIMEOUT_MS);
25532
- worker.once("message", finish);
26020
+ worker.once("message", finish2);
25533
26021
  worker.once("error", failClosed);
25534
26022
  worker.once("exit", (code) => {
25535
26023
  if (code !== 0) failClosed();
@@ -25579,6 +26067,17 @@ function toolOutcomeFor(parsed, agent) {
25579
26067
  if (agent === "codex") {
25580
26068
  return event === "PostToolUse" ? "returned" : void 0;
25581
26069
  }
26070
+ if (agent === "cursor") {
26071
+ if (event === "PostToolUse") return "succeeded";
26072
+ if (event === "PostToolUseFailure") {
26073
+ if (parsed.is_interrupt === true) return "interrupted";
26074
+ const failureType = lowerString(parsed.failure_type);
26075
+ if (failureType === "permission_denied") return "prevented";
26076
+ if (failureType === "error" || failureType === "timeout") return "failed";
26077
+ return "unknown";
26078
+ }
26079
+ return void 0;
26080
+ }
25582
26081
  const extra = parsed.extra;
25583
26082
  if (event === "post_approval_response") {
25584
26083
  const choice = lowerString(extra?.choice);
@@ -25608,9 +26107,9 @@ function toMove(parsed, cliVersion, agent = "claude_code", workspaceId, reposito
25608
26107
  const toolOutcome = toolOutcomeFor(parsed, agent);
25609
26108
  let moveId;
25610
26109
  if (CORRELATED_TOOL_EVENTS.has(eventType) && sessionId && invocationId) {
25611
- moveId = `posttool:v1:${createHash7("sha256").update(JSON.stringify([agent, sessionId, eventType, invocationId])).digest("hex")}`;
25612
- } else if (CORRELATED_TOOL_EVENTS.has(eventType) && sessionId) {
25613
- moveId = `posttool:fallback:v1:${createHash7("sha256").update(
26110
+ moveId = `posttool:v1:${createHash8("sha256").update(JSON.stringify([agent, sessionId, eventType, invocationId])).digest("hex")}`;
26111
+ } else if (CORRELATED_TOOL_EVENTS.has(eventType) && sessionId && agent !== "cursor") {
26112
+ moveId = `posttool:fallback:v1:${createHash8("sha256").update(
25614
26113
  JSON.stringify([
25615
26114
  agent,
25616
26115
  sessionId,
@@ -25670,6 +26169,7 @@ var STDIN_TIMEOUT_MS = 1e3;
25670
26169
  var EDITING_TOOLS = /* @__PURE__ */ new Set(["Edit", "Write", "MultiEdit", "NotebookEdit", "Bash"]);
25671
26170
  var CODEX_EDITING_TOOLS = /* @__PURE__ */ new Set(["apply_patch", "Bash"]);
25672
26171
  var HERMES_EDITING_TOOLS2 = /* @__PURE__ */ new Set(["write_file", "patch"]);
26172
+ var CURSOR_EDITING_TOOLS = /* @__PURE__ */ new Set(["Write", "Delete", "Shell"]);
25673
26173
  function editingToolsFor(agent) {
25674
26174
  if (agent === "codex") {
25675
26175
  return CODEX_EDITING_TOOLS;
@@ -25677,41 +26177,27 @@ function editingToolsFor(agent) {
25677
26177
  if (agent === "hermes") {
25678
26178
  return HERMES_EDITING_TOOLS2;
25679
26179
  }
26180
+ if (agent === "cursor") {
26181
+ return CURSOR_EDITING_TOOLS;
26182
+ }
25680
26183
  return EDITING_TOOLS;
25681
26184
  }
25682
- var here = dirname9(fileURLToPath2(import.meta.url));
26185
+ var here = dirname11(fileURLToPath2(import.meta.url));
25683
26186
  function resolveCliVersion() {
25684
26187
  try {
25685
- const pkg = JSON.parse(readFileSync11(join13(here, "..", "..", "package.json"), "utf-8"));
26188
+ const pkg = JSON.parse(readFileSync14(join16(here, "..", "..", "package.json"), "utf-8"));
25686
26189
  return pkg.version ?? "unknown";
25687
26190
  } catch {
25688
26191
  return "unknown";
25689
26192
  }
25690
26193
  }
25691
- function readStdin() {
25692
- return new Promise((resolve4, reject) => {
25693
- const chunks = [];
25694
- const timer = setTimeout(() => {
25695
- reject(new Error("stdin read timeout"));
25696
- }, STDIN_TIMEOUT_MS);
25697
- process.stdin.on("data", (chunk) => chunks.push(chunk));
25698
- process.stdin.on("end", () => {
25699
- clearTimeout(timer);
25700
- resolve4(Buffer.concat(chunks).toString("utf-8"));
25701
- });
25702
- process.stdin.on("error", (err) => {
25703
- clearTimeout(timer);
25704
- reject(err);
25705
- });
25706
- });
25707
- }
25708
26194
  async function emit(output = {}) {
25709
- return await new Promise((resolve4) => {
26195
+ return await new Promise((resolve6) => {
25710
26196
  try {
25711
26197
  process.stdout.write(`${JSON.stringify(output)}
25712
- `, (error) => resolve4(!error));
26198
+ `, (error) => resolve6(!error));
25713
26199
  } catch {
25714
- resolve4(false);
26200
+ resolve6(false);
25715
26201
  }
25716
26202
  });
25717
26203
  }
@@ -25719,6 +26205,30 @@ async function emitWithAcknowledgment(output, acknowledge) {
25719
26205
  const handedOff = await emit(output);
25720
26206
  await acknowledge?.(handedOff);
25721
26207
  }
26208
+ async function emitCursorContext(envelope) {
26209
+ if (typeof envelope.session_id !== "string" || envelope.session_id.length === 0 || typeof envelope.cwd !== "string" || envelope.cwd.length === 0) {
26210
+ await emit();
26211
+ return;
26212
+ }
26213
+ try {
26214
+ const context = await prepareCodexContext({
26215
+ cwd: envelope.cwd,
26216
+ sessionId: envelope.session_id,
26217
+ includeDigest: true,
26218
+ namespace: "cursor"
26219
+ });
26220
+ await emitWithAcknowledgment(
26221
+ context.context ? { additional_context: context.context } : {},
26222
+ context.acknowledge
26223
+ );
26224
+ } catch {
26225
+ await emit();
26226
+ }
26227
+ }
26228
+ async function finish(agent, envelope) {
26229
+ if (agent === "cursor" && envelope) await emitCursorContext(envelope);
26230
+ else await emit();
26231
+ }
25722
26232
  function debug(msg) {
25723
26233
  if (process.env.PRIM_HOOK_VERBOSE === "1") {
25724
26234
  process.stderr.write(`[prim-post-tool-use] ${msg}
@@ -25729,33 +26239,38 @@ async function main() {
25729
26239
  const agent = parseAgent(process.argv);
25730
26240
  let raw;
25731
26241
  try {
25732
- raw = await readStdin();
26242
+ raw = await readHookStdin(STDIN_TIMEOUT_MS);
25733
26243
  } catch {
25734
26244
  await emit();
25735
26245
  return;
25736
26246
  }
25737
26247
  let parsed;
25738
26248
  try {
25739
- parsed = normalizeEnvelope(JSON.parse(raw), agent);
26249
+ const incoming = JSON.parse(raw);
26250
+ if (agent !== "cursor" && shouldSuppressImportedCursorHandler(incoming, "prim-post-tool-use")) {
26251
+ await emit();
26252
+ return;
26253
+ }
26254
+ parsed = normalizeEnvelope(incoming, agent);
25740
26255
  } catch {
25741
26256
  await emit();
25742
26257
  return;
25743
26258
  }
25744
26259
  let envelope = parsed;
25745
- const isToolResult = envelope.hook_event_name === "PostToolUse" || agent === "claude_code" && envelope.hook_event_name === "PostToolUseFailure";
26260
+ const isToolResult = envelope.hook_event_name === "PostToolUse" || (agent === "claude_code" || agent === "cursor") && envelope.hook_event_name === "PostToolUseFailure";
25746
26261
  const isHermesDenial = agent === "hermes" && envelope.hook_event_name === "post_approval_response" && toolOutcomeFor(parsed, agent) === "prevented";
25747
26262
  if (!isToolResult && !isHermesDenial) {
25748
- await emit();
26263
+ await finish(agent, envelope);
25749
26264
  return;
25750
26265
  }
25751
26266
  const invocationId = postToolInvocationId(parsed, agent);
25752
26267
  if (isHermesDenial && !invocationId) {
25753
- await emit();
26268
+ await finish(agent, envelope);
25754
26269
  return;
25755
26270
  }
25756
26271
  const toolName = typeof envelope.tool_name === "string" ? envelope.tool_name : "";
25757
26272
  if (!isHermesDenial && !editingToolsFor(agent).has(toolName)) {
25758
- await emit();
26273
+ await finish(agent, envelope);
25759
26274
  return;
25760
26275
  }
25761
26276
  if (isHermesDenial && (typeof envelope.session_id !== "string" || envelope.session_id.length === 0) && typeof envelope.extra?.session_key === "string" && envelope.extra.session_key.length > 0) {
@@ -25763,17 +26278,17 @@ async function main() {
25763
26278
  envelope = parsed;
25764
26279
  }
25765
26280
  if (typeof envelope.session_id !== "string" || envelope.session_id.length === 0) {
25766
- await emit();
26281
+ await finish(agent, envelope);
25767
26282
  return;
25768
26283
  }
25769
26284
  const cwd = parsed.cwd ?? process.cwd();
25770
26285
  if (!isRepoActiveForCapture(cwd)) {
25771
- await emit();
26286
+ await finish(agent, envelope);
25772
26287
  return;
25773
26288
  }
25774
26289
  const resolvedRepository = resolveRepositoryContext(cwd);
25775
26290
  if (!resolvedRepository) {
25776
- await emit();
26291
+ await finish(agent, envelope);
25777
26292
  return;
25778
26293
  }
25779
26294
  const repository = { ...resolvedRepository, repoSyncId: repoSyncId(cwd) };
@@ -25786,23 +26301,27 @@ async function main() {
25786
26301
  const { resolution } = enrichment;
25787
26302
  if (!isHermesDenial) {
25788
26303
  if (resolution.shellMutation === "none") {
25789
- await emit();
26304
+ await finish(agent, envelope);
25790
26305
  return;
25791
26306
  }
25792
26307
  if (resolution.shellMutation === void 0 && resolution.fileRefs.length === 0) {
25793
- await emit();
26308
+ await finish(agent, envelope);
25794
26309
  return;
25795
26310
  }
25796
26311
  }
25797
26312
  const pathsComplete = !resolution.targetsIncomplete && !resolution.targetsTruncated && resolution.rejected.length === 0 && resolution.shellMutation !== "unresolved";
25798
26313
  const hasPathEvidence = resolution.fileRefs.length > 0 || resolution.rejected.length > 0 || resolution.targetsIncomplete || resolution.targetsTruncated || resolution.shellMutation === "unresolved";
26314
+ if (agent === "cursor" && (resolution.rejected.length > 0 || resolution.targetsIncomplete || resolution.targetsTruncated || resolution.shellMutation === "unresolved")) {
26315
+ await finish(agent, envelope);
26316
+ return;
26317
+ }
25799
26318
  if (!cachedCollectScopeAdmits(cwd, {
25800
26319
  repository: resolvedRepository.repoFullName,
25801
26320
  branch: currentBranch(cwd),
25802
26321
  agent,
25803
26322
  ...isHermesDenial || !hasPathEvidence ? {} : { paths: resolution.fileRefs, pathsComplete }
25804
26323
  })) {
25805
- await emit();
26324
+ await finish(agent, envelope);
25806
26325
  return;
25807
26326
  }
25808
26327
  const enriched = enrichment.parsed;
@@ -25839,7 +26358,7 @@ async function main() {
25839
26358
  } catch {
25840
26359
  }
25841
26360
  }
25842
- await emit();
26361
+ await finish(agent, envelope);
25843
26362
  }
25844
26363
  main().catch(async () => {
25845
26364
  await emit();