@hasna/loops 0.3.45 → 0.3.46

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.
package/README.md CHANGED
@@ -299,7 +299,9 @@ worktree, pass those stores explicitly with `--add-dir` or template `addDirs`.
299
299
  For task-created routes, pass `--todos-project` so worker/verifier prompts use
300
300
  the actual todos storage project while repo routing and worktree isolation still
301
301
  use the repository path. This avoids `danger-full-access` for normal todos
302
- comments, completion state, and loop evidence writes.
302
+ comments, completion state, and loop evidence writes. `addDirs` is intentionally
303
+ accepted only for Codewith/Codex until other providers expose equivalent
304
+ directory-scoped write controls.
303
305
 
304
306
  Inspect route state with:
305
307
 
@@ -497,7 +499,7 @@ The adapters intentionally use provider command surfaces instead of pretending e
497
499
  - Claude uses `claude -p --output-format json` and safe-mode/local setting sources by default.
498
500
  - Codewith uses `codewith --ask-for-approval never exec --json --ephemeral --skip-git-repo-check`, with `--add-dir` for explicit extra writable directories.
499
501
  - AI Copilot and OpenCode use `run --format json --pure`.
500
- - Cursor is CLI-first for now via `cursor agent -p`, with `agent -p` as the fallback launcher on machines that expose the standalone Cursor Agent binary; treat output as less stable until a stronger public SDK contract is selected.
502
+ - Cursor is CLI-first for now via standalone `agent -p` when available, with `cursor agent -p` as a compatibility fallback; treat output as less stable until a stronger public SDK contract is selected.
501
503
  - Codex uses `codex exec --json --ephemeral --skip-git-repo-check`, with `--add-dir` for explicit extra writable directories where supported.
502
504
  - Agent prompts are sent through child stdin instead of argv so prompt bodies do not appear in process listings.
503
505
  - When `--account` or a step `account` is set, OpenLoops resolves `accounts env <profile> --tool <tool>` before spawning the target, strips inherited tool home/API-key variables, and applies the selected profile only to that process. Missing account profiles fail before the provider binary receives the prompt.
