@a5c-ai/babysitter-sdk 0.0.186 → 0.0.187-staging.02a0ee21

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 (102) hide show
  1. package/dist/cli/commands/costStats.d.ts +13 -0
  2. package/dist/cli/commands/costStats.d.ts.map +1 -0
  3. package/dist/cli/commands/costStats.js +319 -0
  4. package/dist/cli/commands/harnessPhase2.js +10 -10
  5. package/dist/cli/commands/instructions.d.ts.map +1 -1
  6. package/dist/cli/commands/instructions.js +5 -3
  7. package/dist/cli/main.d.ts.map +1 -1
  8. package/dist/cli/main.js +16 -1
  9. package/dist/config/defaults.d.ts +10 -0
  10. package/dist/config/defaults.d.ts.map +1 -1
  11. package/dist/config/defaults.js +19 -0
  12. package/dist/config/index.d.ts +1 -1
  13. package/dist/config/index.d.ts.map +1 -1
  14. package/dist/config/index.js +2 -1
  15. package/dist/cost/claudeCodeParser.d.ts +81 -0
  16. package/dist/cost/claudeCodeParser.d.ts.map +1 -0
  17. package/dist/cost/claudeCodeParser.js +232 -0
  18. package/dist/cost/collector.d.ts +42 -0
  19. package/dist/cost/collector.d.ts.map +1 -0
  20. package/dist/cost/collector.js +105 -0
  21. package/dist/cost/index.d.ts +18 -0
  22. package/dist/cost/index.d.ts.map +1 -0
  23. package/dist/cost/index.js +37 -0
  24. package/dist/cost/journal.d.ts +40 -0
  25. package/dist/cost/journal.d.ts.map +1 -0
  26. package/dist/cost/journal.js +137 -0
  27. package/dist/cost/types.d.ts +164 -0
  28. package/dist/cost/types.d.ts.map +1 -0
  29. package/dist/cost/types.js +231 -0
  30. package/dist/harness/claudeCode.js +1 -1
  31. package/dist/harness/cursor.js +1 -1
  32. package/dist/harness/discovery.d.ts.map +1 -1
  33. package/dist/harness/discovery.js +8 -1
  34. package/dist/harness/geminiCli.js +1 -1
  35. package/dist/harness/githubCopilot.js +1 -1
  36. package/dist/harness/index.d.ts +1 -0
  37. package/dist/harness/index.d.ts.map +1 -1
  38. package/dist/harness/index.js +3 -1
  39. package/dist/harness/invoker.d.ts.map +1 -1
  40. package/dist/harness/invoker.js +1 -0
  41. package/dist/harness/openclaw.d.ts +20 -0
  42. package/dist/harness/openclaw.d.ts.map +1 -0
  43. package/dist/harness/openclaw.js +338 -0
  44. package/dist/harness/opencode.d.ts.map +1 -1
  45. package/dist/harness/opencode.js +75 -5
  46. package/dist/harness/registry.d.ts.map +1 -1
  47. package/dist/harness/registry.js +2 -0
  48. package/dist/hooks/dispatcher.d.ts +9 -0
  49. package/dist/hooks/dispatcher.d.ts.map +1 -1
  50. package/dist/hooks/dispatcher.js +94 -0
  51. package/dist/hooks/index.d.ts +2 -1
  52. package/dist/hooks/index.d.ts.map +1 -1
  53. package/dist/hooks/index.js +2 -1
  54. package/dist/index.d.ts +1 -0
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js +1 -0
  57. package/dist/logging/runLogger.js +2 -2
  58. package/dist/prompts/babysitterMdDiscovery.d.ts +38 -0
  59. package/dist/prompts/babysitterMdDiscovery.d.ts.map +1 -0
  60. package/dist/prompts/babysitterMdDiscovery.js +150 -0
  61. package/dist/prompts/compose.d.ts.map +1 -1
  62. package/dist/prompts/compose.js +5 -0
  63. package/dist/prompts/context.d.ts +4 -0
  64. package/dist/prompts/context.d.ts.map +1 -1
  65. package/dist/prompts/context.js +37 -0
  66. package/dist/prompts/index.d.ts +1 -1
  67. package/dist/prompts/index.d.ts.map +1 -1
  68. package/dist/prompts/index.js +2 -1
  69. package/dist/prompts/parts/index.d.ts +3 -0
  70. package/dist/prompts/parts/index.d.ts.map +1 -1
  71. package/dist/prompts/parts/index.js +7 -1
  72. package/dist/prompts/parts/parallelPhaseDetection.d.ts +6 -0
  73. package/dist/prompts/parts/parallelPhaseDetection.d.ts.map +1 -0
  74. package/dist/prompts/parts/parallelPhaseDetection.js +10 -0
  75. package/dist/prompts/parts/projectInstructions.d.ts +8 -0
  76. package/dist/prompts/parts/projectInstructions.d.ts.map +1 -0
  77. package/dist/prompts/parts/projectInstructions.js +28 -0
  78. package/dist/prompts/parts/runOverlapDetection.d.ts +6 -0
  79. package/dist/prompts/parts/runOverlapDetection.d.ts.map +1 -0
  80. package/dist/prompts/parts/runOverlapDetection.js +10 -0
  81. package/dist/prompts/templates/commands/doctor.md +9 -9
  82. package/dist/prompts/templates/intent-fidelity-checks.md +3 -1
  83. package/dist/prompts/templates/parallel-phase-detection.md +59 -0
  84. package/dist/prompts/templates/process-creation.md +9 -2
  85. package/dist/prompts/templates/process-guidelines.md +5 -2
  86. package/dist/prompts/templates/run-overlap-detection.md +63 -0
  87. package/dist/prompts/templates/task-examples.md +47 -0
  88. package/dist/prompts/templates/task-kinds.md +44 -2
  89. package/dist/runtime/intrinsics/breakpoint.d.ts.map +1 -1
  90. package/dist/runtime/intrinsics/breakpoint.js +20 -1
  91. package/dist/runtime/orchestrateIteration.d.ts.map +1 -1
  92. package/dist/runtime/orchestrateIteration.js +14 -0
  93. package/dist/session/types.d.ts +2 -0
  94. package/dist/session/types.d.ts.map +1 -1
  95. package/dist/storage/createRunDir.d.ts.map +1 -1
  96. package/dist/storage/createRunDir.js +2 -0
  97. package/dist/storage/icloudWarning.d.ts +6 -0
  98. package/dist/storage/icloudWarning.d.ts.map +1 -0
  99. package/dist/storage/icloudWarning.js +84 -0
  100. package/dist/storage/journal.d.ts.map +1 -1
  101. package/dist/storage/journal.js +2 -0
  102. package/package.json +1 -1
