@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
@@ -115,6 +115,61 @@ function canonicalGitRoot(cwd) {
115
115
  return null;
116
116
  }
117
117
  }
118
+ function normalizeOriginRemote(remote) {
119
+ const value = remote.trim();
120
+ if (!value) return void 0;
121
+ const scp = !value.includes("://") ? /^(?:[^@/\s]+@)?(?<host>[^:/\s]+):(?<path>.+)$/.exec(value)?.groups : void 0;
122
+ if (scp?.host && scp.path) {
123
+ const path = scp.path.replace(/^\/+|\/+$/g, "").replace(/\.git$/i, "");
124
+ return path ? `${scp.host.toLowerCase()}/${path}` : void 0;
125
+ }
126
+ try {
127
+ const url = new URL(value);
128
+ url.username = "";
129
+ url.password = "";
130
+ url.search = "";
131
+ url.hash = "";
132
+ const path = url.pathname.replace(/^\/+|\/+$/g, "").replace(/\.git$/i, "");
133
+ if (url.host && path) return `${url.host.toLowerCase()}/${path}`;
134
+ return void 0;
135
+ } catch {
136
+ return void 0;
137
+ }
138
+ }
139
+ function opaqueRepoKey(source, value) {
140
+ return `repo_v1_${createHash("sha256").update(`${source}\0${value}`).digest("hex")}`;
141
+ }
142
+ function resolveRepositoryContext(cwd = process.cwd()) {
143
+ const top = gitToplevel(cwd);
144
+ if (!top) return null;
145
+ let repoRoot;
146
+ try {
147
+ repoRoot = realpathSync.native(top);
148
+ } catch {
149
+ repoRoot = resolve(top);
150
+ }
151
+ const origin = gitValue(repoRoot, ["config", "--get", "remote.origin.url"]);
152
+ const repoFullName = githubRepositoryFullName(repoRoot) ?? void 0;
153
+ const normalizedOrigin = origin ? normalizeOriginRemote(origin) : void 0;
154
+ if (normalizedOrigin) {
155
+ return {
156
+ repoRoot,
157
+ repoKey: opaqueRepoKey("origin", normalizedOrigin),
158
+ identitySource: "origin",
159
+ repoFullName
160
+ };
161
+ }
162
+ const roots = gitValue(repoRoot, ["rev-list", "--max-parents=0", "HEAD"])?.split(/\s+/).filter(Boolean).sort();
163
+ if (roots && roots.length > 0) {
164
+ return {
165
+ repoRoot,
166
+ repoKey: opaqueRepoKey("root_commit", roots.join("\n")),
167
+ identitySource: "root_commit",
168
+ repoFullName
169
+ };
170
+ }
171
+ return { repoRoot, repoFullName };
172
+ }
118
173
  function nearestExistingAncestor(path) {
119
174
  const suffix = [];
120
175
  let cursor = path;
@@ -197,7 +252,7 @@ var PRIM_REPO_SYNC_REPOSITORY_KEY = "prim.repoSyncRepository";
197
252
  var PRIM_REPO_BINDING_STATE_KEY = "prim.repoBindingState";
198
253
  var GIT_TIMEOUT_MS2 = 1e3;
199
254
  var REPO_SYNC_ID_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/;
200
- var PROJECT_INSTALL_FILES = [".claude/settings.json", ".codex/hooks.json"];
255
+ var PROJECT_INSTALL_FILES = [".claude/settings.json", ".codex/hooks.json", ".cursor/hooks.json"];
201
256
  var PRIM_HOOK_BINS = ["prim-hook", "prim-pre-tool-use", "prim-post-tool-use"];
202
257
  function repoActiveFlag(cwd) {
203
258
  try {
@@ -279,6 +334,7 @@ import { dirname as dirname2, isAbsolute as isAbsolute2, join as join2 } from "p
279
334
  import { fileURLToPath } from "url";
280
335
  var PKG_NAME = "@primitive.ai/prim";
281
336
  var ROOT_WALK_LIMIT = 6;
337
+ var STABLE_HOOK_LAUNCHER_NAME = "prim-hook-launcher-v1";
282
338
  var resolvedRoot;
283
339
  function locateRoot() {
284
340
  if (resolvedRoot !== void 0) {
@@ -309,6 +365,34 @@ function locateRoot() {
309
365
  function packageVersion() {
310
366
  return locateRoot()?.version ?? null;
311
367
  }
368
+ function shellQuote(value) {
369
+ return `'${value.replaceAll("'", `'"'"'`)}'`;
370
+ }
371
+ var STABLE_HOOK_ARGUMENTS_RE = /^[-A-Za-z0-9_ ]*$/u;
372
+ var STABLE_HOOK_BIN_RE = /^[A-Za-z0-9][A-Za-z0-9-]*$/u;
373
+ function stableHookCommand(bin, args = "") {
374
+ if (!STABLE_HOOK_BIN_RE.test(bin) || !STABLE_HOOK_ARGUMENTS_RE.test(args)) {
375
+ throw new Error("invalid stable hook command");
376
+ }
377
+ const resolver = [
378
+ // #242 and earlier identify managed commands by this package marker. Keep
379
+ // it as inert data during the rolling window so an older uninstall or
380
+ // reinstall can remove the stable entry without invoking npm or PATH.
381
+ `prim_legacy_reader='-p ${PKG_NAME}@stable prim-shim.sh ${bin} '; `,
382
+ 'prim_absolute() { case "$1" in [/]* ) ;; *) return 1 ;; esac; case "$1" in [[:space:]]*|*[[:space:]]|*[/][/]*|*[/].[/]*|*[/]..[/]*|*[/].|*[/]..|?*[/]) return 1 ;; esac; }; ',
383
+ 'prim_config=${PRIM_CONFIG_DIR:-}; if ! prim_absolute "$prim_config"; then prim_config=${XDG_CONFIG_HOME:-}; if prim_absolute "$prim_config"; then ',
384
+ 'case "$prim_config" in /) prim_config=/prim ;; *) prim_config="$prim_config/prim" ;; esac; ',
385
+ '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; ',
386
+ "fi; fi; ",
387
+ `case "$prim_config" in /) prim_launcher=/${STABLE_HOOK_LAUNCHER_NAME} ;; *) prim_launcher="$prim_config/${STABLE_HOOK_LAUNCHER_NAME}" ;; esac; `,
388
+ 'exec "$prim_launcher" "$@"'
389
+ ].join("");
390
+ const suffix = args ? ` ${args}` : "";
391
+ return `/bin/sh -c ${shellQuote(resolver)} ${STABLE_HOOK_LAUNCHER_NAME} ${bin}${suffix}`;
392
+ }
393
+ function detachedHookShimCommand(bin, args = "") {
394
+ return `payload=$(cat); { trap '' HUP; printf '%s' "$payload" | { ${stableHookCommand(bin, args)}; }; } </dev/null >/dev/null 2>&1 &`;
395
+ }
312
396
 
313
397
  // src/client.ts
314
398
  import { createHash as createHash3 } from "crypto";
@@ -803,14 +887,14 @@ function throwIfAborted(signal) {
803
887
  }
804
888
  async function defaultSleep(ms, signal) {
805
889
  if (!signal) {
806
- await new Promise((resolve3) => setTimeout(resolve3, ms));
890
+ await new Promise((resolve5) => setTimeout(resolve5, ms));
807
891
  return;
808
892
  }
809
893
  throwIfAborted(signal);
810
- await new Promise((resolve3, reject) => {
894
+ await new Promise((resolve5, reject) => {
811
895
  const timer = setTimeout(() => {
812
896
  signal.removeEventListener("abort", onAbort);
813
- resolve3();
897
+ resolve5();
814
898
  }, ms);
815
899
  const onAbort = () => {
816
900
  clearTimeout(timer);
@@ -2166,7 +2250,7 @@ function validate23(data, { instancePath = "", parentData, parentDataProperty, r
2166
2250
  return errors === 0;
2167
2251
  }
2168
2252
  validate23.evaluated = { "props": true, "dynamicProps": false, "dynamicItems": false };
2169
- 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": {} };
2253
+ 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": {} };
2170
2254
  function validate24(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
2171
2255
  ;
2172
2256
  let vErrors = null;
@@ -2717,7 +2801,7 @@ function validate24(data, { instancePath = "", parentData, parentDataProperty, r
2717
2801
  }
2718
2802
  errors++;
2719
2803
  }
2720
- if (!(data18 === "claude_code" || data18 === "codex" || data18 === "hermes")) {
2804
+ if (!(data18 === "claude_code" || data18 === "codex" || data18 === "cursor" || data18 === "hermes")) {
2721
2805
  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" };
2722
2806
  if (vErrors === null) {
2723
2807
  vErrors = [err34];
@@ -3486,7 +3570,7 @@ function validate26(data, { instancePath = "", parentData, parentDataProperty, r
3486
3570
  return errors === 0;
3487
3571
  }
3488
3572
  validate26.evaluated = { "dynamicProps": true, "dynamicItems": false };
3489
- 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"] };
3573
+ 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"] };
3490
3574
  function validate27(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
3491
3575
  ;
3492
3576
  let vErrors = null;
@@ -4190,7 +4274,7 @@ function validate27(data, { instancePath = "", parentData, parentDataProperty, r
4190
4274
  }
4191
4275
  errors++;
4192
4276
  }
4193
- if (!(data34 === "claude_code" || data34 === "codex" || data34 === "hermes")) {
4277
+ if (!(data34 === "claude_code" || data34 === "codex" || data34 === "cursor" || data34 === "hermes")) {
4194
4278
  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" };
4195
4279
  if (vErrors === null) {
4196
4280
  vErrors = [err19];
@@ -4418,7 +4502,7 @@ function validate27(data, { instancePath = "", parentData, parentDataProperty, r
4418
4502
  return errors === 0;
4419
4503
  }
4420
4504
  validate27.evaluated = { "props": true, "dynamicProps": false, "dynamicItems": false };
4421
- 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": {} };
4505
+ 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": {} };
4422
4506
  function validate28(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
4423
4507
  ;
4424
4508
  let vErrors = null;
@@ -4954,7 +5038,7 @@ function validate28(data, { instancePath = "", parentData, parentDataProperty, r
4954
5038
  }
4955
5039
  errors++;
4956
5040
  }
4957
- if (!(data22 === "claude_code" || data22 === "codex" || data22 === "hermes")) {
5041
+ if (!(data22 === "claude_code" || data22 === "codex" || data22 === "cursor" || data22 === "hermes")) {
4958
5042
  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" };
4959
5043
  if (vErrors === null) {
4960
5044
  vErrors = [err19];
@@ -5186,7 +5270,7 @@ function validate28(data, { instancePath = "", parentData, parentDataProperty, r
5186
5270
  return errors === 0;
5187
5271
  }
5188
5272
  validate28.evaluated = { "props": true, "dynamicProps": false, "dynamicItems": false };
5189
- 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": {} };
5273
+ 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": {} };
5190
5274
  function validate29(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
5191
5275
  ;
5192
5276
  let vErrors = null;
@@ -6480,7 +6564,7 @@ function validate29(data, { instancePath = "", parentData, parentDataProperty, r
6480
6564
  }
6481
6565
  errors++;
6482
6566
  }
6483
- if (!(data70 === "claude_code" || data70 === "codex" || data70 === "hermes")) {
6567
+ if (!(data70 === "claude_code" || data70 === "codex" || data70 === "cursor" || data70 === "hermes")) {
6484
6568
  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" };
6485
6569
  if (vErrors === null) {
6486
6570
  vErrors = [err24];
@@ -7041,7 +7125,7 @@ function validate33(data, { instancePath = "", parentData, parentDataProperty, r
7041
7125
  return errors === 0;
7042
7126
  }
7043
7127
  validate33.evaluated = { "props": true, "dynamicProps": false, "dynamicItems": false };
7044
- 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": {} };
7128
+ 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": {} };
7045
7129
  function validate34(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
7046
7130
  ;
7047
7131
  let vErrors = null;
@@ -7682,7 +7766,7 @@ function validate34(data, { instancePath = "", parentData, parentDataProperty, r
7682
7766
  }
7683
7767
  errors++;
7684
7768
  }
7685
- if (!(data19 === "claude_code" || data19 === "codex" || data19 === "hermes")) {
7769
+ if (!(data19 === "claude_code" || data19 === "codex" || data19 === "cursor" || data19 === "hermes")) {
7686
7770
  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" };
7687
7771
  if (vErrors === null) {
7688
7772
  vErrors = [err38];
@@ -7910,7 +7994,7 @@ function validate34(data, { instancePath = "", parentData, parentDataProperty, r
7910
7994
  return errors === 0;
7911
7995
  }
7912
7996
  validate34.evaluated = { "props": true, "dynamicProps": false, "dynamicItems": false };
7913
- 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": {} }] };
7997
+ 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": {} }] };
7914
7998
  function validate35(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
7915
7999
  ;
7916
8000
  let vErrors = null;
@@ -8548,7 +8632,7 @@ function validate35(data, { instancePath = "", parentData, parentDataProperty, r
8548
8632
  }
8549
8633
  errors++;
8550
8634
  }
8551
- if (!(data21 === "claude_code" || data21 === "codex" || data21 === "hermes")) {
8635
+ if (!(data21 === "claude_code" || data21 === "codex" || data21 === "cursor" || data21 === "hermes")) {
8552
8636
  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" };
8553
8637
  if (vErrors === null) {
8554
8638
  vErrors = [err41];
@@ -9472,7 +9556,7 @@ function validate35(data, { instancePath = "", parentData, parentDataProperty, r
9472
9556
  }
9473
9557
  errors++;
9474
9558
  }
9475
- if (!(data49 === "claude_code" || data49 === "codex" || data49 === "hermes")) {
9559
+ if (!(data49 === "claude_code" || data49 === "codex" || data49 === "cursor" || data49 === "hermes")) {
9476
9560
  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" };
9477
9561
  if (vErrors === null) {
9478
9562
  vErrors = [err100];
@@ -15118,7 +15202,7 @@ function validate50(data, { instancePath = "", parentData, parentDataProperty, r
15118
15202
  return errors === 0;
15119
15203
  }
15120
15204
  validate50.evaluated = { "dynamicProps": true, "dynamicItems": false };
15121
- 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": {} };
15205
+ 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": {} };
15122
15206
  var pattern8 = new RegExp("^[A-Za-z0-9_-]+$", "u");
15123
15207
  function validate51(data, { instancePath = "", parentData, parentDataProperty, rootData = data, dynamicAnchors = {} } = {}) {
15124
15208
  ;
@@ -15372,7 +15456,7 @@ function validate51(data, { instancePath = "", parentData, parentDataProperty, r
15372
15456
  }
15373
15457
  errors++;
15374
15458
  }
15375
- if (!(data10 === "claude_code" || data10 === "codex" || data10 === "hermes")) {
15459
+ if (!(data10 === "claude_code" || data10 === "codex" || data10 === "cursor" || data10 === "hermes")) {
15376
15460
  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" };
15377
15461
  if (vErrors === null) {
15378
15462
  vErrors = [err16];
@@ -15684,7 +15768,7 @@ function validate51(data, { instancePath = "", parentData, parentDataProperty, r
15684
15768
  }
15685
15769
  errors++;
15686
15770
  }
15687
- if (!(data21 === "claude_code" || data21 === "codex" || data21 === "hermes")) {
15771
+ if (!(data21 === "claude_code" || data21 === "codex" || data21 === "cursor" || data21 === "hermes")) {
15688
15772
  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" };
15689
15773
  if (vErrors === null) {
15690
15774
  vErrors = [err38];
@@ -15821,7 +15905,7 @@ function validate51(data, { instancePath = "", parentData, parentDataProperty, r
15821
15905
  return errors === 0;
15822
15906
  }
15823
15907
  validate51.evaluated = { "props": true, "dynamicProps": false, "dynamicItems": false };
15824
- 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"] };
15908
+ 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"] };
15825
15909
  var pattern10 = new RegExp("^[A-Za-z0-9._:-]{1,128}$", "u");
15826
15910
  var pattern12 = new RegExp("^[A-Za-z0-9]{1,64}$", "u");
15827
15911
  var pattern13 = new RegExp("^(?!@?$)(?!\\/)(?!.*\\/$)(?!.*\\/\\/)(?!.*(?:^|\\/)\\.{1,2}(?:\\/|$))(?!.*(?:^|\\/)[^/]*\\.lock(?:\\/|$))(?!.*\\.\\.)(?!.*@\\{)(?!.*[~^:?*\\\\]).+$", "u");
@@ -15877,7 +15961,7 @@ function validate52(data, { instancePath = "", parentData, parentDataProperty, r
15877
15961
  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" }];
15878
15962
  return false;
15879
15963
  }
15880
- if (!(data1 === "claude_code" || data1 === "codex" || data1 === "hermes")) {
15964
+ if (!(data1 === "claude_code" || data1 === "codex" || data1 === "cursor" || data1 === "hermes")) {
15881
15965
  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" }];
15882
15966
  return false;
15883
15967
  }
@@ -19252,7 +19336,7 @@ function optionalUserScopeMembers(record) {
19252
19336
  members.push({ kind: "role", role: candidate.role });
19253
19337
  continue;
19254
19338
  }
19255
- if (candidate.kind === "agent" && (candidate.agent === "claude_code" || candidate.agent === "codex" || candidate.agent === "hermes")) {
19339
+ if (candidate.kind === "agent" && (candidate.agent === "claude_code" || candidate.agent === "codex" || candidate.agent === "cursor" || candidate.agent === "hermes")) {
19256
19340
  members.push({ kind: "agent", agent: candidate.agent });
19257
19341
  continue;
19258
19342
  }
@@ -19419,7 +19503,7 @@ function cachedCollectScopeAdmits(cwd, facts) {
19419
19503
  function parseAgent(argv) {
19420
19504
  const i = argv.indexOf("--agent");
19421
19505
  const value = i !== -1 ? argv[i + 1] : void 0;
19422
- if (value === "codex" || value === "hermes") {
19506
+ if (value === "codex" || value === "cursor" || value === "hermes") {
19423
19507
  return value;
19424
19508
  }
19425
19509
  return "claude_code";
@@ -19506,7 +19590,7 @@ function daemonRequest(method, params = {}, opts = {}) {
19506
19590
  ...caller ? { caller } : {}
19507
19591
  };
19508
19592
  const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
19509
- return new Promise((resolve3) => {
19593
+ return new Promise((resolve5) => {
19510
19594
  let settled = false;
19511
19595
  let socket;
19512
19596
  let buffer = Buffer.alloc(0);
@@ -19521,7 +19605,7 @@ function daemonRequest(method, params = {}, opts = {}) {
19521
19605
  } catch {
19522
19606
  }
19523
19607
  }
19524
- resolve3(value);
19608
+ resolve5(value);
19525
19609
  };
19526
19610
  const timer = setTimeout(() => settle(null), timeoutMs);
19527
19611
  timer.unref();
@@ -19706,9 +19790,7 @@ var CODEX_DRAFT_DIGEST_MAX_SEEN_IDS = 4096;
19706
19790
  var CODEX_DIGEST_STATE_RETENTION_MS = 7 * 24 * 60 * 60 * 1e3;
19707
19791
  var CODEX_DIGEST_STATE_MAX_FILES = 256;
19708
19792
  var STATE_VERSION = 1;
19709
- var STATE_DIRECTORY = ["codex", "decision-digests"];
19710
19793
  var DRAFT_STATE_VERSION = 2;
19711
- var DRAFT_STATE_DIRECTORY = ["codex", "decision-draft-deliveries"];
19712
19794
  var NO_CURSOR = -1;
19713
19795
  function hasVisibleCodexMessage(output) {
19714
19796
  if (typeof output !== "object" || output === null || Array.isArray(output)) return false;
@@ -19740,11 +19822,11 @@ function appendCodexContext(output, context) {
19740
19822
  }
19741
19823
  return next;
19742
19824
  }
19743
- function stateRoot() {
19744
- return join8(primConfigDirectory(), ...STATE_DIRECTORY);
19825
+ function stateRoot(namespace) {
19826
+ return join8(primConfigDirectory(), namespace, "decision-digests");
19745
19827
  }
19746
- function draftStateRoot() {
19747
- return join8(primConfigDirectory(), ...DRAFT_STATE_DIRECTORY);
19828
+ function draftStateRoot(namespace) {
19829
+ return join8(primConfigDirectory(), namespace, "decision-draft-deliveries");
19748
19830
  }
19749
19831
  function workspaceFor(cwd) {
19750
19832
  try {
@@ -19756,12 +19838,12 @@ function workspaceFor(cwd) {
19756
19838
  function statePath(args) {
19757
19839
  const identity = `${args.siteUrl}\0${workspaceFor(args.cwd)}\0${args.sessionId}`;
19758
19840
  const key = createHash5("sha256").update(identity).digest("hex");
19759
- return join8(stateRoot(), `${key}.json`);
19841
+ return join8(stateRoot(args.namespace), `${key}.json`);
19760
19842
  }
19761
19843
  function draftStatePath(args) {
19762
19844
  const identity = `${args.siteUrl}\0${workspaceFor(args.cwd)}\0${args.sessionId}\0${args.principalId}\0${args.organizationId}\0${args.credentialFingerprint}`;
19763
19845
  const key = createHash5("sha256").update(identity).digest("hex");
19764
- return join8(draftStateRoot(), `${key}.json`);
19846
+ return join8(draftStateRoot(args.namespace), `${key}.json`);
19765
19847
  }
19766
19848
  function parseState(value) {
19767
19849
  if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
@@ -19952,14 +20034,14 @@ function mergeState(latest, args) {
19952
20034
  updatedAt: args.now
19953
20035
  };
19954
20036
  }
19955
- async function commitState(path, args) {
20037
+ async function commitState(path, args, namespace) {
19956
20038
  try {
19957
20039
  await withFileLock(
19958
20040
  `${path}.lock`,
19959
20041
  () => {
19960
20042
  const latest = readState(path);
19961
- writeStateFile(path, stateRoot(), mergeState(latest, args));
19962
- cleanupStateFiles(stateRoot(), args.now);
20043
+ writeStateFile(path, stateRoot(namespace), mergeState(latest, args));
20044
+ cleanupStateFiles(stateRoot(namespace), args.now);
19963
20045
  },
19964
20046
  { timeoutMs: 50, pollMs: 10 }
19965
20047
  );
@@ -19981,7 +20063,7 @@ function mergeDraftState(latest, args) {
19981
20063
  updatedAt: args.now
19982
20064
  };
19983
20065
  }
19984
- async function commitDraftState(path, args) {
20066
+ async function commitDraftState(path, args, namespace) {
19985
20067
  try {
19986
20068
  let next;
19987
20069
  await withFileLock(
@@ -19989,8 +20071,8 @@ async function commitDraftState(path, args) {
19989
20071
  () => {
19990
20072
  const latest = readDraftState(path);
19991
20073
  next = mergeDraftState(latest, args);
19992
- writeStateFile(path, draftStateRoot(), next);
19993
- cleanupStateFiles(draftStateRoot(), args.now);
20074
+ writeStateFile(path, draftStateRoot(namespace), next);
20075
+ cleanupStateFiles(draftStateRoot(namespace), args.now);
19994
20076
  },
19995
20077
  { timeoutMs: 50, pollMs: 10 }
19996
20078
  );
@@ -20000,9 +20082,10 @@ async function commitDraftState(path, args) {
20000
20082
  }
20001
20083
  }
20002
20084
  async function prepareCodexContext(options) {
20085
+ const namespace = options.namespace ?? "codex";
20003
20086
  const siteUrl = getSiteUrl();
20004
20087
  const workspace = workspaceFor(options.cwd);
20005
- const path = statePath({ cwd: options.cwd, sessionId: options.sessionId, siteUrl });
20088
+ const path = statePath({ cwd: options.cwd, sessionId: options.sessionId, siteUrl, namespace });
20006
20089
  const previous = readState(path);
20007
20090
  const principal = resolveDaemonPrincipal();
20008
20091
  const privatePath = principal ? draftStatePath({
@@ -20011,7 +20094,8 @@ async function prepareCodexContext(options) {
20011
20094
  siteUrl,
20012
20095
  principalId: principal.principalId,
20013
20096
  organizationId: principal.organizationId,
20014
- credentialFingerprint: principal.credentialFingerprint
20097
+ credentialFingerprint: principal.credentialFingerprint,
20098
+ namespace
20015
20099
  }) : void 0;
20016
20100
  const previousDraft = privatePath ? readDraftState(privatePath) : void 0;
20017
20101
  const startup = options.startup === true;
@@ -20101,32 +20185,40 @@ async function prepareCodexContext(options) {
20101
20185
  acknowledge: async (handedOff) => {
20102
20186
  if (!handedOff || acknowledged) return;
20103
20187
  acknowledged = true;
20104
- await commitState(path, {
20105
- sessionId: options.sessionId,
20106
- siteUrl,
20107
- workspace,
20108
- startedAt,
20109
- watermarkMs: pageWatermark,
20110
- seenIds: freshRows.map((row) => row.id),
20111
- report,
20112
- feedAvailable,
20113
- now: Date.now()
20114
- });
20188
+ await commitState(
20189
+ path,
20190
+ {
20191
+ sessionId: options.sessionId,
20192
+ siteUrl,
20193
+ workspace,
20194
+ startedAt,
20195
+ watermarkMs: pageWatermark,
20196
+ seenIds: freshRows.map((row) => row.id),
20197
+ report,
20198
+ feedAvailable,
20199
+ now: Date.now()
20200
+ },
20201
+ namespace
20202
+ );
20115
20203
  if (privatePath === void 0 || principal === void 0 || draftPageToken === void 0) {
20116
20204
  return;
20117
20205
  }
20118
20206
  let persistedDraft = previousDraft;
20119
20207
  if (draftDigest?.deliveredIds.length) {
20120
- persistedDraft = await commitDraftState(privatePath, {
20121
- sessionId: options.sessionId,
20122
- siteUrl,
20123
- workspace,
20124
- principalId: principal.principalId,
20125
- organizationId: principal.organizationId,
20126
- credentialFingerprint: principal.credentialFingerprint,
20127
- deliveredIds: draftDigest.deliveredIds,
20128
- now: Date.now()
20129
- });
20208
+ persistedDraft = await commitDraftState(
20209
+ privatePath,
20210
+ {
20211
+ sessionId: options.sessionId,
20212
+ siteUrl,
20213
+ workspace,
20214
+ principalId: principal.principalId,
20215
+ organizationId: principal.organizationId,
20216
+ credentialFingerprint: principal.credentialFingerprint,
20217
+ deliveredIds: draftDigest.deliveredIds,
20218
+ now: Date.now()
20219
+ },
20220
+ namespace
20221
+ );
20130
20222
  }
20131
20223
  const seenDrafts = new Set(persistedDraft?.seenDraftIds ?? []);
20132
20224
  const deliveredOnThisPage = draftPageActionableIds.filter((id) => seenDrafts.has(id));
@@ -20143,8 +20235,325 @@ async function prepareCodexContext(options) {
20143
20235
  };
20144
20236
  }
20145
20237
 
20238
+ // src/commands/cursor-install.ts
20239
+ import { existsSync as existsSync8, readFileSync as readFileSync9 } from "fs";
20240
+ import { homedir as homedir4 } from "os";
20241
+ import { isAbsolute as isAbsolute5, join as join11 } from "path";
20242
+
20243
+ // src/lib/hook-runtime.ts
20244
+ import { createHash as createHash6, randomBytes as randomBytes4 } from "crypto";
20245
+ import {
20246
+ constants as constants2,
20247
+ accessSync,
20248
+ chmodSync as chmodSync3,
20249
+ copyFileSync,
20250
+ existsSync as existsSync6,
20251
+ lstatSync as lstatSync2,
20252
+ mkdirSync as mkdirSync5,
20253
+ mkdtempSync,
20254
+ readFileSync as readFileSync7,
20255
+ readdirSync as readdirSync2,
20256
+ realpathSync as realpathSync2,
20257
+ renameSync as renameSync3,
20258
+ rmSync as rmSync5,
20259
+ statSync as statSync3,
20260
+ utimesSync,
20261
+ writeFileSync as writeFileSync4
20262
+ } from "fs";
20263
+ import { dirname as dirname6, isAbsolute as isAbsolute4, join as join9, resolve as resolve3 } from "path";
20264
+ var RELEASE_PREFIX = "release-";
20265
+ var MAX_MANIFEST_BYTES = 64 * 1024;
20266
+ var RELEASE_GRACE_MS = 10 * 60 * 1e3;
20267
+ var HOOK_RUNTIME_ENTRIES = {
20268
+ // SessionStart self-healing resolves this exact CLI entry to run
20269
+ // `daemon ensure`; it must travel with the immutable hook release.
20270
+ prim: "dist/index.js",
20271
+ "prim-hook": "dist/hooks/prim-hook.js",
20272
+ "prim-pre-commit": "dist/hooks/pre-commit.js",
20273
+ "prim-post-commit": "dist/hooks/post-commit.js",
20274
+ "prim-post-rewrite": "dist/hooks/post-rewrite.js",
20275
+ "prim-pre-tool-use": "dist/hooks/pre-tool-use.js",
20276
+ "prim-post-tool-use": "dist/hooks/post-tool-use.js",
20277
+ "prim-session-start": "dist/hooks/session-start.js",
20278
+ "prim-session-end": "dist/hooks/session-end.js",
20279
+ "prim-daemon-server": "dist/daemon/server.js",
20280
+ "prim-statusline": "dist/statusline-main.js"
20281
+ };
20282
+ var SOURCE_ENTRIES = Object.fromEntries(
20283
+ Object.entries(HOOK_RUNTIME_ENTRIES).map(([bin, target]) => [
20284
+ bin,
20285
+ target.replace(/^dist\//u, "")
20286
+ ])
20287
+ );
20288
+ var STABLE_HOOK_LAUNCHER_CONTENT = `#!/bin/sh
20289
+ set -eu
20290
+ case "$0" in */*) prim_launcher_dir=\${0%/*} ;; *) exit 78 ;; esac
20291
+ IFS= read -r prim_release_name < "$prim_launcher_dir/hook-runtime/current" || exit 69
20292
+ case "$prim_release_name" in ${RELEASE_PREFIX}*) ;; *) exit 69 ;; esac
20293
+ prim_release_id=\${prim_release_name#${RELEASE_PREFIX}}
20294
+ case "$prim_release_id" in *[!0-9a-f]*|"") exit 69 ;; esac
20295
+ [ "\${#prim_release_id}" -eq 64 ] || exit 69
20296
+ prim_release="$prim_launcher_dir/hook-runtime/releases/$prim_release_name"
20297
+ case "\${1-}" in
20298
+ ${Object.entries(HOOK_RUNTIME_ENTRIES).map(([bin, entry]) => ` ${bin}) prim_entry="$prim_release/${entry}" ;;`).join("\n")}
20299
+ *) exit 64 ;;
20300
+ esac
20301
+ shift
20302
+ IFS= read -r prim_node < "$prim_release/node" || exit 69
20303
+ case "$prim_node" in /*) ;; *) exit 69 ;; esac
20304
+ [ -x "$prim_node" ] && [ -f "$prim_entry" ] || exit 69
20305
+ exec "$prim_node" "$prim_entry" "$@"
20306
+ `;
20307
+
20308
+ // src/commands/claude-install.ts
20309
+ import { existsSync as existsSync7, readFileSync as readFileSync8 } from "fs";
20310
+ import { homedir as homedir3 } from "os";
20311
+ import { join as join10 } from "path";
20312
+ var CAPTURE_BIN = "prim-hook";
20313
+ var GATE_BIN = "prim-pre-tool-use";
20314
+ var POST_TOOL_USE_BIN = "prim-post-tool-use";
20315
+ var SESSION_START_BIN = "prim-session-start";
20316
+ var SESSION_END_BIN = "prim-session-end";
20317
+ var STATUSLINE_BIN = "prim-statusline";
20318
+ var STATUSLINE_ARGS = "";
20319
+ var STATUSLINE_COMMAND = stableHookCommand(STATUSLINE_BIN, STATUSLINE_ARGS);
20320
+ var USER_SCOPE_PATH = join10(homedir3(), ".claude", "settings.json");
20321
+ function projectRoot() {
20322
+ return gitToplevel() ?? process.cwd();
20323
+ }
20324
+ var CAPTURE_EVENTS = [
20325
+ "SessionStart",
20326
+ "UserPromptSubmit",
20327
+ "PreToolUse",
20328
+ "PostToolUse",
20329
+ "PostToolUseFailure",
20330
+ "Stop",
20331
+ "SessionEnd",
20332
+ "SubagentStop"
20333
+ ];
20334
+ function makeRegistration(event, matcher, bin, args = "") {
20335
+ return {
20336
+ event,
20337
+ matcher,
20338
+ bin,
20339
+ command: stableHookCommand(bin, args)
20340
+ };
20341
+ }
20342
+ function makeDetachedRegistration(event, matcher, bin, args = "") {
20343
+ return { event, matcher, bin, command: detachedHookShimCommand(bin, args) };
20344
+ }
20345
+ var REGISTRATIONS = [
20346
+ ...CAPTURE_EVENTS.map(
20347
+ (event) => event === "SessionEnd" ? makeDetachedRegistration(event, "*", CAPTURE_BIN) : makeRegistration(event, "*", CAPTURE_BIN)
20348
+ ),
20349
+ makeRegistration("PreToolUse", "Edit|Write|MultiEdit|NotebookEdit|Bash", GATE_BIN),
20350
+ makeRegistration("PostToolUse", "Edit|Write|MultiEdit|NotebookEdit|Bash", POST_TOOL_USE_BIN),
20351
+ makeRegistration(
20352
+ "PostToolUseFailure",
20353
+ "Edit|Write|MultiEdit|NotebookEdit|Bash",
20354
+ POST_TOOL_USE_BIN
20355
+ ),
20356
+ makeRegistration("SessionStart", "*", SESSION_START_BIN),
20357
+ makeDetachedRegistration("SessionEnd", "*", SESSION_END_BIN)
20358
+ ];
20359
+ var PRIM_PERMISSION_RULE = "Bash(npx --yes @primitive.ai/prim*)";
20360
+ var LEGACY_PRIM_PERMISSION_RULES = [
20361
+ "Bash(npx --yes @primitive.ai/prim@latest:*)",
20362
+ "Bash(npx --yes @primitive.ai/prim:*)"
20363
+ ];
20364
+ var ALL_PRIM_PERMISSION_RULES = /* @__PURE__ */ new Set([
20365
+ PRIM_PERMISSION_RULE,
20366
+ ...LEGACY_PRIM_PERMISSION_RULES
20367
+ ]);
20368
+
20369
+ // src/commands/cursor-install.ts
20370
+ var CAPTURE_BIN2 = "prim-hook";
20371
+ var GATE_BIN2 = "prim-pre-tool-use";
20372
+ var POST_TOOL_BIN = "prim-post-tool-use";
20373
+ var SESSION_START_BIN2 = "prim-session-start";
20374
+ var SESSION_END_BIN2 = "prim-session-end";
20375
+ var STATUSLINE_BIN2 = "prim-statusline";
20376
+ var CURSOR_EVENTS = [
20377
+ "sessionStart",
20378
+ "beforeSubmitPrompt",
20379
+ "preToolUse",
20380
+ "postToolUse",
20381
+ "postToolUseFailure",
20382
+ "afterAgentResponse",
20383
+ "subagentStop",
20384
+ "stop",
20385
+ "sessionEnd"
20386
+ ];
20387
+ var REGISTRATIONS2 = [
20388
+ ...CURSOR_EVENTS.map((event) => ({ event, bin: CAPTURE_BIN2 })),
20389
+ { event: "preToolUse", bin: GATE_BIN2, matcher: "Write|Delete|Shell", timeout: 10 },
20390
+ { event: "postToolUse", bin: POST_TOOL_BIN },
20391
+ { event: "postToolUseFailure", bin: POST_TOOL_BIN },
20392
+ { event: "sessionStart", bin: SESSION_START_BIN2 },
20393
+ { event: "sessionEnd", bin: SESSION_END_BIN2 }
20394
+ ];
20395
+ function cursorConfigDirectory(env = process.env, home = homedir4(), platform = process.platform) {
20396
+ const explicit = env.CURSOR_CONFIG_DIR?.trim();
20397
+ if (explicit && isAbsolute5(explicit)) return explicit;
20398
+ const xdg = env.XDG_CONFIG_HOME?.trim();
20399
+ if (platform !== "darwin" && xdg && isAbsolute5(xdg)) return join11(xdg, "cursor");
20400
+ return join11(home, ".cursor");
20401
+ }
20402
+ function cursorHooksPath(scope, root = projectRoot()) {
20403
+ return scope === "user" ? join11(cursorConfigDirectory(), "hooks.json") : join11(root, ".cursor", "hooks.json");
20404
+ }
20405
+ function plainObject(value) {
20406
+ return typeof value === "object" && value !== null && !Array.isArray(value);
20407
+ }
20408
+ function readCursorHooks(path) {
20409
+ if (!existsSync8(path)) return {};
20410
+ let parsed;
20411
+ try {
20412
+ parsed = JSON.parse(readFileSync9(path, "utf8"));
20413
+ } catch {
20414
+ throw new Error(`invalid Cursor hooks JSON at ${path}`);
20415
+ }
20416
+ if (!plainObject(parsed)) throw new Error(`Cursor hooks config must be an object: ${path}`);
20417
+ if (parsed.version !== void 0 && parsed.version !== 1) {
20418
+ throw new Error(`unsupported Cursor hooks version at ${path} (expected version 1)`);
20419
+ }
20420
+ if (parsed.hooks !== void 0) {
20421
+ if (!plainObject(parsed.hooks)) throw new Error(`Cursor hooks must be an object: ${path}`);
20422
+ for (const [event, entries] of Object.entries(parsed.hooks)) {
20423
+ if (!Array.isArray(entries) || !entries.every(plainObject)) {
20424
+ throw new Error(`Cursor hook list must contain objects: ${event} in ${path}`);
20425
+ }
20426
+ }
20427
+ }
20428
+ return parsed;
20429
+ }
20430
+ function commandFor(registration, scope) {
20431
+ return stableHookCommand(
20432
+ registration.bin,
20433
+ `--agent cursor --event ${registration.event} --scope ${scope}`
20434
+ );
20435
+ }
20436
+ var OWNED_COMMANDS = new Set(
20437
+ ["project", "user"].flatMap(
20438
+ (scope) => REGISTRATIONS2.map((registration) => commandFor(registration, scope))
20439
+ )
20440
+ );
20441
+ function jsoncUnsafeCommand(command) {
20442
+ return command.replace('case "$1" in [/]* ', 'case "$1" in /*').replace("*[/][/]*", "*//*").replace("*[/].[/]*", "*/./*").replace("*[/]..[/]*", "*/../*").replace("*[/].", "*/.").replace("*[/]..", "*/..").replace("?*[/]", "?*/");
20443
+ }
20444
+ var JSONC_UNSAFE_OWNED_COMMANDS = new Set([...OWNED_COMMANDS].map(jsoncUnsafeCommand));
20445
+ function hookFor(registration, scope) {
20446
+ return {
20447
+ command: commandFor(registration, scope),
20448
+ ...registration.matcher ? { matcher: registration.matcher } : {},
20449
+ ...registration.timeout ? { timeout: registration.timeout } : {}
20450
+ };
20451
+ }
20452
+ function exactHook(entry, registration, scope) {
20453
+ return JSON.stringify(entry) === JSON.stringify(hookFor(registration, scope));
20454
+ }
20455
+ function hasExactCursorHandler(settings, event, bin, scope) {
20456
+ const registration = REGISTRATIONS2.find(
20457
+ (candidate) => candidate.event === event && candidate.bin === bin
20458
+ );
20459
+ return registration ? (settings.hooks?.[event] ?? []).some((entry) => exactHook(entry, registration, scope)) : false;
20460
+ }
20461
+ var FOOTER = {
20462
+ type: "command",
20463
+ command: stableHookCommand(STATUSLINE_BIN2),
20464
+ updateIntervalMs: 1e3,
20465
+ timeoutMs: 2e3
20466
+ };
20467
+ var JSONC_UNSAFE_FOOTER = {
20468
+ ...FOOTER,
20469
+ command: jsoncUnsafeCommand(FOOTER.command)
20470
+ };
20471
+
20472
+ // src/hooks/cursor-coexistence.ts
20473
+ var CURSOR_EVENTS2 = /* @__PURE__ */ new Set([
20474
+ "sessionStart",
20475
+ "beforeSubmitPrompt",
20476
+ "preToolUse",
20477
+ "postToolUse",
20478
+ "postToolUseFailure",
20479
+ "afterAgentResponse",
20480
+ "subagentStop",
20481
+ "stop",
20482
+ "sessionEnd"
20483
+ ]);
20484
+ function cursorEvidence(parsed) {
20485
+ 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);
20486
+ }
20487
+ function uniqueProjectRoot(parsed) {
20488
+ if (!Array.isArray(parsed.workspace_roots)) return;
20489
+ const roots = new Set(
20490
+ parsed.workspace_roots.filter((value) => typeof value === "string" && value.length > 0).map((value) => resolveRepositoryContext(value)?.repoRoot).filter((value) => !!value)
20491
+ );
20492
+ return roots.size === 1 ? [...roots][0] : void 0;
20493
+ }
20494
+ function shouldSuppressImportedCursorHandler(parsed, bin) {
20495
+ if (!cursorEvidence(parsed)) return false;
20496
+ const project = uniqueProjectRoot(parsed);
20497
+ if (project) {
20498
+ try {
20499
+ if (hasExactCursorHandler(
20500
+ readCursorHooks(cursorHooksPath("project", project)),
20501
+ parsed.hook_event_name,
20502
+ bin,
20503
+ "project"
20504
+ )) {
20505
+ return true;
20506
+ }
20507
+ } catch {
20508
+ }
20509
+ }
20510
+ try {
20511
+ return hasExactCursorHandler(
20512
+ readCursorHooks(cursorHooksPath("user")),
20513
+ parsed.hook_event_name,
20514
+ bin,
20515
+ "user"
20516
+ );
20517
+ } catch {
20518
+ return false;
20519
+ }
20520
+ }
20521
+
20522
+ // src/hooks/hook-stdin.ts
20523
+ var DEFAULT_MAX_BYTES = 1024 * 1024;
20524
+ function readHookStdin(timeoutMs = 1e3, maxBytes = DEFAULT_MAX_BYTES) {
20525
+ return new Promise((resolve5, reject) => {
20526
+ const chunks = [];
20527
+ let bytes = 0;
20528
+ let settled = false;
20529
+ const finish = (error) => {
20530
+ if (settled) return;
20531
+ settled = true;
20532
+ clearTimeout(timer);
20533
+ process.stdin.removeAllListeners("data");
20534
+ process.stdin.removeAllListeners("end");
20535
+ process.stdin.removeAllListeners("error");
20536
+ if (error) reject(error);
20537
+ else resolve5(Buffer.concat(chunks, bytes).toString("utf-8"));
20538
+ };
20539
+ const timer = setTimeout(() => finish(new Error("stdin read timeout")), timeoutMs);
20540
+ process.stdin.on("data", (chunk) => {
20541
+ bytes += chunk.length;
20542
+ if (bytes > maxBytes) {
20543
+ finish(new Error("stdin envelope exceeds size limit"));
20544
+ return;
20545
+ }
20546
+ chunks.push(chunk);
20547
+ });
20548
+ process.stdin.on("end", () => finish());
20549
+ process.stdin.on("error", (error) => finish(error));
20550
+ });
20551
+ }
20552
+
20146
20553
  // src/hooks/normalize.ts
20147
- import { createHash as createHash6 } from "crypto";
20554
+ import { createHash as createHash7 } from "crypto";
20555
+ import { realpathSync as realpathSync3 } from "fs";
20556
+ import { isAbsolute as isAbsolute6, resolve as resolve4 } from "path";
20148
20557
  var HERMES_EVENT_MAP = {
20149
20558
  on_session_start: "SessionStart",
20150
20559
  on_session_end: "SessionEnd",
@@ -20154,7 +20563,125 @@ var HERMES_EVENT_MAP = {
20154
20563
  post_tool_call: "PostToolUse",
20155
20564
  subagent_stop: "SubagentStop"
20156
20565
  };
20566
+ var CURSOR_EVENT_MAP = {
20567
+ sessionStart: "SessionStart",
20568
+ beforeSubmitPrompt: "UserPromptSubmit",
20569
+ preToolUse: "PreToolUse",
20570
+ postToolUse: "PostToolUse",
20571
+ postToolUseFailure: "PostToolUseFailure",
20572
+ afterAgentResponse: "AssistantResponse",
20573
+ subagentStop: "SubagentStop",
20574
+ stop: "Stop",
20575
+ sessionEnd: "SessionEnd"
20576
+ };
20577
+ var CURSOR_TOOL_EVENTS = /* @__PURE__ */ new Set(["PreToolUse", "PostToolUse", "PostToolUseFailure"]);
20578
+ var SAFE_CORRELATION_ID_RE = /^[A-Za-z0-9._:-]{1,128}$/u;
20579
+ var CURSOR_LOCAL_ONLY_FIELDS = /* @__PURE__ */ new Set([
20580
+ "conversation_id",
20581
+ "generation_id",
20582
+ "user_email",
20583
+ "account_email",
20584
+ "transcript_path",
20585
+ "transcript",
20586
+ "thought",
20587
+ "thoughts",
20588
+ "thinking",
20589
+ "tool_output"
20590
+ ]);
20591
+ function requiredId(value, field) {
20592
+ if (typeof value !== "string" || value.length === 0) {
20593
+ throw new TypeError(`Cursor hook envelope is missing ${field}`);
20594
+ }
20595
+ return value;
20596
+ }
20597
+ function cursorToolUseId(value) {
20598
+ if (SAFE_CORRELATION_ID_RE.test(value)) return value;
20599
+ return `cursor:tool:v1:${createHash7("sha256").update(value).digest("hex")}`;
20600
+ }
20601
+ function workspaceCandidates(value) {
20602
+ if (!Array.isArray(value)) return [];
20603
+ const roots = value.filter((item) => typeof item === "string" && item.length > 0);
20604
+ if (roots.some((root) => !isAbsolute6(root))) {
20605
+ throw new TypeError("Cursor workspace roots must be absolute");
20606
+ }
20607
+ return roots;
20608
+ }
20609
+ function pathIdentity(path) {
20610
+ try {
20611
+ return realpathSync3.native(path);
20612
+ } catch {
20613
+ return resolve4(path);
20614
+ }
20615
+ }
20616
+ function resolveCursorCwd(parsed) {
20617
+ const roots = workspaceCandidates(parsed.workspace_roots).map(pathIdentity);
20618
+ const rootRepositories = roots.map((root) => resolveRepositoryContext(root)?.repoRoot);
20619
+ const repositoryRoots = new Set(rootRepositories.filter((root) => !!root));
20620
+ if (repositoryRoots.size > 1) {
20621
+ throw new TypeError("Cursor hook envelope spans multiple repositories");
20622
+ }
20623
+ if (roots.length > 1 && rootRepositories.some((root) => root === void 0)) {
20624
+ throw new TypeError("Cursor hook envelope has ambiguous workspace roots");
20625
+ }
20626
+ const expectedRepo = [...repositoryRoots][0];
20627
+ const rawCwd = typeof parsed.cwd === "string" && parsed.cwd.length > 0 ? parsed.cwd : void 0;
20628
+ if (rawCwd && !isAbsolute6(rawCwd)) {
20629
+ throw new TypeError("Cursor hook cwd must be absolute");
20630
+ }
20631
+ const envelopeCwd = rawCwd ? pathIdentity(rawCwd) : void 0;
20632
+ const input = typeof parsed.tool_input === "object" && parsed.tool_input !== null && !Array.isArray(parsed.tool_input) ? parsed.tool_input : void 0;
20633
+ const rawToolCwd = parsed.tool_name === "Shell" && typeof input?.working_directory === "string" ? input.working_directory : void 0;
20634
+ const base = envelopeCwd ?? (roots.length === 1 ? roots[0] : expectedRepo);
20635
+ if (rawToolCwd && !isAbsolute6(rawToolCwd) && !base) {
20636
+ throw new TypeError("relative Cursor tool cwd has no workspace base");
20637
+ }
20638
+ const toolCwd = rawToolCwd ? pathIdentity(isAbsolute6(rawToolCwd) ? rawToolCwd : resolve4(base, rawToolCwd)) : void 0;
20639
+ const selected = toolCwd ?? envelopeCwd ?? (roots.length === 1 ? roots[0] : expectedRepo);
20640
+ if (!selected) {
20641
+ throw new TypeError("Cursor hook envelope has no unambiguous workspace");
20642
+ }
20643
+ const selectedRepo = resolveRepositoryContext(selected)?.repoRoot;
20644
+ if (expectedRepo && selectedRepo !== expectedRepo) {
20645
+ throw new TypeError("Cursor hook cwd conflicts with workspace repository");
20646
+ }
20647
+ return selected;
20648
+ }
20649
+ function normalizeCursorEnvelope(parsed) {
20650
+ const rawEvent = requiredId(parsed.hook_event_name, "hook_event_name");
20651
+ const event = CURSOR_EVENT_MAP[rawEvent];
20652
+ if (!event) throw new TypeError(`unsupported Cursor hook event: ${rawEvent}`);
20653
+ const sessionId = requiredId(parsed.conversation_id, "conversation_id");
20654
+ const turnId = requiredId(parsed.generation_id, "generation_id");
20655
+ if (parsed.session_id !== void 0 && parsed.session_id !== sessionId) {
20656
+ throw new TypeError("Cursor conversation_id conflicts with session_id");
20657
+ }
20658
+ if (parsed.turn_id !== void 0 && parsed.turn_id !== turnId) {
20659
+ throw new TypeError("Cursor generation_id conflicts with turn_id");
20660
+ }
20661
+ const rawToolUseId = CURSOR_TOOL_EVENTS.has(event) ? requiredId(parsed.tool_use_id, "tool_use_id") : void 0;
20662
+ const normalized = {
20663
+ ...Object.fromEntries(
20664
+ Object.entries(parsed).filter(([key]) => !CURSOR_LOCAL_ONLY_FIELDS.has(key))
20665
+ ),
20666
+ hook_event_name: event,
20667
+ session_id: sessionId,
20668
+ turn_id: turnId,
20669
+ cwd: resolveCursorCwd(parsed),
20670
+ ...rawToolUseId === void 0 ? {} : { tool_use_id: cursorToolUseId(rawToolUseId) }
20671
+ };
20672
+ if (typeof parsed.tool_output === "string") {
20673
+ try {
20674
+ normalized.tool_response = JSON.parse(parsed.tool_output);
20675
+ } catch {
20676
+ normalized.tool_response = parsed.tool_output;
20677
+ }
20678
+ }
20679
+ return normalized;
20680
+ }
20157
20681
  function normalizeEnvelope(parsed, agent2) {
20682
+ if (agent2 === "cursor") {
20683
+ return normalizeCursorEnvelope(parsed);
20684
+ }
20158
20685
  if (agent2 === "codex") {
20159
20686
  const event = parsed.hook_event_name;
20160
20687
  if ((event === "PreToolUse" || event === "PostToolUse") && (typeof parsed.tool_use_id !== "string" || parsed.tool_use_id.length === 0)) {
@@ -20166,7 +20693,7 @@ function normalizeEnvelope(parsed, agent2) {
20166
20693
  ]);
20167
20694
  return {
20168
20695
  ...parsed,
20169
- tool_use_id: `codex:fallback:v1:${createHash6("sha256").update(stableToolIdentity).digest("hex")}`
20696
+ tool_use_id: `codex:fallback:v1:${createHash7("sha256").update(stableToolIdentity).digest("hex")}`
20170
20697
  };
20171
20698
  }
20172
20699
  return parsed;
@@ -20182,7 +20709,7 @@ function normalizeEnvelope(parsed, agent2) {
20182
20709
  }
20183
20710
 
20184
20711
  // src/hooks/pre-tool-use-scoring.ts
20185
- import { isAbsolute as isAbsolute4, relative as relative2, sep as sep2 } from "path";
20712
+ import { isAbsolute as isAbsolute7, relative as relative2, sep as sep2 } from "path";
20186
20713
  function anyUnverified(results) {
20187
20714
  return results.some((r) => r.verdict === "unavailable" || r.truncated);
20188
20715
  }
@@ -20255,6 +20782,14 @@ function buildCodexOutput(aggregate, results) {
20255
20782
  hookSpecificOutput: { hookEventName: "PreToolUse", additionalContext: notes }
20256
20783
  } : {};
20257
20784
  }
20785
+ function buildCursorOutput(aggregate, results) {
20786
+ if (aggregate === "deny" || aggregate === "ask") {
20787
+ const reason = blockingReason(results);
20788
+ return { permission: "deny", user_message: reason, agent_message: reason };
20789
+ }
20790
+ const notes = advisoryNote(aggregate, results);
20791
+ return notes ? { permission: "allow", agent_message: notes } : { permission: "allow" };
20792
+ }
20258
20793
  function failOpenOutput() {
20259
20794
  return {
20260
20795
  hookSpecificOutput: {
@@ -20266,6 +20801,9 @@ function failOpenOutput() {
20266
20801
  function failOpenCodex() {
20267
20802
  return {};
20268
20803
  }
20804
+ function failOpenCursor() {
20805
+ return { permission: "allow" };
20806
+ }
20269
20807
  function buildHermesOutput(aggregate, results) {
20270
20808
  if (aggregate !== "deny" && aggregate !== "ask") {
20271
20809
  return {};
@@ -20348,10 +20886,25 @@ function extractHermesFileTargets(toolName, toolInput) {
20348
20886
  const mode = input.mode;
20349
20887
  return { paths, complete: paths.length > 0 && (mode === void 0 || mode === "replace") };
20350
20888
  }
20889
+ function extractCursorFileTargets(toolName, toolInput) {
20890
+ if (toolName !== "Write" && toolName !== "Delete") return null;
20891
+ if (!toolInput || typeof toolInput !== "object" || Array.isArray(toolInput)) {
20892
+ return { paths: [], complete: false };
20893
+ }
20894
+ const input = toolInput;
20895
+ const candidates = [input.file_path, input.path].filter(
20896
+ (value) => typeof value === "string" && value.length > 0
20897
+ );
20898
+ const paths = [...new Set(candidates)];
20899
+ return { paths, complete: paths.length === 1 };
20900
+ }
20351
20901
  function extractFileTargets(toolName, toolInput, agent2 = "claude_code") {
20352
20902
  if (agent2 === "codex") {
20353
20903
  return extractCodexFileTargets(toolName, toolInput);
20354
20904
  }
20905
+ if (agent2 === "cursor") {
20906
+ return extractCursorFileTargets(toolName, toolInput);
20907
+ }
20355
20908
  if (agent2 === "hermes") {
20356
20909
  return extractHermesFileTargets(toolName, toolInput);
20357
20910
  }
@@ -20402,8 +20955,8 @@ function boundedHealthError(value) {
20402
20955
  }
20403
20956
 
20404
20957
  // src/hooks/redact.ts
20405
- import { existsSync as existsSync6, readFileSync as readFileSync7, statSync as statSync3 } from "fs";
20406
- import { join as join9 } from "path";
20958
+ import { existsSync as existsSync9, readFileSync as readFileSync10, statSync as statSync4 } from "fs";
20959
+ import { join as join12 } from "path";
20407
20960
  import { Worker } from "worker_threads";
20408
20961
  var USER_HOME_RULES = [
20409
20962
  {
@@ -24965,7 +25518,7 @@ function analyzeShellTargets(source) {
24965
25518
 
24966
25519
  // src/hooks/preflight-v3.ts
24967
25520
  var PREFLIGHT_PROTOCOL_VERSION = 3;
24968
- var PREFLIGHT_TIMEOUT_MS = 9500;
25521
+ var PREFLIGHT_TIMEOUT_MS = 6500;
24969
25522
  var MAX_PREFLIGHT_PATHS = 32;
24970
25523
  var MAX_PROPOSAL_BYTES = 6144;
24971
25524
  var MAX_CLIENT_VERSION_CHARS = 32;
@@ -24981,7 +25534,8 @@ function resolvePreflightTargets(args) {
24981
25534
  let coverage = "complete";
24982
25535
  let mutation = "present";
24983
25536
  let definite = false;
24984
- if ((args.agent === "claude_code" || args.agent === "codex") && args.toolName === "Bash") {
25537
+ const shellTool = (args.agent === "claude_code" || args.agent === "codex") && args.toolName === "Bash" || args.agent === "cursor" && args.toolName === "Shell";
25538
+ if (shellTool) {
24985
25539
  const command = typeof args.toolInput === "string" ? args.toolInput : args.toolInput && typeof args.toolInput === "object" ? args.toolInput.command : void 0;
24986
25540
  if (typeof command !== "string") {
24987
25541
  return { paths: [], coverage: "unverified", mutation: "present" };
@@ -25091,31 +25645,14 @@ function unverifiedResult(message) {
25091
25645
 
25092
25646
  // src/hooks/pre-tool-use.ts
25093
25647
  var STDIN_TIMEOUT_MS = 1e3;
25094
- async function readStdin() {
25095
- return new Promise((resolve3, reject) => {
25096
- const chunks = [];
25097
- const timer = setTimeout(() => {
25098
- reject(new Error("stdin read timeout"));
25099
- }, STDIN_TIMEOUT_MS);
25100
- process.stdin.on("data", (chunk) => chunks.push(chunk));
25101
- process.stdin.on("end", () => {
25102
- clearTimeout(timer);
25103
- resolve3(Buffer.concat(chunks).toString("utf-8"));
25104
- });
25105
- process.stdin.on("error", (err) => {
25106
- clearTimeout(timer);
25107
- reject(err);
25108
- });
25109
- });
25110
- }
25111
25648
  var agent = parseAgent(process.argv);
25112
25649
  async function emit(output) {
25113
- return await new Promise((resolve3) => {
25650
+ return await new Promise((resolve5) => {
25114
25651
  try {
25115
25652
  process.stdout.write(`${JSON.stringify(output)}
25116
- `, (error) => resolve3(!error));
25653
+ `, (error) => resolve5(!error));
25117
25654
  } catch {
25118
- resolve3(false);
25655
+ resolve5(false);
25119
25656
  }
25120
25657
  });
25121
25658
  }
@@ -25125,6 +25662,7 @@ async function emitWithAcknowledgment(output, acknowledge) {
25125
25662
  }
25126
25663
  function failOpen() {
25127
25664
  if (agent === "hermes") return failOpenHermes();
25665
+ if (agent === "cursor") return failOpenCursor();
25128
25666
  return agent === "codex" ? failOpenCodex() : failOpenOutput();
25129
25667
  }
25130
25668
  function invocationId(envelope) {
@@ -25149,6 +25687,10 @@ async function emitUnverified(message, envelope) {
25149
25687
  process.stderr.write(`[primitive] ${message}
25150
25688
  `);
25151
25689
  await emit(failOpenHermes());
25690
+ } else if (agent === "cursor") {
25691
+ process.stderr.write(`[primitive] ${message}
25692
+ `);
25693
+ await emit(buildCursorOutput("allow", [result]));
25152
25694
  } else {
25153
25695
  let output = agent === "codex" ? buildCodexOutput("allow", [result]) : buildHookOutput("allow", [result]);
25154
25696
  if (agent === "codex" && typeof envelope?.session_id === "string" && envelope.session_id) {
@@ -25170,17 +25712,19 @@ async function emitUnverified(message, envelope) {
25170
25712
  async function main() {
25171
25713
  let raw;
25172
25714
  try {
25173
- raw = await readStdin();
25715
+ raw = await readHookStdin(STDIN_TIMEOUT_MS);
25174
25716
  } catch {
25175
25717
  await emit(failOpen());
25176
25718
  return;
25177
25719
  }
25178
25720
  let envelope;
25179
25721
  try {
25180
- envelope = normalizeEnvelope(
25181
- JSON.parse(raw),
25182
- agent
25183
- );
25722
+ const incoming = JSON.parse(raw);
25723
+ if (agent !== "cursor" && shouldSuppressImportedCursorHandler(incoming, "prim-pre-tool-use")) {
25724
+ await emit(failOpenCursor());
25725
+ return;
25726
+ }
25727
+ envelope = normalizeEnvelope(incoming, agent);
25184
25728
  } catch {
25185
25729
  await emit(failOpen());
25186
25730
  return;
@@ -25215,6 +25759,10 @@ async function main() {
25215
25759
  await emit(failOpen());
25216
25760
  return;
25217
25761
  }
25762
+ if (agent === "cursor" && targets.coverage === "unverified") {
25763
+ await emitUnverified("tool targets were ambiguous or outside the active repository", envelope);
25764
+ return;
25765
+ }
25218
25766
  const binding = repoSyncId(cwd);
25219
25767
  const branch = currentBranch(cwd);
25220
25768
  const sessionId = envelope.session_id;
@@ -25267,7 +25815,7 @@ async function main() {
25267
25815
  if (advisory) process.stderr.write(`${advisory}
25268
25816
  `);
25269
25817
  }
25270
- let output = agent === "hermes" ? buildHermesOutput(aggregate, [result]) : agent === "codex" ? buildCodexOutput(aggregate, [result]) : buildHookOutput(aggregate, [result]);
25818
+ let output = agent === "hermes" ? buildHermesOutput(aggregate, [result]) : agent === "cursor" ? buildCursorOutput(aggregate, [result]) : agent === "codex" ? buildCodexOutput(aggregate, [result]) : buildHookOutput(aggregate, [result]);
25271
25819
  if (agent === "codex" && hasVisibleCodexMessage(output) && typeof sessionId === "string" && sessionId.length > 0) {
25272
25820
  try {
25273
25821
  const context = await prepareCodexContext({ cwd, sessionId, includeDigest: false });