@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
@@ -53,8 +53,8 @@ var require_ucs2length = __commonJS({
53
53
 
54
54
  // src/hooks/prim-hook.ts
55
55
  import { spawn } from "child_process";
56
- import { readFileSync as readFileSync11 } from "fs";
57
- import { dirname as dirname9, join as join13 } from "path";
56
+ import { readFileSync as readFileSync14 } from "fs";
57
+ import { dirname as dirname11, join as join16 } from "path";
58
58
  import { fileURLToPath as fileURLToPath2 } from "url";
59
59
 
60
60
  // src/binding.ts
@@ -613,14 +613,14 @@ function throwIfAborted(signal) {
613
613
  }
614
614
  async function defaultSleep(ms, signal) {
615
615
  if (!signal) {
616
- await new Promise((resolve4) => setTimeout(resolve4, ms));
616
+ await new Promise((resolve6) => setTimeout(resolve6, ms));
617
617
  return;
618
618
  }
619
619
  throwIfAborted(signal);
620
- await new Promise((resolve4, reject) => {
620
+ await new Promise((resolve6, reject) => {
621
621
  const timer = setTimeout(() => {
622
622
  signal.removeEventListener("abort", onAbort);
623
- resolve4();
623
+ resolve6();
624
624
  }, ms);
625
625
  const onAbort = () => {
626
626
  clearTimeout(timer);
@@ -1591,7 +1591,7 @@ var PRIM_REPO_SYNC_REPOSITORY_KEY = "prim.repoSyncRepository";
1591
1591
  var PRIM_REPO_BINDING_STATE_KEY = "prim.repoBindingState";
1592
1592
  var GIT_TIMEOUT_MS2 = 1e3;
1593
1593
  var REPO_SYNC_ID_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/;
1594
- var PROJECT_INSTALL_FILES = [".claude/settings.json", ".codex/hooks.json"];
1594
+ var PROJECT_INSTALL_FILES = [".claude/settings.json", ".codex/hooks.json", ".cursor/hooks.json"];
1595
1595
  var PRIM_HOOK_BINS = ["prim-hook", "prim-pre-tool-use", "prim-post-tool-use"];
1596
1596
  function repoActiveFlag(cwd) {
1597
1597
  try {
@@ -2486,7 +2486,7 @@ function validate23(data, { instancePath = "", parentData, parentDataProperty, r
2486
2486
  return errors === 0;
2487
2487
  }
2488
2488
  validate23.evaluated = { "props": true, "dynamicProps": false, "dynamicItems": false };
2489
- 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": {} };
2489
+ 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": {} };
2490
2490
  function validate24(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
2491
2491
  ;
2492
2492
  let vErrors = null;
@@ -3037,7 +3037,7 @@ function validate24(data, { instancePath = "", parentData, parentDataProperty, r
3037
3037
  }
3038
3038
  errors++;
3039
3039
  }
3040
- if (!(data18 === "claude_code" || data18 === "codex" || data18 === "hermes")) {
3040
+ if (!(data18 === "claude_code" || data18 === "codex" || data18 === "cursor" || data18 === "hermes")) {
3041
3041
  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" };
3042
3042
  if (vErrors === null) {
3043
3043
  vErrors = [err34];
@@ -3806,7 +3806,7 @@ function validate26(data, { instancePath = "", parentData, parentDataProperty, r
3806
3806
  return errors === 0;
3807
3807
  }
3808
3808
  validate26.evaluated = { "dynamicProps": true, "dynamicItems": false };
3809
- 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"] };
3809
+ 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"] };
3810
3810
  function validate27(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
3811
3811
  ;
3812
3812
  let vErrors = null;
@@ -4510,7 +4510,7 @@ function validate27(data, { instancePath = "", parentData, parentDataProperty, r
4510
4510
  }
4511
4511
  errors++;
4512
4512
  }
4513
- if (!(data34 === "claude_code" || data34 === "codex" || data34 === "hermes")) {
4513
+ if (!(data34 === "claude_code" || data34 === "codex" || data34 === "cursor" || data34 === "hermes")) {
4514
4514
  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" };
4515
4515
  if (vErrors === null) {
4516
4516
  vErrors = [err19];
@@ -4738,7 +4738,7 @@ function validate27(data, { instancePath = "", parentData, parentDataProperty, r
4738
4738
  return errors === 0;
4739
4739
  }
4740
4740
  validate27.evaluated = { "props": true, "dynamicProps": false, "dynamicItems": false };
4741
- 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": {} };
4741
+ 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": {} };
4742
4742
  function validate28(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
4743
4743
  ;
4744
4744
  let vErrors = null;
@@ -5274,7 +5274,7 @@ function validate28(data, { instancePath = "", parentData, parentDataProperty, r
5274
5274
  }
5275
5275
  errors++;
5276
5276
  }
5277
- if (!(data22 === "claude_code" || data22 === "codex" || data22 === "hermes")) {
5277
+ if (!(data22 === "claude_code" || data22 === "codex" || data22 === "cursor" || data22 === "hermes")) {
5278
5278
  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" };
5279
5279
  if (vErrors === null) {
5280
5280
  vErrors = [err19];
@@ -5506,7 +5506,7 @@ function validate28(data, { instancePath = "", parentData, parentDataProperty, r
5506
5506
  return errors === 0;
5507
5507
  }
5508
5508
  validate28.evaluated = { "props": true, "dynamicProps": false, "dynamicItems": false };
5509
- 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": {} };
5509
+ 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": {} };
5510
5510
  function validate29(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
5511
5511
  ;
5512
5512
  let vErrors = null;
@@ -6800,7 +6800,7 @@ function validate29(data, { instancePath = "", parentData, parentDataProperty, r
6800
6800
  }
6801
6801
  errors++;
6802
6802
  }
6803
- if (!(data70 === "claude_code" || data70 === "codex" || data70 === "hermes")) {
6803
+ if (!(data70 === "claude_code" || data70 === "codex" || data70 === "cursor" || data70 === "hermes")) {
6804
6804
  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" };
6805
6805
  if (vErrors === null) {
6806
6806
  vErrors = [err24];
@@ -7361,7 +7361,7 @@ function validate33(data, { instancePath = "", parentData, parentDataProperty, r
7361
7361
  return errors === 0;
7362
7362
  }
7363
7363
  validate33.evaluated = { "props": true, "dynamicProps": false, "dynamicItems": false };
7364
- 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": {} };
7364
+ 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": {} };
7365
7365
  function validate34(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
7366
7366
  ;
7367
7367
  let vErrors = null;
@@ -8002,7 +8002,7 @@ function validate34(data, { instancePath = "", parentData, parentDataProperty, r
8002
8002
  }
8003
8003
  errors++;
8004
8004
  }
8005
- if (!(data19 === "claude_code" || data19 === "codex" || data19 === "hermes")) {
8005
+ if (!(data19 === "claude_code" || data19 === "codex" || data19 === "cursor" || data19 === "hermes")) {
8006
8006
  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" };
8007
8007
  if (vErrors === null) {
8008
8008
  vErrors = [err38];
@@ -8230,7 +8230,7 @@ function validate34(data, { instancePath = "", parentData, parentDataProperty, r
8230
8230
  return errors === 0;
8231
8231
  }
8232
8232
  validate34.evaluated = { "props": true, "dynamicProps": false, "dynamicItems": false };
8233
- 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": {} }] };
8233
+ 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": {} }] };
8234
8234
  function validate35(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
8235
8235
  ;
8236
8236
  let vErrors = null;
@@ -8868,7 +8868,7 @@ function validate35(data, { instancePath = "", parentData, parentDataProperty, r
8868
8868
  }
8869
8869
  errors++;
8870
8870
  }
8871
- if (!(data21 === "claude_code" || data21 === "codex" || data21 === "hermes")) {
8871
+ if (!(data21 === "claude_code" || data21 === "codex" || data21 === "cursor" || data21 === "hermes")) {
8872
8872
  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" };
8873
8873
  if (vErrors === null) {
8874
8874
  vErrors = [err41];
@@ -9792,7 +9792,7 @@ function validate35(data, { instancePath = "", parentData, parentDataProperty, r
9792
9792
  }
9793
9793
  errors++;
9794
9794
  }
9795
- if (!(data49 === "claude_code" || data49 === "codex" || data49 === "hermes")) {
9795
+ if (!(data49 === "claude_code" || data49 === "codex" || data49 === "cursor" || data49 === "hermes")) {
9796
9796
  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" };
9797
9797
  if (vErrors === null) {
9798
9798
  vErrors = [err100];
@@ -15438,7 +15438,7 @@ function validate50(data, { instancePath = "", parentData, parentDataProperty, r
15438
15438
  return errors === 0;
15439
15439
  }
15440
15440
  validate50.evaluated = { "dynamicProps": true, "dynamicItems": false };
15441
- 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": {} };
15441
+ 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": {} };
15442
15442
  var pattern8 = new RegExp("^[A-Za-z0-9_-]+$", "u");
15443
15443
  function validate51(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
15444
15444
  ;
@@ -15692,7 +15692,7 @@ function validate51(data, { instancePath = "", parentData, parentDataProperty, r
15692
15692
  }
15693
15693
  errors++;
15694
15694
  }
15695
- if (!(data10 === "claude_code" || data10 === "codex" || data10 === "hermes")) {
15695
+ if (!(data10 === "claude_code" || data10 === "codex" || data10 === "cursor" || data10 === "hermes")) {
15696
15696
  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" };
15697
15697
  if (vErrors === null) {
15698
15698
  vErrors = [err16];
@@ -16004,7 +16004,7 @@ function validate51(data, { instancePath = "", parentData, parentDataProperty, r
16004
16004
  }
16005
16005
  errors++;
16006
16006
  }
16007
- if (!(data21 === "claude_code" || data21 === "codex" || data21 === "hermes")) {
16007
+ if (!(data21 === "claude_code" || data21 === "codex" || data21 === "cursor" || data21 === "hermes")) {
16008
16008
  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" };
16009
16009
  if (vErrors === null) {
16010
16010
  vErrors = [err38];
@@ -16141,7 +16141,7 @@ function validate51(data, { instancePath = "", parentData, parentDataProperty, r
16141
16141
  return errors === 0;
16142
16142
  }
16143
16143
  validate51.evaluated = { "props": true, "dynamicProps": false, "dynamicItems": false };
16144
- 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"] };
16144
+ 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"] };
16145
16145
  var pattern10 = new RegExp("^[A-Za-z0-9._:-]{1,128}$", "u");
16146
16146
  var pattern12 = new RegExp("^[A-Za-z0-9]{1,64}$", "u");
16147
16147
  var pattern13 = new RegExp("^(?!@?$)(?!\\/)(?!.*\\/$)(?!.*\\/\\/)(?!.*(?:^|\\/)\\.{1,2}(?:\\/|$))(?!.*(?:^|\\/)[^/]*\\.lock(?:\\/|$))(?!.*\\.\\.)(?!.*@\\{)(?!.*[~^:?*\\\\]).+$", "u");
@@ -16197,7 +16197,7 @@ function validate52(data, { instancePath = "", parentData, parentDataProperty, r
16197
16197
  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" }];
16198
16198
  return false;
16199
16199
  }
16200
- if (!(data1 === "claude_code" || data1 === "codex" || data1 === "hermes")) {
16200
+ if (!(data1 === "claude_code" || data1 === "codex" || data1 === "cursor" || data1 === "hermes")) {
16201
16201
  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" }];
16202
16202
  return false;
16203
16203
  }
@@ -19572,7 +19572,7 @@ function optionalUserScopeMembers(record) {
19572
19572
  members.push({ kind: "role", role: candidate.role });
19573
19573
  continue;
19574
19574
  }
19575
- if (candidate.kind === "agent" && (candidate.agent === "claude_code" || candidate.agent === "codex" || candidate.agent === "hermes")) {
19575
+ if (candidate.kind === "agent" && (candidate.agent === "claude_code" || candidate.agent === "codex" || candidate.agent === "cursor" || candidate.agent === "hermes")) {
19576
19576
  members.push({ kind: "agent", agent: candidate.agent });
19577
19577
  continue;
19578
19578
  }
@@ -19945,7 +19945,7 @@ function errorCode(error) {
19945
19945
  function parseAgent(argv) {
19946
19946
  const i = argv.indexOf("--agent");
19947
19947
  const value = i !== -1 ? argv[i + 1] : void 0;
19948
- if (value === "codex" || value === "hermes") {
19948
+ if (value === "codex" || value === "cursor" || value === "hermes") {
19949
19949
  return value;
19950
19950
  }
19951
19951
  return "claude_code";
@@ -20032,7 +20032,7 @@ function daemonRequest(method, params = {}, opts = {}) {
20032
20032
  ...caller ? { caller } : {}
20033
20033
  };
20034
20034
  const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
20035
- return new Promise((resolve4) => {
20035
+ return new Promise((resolve6) => {
20036
20036
  let settled = false;
20037
20037
  let socket;
20038
20038
  let buffer = Buffer.alloc(0);
@@ -20047,7 +20047,7 @@ function daemonRequest(method, params = {}, opts = {}) {
20047
20047
  } catch {
20048
20048
  }
20049
20049
  }
20050
- resolve4(value);
20050
+ resolve6(value);
20051
20051
  };
20052
20052
  const timer = setTimeout(() => settle(null), timeoutMs);
20053
20053
  timer.unref();
@@ -20125,6 +20125,7 @@ import { dirname as dirname8, isAbsolute as isAbsolute4, join as join10 } from "
20125
20125
  import { fileURLToPath } from "url";
20126
20126
  var PKG_NAME = "@primitive.ai/prim";
20127
20127
  var ROOT_WALK_LIMIT = 6;
20128
+ var STABLE_HOOK_LAUNCHER_NAME = "prim-hook-launcher-v1";
20128
20129
  var resolvedRoot;
20129
20130
  function locateRoot() {
20130
20131
  if (resolvedRoot !== void 0) {
@@ -20155,6 +20156,34 @@ function locateRoot() {
20155
20156
  function packageVersion() {
20156
20157
  return locateRoot()?.version ?? null;
20157
20158
  }
20159
+ function shellQuote(value) {
20160
+ return `'${value.replaceAll("'", `'"'"'`)}'`;
20161
+ }
20162
+ var STABLE_HOOK_ARGUMENTS_RE = /^[-A-Za-z0-9_ ]*$/u;
20163
+ var STABLE_HOOK_BIN_RE = /^[A-Za-z0-9][A-Za-z0-9-]*$/u;
20164
+ function stableHookCommand(bin, args = "") {
20165
+ if (!STABLE_HOOK_BIN_RE.test(bin) || !STABLE_HOOK_ARGUMENTS_RE.test(args)) {
20166
+ throw new Error("invalid stable hook command");
20167
+ }
20168
+ const resolver = [
20169
+ // #242 and earlier identify managed commands by this package marker. Keep
20170
+ // it as inert data during the rolling window so an older uninstall or
20171
+ // reinstall can remove the stable entry without invoking npm or PATH.
20172
+ `prim_legacy_reader='-p ${PKG_NAME}@stable prim-shim.sh ${bin} '; `,
20173
+ 'prim_absolute() { case "$1" in [/]* ) ;; *) return 1 ;; esac; case "$1" in [[:space:]]*|*[[:space:]]|*[/][/]*|*[/].[/]*|*[/]..[/]*|*[/].|*[/]..|?*[/]) return 1 ;; esac; }; ',
20174
+ 'prim_config=${PRIM_CONFIG_DIR:-}; if ! prim_absolute "$prim_config"; then prim_config=${XDG_CONFIG_HOME:-}; if prim_absolute "$prim_config"; then ',
20175
+ 'case "$prim_config" in /) prim_config=/prim ;; *) prim_config="$prim_config/prim" ;; esac; ',
20176
+ '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; ',
20177
+ "fi; fi; ",
20178
+ `case "$prim_config" in /) prim_launcher=/${STABLE_HOOK_LAUNCHER_NAME} ;; *) prim_launcher="$prim_config/${STABLE_HOOK_LAUNCHER_NAME}" ;; esac; `,
20179
+ 'exec "$prim_launcher" "$@"'
20180
+ ].join("");
20181
+ const suffix = args ? ` ${args}` : "";
20182
+ return `/bin/sh -c ${shellQuote(resolver)} ${STABLE_HOOK_LAUNCHER_NAME} ${bin}${suffix}`;
20183
+ }
20184
+ function detachedHookShimCommand(bin, args = "") {
20185
+ return `payload=$(cat); { trap '' HUP; printf '%s' "$payload" | { ${stableHookCommand(bin, args)}; }; } </dev/null >/dev/null 2>&1 &`;
20186
+ }
20158
20187
 
20159
20188
  // src/lib/presence.ts
20160
20189
  var DECISION_ORIGIN = "https://app.getprimitive.ai";
@@ -20269,15 +20298,13 @@ var CODEX_DRAFT_DIGEST_MAX_SEEN_IDS = 4096;
20269
20298
  var CODEX_DIGEST_STATE_RETENTION_MS = 7 * 24 * 60 * 60 * 1e3;
20270
20299
  var CODEX_DIGEST_STATE_MAX_FILES = 256;
20271
20300
  var STATE_VERSION = 1;
20272
- var STATE_DIRECTORY = ["codex", "decision-digests"];
20273
20301
  var DRAFT_STATE_VERSION = 2;
20274
- var DRAFT_STATE_DIRECTORY = ["codex", "decision-draft-deliveries"];
20275
20302
  var NO_CURSOR = -1;
20276
- function stateRoot() {
20277
- return join11(primConfigDirectory(), ...STATE_DIRECTORY);
20303
+ function stateRoot(namespace) {
20304
+ return join11(primConfigDirectory(), namespace, "decision-digests");
20278
20305
  }
20279
- function draftStateRoot() {
20280
- return join11(primConfigDirectory(), ...DRAFT_STATE_DIRECTORY);
20306
+ function draftStateRoot(namespace) {
20307
+ return join11(primConfigDirectory(), namespace, "decision-draft-deliveries");
20281
20308
  }
20282
20309
  function workspaceFor(cwd) {
20283
20310
  try {
@@ -20289,12 +20316,12 @@ function workspaceFor(cwd) {
20289
20316
  function statePath(args) {
20290
20317
  const identity = `${args.siteUrl}\0${workspaceFor(args.cwd)}\0${args.sessionId}`;
20291
20318
  const key = createHash5("sha256").update(identity).digest("hex");
20292
- return join11(stateRoot(), `${key}.json`);
20319
+ return join11(stateRoot(args.namespace), `${key}.json`);
20293
20320
  }
20294
20321
  function draftStatePath(args) {
20295
20322
  const identity = `${args.siteUrl}\0${workspaceFor(args.cwd)}\0${args.sessionId}\0${args.principalId}\0${args.organizationId}\0${args.credentialFingerprint}`;
20296
20323
  const key = createHash5("sha256").update(identity).digest("hex");
20297
- return join11(draftStateRoot(), `${key}.json`);
20324
+ return join11(draftStateRoot(args.namespace), `${key}.json`);
20298
20325
  }
20299
20326
  function parseState(value) {
20300
20327
  if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
@@ -20485,14 +20512,14 @@ function mergeState(latest, args) {
20485
20512
  updatedAt: args.now
20486
20513
  };
20487
20514
  }
20488
- async function commitState(path, args) {
20515
+ async function commitState(path, args, namespace) {
20489
20516
  try {
20490
20517
  await withFileLock(
20491
20518
  `${path}.lock`,
20492
20519
  () => {
20493
20520
  const latest = readState(path);
20494
- writeStateFile(path, stateRoot(), mergeState(latest, args));
20495
- cleanupStateFiles(stateRoot(), args.now);
20521
+ writeStateFile(path, stateRoot(namespace), mergeState(latest, args));
20522
+ cleanupStateFiles(stateRoot(namespace), args.now);
20496
20523
  },
20497
20524
  { timeoutMs: 50, pollMs: 10 }
20498
20525
  );
@@ -20514,7 +20541,7 @@ function mergeDraftState(latest, args) {
20514
20541
  updatedAt: args.now
20515
20542
  };
20516
20543
  }
20517
- async function commitDraftState(path, args) {
20544
+ async function commitDraftState(path, args, namespace) {
20518
20545
  try {
20519
20546
  let next;
20520
20547
  await withFileLock(
@@ -20522,8 +20549,8 @@ async function commitDraftState(path, args) {
20522
20549
  () => {
20523
20550
  const latest = readDraftState(path);
20524
20551
  next = mergeDraftState(latest, args);
20525
- writeStateFile(path, draftStateRoot(), next);
20526
- cleanupStateFiles(draftStateRoot(), args.now);
20552
+ writeStateFile(path, draftStateRoot(namespace), next);
20553
+ cleanupStateFiles(draftStateRoot(namespace), args.now);
20527
20554
  },
20528
20555
  { timeoutMs: 50, pollMs: 10 }
20529
20556
  );
@@ -20533,9 +20560,10 @@ async function commitDraftState(path, args) {
20533
20560
  }
20534
20561
  }
20535
20562
  async function prepareCodexContext(options) {
20563
+ const namespace = options.namespace ?? "codex";
20536
20564
  const siteUrl = getSiteUrl();
20537
20565
  const workspace = workspaceFor(options.cwd);
20538
- const path = statePath({ cwd: options.cwd, sessionId: options.sessionId, siteUrl });
20566
+ const path = statePath({ cwd: options.cwd, sessionId: options.sessionId, siteUrl, namespace });
20539
20567
  const previous = readState(path);
20540
20568
  const principal = resolveDaemonPrincipal();
20541
20569
  const privatePath = principal ? draftStatePath({
@@ -20544,7 +20572,8 @@ async function prepareCodexContext(options) {
20544
20572
  siteUrl,
20545
20573
  principalId: principal.principalId,
20546
20574
  organizationId: principal.organizationId,
20547
- credentialFingerprint: principal.credentialFingerprint
20575
+ credentialFingerprint: principal.credentialFingerprint,
20576
+ namespace
20548
20577
  }) : void 0;
20549
20578
  const previousDraft = privatePath ? readDraftState(privatePath) : void 0;
20550
20579
  const startup = options.startup === true;
@@ -20634,32 +20663,40 @@ async function prepareCodexContext(options) {
20634
20663
  acknowledge: async (handedOff) => {
20635
20664
  if (!handedOff || acknowledged) return;
20636
20665
  acknowledged = true;
20637
- await commitState(path, {
20638
- sessionId: options.sessionId,
20639
- siteUrl,
20640
- workspace,
20641
- startedAt,
20642
- watermarkMs: pageWatermark,
20643
- seenIds: freshRows.map((row) => row.id),
20644
- report,
20645
- feedAvailable,
20646
- now: Date.now()
20647
- });
20666
+ await commitState(
20667
+ path,
20668
+ {
20669
+ sessionId: options.sessionId,
20670
+ siteUrl,
20671
+ workspace,
20672
+ startedAt,
20673
+ watermarkMs: pageWatermark,
20674
+ seenIds: freshRows.map((row) => row.id),
20675
+ report,
20676
+ feedAvailable,
20677
+ now: Date.now()
20678
+ },
20679
+ namespace
20680
+ );
20648
20681
  if (privatePath === void 0 || principal === void 0 || draftPageToken === void 0) {
20649
20682
  return;
20650
20683
  }
20651
20684
  let persistedDraft = previousDraft;
20652
20685
  if (draftDigest?.deliveredIds.length) {
20653
- persistedDraft = await commitDraftState(privatePath, {
20654
- sessionId: options.sessionId,
20655
- siteUrl,
20656
- workspace,
20657
- principalId: principal.principalId,
20658
- organizationId: principal.organizationId,
20659
- credentialFingerprint: principal.credentialFingerprint,
20660
- deliveredIds: draftDigest.deliveredIds,
20661
- now: Date.now()
20662
- });
20686
+ persistedDraft = await commitDraftState(
20687
+ privatePath,
20688
+ {
20689
+ sessionId: options.sessionId,
20690
+ siteUrl,
20691
+ workspace,
20692
+ principalId: principal.principalId,
20693
+ organizationId: principal.organizationId,
20694
+ credentialFingerprint: principal.credentialFingerprint,
20695
+ deliveredIds: draftDigest.deliveredIds,
20696
+ now: Date.now()
20697
+ },
20698
+ namespace
20699
+ );
20663
20700
  }
20664
20701
  const seenDrafts = new Set(persistedDraft?.seenDraftIds ?? []);
20665
20702
  const deliveredOnThisPage = draftPageActionableIds.filter((id) => seenDrafts.has(id));
@@ -20709,6 +20746,290 @@ async function processCodexMessageContext(envelope, deps = defaultDeps) {
20709
20746
  };
20710
20747
  }
20711
20748
 
20749
+ // src/commands/cursor-install.ts
20750
+ import { existsSync as existsSync10, readFileSync as readFileSync12 } from "fs";
20751
+ import { homedir as homedir4 } from "os";
20752
+ import { isAbsolute as isAbsolute6, join as join14 } from "path";
20753
+
20754
+ // src/lib/hook-runtime.ts
20755
+ import { createHash as createHash6, randomBytes as randomBytes4 } from "crypto";
20756
+ import {
20757
+ constants as constants3,
20758
+ accessSync,
20759
+ chmodSync as chmodSync4,
20760
+ copyFileSync,
20761
+ existsSync as existsSync8,
20762
+ lstatSync as lstatSync3,
20763
+ mkdirSync as mkdirSync7,
20764
+ mkdtempSync,
20765
+ readFileSync as readFileSync10,
20766
+ readdirSync as readdirSync3,
20767
+ realpathSync as realpathSync2,
20768
+ renameSync as renameSync3,
20769
+ rmSync as rmSync5,
20770
+ statSync as statSync4,
20771
+ utimesSync,
20772
+ writeFileSync as writeFileSync5
20773
+ } from "fs";
20774
+ import { dirname as dirname9, isAbsolute as isAbsolute5, join as join12, resolve as resolve4 } from "path";
20775
+ var RELEASE_PREFIX = "release-";
20776
+ var MAX_MANIFEST_BYTES = 64 * 1024;
20777
+ var RELEASE_GRACE_MS = 10 * 60 * 1e3;
20778
+ var HOOK_RUNTIME_ENTRIES = {
20779
+ // SessionStart self-healing resolves this exact CLI entry to run
20780
+ // `daemon ensure`; it must travel with the immutable hook release.
20781
+ prim: "dist/index.js",
20782
+ "prim-hook": "dist/hooks/prim-hook.js",
20783
+ "prim-pre-commit": "dist/hooks/pre-commit.js",
20784
+ "prim-post-commit": "dist/hooks/post-commit.js",
20785
+ "prim-post-rewrite": "dist/hooks/post-rewrite.js",
20786
+ "prim-pre-tool-use": "dist/hooks/pre-tool-use.js",
20787
+ "prim-post-tool-use": "dist/hooks/post-tool-use.js",
20788
+ "prim-session-start": "dist/hooks/session-start.js",
20789
+ "prim-session-end": "dist/hooks/session-end.js",
20790
+ "prim-daemon-server": "dist/daemon/server.js",
20791
+ "prim-statusline": "dist/statusline-main.js"
20792
+ };
20793
+ var SOURCE_ENTRIES = Object.fromEntries(
20794
+ Object.entries(HOOK_RUNTIME_ENTRIES).map(([bin, target]) => [
20795
+ bin,
20796
+ target.replace(/^dist\//u, "")
20797
+ ])
20798
+ );
20799
+ var STABLE_HOOK_LAUNCHER_CONTENT = `#!/bin/sh
20800
+ set -eu
20801
+ case "$0" in */*) prim_launcher_dir=\${0%/*} ;; *) exit 78 ;; esac
20802
+ IFS= read -r prim_release_name < "$prim_launcher_dir/hook-runtime/current" || exit 69
20803
+ case "$prim_release_name" in ${RELEASE_PREFIX}*) ;; *) exit 69 ;; esac
20804
+ prim_release_id=\${prim_release_name#${RELEASE_PREFIX}}
20805
+ case "$prim_release_id" in *[!0-9a-f]*|"") exit 69 ;; esac
20806
+ [ "\${#prim_release_id}" -eq 64 ] || exit 69
20807
+ prim_release="$prim_launcher_dir/hook-runtime/releases/$prim_release_name"
20808
+ case "\${1-}" in
20809
+ ${Object.entries(HOOK_RUNTIME_ENTRIES).map(([bin, entry]) => ` ${bin}) prim_entry="$prim_release/${entry}" ;;`).join("\n")}
20810
+ *) exit 64 ;;
20811
+ esac
20812
+ shift
20813
+ IFS= read -r prim_node < "$prim_release/node" || exit 69
20814
+ case "$prim_node" in /*) ;; *) exit 69 ;; esac
20815
+ [ -x "$prim_node" ] && [ -f "$prim_entry" ] || exit 69
20816
+ exec "$prim_node" "$prim_entry" "$@"
20817
+ `;
20818
+
20819
+ // src/commands/claude-install.ts
20820
+ import { existsSync as existsSync9, readFileSync as readFileSync11 } from "fs";
20821
+ import { homedir as homedir3 } from "os";
20822
+ import { join as join13 } from "path";
20823
+ var CAPTURE_BIN = "prim-hook";
20824
+ var GATE_BIN = "prim-pre-tool-use";
20825
+ var POST_TOOL_USE_BIN = "prim-post-tool-use";
20826
+ var SESSION_START_BIN = "prim-session-start";
20827
+ var SESSION_END_BIN = "prim-session-end";
20828
+ var STATUSLINE_BIN = "prim-statusline";
20829
+ var STATUSLINE_ARGS = "";
20830
+ var STATUSLINE_COMMAND = stableHookCommand(STATUSLINE_BIN, STATUSLINE_ARGS);
20831
+ var USER_SCOPE_PATH = join13(homedir3(), ".claude", "settings.json");
20832
+ function projectRoot() {
20833
+ return gitToplevel() ?? process.cwd();
20834
+ }
20835
+ var CAPTURE_EVENTS = [
20836
+ "SessionStart",
20837
+ "UserPromptSubmit",
20838
+ "PreToolUse",
20839
+ "PostToolUse",
20840
+ "PostToolUseFailure",
20841
+ "Stop",
20842
+ "SessionEnd",
20843
+ "SubagentStop"
20844
+ ];
20845
+ function makeRegistration(event, matcher, bin, args = "") {
20846
+ return {
20847
+ event,
20848
+ matcher,
20849
+ bin,
20850
+ command: stableHookCommand(bin, args)
20851
+ };
20852
+ }
20853
+ function makeDetachedRegistration(event, matcher, bin, args = "") {
20854
+ return { event, matcher, bin, command: detachedHookShimCommand(bin, args) };
20855
+ }
20856
+ var REGISTRATIONS = [
20857
+ ...CAPTURE_EVENTS.map(
20858
+ (event) => event === "SessionEnd" ? makeDetachedRegistration(event, "*", CAPTURE_BIN) : makeRegistration(event, "*", CAPTURE_BIN)
20859
+ ),
20860
+ makeRegistration("PreToolUse", "Edit|Write|MultiEdit|NotebookEdit|Bash", GATE_BIN),
20861
+ makeRegistration("PostToolUse", "Edit|Write|MultiEdit|NotebookEdit|Bash", POST_TOOL_USE_BIN),
20862
+ makeRegistration(
20863
+ "PostToolUseFailure",
20864
+ "Edit|Write|MultiEdit|NotebookEdit|Bash",
20865
+ POST_TOOL_USE_BIN
20866
+ ),
20867
+ makeRegistration("SessionStart", "*", SESSION_START_BIN),
20868
+ makeDetachedRegistration("SessionEnd", "*", SESSION_END_BIN)
20869
+ ];
20870
+ var PRIM_PERMISSION_RULE = "Bash(npx --yes @primitive.ai/prim*)";
20871
+ var LEGACY_PRIM_PERMISSION_RULES = [
20872
+ "Bash(npx --yes @primitive.ai/prim@latest:*)",
20873
+ "Bash(npx --yes @primitive.ai/prim:*)"
20874
+ ];
20875
+ var ALL_PRIM_PERMISSION_RULES = /* @__PURE__ */ new Set([
20876
+ PRIM_PERMISSION_RULE,
20877
+ ...LEGACY_PRIM_PERMISSION_RULES
20878
+ ]);
20879
+
20880
+ // src/commands/cursor-install.ts
20881
+ var CAPTURE_BIN2 = "prim-hook";
20882
+ var GATE_BIN2 = "prim-pre-tool-use";
20883
+ var POST_TOOL_BIN = "prim-post-tool-use";
20884
+ var SESSION_START_BIN2 = "prim-session-start";
20885
+ var SESSION_END_BIN2 = "prim-session-end";
20886
+ var STATUSLINE_BIN2 = "prim-statusline";
20887
+ var CURSOR_EVENTS = [
20888
+ "sessionStart",
20889
+ "beforeSubmitPrompt",
20890
+ "preToolUse",
20891
+ "postToolUse",
20892
+ "postToolUseFailure",
20893
+ "afterAgentResponse",
20894
+ "subagentStop",
20895
+ "stop",
20896
+ "sessionEnd"
20897
+ ];
20898
+ var REGISTRATIONS2 = [
20899
+ ...CURSOR_EVENTS.map((event) => ({ event, bin: CAPTURE_BIN2 })),
20900
+ { event: "preToolUse", bin: GATE_BIN2, matcher: "Write|Delete|Shell", timeout: 10 },
20901
+ { event: "postToolUse", bin: POST_TOOL_BIN },
20902
+ { event: "postToolUseFailure", bin: POST_TOOL_BIN },
20903
+ { event: "sessionStart", bin: SESSION_START_BIN2 },
20904
+ { event: "sessionEnd", bin: SESSION_END_BIN2 }
20905
+ ];
20906
+ function cursorConfigDirectory(env = process.env, home = homedir4(), platform2 = process.platform) {
20907
+ const explicit = env.CURSOR_CONFIG_DIR?.trim();
20908
+ if (explicit && isAbsolute6(explicit)) return explicit;
20909
+ const xdg = env.XDG_CONFIG_HOME?.trim();
20910
+ if (platform2 !== "darwin" && xdg && isAbsolute6(xdg)) return join14(xdg, "cursor");
20911
+ return join14(home, ".cursor");
20912
+ }
20913
+ function cursorHooksPath(scope, root = projectRoot()) {
20914
+ return scope === "user" ? join14(cursorConfigDirectory(), "hooks.json") : join14(root, ".cursor", "hooks.json");
20915
+ }
20916
+ function plainObject(value) {
20917
+ return typeof value === "object" && value !== null && !Array.isArray(value);
20918
+ }
20919
+ function readCursorHooks(path) {
20920
+ if (!existsSync10(path)) return {};
20921
+ let parsed;
20922
+ try {
20923
+ parsed = JSON.parse(readFileSync12(path, "utf8"));
20924
+ } catch {
20925
+ throw new Error(`invalid Cursor hooks JSON at ${path}`);
20926
+ }
20927
+ if (!plainObject(parsed)) throw new Error(`Cursor hooks config must be an object: ${path}`);
20928
+ if (parsed.version !== void 0 && parsed.version !== 1) {
20929
+ throw new Error(`unsupported Cursor hooks version at ${path} (expected version 1)`);
20930
+ }
20931
+ if (parsed.hooks !== void 0) {
20932
+ if (!plainObject(parsed.hooks)) throw new Error(`Cursor hooks must be an object: ${path}`);
20933
+ for (const [event, entries] of Object.entries(parsed.hooks)) {
20934
+ if (!Array.isArray(entries) || !entries.every(plainObject)) {
20935
+ throw new Error(`Cursor hook list must contain objects: ${event} in ${path}`);
20936
+ }
20937
+ }
20938
+ }
20939
+ return parsed;
20940
+ }
20941
+ function commandFor(registration, scope) {
20942
+ return stableHookCommand(
20943
+ registration.bin,
20944
+ `--agent cursor --event ${registration.event} --scope ${scope}`
20945
+ );
20946
+ }
20947
+ var OWNED_COMMANDS = new Set(
20948
+ ["project", "user"].flatMap(
20949
+ (scope) => REGISTRATIONS2.map((registration) => commandFor(registration, scope))
20950
+ )
20951
+ );
20952
+ function jsoncUnsafeCommand(command) {
20953
+ return command.replace('case "$1" in [/]* ', 'case "$1" in /*').replace("*[/][/]*", "*//*").replace("*[/].[/]*", "*/./*").replace("*[/]..[/]*", "*/../*").replace("*[/].", "*/.").replace("*[/]..", "*/..").replace("?*[/]", "?*/");
20954
+ }
20955
+ var JSONC_UNSAFE_OWNED_COMMANDS = new Set([...OWNED_COMMANDS].map(jsoncUnsafeCommand));
20956
+ function hookFor(registration, scope) {
20957
+ return {
20958
+ command: commandFor(registration, scope),
20959
+ ...registration.matcher ? { matcher: registration.matcher } : {},
20960
+ ...registration.timeout ? { timeout: registration.timeout } : {}
20961
+ };
20962
+ }
20963
+ function exactHook(entry, registration, scope) {
20964
+ return JSON.stringify(entry) === JSON.stringify(hookFor(registration, scope));
20965
+ }
20966
+ function hasExactCursorHandler(settings, event, bin, scope) {
20967
+ const registration = REGISTRATIONS2.find(
20968
+ (candidate) => candidate.event === event && candidate.bin === bin
20969
+ );
20970
+ return registration ? (settings.hooks?.[event] ?? []).some((entry) => exactHook(entry, registration, scope)) : false;
20971
+ }
20972
+ var FOOTER = {
20973
+ type: "command",
20974
+ command: stableHookCommand(STATUSLINE_BIN2),
20975
+ updateIntervalMs: 1e3,
20976
+ timeoutMs: 2e3
20977
+ };
20978
+ var JSONC_UNSAFE_FOOTER = {
20979
+ ...FOOTER,
20980
+ command: jsoncUnsafeCommand(FOOTER.command)
20981
+ };
20982
+
20983
+ // src/hooks/cursor-coexistence.ts
20984
+ var CURSOR_EVENTS2 = /* @__PURE__ */ new Set([
20985
+ "sessionStart",
20986
+ "beforeSubmitPrompt",
20987
+ "preToolUse",
20988
+ "postToolUse",
20989
+ "postToolUseFailure",
20990
+ "afterAgentResponse",
20991
+ "subagentStop",
20992
+ "stop",
20993
+ "sessionEnd"
20994
+ ]);
20995
+ function cursorEvidence(parsed) {
20996
+ 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);
20997
+ }
20998
+ function uniqueProjectRoot(parsed) {
20999
+ if (!Array.isArray(parsed.workspace_roots)) return;
21000
+ const roots = new Set(
21001
+ parsed.workspace_roots.filter((value) => typeof value === "string" && value.length > 0).map((value) => resolveRepositoryContext(value)?.repoRoot).filter((value) => !!value)
21002
+ );
21003
+ return roots.size === 1 ? [...roots][0] : void 0;
21004
+ }
21005
+ function shouldSuppressImportedCursorHandler(parsed, bin) {
21006
+ if (!cursorEvidence(parsed)) return false;
21007
+ const project = uniqueProjectRoot(parsed);
21008
+ if (project) {
21009
+ try {
21010
+ if (hasExactCursorHandler(
21011
+ readCursorHooks(cursorHooksPath("project", project)),
21012
+ parsed.hook_event_name,
21013
+ bin,
21014
+ "project"
21015
+ )) {
21016
+ return true;
21017
+ }
21018
+ } catch {
21019
+ }
21020
+ }
21021
+ try {
21022
+ return hasExactCursorHandler(
21023
+ readCursorHooks(cursorHooksPath("user")),
21024
+ parsed.hook_event_name,
21025
+ bin,
21026
+ "user"
21027
+ );
21028
+ } catch {
21029
+ return false;
21030
+ }
21031
+ }
21032
+
20712
21033
  // src/hooks/decision-feedback-core.ts
20713
21034
  function buildHookOutput(options) {
20714
21035
  const output = {};
@@ -20722,13 +21043,13 @@ function buildHookOutput(options) {
20722
21043
  return output;
20723
21044
  }
20724
21045
  function writeHookOutput(output, stream = process.stdout) {
20725
- return new Promise((resolve4) => {
21046
+ return new Promise((resolve6) => {
20726
21047
  let settled = false;
20727
21048
  const finish = (ok, retainErrorListener = false) => {
20728
21049
  if (settled) return;
20729
21050
  settled = true;
20730
21051
  if (!retainErrorListener) stream.off("error", onError);
20731
- resolve4(ok);
21052
+ resolve6(ok);
20732
21053
  };
20733
21054
  const onError = () => {
20734
21055
  if (settled) {
@@ -20761,7 +21082,7 @@ async function handoffHookOutput(output, acknowledge, stream = process.stdout) {
20761
21082
  }
20762
21083
 
20763
21084
  // src/hooks/pre-tool-use-scoring.ts
20764
- import { isAbsolute as isAbsolute5, relative as relative2, sep as sep2 } from "path";
21085
+ import { isAbsolute as isAbsolute7, relative as relative2, sep as sep2 } from "path";
20765
21086
  var SUPPORTED_TOOLS = /* @__PURE__ */ new Set(["Edit", "Write", "MultiEdit", "NotebookEdit"]);
20766
21087
  var APPLY_PATCH_FILE_RE = /^\*\*\* (?:Update|Add|Delete) File: (?<path>.+)$/;
20767
21088
  var MOVE_FILE_RE = /^\*\*\* Move File:\s*(?<src>.+?)\s*->\s*(?<dst>.+?)\s*$/;
@@ -20832,10 +21153,25 @@ function extractHermesFileTargets(toolName, toolInput) {
20832
21153
  const mode = input.mode;
20833
21154
  return { paths, complete: paths.length > 0 && (mode === void 0 || mode === "replace") };
20834
21155
  }
21156
+ function extractCursorFileTargets(toolName, toolInput) {
21157
+ if (toolName !== "Write" && toolName !== "Delete") return null;
21158
+ if (!toolInput || typeof toolInput !== "object" || Array.isArray(toolInput)) {
21159
+ return { paths: [], complete: false };
21160
+ }
21161
+ const input = toolInput;
21162
+ const candidates = [input.file_path, input.path].filter(
21163
+ (value) => typeof value === "string" && value.length > 0
21164
+ );
21165
+ const paths = [...new Set(candidates)];
21166
+ return { paths, complete: paths.length === 1 };
21167
+ }
20835
21168
  function extractFileTargets(toolName, toolInput, agent = "claude_code") {
20836
21169
  if (agent === "codex") {
20837
21170
  return extractCodexFileTargets(toolName, toolInput);
20838
21171
  }
21172
+ if (agent === "cursor") {
21173
+ return extractCursorFileTargets(toolName, toolInput);
21174
+ }
20839
21175
  if (agent === "hermes") {
20840
21176
  return extractHermesFileTargets(toolName, toolInput);
20841
21177
  }
@@ -25302,7 +25638,8 @@ function preserveHookFileMetadata(payload, resolution) {
25302
25638
  return { ...payload, primitive };
25303
25639
  }
25304
25640
  function resolveHookFileRefs(args) {
25305
- 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;
25641
+ const isShellTool = (args.agent === "claude_code" || args.agent === "codex") && args.toolName === "Bash" || args.agent === "cursor" && args.toolName === "Shell";
25642
+ 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;
25306
25643
  const shell = command === void 0 ? void 0 : analyzeShellTargets(command);
25307
25644
  const shellMutation = shell?.mutation === "none" ? "none" : shell?.coverage === "complete" ? "resolved" : shell ? "unresolved" : void 0;
25308
25645
  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;
@@ -25347,8 +25684,41 @@ function enrichHookPayloadWithFileRefs(args) {
25347
25684
  };
25348
25685
  }
25349
25686
 
25687
+ // src/hooks/hook-stdin.ts
25688
+ var DEFAULT_MAX_BYTES = 1024 * 1024;
25689
+ function readHookStdin(timeoutMs = 1e3, maxBytes = DEFAULT_MAX_BYTES) {
25690
+ return new Promise((resolve6, reject) => {
25691
+ const chunks = [];
25692
+ let bytes = 0;
25693
+ let settled = false;
25694
+ const finish = (error) => {
25695
+ if (settled) return;
25696
+ settled = true;
25697
+ clearTimeout(timer);
25698
+ process.stdin.removeAllListeners("data");
25699
+ process.stdin.removeAllListeners("end");
25700
+ process.stdin.removeAllListeners("error");
25701
+ if (error) reject(error);
25702
+ else resolve6(Buffer.concat(chunks, bytes).toString("utf-8"));
25703
+ };
25704
+ const timer = setTimeout(() => finish(new Error("stdin read timeout")), timeoutMs);
25705
+ process.stdin.on("data", (chunk) => {
25706
+ bytes += chunk.length;
25707
+ if (bytes > maxBytes) {
25708
+ finish(new Error("stdin envelope exceeds size limit"));
25709
+ return;
25710
+ }
25711
+ chunks.push(chunk);
25712
+ });
25713
+ process.stdin.on("end", () => finish());
25714
+ process.stdin.on("error", (error) => finish(error));
25715
+ });
25716
+ }
25717
+
25350
25718
  // src/hooks/normalize.ts
25351
- import { createHash as createHash6 } from "crypto";
25719
+ import { createHash as createHash7 } from "crypto";
25720
+ import { realpathSync as realpathSync3 } from "fs";
25721
+ import { isAbsolute as isAbsolute8, resolve as resolve5 } from "path";
25352
25722
  var HERMES_EVENT_MAP = {
25353
25723
  on_session_start: "SessionStart",
25354
25724
  on_session_end: "SessionEnd",
@@ -25358,7 +25728,125 @@ var HERMES_EVENT_MAP = {
25358
25728
  post_tool_call: "PostToolUse",
25359
25729
  subagent_stop: "SubagentStop"
25360
25730
  };
25731
+ var CURSOR_EVENT_MAP = {
25732
+ sessionStart: "SessionStart",
25733
+ beforeSubmitPrompt: "UserPromptSubmit",
25734
+ preToolUse: "PreToolUse",
25735
+ postToolUse: "PostToolUse",
25736
+ postToolUseFailure: "PostToolUseFailure",
25737
+ afterAgentResponse: "AssistantResponse",
25738
+ subagentStop: "SubagentStop",
25739
+ stop: "Stop",
25740
+ sessionEnd: "SessionEnd"
25741
+ };
25742
+ var CURSOR_TOOL_EVENTS = /* @__PURE__ */ new Set(["PreToolUse", "PostToolUse", "PostToolUseFailure"]);
25743
+ var SAFE_CORRELATION_ID_RE = /^[A-Za-z0-9._:-]{1,128}$/u;
25744
+ var CURSOR_LOCAL_ONLY_FIELDS = /* @__PURE__ */ new Set([
25745
+ "conversation_id",
25746
+ "generation_id",
25747
+ "user_email",
25748
+ "account_email",
25749
+ "transcript_path",
25750
+ "transcript",
25751
+ "thought",
25752
+ "thoughts",
25753
+ "thinking",
25754
+ "tool_output"
25755
+ ]);
25756
+ function requiredId(value, field) {
25757
+ if (typeof value !== "string" || value.length === 0) {
25758
+ throw new TypeError(`Cursor hook envelope is missing ${field}`);
25759
+ }
25760
+ return value;
25761
+ }
25762
+ function cursorToolUseId(value) {
25763
+ if (SAFE_CORRELATION_ID_RE.test(value)) return value;
25764
+ return `cursor:tool:v1:${createHash7("sha256").update(value).digest("hex")}`;
25765
+ }
25766
+ function workspaceCandidates(value) {
25767
+ if (!Array.isArray(value)) return [];
25768
+ const roots = value.filter((item) => typeof item === "string" && item.length > 0);
25769
+ if (roots.some((root) => !isAbsolute8(root))) {
25770
+ throw new TypeError("Cursor workspace roots must be absolute");
25771
+ }
25772
+ return roots;
25773
+ }
25774
+ function pathIdentity(path) {
25775
+ try {
25776
+ return realpathSync3.native(path);
25777
+ } catch {
25778
+ return resolve5(path);
25779
+ }
25780
+ }
25781
+ function resolveCursorCwd(parsed) {
25782
+ const roots = workspaceCandidates(parsed.workspace_roots).map(pathIdentity);
25783
+ const rootRepositories = roots.map((root) => resolveRepositoryContext(root)?.repoRoot);
25784
+ const repositoryRoots = new Set(rootRepositories.filter((root) => !!root));
25785
+ if (repositoryRoots.size > 1) {
25786
+ throw new TypeError("Cursor hook envelope spans multiple repositories");
25787
+ }
25788
+ if (roots.length > 1 && rootRepositories.some((root) => root === void 0)) {
25789
+ throw new TypeError("Cursor hook envelope has ambiguous workspace roots");
25790
+ }
25791
+ const expectedRepo = [...repositoryRoots][0];
25792
+ const rawCwd = typeof parsed.cwd === "string" && parsed.cwd.length > 0 ? parsed.cwd : void 0;
25793
+ if (rawCwd && !isAbsolute8(rawCwd)) {
25794
+ throw new TypeError("Cursor hook cwd must be absolute");
25795
+ }
25796
+ const envelopeCwd = rawCwd ? pathIdentity(rawCwd) : void 0;
25797
+ const input = typeof parsed.tool_input === "object" && parsed.tool_input !== null && !Array.isArray(parsed.tool_input) ? parsed.tool_input : void 0;
25798
+ const rawToolCwd = parsed.tool_name === "Shell" && typeof input?.working_directory === "string" ? input.working_directory : void 0;
25799
+ const base = envelopeCwd ?? (roots.length === 1 ? roots[0] : expectedRepo);
25800
+ if (rawToolCwd && !isAbsolute8(rawToolCwd) && !base) {
25801
+ throw new TypeError("relative Cursor tool cwd has no workspace base");
25802
+ }
25803
+ const toolCwd = rawToolCwd ? pathIdentity(isAbsolute8(rawToolCwd) ? rawToolCwd : resolve5(base, rawToolCwd)) : void 0;
25804
+ const selected = toolCwd ?? envelopeCwd ?? (roots.length === 1 ? roots[0] : expectedRepo);
25805
+ if (!selected) {
25806
+ throw new TypeError("Cursor hook envelope has no unambiguous workspace");
25807
+ }
25808
+ const selectedRepo = resolveRepositoryContext(selected)?.repoRoot;
25809
+ if (expectedRepo && selectedRepo !== expectedRepo) {
25810
+ throw new TypeError("Cursor hook cwd conflicts with workspace repository");
25811
+ }
25812
+ return selected;
25813
+ }
25814
+ function normalizeCursorEnvelope(parsed) {
25815
+ const rawEvent = requiredId(parsed.hook_event_name, "hook_event_name");
25816
+ const event = CURSOR_EVENT_MAP[rawEvent];
25817
+ if (!event) throw new TypeError(`unsupported Cursor hook event: ${rawEvent}`);
25818
+ const sessionId = requiredId(parsed.conversation_id, "conversation_id");
25819
+ const turnId = requiredId(parsed.generation_id, "generation_id");
25820
+ if (parsed.session_id !== void 0 && parsed.session_id !== sessionId) {
25821
+ throw new TypeError("Cursor conversation_id conflicts with session_id");
25822
+ }
25823
+ if (parsed.turn_id !== void 0 && parsed.turn_id !== turnId) {
25824
+ throw new TypeError("Cursor generation_id conflicts with turn_id");
25825
+ }
25826
+ const rawToolUseId = CURSOR_TOOL_EVENTS.has(event) ? requiredId(parsed.tool_use_id, "tool_use_id") : void 0;
25827
+ const normalized = {
25828
+ ...Object.fromEntries(
25829
+ Object.entries(parsed).filter(([key]) => !CURSOR_LOCAL_ONLY_FIELDS.has(key))
25830
+ ),
25831
+ hook_event_name: event,
25832
+ session_id: sessionId,
25833
+ turn_id: turnId,
25834
+ cwd: resolveCursorCwd(parsed),
25835
+ ...rawToolUseId === void 0 ? {} : { tool_use_id: cursorToolUseId(rawToolUseId) }
25836
+ };
25837
+ if (typeof parsed.tool_output === "string") {
25838
+ try {
25839
+ normalized.tool_response = JSON.parse(parsed.tool_output);
25840
+ } catch {
25841
+ normalized.tool_response = parsed.tool_output;
25842
+ }
25843
+ }
25844
+ return normalized;
25845
+ }
25361
25846
  function normalizeEnvelope(parsed, agent) {
25847
+ if (agent === "cursor") {
25848
+ return normalizeCursorEnvelope(parsed);
25849
+ }
25362
25850
  if (agent === "codex") {
25363
25851
  const event = parsed.hook_event_name;
25364
25852
  if ((event === "PreToolUse" || event === "PostToolUse") && (typeof parsed.tool_use_id !== "string" || parsed.tool_use_id.length === 0)) {
@@ -25370,7 +25858,7 @@ function normalizeEnvelope(parsed, agent) {
25370
25858
  ]);
25371
25859
  return {
25372
25860
  ...parsed,
25373
- tool_use_id: `codex:fallback:v1:${createHash6("sha256").update(stableToolIdentity).digest("hex")}`
25861
+ tool_use_id: `codex:fallback:v1:${createHash7("sha256").update(stableToolIdentity).digest("hex")}`
25374
25862
  };
25375
25863
  }
25376
25864
  return parsed;
@@ -25386,15 +25874,15 @@ function normalizeEnvelope(parsed, agent) {
25386
25874
  }
25387
25875
 
25388
25876
  // src/hooks/prim-hook-core.ts
25389
- import { createHash as createHash7, randomUUID as randomUUID3 } from "crypto";
25877
+ import { createHash as createHash8, randomUUID as randomUUID3 } from "crypto";
25390
25878
  import { platform } from "os";
25391
25879
 
25392
25880
  // src/protocol/move.ts
25393
25881
  var AGENT_ENVELOPE_VERSION = 3;
25394
25882
 
25395
25883
  // src/hooks/redact.ts
25396
- import { existsSync as existsSync8, readFileSync as readFileSync10, statSync as statSync4 } from "fs";
25397
- import { join as join12 } from "path";
25884
+ import { existsSync as existsSync11, readFileSync as readFileSync13, statSync as statSync5 } from "fs";
25885
+ import { join as join15 } from "path";
25398
25886
  import { Worker } from "worker_threads";
25399
25887
 
25400
25888
  // src/lib/ansi.ts
@@ -25481,15 +25969,15 @@ function normalizedWorkspaceFlags(value) {
25481
25969
  return [...new Set(`g${requested}`)].sort().join("");
25482
25970
  }
25483
25971
  function loadWorkspaceRules(cwd) {
25484
- const path = join12(cwd, WORKSPACE_FILE2);
25485
- if (!existsSync8(path)) return [];
25972
+ const path = join15(cwd, WORKSPACE_FILE2);
25973
+ if (!existsSync11(path)) return [];
25486
25974
  let cfg;
25487
25975
  try {
25488
- if (statSync4(path).size > MAX_WORKSPACE_CONFIG_BYTES) {
25976
+ if (statSync5(path).size > MAX_WORKSPACE_CONFIG_BYTES) {
25489
25977
  debugRedaction(`ignoring oversized ${WORKSPACE_FILE2}`);
25490
25978
  return [];
25491
25979
  }
25492
- cfg = JSON.parse(readFileSync10(path, "utf-8"));
25980
+ cfg = JSON.parse(readFileSync13(path, "utf-8"));
25493
25981
  } catch {
25494
25982
  debugRedaction(`ignoring unparseable ${WORKSPACE_FILE2}`);
25495
25983
  return [];
@@ -25608,7 +26096,7 @@ function applyWorkspaceRules(value, rules) {
25608
26096
  flags: pattern.flags,
25609
26097
  reason
25610
26098
  }));
25611
- return new Promise((resolve4) => {
26099
+ return new Promise((resolve6) => {
25612
26100
  let worker;
25613
26101
  try {
25614
26102
  worker = new Worker(WORKSPACE_REDACTION_WORKER, {
@@ -25616,7 +26104,7 @@ function applyWorkspaceRules(value, rules) {
25616
26104
  workerData: { value, rules: serialized }
25617
26105
  });
25618
26106
  } catch {
25619
- resolve4(redactEveryString(value, "workspace-rule-failed"));
26107
+ resolve6(redactEveryString(value, "workspace-rule-failed"));
25620
26108
  return;
25621
26109
  }
25622
26110
  let settled = false;
@@ -25625,7 +26113,7 @@ function applyWorkspaceRules(value, rules) {
25625
26113
  settled = true;
25626
26114
  clearTimeout(timer);
25627
26115
  void worker.terminate();
25628
- resolve4(result);
26116
+ resolve6(result);
25629
26117
  };
25630
26118
  const failClosed = () => finish(redactEveryString(value, "workspace-rule-failed"));
25631
26119
  const timer = setTimeout(failClosed, WORKSPACE_RULE_TIMEOUT_MS);
@@ -25679,6 +26167,17 @@ function toolOutcomeFor(parsed, agent) {
25679
26167
  if (agent === "codex") {
25680
26168
  return event === "PostToolUse" ? "returned" : void 0;
25681
26169
  }
26170
+ if (agent === "cursor") {
26171
+ if (event === "PostToolUse") return "succeeded";
26172
+ if (event === "PostToolUseFailure") {
26173
+ if (parsed.is_interrupt === true) return "interrupted";
26174
+ const failureType = lowerString(parsed.failure_type);
26175
+ if (failureType === "permission_denied") return "prevented";
26176
+ if (failureType === "error" || failureType === "timeout") return "failed";
26177
+ return "unknown";
26178
+ }
26179
+ return void 0;
26180
+ }
25682
26181
  const extra = parsed.extra;
25683
26182
  if (event === "post_approval_response") {
25684
26183
  const choice = lowerString(extra?.choice);
@@ -25708,9 +26207,9 @@ function toMove(parsed, cliVersion, agent = "claude_code", workspaceId, reposito
25708
26207
  const toolOutcome = toolOutcomeFor(parsed, agent);
25709
26208
  let moveId;
25710
26209
  if (CORRELATED_TOOL_EVENTS.has(eventType) && sessionId && invocationId) {
25711
- moveId = `posttool:v1:${createHash7("sha256").update(JSON.stringify([agent, sessionId, eventType, invocationId])).digest("hex")}`;
25712
- } else if (CORRELATED_TOOL_EVENTS.has(eventType) && sessionId) {
25713
- moveId = `posttool:fallback:v1:${createHash7("sha256").update(
26210
+ moveId = `posttool:v1:${createHash8("sha256").update(JSON.stringify([agent, sessionId, eventType, invocationId])).digest("hex")}`;
26211
+ } else if (CORRELATED_TOOL_EVENTS.has(eventType) && sessionId && agent !== "cursor") {
26212
+ moveId = `posttool:fallback:v1:${createHash8("sha256").update(
25714
26213
  JSON.stringify([
25715
26214
  agent,
25716
26215
  sessionId,
@@ -25748,12 +26247,12 @@ function toMove(parsed, cliVersion, agent = "claude_code", workspaceId, reposito
25748
26247
  ...toolOutcome ? { toolOutcome } : {}
25749
26248
  };
25750
26249
  }
25751
- function shouldFlushAfter(eventType) {
25752
- return eventType === "SessionEnd";
26250
+ function shouldFlushAfter(eventType, agent = "claude_code") {
26251
+ return eventType === "SessionEnd" || agent === "cursor" && eventType === "Stop";
25753
26252
  }
25754
26253
 
25755
26254
  // src/hooks/prim-hook.ts
25756
- var here = dirname9(fileURLToPath2(import.meta.url));
26255
+ var here = dirname11(fileURLToPath2(import.meta.url));
25757
26256
  var outputAttempted = false;
25758
26257
  function emitOutput(output, acknowledge) {
25759
26258
  outputAttempted = true;
@@ -25761,14 +26260,14 @@ function emitOutput(output, acknowledge) {
25761
26260
  }
25762
26261
  function resolveCliVersion() {
25763
26262
  try {
25764
- const pkg = JSON.parse(readFileSync11(join13(here, "..", "..", "package.json"), "utf-8"));
26263
+ const pkg = JSON.parse(readFileSync14(join16(here, "..", "..", "package.json"), "utf-8"));
25765
26264
  return pkg.version ?? "unknown";
25766
26265
  } catch {
25767
26266
  return "unknown";
25768
26267
  }
25769
26268
  }
25770
26269
  function spawnBackgroundFlush() {
25771
- const entry = join13(here, "..", "index.js");
26270
+ const entry = join16(here, "..", "index.js");
25772
26271
  spawn(process.execPath, [entry, "moves", "flush"], {
25773
26272
  detached: true,
25774
26273
  stdio: "ignore"
@@ -25780,18 +26279,22 @@ async function main() {
25780
26279
  let raw;
25781
26280
  let parsed;
25782
26281
  try {
25783
- raw = readFileSync11(0, "utf-8");
25784
- parsed = normalizeEnvelope(JSON.parse(raw), agent);
26282
+ raw = await readHookStdin();
26283
+ const incoming = JSON.parse(raw);
26284
+ if (agent !== "cursor" && shouldSuppressImportedCursorHandler(incoming, "prim-hook")) return;
26285
+ parsed = normalizeEnvelope(incoming, agent);
25785
26286
  } catch (error) {
25786
26287
  writeHookDebug("capture failed", error);
25787
- await emitOutput(buildHookOutput({}));
26288
+ await emitOutput(cursorPassiveOutput());
25788
26289
  return;
25789
26290
  }
25790
26291
  const cwd = parsed.cwd ?? process.cwd();
25791
26292
  const isClaudeStop = agent === "claude_code" && parsed.hook_event_name === "Stop";
25792
26293
  const isCodexContextEvent = agent === "codex" && (parsed.hook_event_name === "UserPromptSubmit" || parsed.hook_event_name === "Stop");
25793
26294
  if (!isRepoActiveForCapture(cwd)) {
25794
- if (isClaudeStop || isCodexContextEvent) await emitOutput(buildHookOutput({}));
26295
+ if (isClaudeStop || isCodexContextEvent || agent === "cursor") {
26296
+ await emitOutput(cursorPassiveOutput());
26297
+ }
25795
26298
  return;
25796
26299
  }
25797
26300
  const identity = getOrCreateWorkspaceId(cwd);
@@ -25803,7 +26306,8 @@ async function main() {
25803
26306
  const resolution = enrichment?.resolution;
25804
26307
  const hasPathEvidence = resolution !== void 0 && (resolution.fileRefs.length > 0 || resolution.rejected.length > 0 || resolution.targetsIncomplete || resolution.targetsTruncated || resolution.shellMutation === "unresolved");
25805
26308
  const pathsComplete = resolution !== void 0 && !resolution.targetsIncomplete && !resolution.targetsTruncated && resolution.rejected.length === 0 && resolution.shellMutation !== "unresolved";
25806
- if (cachedCollectScopeAdmits(cwd, {
26309
+ const cursorAmbiguousTargets = agent === "cursor" && resolution !== void 0 && (resolution.rejected.length > 0 || resolution.targetsIncomplete || resolution.targetsTruncated || resolution.shellMutation === "unresolved");
26310
+ if (!cursorAmbiguousTargets && cachedCollectScopeAdmits(cwd, {
25807
26311
  repository: resolvedRepository?.repoFullName,
25808
26312
  branch: currentBranch(cwd),
25809
26313
  agent,
@@ -25826,7 +26330,7 @@ async function main() {
25826
26330
  };
25827
26331
  const { orgId } = resolveOrg({ sessionId: move.sessionId, cwd });
25828
26332
  appendMove(move, orgId);
25829
- if (shouldFlushAfter(move.eventType)) {
26333
+ if (shouldFlushAfter(move.eventType, agent)) {
25830
26334
  spawnBackgroundFlush();
25831
26335
  }
25832
26336
  }
@@ -25838,6 +26342,10 @@ async function main() {
25838
26342
  await emitOutput(result.output, result.acknowledge);
25839
26343
  return;
25840
26344
  }
26345
+ if (agent === "cursor") {
26346
+ await emitOutput(cursorPassiveOutput());
26347
+ return;
26348
+ }
25841
26349
  if (!isClaudeStop) return;
25842
26350
  const sessionId = typeof parsed.session_id === "string" ? parsed.session_id : "";
25843
26351
  if (!workspaceId || !sessionId) {
@@ -25866,5 +26374,13 @@ async function main() {
25866
26374
  }
25867
26375
  void main().catch(async (error) => {
25868
26376
  writeHookDebug("capture failed", error);
25869
- if (!outputAttempted) await emitOutput(buildHookOutput({}));
26377
+ if (!outputAttempted) await emitOutput(cursorPassiveOutput());
25870
26378
  });
26379
+ function cursorPassiveOutput() {
26380
+ if (parseAgent(process.argv) !== "cursor") return buildHookOutput({});
26381
+ const index = process.argv.indexOf("--event");
26382
+ const event = index === -1 ? void 0 : process.argv[index + 1];
26383
+ if (event === "beforeSubmitPrompt") return { continue: true };
26384
+ if (event === "preToolUse") return { permission: "allow" };
26385
+ return {};
26386
+ }