@@ -55,7 +55,14 @@ After the process is created and before creating the run:
55
55
  - wrong: skipping repo/process-library research before writing the process
56
56
  - wrong: bypassing the orchestration model with helper scripts or inline logic
57
57
  - wrong: using `kind: 'node'` in generated tasks
58
- - correct: use `agent` or `skill` tasks for reasoning work, with `shell` only
59
- for existing CLIs, tests, linters, git, or builds
58
+ - wrong: using `kind: 'agent'` for deterministic verification (compilation,
59
+ linting, test execution, grep checks, dependency validation) -- these MUST
60
+ use `kind: 'shell'` with `expectedExitCode` for binary pass/fail enforcement
61
+ - correct: use `agent` or `skill` tasks for reasoning work (planning, code
62
+ review, architecture assessment, subjective evaluation)
63
+ - correct: use `shell` tasks for all objectively verifiable checks (tsc, eslint,
64
+ vitest, grep, dependency imports, runtime smoke tests)
60
65
  - correct: include verification loops, refinement loops, quality gates, and
61
66
  breakpoints where appropriate
67
+ - correct: pair shell verification gates with agent analysis tasks (shell runs
68
+ the check, agent interprets failures and suggests fixes)
@@ -75,8 +75,11 @@ specified:
75
75
  - Integrate/link the main pages (or entry points) with functionality created