package/dist/cli/index.js CHANGED
@@ -389,6 +389,9 @@ function validateTarget(value, label) {
389
389
  if (value.variant !== undefined)
390
390
  assertString(value.variant, `${label}.variant`);
391
391
  optionalStringArray(value.addDirs, `${label}.addDirs`);
392
+ if (Array.isArray(value.addDirs) && value.addDirs.length > 0 && !["codewith", "codex"].includes(value.provider)) {
393
+ throw new Error(`${label}.addDirs is currently supported only for provider codewith or codex`);
394
+ }
392
395
  if (value.permissionMode !== undefined) {
393
396
  assertString(value.permissionMode, `${label}.permissionMode`);
394
397
  const permissionModes = ["default", "plan", "auto", "bypass"];
@@ -3154,6 +3157,9 @@ function assertSupportedAgentOptions(target) {
3154
3157
  if (target.authProfile !== undefined && target.provider !== "codewith") {
3155
3158
  throw new Error(`${target.provider}.authProfile is supported only for codewith`);
3156
3159
  }
3160
+ if (target.addDirs?.length && !["codewith", "codex"].includes(target.provider)) {
3161
+ throw new Error(`${target.provider}.addDirs is currently supported only for codewith or codex`);
3162
+ }
3157
3163
  if (target.permissionMode && !["default", "plan", "auto", "bypass"].includes(target.permissionMode)) {
3158
3164
  throw new Error(`${target.provider}.permissionMode must be default, plan, auto, or bypass`);
3159
3165
  }
@@ -3213,10 +3219,10 @@ function agentArgs(target) {
3213
3219
  case "cursor":
3214
3220
  args.push("-c", [
3215
3221
  "set -eu",
3216
- "if command -v cursor >/dev/null 2>&1; then",
3217
- ' exec cursor agent "$@"',
3218
- "elif command -v agent >/dev/null 2>&1; then",
3222
+ "if command -v agent >/dev/null 2>&1; then",
3219
3223
  ' exec agent "$@"',
3224
+ "elif command -v cursor >/dev/null 2>&1; then",
3225
+ ' exec cursor agent "$@"',
3220
3226
  "else",
3221
3227
  " echo 'Executable not found in PATH: cursor agent or agent' >&2",
3222
3228
  " exit 127",
@@ -5737,7 +5743,7 @@ function buildScriptInventoryReport(store, opts = {}) {
5737
5743
  // package.json
5738
5744
  var package_default = {
5739
5745
  name: "@hasna/loops",
5740
- version: "0.3.45",
5746
+ version: "0.3.46",
5741
5747
  description: "Persistent local loop and workflow runner for deterministic commands and headless AI coding agents",
5742
5748
  type: "module",
5743
5749
  main: "dist/index.js",
@@ -8593,6 +8599,7 @@ eventsHandle.command("generic").description("create a one-shot worker/verifier w
8593
8599
  model: opts.model,
8594
8600
  variant: opts.variant,
8595
8601
  agent: opts.agent,
8602
+ addDirs: listFromRepeatedOpts(opts.addDir),
8596
8603
  permissionMode,
8597
8604
  sandbox,
8598
8605
  manualBreakGlass: Boolean(opts.manualBreakGlass),
@@ -389,6 +389,9 @@ function validateTarget(value, label) {
389
389
  if (value.variant !== undefined)
390
390
  assertString(value.variant, `${label}.variant`);
391
391
  optionalStringArray(value.addDirs, `${label}.addDirs`);
392
+ if (Array.isArray(value.addDirs) && value.addDirs.length > 0 && !["codewith", "codex"].includes(value.provider)) {
393
+ throw new Error(`${label}.addDirs is currently supported only for provider codewith or codex`);
394
+ }
392
395
  if (value.permissionMode !== undefined) {
393
396
  assertString(value.permissionMode, `${label}.permissionMode`);
394
397
  const permissionModes = ["default", "plan", "auto", "bypass"];
@@ -3038,6 +3041,9 @@ function assertSupportedAgentOptions(target) {
3038
3041
  if (target.authProfile !== undefined && target.provider !== "codewith") {
3039
3042
  throw new Error(`${target.provider}.authProfile is supported only for codewith`);
3040
3043
  }
3044
+ if (target.addDirs?.length && !["codewith", "codex"].includes(target.provider)) {
3045
+ throw new Error(`${target.provider}.addDirs is currently supported only for codewith or codex`);
3046
+ }
3041
3047
  if (target.permissionMode && !["default", "plan", "auto", "bypass"].includes(target.permissionMode)) {
3042
3048
  throw new Error(`${target.provider}.permissionMode must be default, plan, auto, or bypass`);
3043
3049
  }
@@ -3097,10 +3103,10 @@ function agentArgs(target) {
3097
3103
  case "cursor":
3098
3104
  args.push("-c", [
3099
3105
  "set -eu",
3100
- "if command -v cursor >/dev/null 2>&1; then",
3101
- ' exec cursor agent "$@"',
3102
- "elif command -v agent >/dev/null 2>&1; then",
3106
+ "if command -v agent >/dev/null 2>&1; then",
3103
3107
  ' exec agent "$@"',
3108
+ "elif command -v cursor >/dev/null 2>&1; then",
3109
+ ' exec cursor agent "$@"',
3104
3110
  "else",
3105
3111
  " echo 'Executable not found in PATH: cursor agent or agent' >&2",
3106
3112
  " exit 127",
@@ -5051,7 +5057,7 @@ function enableStartup(result) {
5051
5057
  // package.json
5052
5058
  var package_default = {
5053
5059
  name: "@hasna/loops",
5054
- version: "0.3.45",
5060
+ version: "0.3.46",
5055
5061
  description: "Persistent local loop and workflow runner for deterministic commands and headless AI coding agents",
5056
5062
  type: "module",
5057
5063
  main: "dist/index.js",
package/dist/index.js CHANGED
@@ -387,6 +387,9 @@ function validateTarget(value, label) {
387
387
  if (value.variant !== undefined)
388
388
  assertString(value.variant, `${label}.variant`);
389
389
  optionalStringArray(value.addDirs, `${label}.addDirs`);
390
+ if (Array.isArray(value.addDirs) && value.addDirs.length > 0 && !["codewith", "codex"].includes(value.provider)) {
391
+ throw new Error(`${label}.addDirs is currently supported only for provider codewith or codex`);
392
+ }
390
393
  if (value.permissionMode !== undefined) {
391
394
  assertString(value.permissionMode, `${label}.permissionMode`);
392
395
  const permissionModes = ["default", "plan", "auto", "bypass"];
@@ -3028,6 +3031,9 @@ function assertSupportedAgentOptions(target) {
3028
3031
  if (target.authProfile !== undefined && target.provider !== "codewith") {
3029
3032
  throw new Error(`${target.provider}.authProfile is supported only for codewith`);
3030
3033
  }
3034
+ if (target.addDirs?.length && !["codewith", "codex"].includes(target.provider)) {
3035
+ throw new Error(`${target.provider}.addDirs is currently supported only for codewith or codex`);
3036
+ }
3031
3037
  if (target.permissionMode && !["default", "plan", "auto", "bypass"].includes(target.permissionMode)) {
3032
3038
  throw new Error(`${target.provider}.permissionMode must be default, plan, auto, or bypass`);
3033
3039
  }
@@ -3087,10 +3093,10 @@ function agentArgs(target) {
3087
3093
  case "cursor":
3088
3094
  args.push("-c", [
3089
3095
  "set -eu",
3090
- "if command -v cursor >/dev/null 2>&1; then",
3091
- ' exec cursor agent "$@"',
3092
- "elif command -v agent >/dev/null 2>&1; then",
3096
+ "if command -v agent >/dev/null 2>&1; then",
3093
3097
  ' exec agent "$@"',
3098
+ "elif command -v cursor >/dev/null 2>&1; then",
3099
+ ' exec cursor agent "$@"',
3094
3100
  "else",
3095
3101
  " echo 'Executable not found in PATH: cursor agent or agent' >&2",
3096
3102
  " exit 127",
package/dist/lib/store.js CHANGED
@@ -387,6 +387,9 @@ function validateTarget(value, label) {
387
387
  if (value.variant !== undefined)
388
388
  assertString(value.variant, `${label}.variant`);
389
389
  optionalStringArray(value.addDirs, `${label}.addDirs`);
390
+ if (Array.isArray(value.addDirs) && value.addDirs.length > 0 && !["codewith", "codex"].includes(value.provider)) {
391
+ throw new Error(`${label}.addDirs is currently supported only for provider codewith or codex`);
392
+ }
390
393
  if (value.permissionMode !== undefined) {
391
394
  assertString(value.permissionMode, `${label}.permissionMode`);
392
395
  const permissionModes = ["default", "plan", "auto", "bypass"];
package/dist/sdk/index.js CHANGED
@@ -387,6 +387,9 @@ function validateTarget(value, label) {
387
387
  if (value.variant !== undefined)
388
388
  assertString(value.variant, `${label}.variant`);
389
389
  optionalStringArray(value.addDirs, `${label}.addDirs`);
390
+ if (Array.isArray(value.addDirs) && value.addDirs.length > 0 && !["codewith", "codex"].includes(value.provider)) {
391
+ throw new Error(`${label}.addDirs is currently supported only for provider codewith or codex`);
392
+ }
390
393
  if (value.permissionMode !== undefined) {
391
394
  assertString(value.permissionMode, `${label}.permissionMode`);
392
395
  const permissionModes = ["default", "plan", "auto", "bypass"];
@@ -3028,6 +3031,9 @@ function assertSupportedAgentOptions(target) {
3028
3031
  if (target.authProfile !== undefined && target.provider !== "codewith") {
3029
3032
  throw new Error(`${target.provider}.authProfile is supported only for codewith`);
3030
3033
  }
3034
+ if (target.addDirs?.length && !["codewith", "codex"].includes(target.provider)) {
3035
+ throw new Error(`${target.provider}.addDirs is currently supported only for codewith or codex`);
3036
+ }
3031
3037
  if (target.permissionMode && !["default", "plan", "auto", "bypass"].includes(target.permissionMode)) {
3032
3038
  throw new Error(`${target.provider}.permissionMode must be default, plan, auto, or bypass`);
3033
3039
  }
@@ -3087,10 +3093,10 @@ function agentArgs(target) {
3087
3093
  case "cursor":
3088
3094
  args.push("-c", [
3089
3095
  "set -eu",
3090
- "if command -v cursor >/dev/null 2>&1; then",
3091
- ' exec cursor agent "$@"',
3092
- "elif command -v agent >/dev/null 2>&1; then",
3096
+ "if command -v agent >/dev/null 2>&1; then",
3093
3097
  ' exec agent "$@"',
3098
+ "elif command -v cursor >/dev/null 2>&1; then",
3099
+ ' exec cursor agent "$@"',
3094
3100
  "else",
3095
3101
  " echo 'Executable not found in PATH: cursor agent or agent' >&2",
3096
3102
  " exit 127",
package/docs/USAGE.md CHANGED
@@ -331,7 +331,9 @@ worktree, pass those stores explicitly with `--add-dir` or template `addDirs`.
331
331
  For task-created routes, pass `--todos-project` so worker/verifier prompts use
332
332
  the actual todos storage project while route concurrency and worktree isolation
333
333
  still use the repository path. This avoids `danger-full-access` for normal
334
- todos comments, completion state, and loop evidence writes.
334
+ todos comments, completion state, and loop evidence writes. `addDirs` is
335
+ intentionally accepted only for Codewith/Codex until other providers expose
336
+ equivalent directory-scoped write controls.
335
337
 
336
338
  Inspect route state with:
337
339
 
@@ -576,7 +578,7 @@ The adapters intentionally use provider command surfaces instead of pretending e
576
578
  - Claude uses `claude -p --output-format json` and safe-mode/local setting sources by default.
577
579
  - Codewith uses `codewith --ask-for-approval never exec --json --ephemeral --skip-git-repo-check`, with `--add-dir` for explicit extra writable directories.
578
580
  - AI Copilot and OpenCode use `run --format json --pure`.
579
- - Cursor is CLI-first for now via `cursor agent -p`, with `agent -p` as the fallback launcher on machines that expose the standalone Cursor Agent binary; treat output as less stable until a stronger public SDK contract is selected.
581
+ - Cursor is CLI-first for now via standalone `agent -p` when available, with `cursor agent -p` as a compatibility fallback; treat output as less stable until a stronger public SDK contract is selected.
580
582
  - Codex uses `codex exec --json --ephemeral --skip-git-repo-check`, with `--add-dir` for explicit extra writable directories where supported.
581
583
  - Agent prompts are sent through child stdin instead of argv so prompt bodies do not appear in process listings.
582
584
  - When `--account` or a step `account` is set, OpenLoops resolves `accounts env <profile> --tool <tool>` before spawning the target, strips inherited tool home/API-key variables, and applies the selected profile only to that process. Missing account profiles fail before the provider binary receives the prompt.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/loops",
3
- "version": "0.3.45",
3
+ "version": "0.3.46",
4
4
  "description": "Persistent local loop and workflow runner for deterministic commands and headless AI coding agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",