76
76
  for every phase of the development process
77
77
  - Quality gated iterative and convergent development/refinement loops
78
- - Test driven -- where quality gates can use executable tools, scripts, and
79
- tests to verify accuracy and completeness
78
+ - Test driven -- where quality gates use `kind: 'shell'` tasks with
79
+ `expectedExitCode` for deterministic verification (compilation, linting,
80
+ test suites, grep checks, dependency availability, runtime smoke tests).
81
+ Reserve `kind: 'agent'` for subjective assessment only (code review,
82
+ architecture evaluation, UX quality)
80
83
  - Integration phases for each new functionality in every milestone
81
84
  - Where relevant -- beautiful and polished UX with pixel-perfect verification
82
85
  - Accurate and complete implementation of the user request
@@ -0,0 +1,63 @@
1
+ ### 2.0 Run Overlap Detection
2
+
3
+ Before calling `$CLI run:create`, scan for recent runs that may already cover
4
+ the same work. This avoids creating duplicate runs that waste tokens and
5
+ complicate the run history.
6
+
7
+ **Scan procedure:**
8
+
9
+ 1. List recent run directories:
10
+ ```bash
11
+ ls -lt .a5c/runs/ | head -20
12
+ ```
13
+ 2. For each run created within the last 30 minutes, read its metadata:
14
+ ```bash
15
+ cat .a5c/runs/<runId>/run.json
16
+ ```
17
+ 3. Compare the candidate run's `prompt` and `processId` against the new
18
+ request:
19
+ - **Keyword overlap**: does the existing prompt share 3 or more significant
20
+ keywords with the new prompt?
21
+ - **Process match**: does `processId` match the process you intend to use?
22
+ 4. If overlap is detected, check its current status:
23
+ ```bash
24
+ $CLI run:status .a5c/runs/<runId>
25
+ ```
26
+
27
+ **If an overlapping run is found:**
28
+
29
+ {{#interactive}}
30
+ Surface a clear warning to the user with the similar run's details:
31
+
32
+ - Run ID: `<runId>`
33
+ - Process: `<processId>`
34
+ - Created: `<createdAt>`
35
+ - Status: `<status>`
36
+ - Prompt excerpt: `<first 120 chars of prompt>`
37
+
38
+ Ask the user to choose one of:
39
+ 1. **Proceed** — create a new run anyway (e.g., intentional retry or variant)
40
+ 2. **Skip** — abort run creation; the existing run already covers the request
41
+ 3. **Resume** — resume the existing run via `$CLI run:iterate .a5c/runs/<runId>`
42
+
43
+ Do not proceed with `run:create` until the user has responded.
44
+ {{/interactive}}
45
+ {{^interactive}}
46
+ Log a warning with the overlapping run's details (runId, processId, createdAt,
47
+ status) and continue creating the new run. Non-interactive mode does not block
48
+ on overlap — the caller is responsible for deduplication.
49
+ {{/interactive}}
50
+
51
+ **No overlap found:** proceed directly to `$CLI run:create` as normal.
52
+
53
+ **Tracking run chains:**
54
+
55
+ When creating a run that intentionally follows or retries a previous run,
56
+ include the related run ID in the inputs so the process can reference it:
57
+
58
+ ```json
59
+ {
60
+ "relatedRunId": "<previousRunId>",
61
+ "relatedRunReason": "retry|variant|follow-up"
62
+ }
63
+ ```
@@ -37,6 +37,53 @@ export const agentTask = defineTask('agent-scorer', (args, taskCtx) => ({
37
37
  }));
38
38
  ```
39
39
 
40
+ ### Shell Verification Task Example
41
+
42
+ Use shell tasks for all deterministic verification gates. Shell tasks produce
43
+ binary pass/fail results via exit codes that cannot be bypassed by agent
44
+ reasoning.
45
+
46
+ ```javascript
47
+ // Grep-based integration check
48
+ export const grepCheckTask = defineTask('grep-integration-check', (args, taskCtx) => ({
49
+ kind: 'shell',
50
+ title: 'Verify integration points exist',
51
+ shell: {
52
+ command: `cd ${args.projectDir || '.'} && grep -q "${args.pattern}" ${args.file}`,
53
+ expectedExitCode: 0,
54
+ timeout: 10000
55
+ },
56
+ io: {
57
+ inputJsonPath: `tasks/${taskCtx.effectId}/input.json`,
58
+ outputJsonPath: `tasks/${taskCtx.effectId}/output.json`
59
+ }
60
+ }));
61
+
62
+ // Multi-check verification gate
63
+ export const verificationGateTask = defineTask('verification-gate', (args, taskCtx) => ({
64
+ kind: 'shell',
65
+ title: 'Deterministic verification gate',
66
+ shell: {
67
+ command: [
68
+ `cd ${args.projectDir || '.'}`,
69
+ 'npx tsc --noEmit',
70
+ 'npx eslint src/ --max-warnings=0',
71
+ 'npx vitest run --reporter=verbose'
72
+ ].join(' && '),
73
+ expectedExitCode: 0,
74
+ timeout: 300000
75
+ },
76
+ io: {
77
+ inputJsonPath: `tasks/${taskCtx.effectId}/input.json`,
78
+ outputJsonPath: `tasks/${taskCtx.effectId}/output.json`
79
+ }
80
+ }));
81
+ ```
82
+
83
+ Use `library/processes/shared/deterministic-quality-gate.js` for composable
84
+ preset gates (createGrepCheck, createCompilationGate, createTestSuiteGate,
85
+ createRuntimeSmokeTest).
86
+
40
87
  ### Skill Task Example
41
88
 
42
89
  Important: Check which skills are actually available before assigning the skill
@@ -10,12 +10,54 @@ build tools), `breakpoint` (human approval), and `sleep` (time gates).
10
10
  | Kind | Description | Executor | When to use |
11
11
  |------|-------------|----------|-------------|
12
12
  | ~~`node`~~ | ~~Node.js script~~ | ~~Local node process~~ | **NEVER -- forbidden. Convert to `agent` or `skill`.** |
13
- | `shell` | Shell command | Local shell process | Only for running existing CLI tools, test suites, git, linters, builds. The orchestrating agent must execute it intentionally and post the result |
14
- | `agent` | LLM agent | Agent runtime | **Default for all tasks** -- planning, implementation, analysis, verification, scoring, debugging, code writing, research |
13
+ | `shell` | Shell command | Local shell process | **Deterministic verification** (compilation, linting, tests, grep, dependency checks, smoke tests) AND running existing CLI tools, git, builds. The orchestrating agent must execute it intentionally and post the result |
14
+ | `agent` | LLM agent | Agent runtime | **Default for reasoning tasks** -- planning, implementation, analysis, scoring, debugging, code writing, research. Also for **subjective verification** (code review, architecture assessment, UX evaluation) |
15
15
  | `skill` | {{skillSystemLabel}} | Skill system | When a matching installed skill exists (preferred over agent when available) |
16
16
  | `breakpoint` | Human approval | UI/CLI | Decision gates requiring user input |
17
17
  | `sleep` | Time gate | Scheduler | Time-based pauses |
18
18
 
19
+ ### Shell vs Agent for Verification Tasks
20
+
21
+ **CRITICAL:** Verification tasks that produce deterministic, binary pass/fail
22
+ results MUST use `kind: 'shell'` with `expectedExitCode`, NOT `kind: 'agent'`.
23
+ Agent-interpreted verification creates soft gates where an LLM subjectively
24
+ assesses pass/fail -- this is unreliable for objectively testable checks.
25
+
26
+ | Verification type | Correct kind | Why |
27
+ |-------------------|-------------|-----|
28
+ | Compilation (tsc, gcc) | `shell` | Exit code is deterministic pass/fail |
29
+ | Linting (eslint, ruff) | `shell` | Exit code is deterministic pass/fail |
30
+ | Test suites (vitest, jest) | `shell` | Exit code is deterministic pass/fail |
31
+ | Grep/pattern checks | `shell` | Pattern exists or it doesn't |
32
+ | Dependency availability | `shell` | `node -e "require('pkg')"` succeeds or fails |
33
+ | Runtime smoke tests | `shell` | Start, curl, check status code, stop |
34
+ | Code review / design quality | `agent` | Requires subjective judgment |
35
+ | Architecture assessment | `agent` | Requires reasoning about tradeoffs |
36
+ | UX evaluation | `agent` | Subjective quality assessment |
37
+
38
+ **Anti-pattern (wrong):**
39
+ ```javascript
40
+ // BAD: agent-interpreted verification -- the agent can say "looks good" without running anything
41
+ const verifyTask = defineTask('verify-compilation', (args, taskCtx) => ({
42
+ kind: 'agent',
43
+ title: 'Verify TypeScript compiles',
44
+ agent: { prompt: { instructions: ['Run tsc and check it passes'] } }
45
+ }));
46
+ ```
47
+
48
+ **Correct pattern:**
49
+ ```javascript
50
+ // GOOD: deterministic shell gate -- exit code cannot be negotiated
51
+ const verifyTask = defineTask('verify-compilation', (args, taskCtx) => ({
52
+ kind: 'shell',
53
+ title: 'TypeScript compilation check',
54
+ shell: { command: 'npx tsc --noEmit', expectedExitCode: 0, timeout: 120000 }
55
+ }));
56
+ ```
57
+
58
+ Use `library/processes/shared/deterministic-quality-gate.js` for composable
59
+ preset gates (grep checks, compilation, test suites, runtime smoke tests).
60
+
19
61
  ### Effect Execution Hints
20
62
 
21
63
  Tasks can include an `execution` field to express preferences about how the effect should be executed:
@@ -1 +1 @@
1
- {"version":3,"file":"breakpoint.d.ts","sourceRoot":"","sources":["../../../src/runtime/intrinsics/breakpoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,wBAAwB,EAAmC,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC1H,OAAO,EAAoB,oBAAoB,EAAE,MAAM,QAAQ,CAAC;AAkChE,wBAAgB,sBAAsB,CAAC,CAAC,GAAG,OAAO,EAChD,OAAO,EAAE,CAAC,EACV,OAAO,EAAE,oBAAoB,EAC7B,OAAO,CAAC,EAAE,iBAAiB,GAAG,wBAAwB,GACrD,OAAO,CAAC,gBAAgB,CAAC,CA+B3B"}
1
+ {"version":3,"file":"breakpoint.d.ts","sourceRoot":"","sources":["../../../src/runtime/intrinsics/breakpoint.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,wBAAwB,EAAmC,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC1H,OAAO,EAAoB,oBAAoB,EAAE,MAAM,QAAQ,CAAC;AAkChE,wBAAgB,sBAAsB,CAAC,CAAC,GAAG,OAAO,EAChD,OAAO,EAAE,CAAC,EACV,OAAO,EAAE,oBAAoB,EAC7B,OAAO,CAAC,EAAE,iBAAiB,GAAG,wBAAwB,GACrD,OAAO,CAAC,gBAAgB,CAAC,CAiD3B"}
@@ -1,6 +1,11 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.runBreakpointIntrinsic = runBreakpointIntrinsic;
7
+ const node_fs_1 = require("node:fs");
8
+ const node_path_1 = __importDefault(require("node:path"));
4
9
  const task_1 = require("./task");
5
10
  const journal_1 = require("../../storage/journal");
6
11
  const BREAKPOINT_TASK_ID = "__sdk.breakpoint";
@@ -28,10 +33,24 @@ function runBreakpointIntrinsic(payload, context, options) {
28
33
  const ctx = context;
29
34
  if (ctx.nonInteractive) {
30
35
  const bpLabel = options?.label ?? "unnamed";
36
+ let logSeq;
37
+ if (ctx.logSeq !== undefined && ctx.recordedLogSeqs !== undefined) {
38
+ logSeq = ++ctx.logSeq;
39
+ if (ctx.recordedLogSeqs.has(logSeq)) {
40
+ return Promise.resolve({ approved: true, response: "Auto-approved (non-interactive mode)" });
41
+ }
42
+ ctx.recordedLogSeqs.add(logSeq);
43
+ void node_fs_1.promises.appendFile(node_path_1.default.join(context.runDir, "state", "logSeqs.txt"), `${logSeq}\n`).catch(() => {
44
+ // Never let logging break orchestration.
45
+ });
46
+ }
47
+ else {
48
+ logSeq = -1;
49
+ }
31
50
  void (0, journal_1.appendEvent)({
32
51
  runDir: context.runDir,
33
52
  eventType: "PROCESS_LOG",
34
- event: { logSeq: -1, label: "breakpoint:skipped", message: `Breakpoint '${bpLabel}' auto-approved (non-interactive mode)` },
53
+ event: { logSeq, label: "breakpoint:skipped", message: `Breakpoint '${bpLabel}' auto-approved (non-interactive mode)` },
35
54
  }).catch(() => {
36
55
  // Never let logging break orchestration.
37
56
  });
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrateIteration.d.ts","sourceRoot":"","sources":["../../src/runtime/orchestrateIteration.ts"],"names":[],"mappings":"AAcA,OAAO,EAEL,eAAe,EACf,kBAAkB,EAInB,MAAM,SAAS,CAAC;AAgBjB,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,eAAe,CAAC,CAqIhG"}
1
+ {"version":3,"file":"orchestrateIteration.d.ts","sourceRoot":"","sources":["../../src/runtime/orchestrateIteration.ts"],"names":[],"mappings":"AAeA,OAAO,EAEL,eAAe,EACf,kBAAkB,EAInB,MAAM,SAAS,CAAC;AAgBjB,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,eAAe,CAAC,CAmJhG"}
@@ -41,6 +41,7 @@ const path_1 = __importDefault(require("path"));
41
41
  const url_1 = require("url");
42
42
  const journal_1 = require("../storage/journal");
43
43
  const runFiles_1 = require("../storage/runFiles");
44
+ const journal_2 = require("../cost/journal");
44
45
  const lock_1 = require("../storage/lock");
45
46
  const createReplayEngine_1 = require("./replay/createReplayEngine");
46
47
  const stateCache_1 = require("./replay/stateCache");
@@ -86,11 +87,24 @@ async function orchestrateIteration(options) {
86
87
  try {
87
88
  const output = await (0, processContext_1.withProcessContext)(engine.internalContext, () => processFn(inputs, engine.context, options.context));
88
89
  const outputRef = await (0, runFiles_1.writeRunOutput)(options.runDir, output);
90
+ // Compute cost stats for run completion
91
+ let costStats = undefined;
92
+ try {
93
+ const journalEvents = await (0, journal_1.loadJournal)(options.runDir);
94
+ const costEvents = (0, journal_2.extractCostEvents)(journalEvents);
95
+ if (costEvents.length > 0) {
96
+ costStats = (0, journal_2.computeRunCostStats)(engine.runId, journalEvents);
97
+ }
98
+ }
99
+ catch {
100
+ // Cost stats are optional - don't fail the run
101
+ }
89
102
  await (0, journal_1.appendEvent)({
90
103
  runDir: options.runDir,
91
104
  eventType: "RUN_COMPLETED",
92
105
  event: {
93
106
  outputRef,
107
+ costStats,
94
108
  },
95
109
  });
96
110
  // Rebuild state cache so it includes the terminal event.
@@ -20,6 +20,8 @@ export interface SessionState {
20
20
  lastIterationAt: string;
21
21
  /** Array of recent iteration durations in seconds (last 3) */
22
22
  iterationTimes: number[];
23
+ /** Optional key-value metadata (e.g. external correlation IDs) */
24
+ metadata?: Record<string, string>;
23
25
  }
24
26
  /**
25
27
  * Complete session file content including state and prompt.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/session/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/session/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"createRunDir.d.ts","sourceRoot":"","sources":["../../src/storage/createRunDir.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAyB,WAAW,EAAE,MAAM,SAAS,CAAC;AAkBlF,wBAAsB,YAAY,CAAC,OAAO,EAAE,mBAAmB;;;GAoC9D"}
1
+ {"version":3,"file":"createRunDir.d.ts","sourceRoot":"","sources":["../../src/storage/createRunDir.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAyB,WAAW,EAAE,MAAM,SAAS,CAAC;AAmBlF,wBAAsB,YAAY,CAAC,OAAO,EAAE,mBAAmB;;;GAqC9D"}
@@ -9,9 +9,11 @@ const path_1 = __importDefault(require("path"));
9
9
  const paths_1 = require("./paths");
10
10
  const atomic_1 = require("./atomic");
11
11
  const clock_1 = require("./clock");
12
+ const icloudWarning_1 = require("./icloudWarning");
12
13
  const GITIGNORE_CONTENT = `state/\ntasks/*/artifacts/\nblobs/\norphaned/\n`;
13
14
  async function createRunDir(options) {
14
15
  const runDir = (0, paths_1.getRunDir)(options.runsRoot, options.runId);
16
+ await (0, icloudWarning_1.warnIfICloudDrivePath)(runDir);
15
17
  await fs_1.promises.mkdir(runDir, { recursive: true });
16
18
  await Promise.all([
17
19
  fs_1.promises.mkdir((0, paths_1.getJournalDir)(runDir), { recursive: true }),
@@ -0,0 +1,6 @@
1
+ type WarningOutput = Pick<NodeJS.WriteStream, "write">;
2
+ export declare function detectICloudDrivePath(inputPath: string): Promise<string | undefined>;
3
+ export declare function warnIfICloudDrivePath(inputPath: string, output?: WarningOutput): Promise<boolean>;
4
+ export declare function __resetICloudDriveWarningCacheForTests(): void;
5
+ export {};
6
+ //# sourceMappingURL=icloudWarning.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icloudWarning.d.ts","sourceRoot":"","sources":["../../src/storage/icloudWarning.ts"],"names":[],"mappings":"AAMA,KAAK,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;AA0CvD,wBAAsB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAS1F;AAED,wBAAsB,qBAAqB,CACzC,SAAS,EAAE,MAAM,EACjB,MAAM,GAAE,aAA8B,GACrC,OAAO,CAAC,OAAO,CAAC,CAuBlB;AAED,wBAAgB,sCAAsC,IAAI,IAAI,CAE7D"}
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.detectICloudDrivePath = detectICloudDrivePath;
7
+ exports.warnIfICloudDrivePath = warnIfICloudDrivePath;
8
+ exports.__resetICloudDriveWarningCacheForTests = __resetICloudDriveWarningCacheForTests;
9
+ const fs_1 = require("fs");
10
+ const path_1 = __importDefault(require("path"));
11
+ const ICLOUD_DRIVE_MARKER = "/Library/Mobile Documents/com~apple~CloudDocs";
12
+ const warnedPaths = new Set();
13
+ function normalizePathForMatch(inputPath) {
14
+ return inputPath.replace(/\\/g, "/").replace(/\/+$/, "");
15
+ }
16
+ function getICloudWarningKey(candidatePath) {
17
+ const normalized = normalizePathForMatch(candidatePath);
18
+ const markerIndex = normalized.indexOf(ICLOUD_DRIVE_MARKER);
19
+ if (markerIndex === -1) {
20
+ return normalized;
21
+ }
22
+ return normalized.slice(0, markerIndex + ICLOUD_DRIVE_MARKER.length);
23
+ }
24
+ function isICloudDrivePath(candidatePath) {
25
+ const normalized = normalizePathForMatch(candidatePath);
26
+ return normalized === ICLOUD_DRIVE_MARKER || normalized.includes(`${ICLOUD_DRIVE_MARKER}/`);
27
+ }
28
+ async function resolveExistingAncestorRealPath(inputPath) {
29
+ let current = path_1.default.resolve(inputPath);
30
+ let reachedFilesystemRoot = false;
31
+ while (!reachedFilesystemRoot) {
32
+ try {
33
+ return await fs_1.promises.realpath(current);
34
+ }
35
+ catch (error) {
36
+ const err = error;
37
+ if (err.code !== "ENOENT") {
38
+ return undefined;
39
+ }
40
+ const parent = path_1.default.dirname(current);
41
+ if (parent === current) {
42
+ reachedFilesystemRoot = true;
43
+ }
44
+ else {
45
+ current = parent;
46
+ }
47
+ }
48
+ }
49
+ return undefined;
50
+ }
51
+ async function detectICloudDrivePath(inputPath) {
52
+ const realAncestor = await resolveExistingAncestorRealPath(inputPath);
53
+ const candidates = [
54
+ realAncestor,
55
+ path_1.default.resolve(inputPath),
56
+ inputPath,
57
+ ].filter((candidate) => typeof candidate === "string" && candidate.trim() !== "");
58
+ return candidates.find((candidate) => isICloudDrivePath(candidate));
59
+ }
60
+ async function warnIfICloudDrivePath(inputPath, output = process.stderr) {
61
+ const matchedPath = await detectICloudDrivePath(inputPath);
62
+ if (!matchedPath) {
63
+ return false;
64
+ }
65
+ const dedupeKey = getICloudWarningKey(matchedPath);
66
+ if (warnedPaths.has(dedupeKey)) {
67
+ return true;
68
+ }
69
+ warnedPaths.add(dedupeKey);
70
+ const message = [
71
+ "",
72
+ "!!! WARNING: Babysitter state is inside iCloud Drive.",
73
+ `Path: ${path_1.default.resolve(inputPath)}`,
74
+ "iCloud sync can race .a5c journal writes and produce duplicate or conflicting journal events.",
75
+ "Recommendation: move the project or set BABYSITTER_STATE_DIR/BABYSITTER_RUNS_DIR outside iCloud Drive.",
76
+ "Known issue: github.com/a5c-ai/babysitter/issues/77",
77
+ "",
78
+ ].join("\n");
79
+ output.write(`${message}\n`);
80
+ return true;
81
+ }
82
+ function __resetICloudDriveWarningCacheForTests() {
83
+ warnedPaths.clear();
84
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"journal.d.ts","sourceRoot":"","sources":["../../src/storage/journal.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,YAAY,EAAc,MAAM,SAAS,CAAC;AAuB1F,wBAAsB,WAAW,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAuBtF;AA2BD,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CA6BzE"}
1
+ {"version":3,"file":"journal.d.ts","sourceRoot":"","sources":["../../src/storage/journal.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,YAAY,EAAc,MAAM,SAAS,CAAC;AAwB1F,wBAAsB,WAAW,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAwBtF;AA2BD,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CA6BzE"}
@@ -12,6 +12,7 @@ const paths_1 = require("./paths");
12
12
  const atomic_1 = require("./atomic");
13
13
  const ulids_1 = require("./ulids");
14
14
  const clock_1 = require("./clock");
15
+ const icloudWarning_1 = require("./icloudWarning");
15
16
  function formatSeq(seq) {
16
17
  return seq.toString().padStart(6, "0");
17
18
  }
@@ -31,6 +32,7 @@ async function getExistingSeqs(journalDir) {
31
32
  }
32
33
  async function appendEvent(opts) {
33
34
  const journalDir = (0, paths_1.getJournalDir)(opts.runDir);
35
+ await (0, icloudWarning_1.warnIfICloudDrivePath)(journalDir);
34
36
  await fs_1.promises.mkdir(journalDir, { recursive: true });
35
37
  const seqs = await getExistingSeqs(journalDir);
36
38
  const seq = (seqs.length ? Math.max(...seqs) : 0) + 1;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a5c-ai/babysitter-sdk",
3
- "version": "0.0.186",
3
+ "version": "0.0.187-staging.02a0ee21",
4
4
  "description": "Storage and run-registry primitives for event-sourced babysitter workflows.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "commonjs",