@snappedly-tools/shipyard 0.5.0 → 0.7.0-staging.36081473933

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 (89) hide show
  1. package/README.md +64 -117
  2. package/dist/MountConfig-BHnKnA4h.d.ts +145 -0
  3. package/dist/{chunk-WAXEMZUV.js → chunk-44I2BL6E.js} +225 -33
  4. package/dist/chunk-44I2BL6E.js.map +1 -0
  5. package/dist/{chunk-56TDSWFU.js → chunk-JI3HDDMS.js} +3 -3
  6. package/dist/{chunk-56TDSWFU.js.map → chunk-JI3HDDMS.js.map} +1 -1
  7. package/dist/{chunk-FDYOTN55.js → chunk-L6PX5QTU.js} +253 -878
  8. package/dist/chunk-L6PX5QTU.js.map +1 -0
  9. package/dist/index.d.ts +117 -97
  10. package/dist/index.js +349 -353
  11. package/dist/index.js.map +1 -1
  12. package/dist/main.js +285 -153
  13. package/dist/main.js.map +1 -1
  14. package/dist/sandboxes/docker.d.ts +1 -3
  15. package/dist/sandboxes/docker.js +2 -4
  16. package/dist/templates/parallel-planner/block-scope.sh +160 -0
  17. package/dist/templates/parallel-planner/conflict-prompt.md +22 -0
  18. package/dist/templates/parallel-planner/handoff.sh +175 -0
  19. package/dist/templates/parallel-planner/implement-prompt.md +10 -56
  20. package/dist/templates/parallel-planner/main.mts +493 -189
  21. package/dist/templates/parallel-planner/merge-prompt.md +9 -21
  22. package/dist/templates/parallel-planner/plan-prompt.md +5 -31
  23. package/dist/templates/parallel-planner/planner-branch.mts +151 -0
  24. package/dist/templates/parallel-planner/select-issues.mjs +788 -0
  25. package/dist/templates/parallel-planner/setup.sh +51 -0
  26. package/dist/templates/parallel-planner/spec-wave-prompt.md +16 -0
  27. package/dist/templates/parallel-planner/template.json +1 -1
  28. package/dist/templates/parallel-planner/triage-prompt.md +5 -0
  29. package/dist/templates/parallel-planner/verify-triage.sh +19 -0
  30. package/dist/templates/parallel-planner-with-review/block-scope.sh +160 -0
  31. package/dist/templates/parallel-planner-with-review/conflict-prompt.md +22 -0
  32. package/dist/templates/parallel-planner-with-review/handoff.sh +175 -0
  33. package/dist/templates/parallel-planner-with-review/implement-prompt.md +10 -56
  34. package/dist/templates/parallel-planner-with-review/main.mts +533 -207
  35. package/dist/templates/parallel-planner-with-review/merge-prompt.md +9 -21
  36. package/dist/templates/parallel-planner-with-review/plan-prompt.md +5 -31
  37. package/dist/templates/parallel-planner-with-review/planner-branch.mts +151 -0
  38. package/dist/templates/parallel-planner-with-review/review-prompt.md +11 -49
  39. package/dist/templates/parallel-planner-with-review/select-issues.mjs +788 -0
  40. package/dist/templates/parallel-planner-with-review/setup.sh +51 -0
  41. package/dist/templates/parallel-planner-with-review/spec-wave-prompt.md +16 -0
  42. package/dist/templates/parallel-planner-with-review/template.json +1 -1
  43. package/dist/templates/parallel-planner-with-review/triage-prompt.md +5 -0
  44. package/dist/templates/parallel-planner-with-review/verify-triage.sh +19 -0
  45. package/dist/templates/sequential-reviewer/block-scope.sh +160 -0
  46. package/dist/templates/sequential-reviewer/handoff.sh +175 -0
  47. package/dist/templates/sequential-reviewer/implement-prompt.md +12 -46
  48. package/dist/templates/sequential-reviewer/main.mts +248 -103
  49. package/dist/templates/sequential-reviewer/review-prompt.md +11 -49
  50. package/dist/templates/sequential-reviewer/select-issues.mjs +788 -0
  51. package/dist/templates/sequential-reviewer/setup.sh +51 -0
  52. package/dist/templates/sequential-reviewer/template.json +1 -1
  53. package/dist/templates/sequential-reviewer/triage-prompt.md +5 -0
  54. package/dist/templates/sequential-reviewer/verify-triage.sh +19 -0
  55. package/dist/templates/shared/block-scope.sh +160 -0
  56. package/dist/templates/shared/handoff.sh +175 -0
  57. package/dist/templates/shared/select-issues.mjs +788 -0
  58. package/dist/templates/shared/setup.sh +51 -0
  59. package/dist/templates/shared/triage-prompt.md +5 -0
  60. package/dist/templates/shared/verify-triage.sh +19 -0
  61. package/dist/templates/simple-loop/block-scope.sh +160 -0
  62. package/dist/templates/simple-loop/handoff.sh +175 -0
  63. package/dist/templates/simple-loop/main.mts +239 -45
  64. package/dist/templates/simple-loop/prompt.md +12 -46
  65. package/dist/templates/simple-loop/select-issues.mjs +788 -0
  66. package/dist/templates/simple-loop/setup.sh +51 -0
  67. package/dist/templates/simple-loop/template.json +1 -1
  68. package/dist/templates/simple-loop/triage-prompt.md +5 -0
  69. package/dist/templates/simple-loop/verify-triage.sh +19 -0
  70. package/package.json +1 -17
  71. package/dist/MountConfig-bZoCs4Dd.d.ts +0 -26
  72. package/dist/SandboxProvider-XJQqEdSf.d.ts +0 -261
  73. package/dist/chunk-ACD46ZM4.js +0 -136
  74. package/dist/chunk-ACD46ZM4.js.map +0 -1
  75. package/dist/chunk-FDYOTN55.js.map +0 -1
  76. package/dist/chunk-KMGNFXKN.js +0 -38
  77. package/dist/chunk-KMGNFXKN.js.map +0 -1
  78. package/dist/chunk-SOJTAJTF.js +0 -78
  79. package/dist/chunk-SOJTAJTF.js.map +0 -1
  80. package/dist/chunk-WAXEMZUV.js.map +0 -1
  81. package/dist/sandboxes/no-sandbox.d.ts +0 -37
  82. package/dist/sandboxes/no-sandbox.js +0 -4
  83. package/dist/sandboxes/no-sandbox.js.map +0 -1
  84. package/dist/sandboxes/vercel.d.ts +0 -104
  85. package/dist/sandboxes/vercel.js +0 -166
  86. package/dist/sandboxes/vercel.js.map +0 -1
  87. package/dist/templates/blank/main.mts +0 -13
  88. package/dist/templates/blank/prompt.md +0 -12
  89. package/dist/templates/blank/template.json +0 -4
@@ -1,4 +1,4 @@
1
- import { CONFIG_DIR, ConfigDirError, assertNoSymlinkComponents, LOGS_DIR, Display } from './chunk-FDYOTN55.js';
1
+ import { CONFIG_DIR, ConfigDirError, assertNoSymlinkComponents, LOGS_DIR, Display } from './chunk-L6PX5QTU.js';
2
2
  import { Effect } from 'effect';
3
3
  import { FileSystem } from '@effect/platform';
4
4
  import { join } from 'path';
@@ -251,5 +251,5 @@ var purgeRunLogs = async (options) => {
251
251
  };
252
252
 
253
253
  export { CODEX_MODELS, CODEX_REASONING_EFFORTS, DEFAULT_LOG_RETENTION_DAYS, buildLogDirectoryName, formatErrorMessage, purgeRunLogs, resolveEnv, withFriendlyErrors };
254
- //# sourceMappingURL=chunk-56TDSWFU.js.map
255
- //# sourceMappingURL=chunk-56TDSWFU.js.map
254
+ //# sourceMappingURL=chunk-JI3HDDMS.js.map
255
+ //# sourceMappingURL=chunk-JI3HDDMS.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ErrorHandler.ts","../src/modelConfig.ts","../src/EnvResolver.ts","../src/LogRetention.ts"],"names":["Effect","join"],"mappings":"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","file":"chunk-56TDSWFU.js","sourcesContent":["import { Effect } from \"effect\";\nimport { Display } from \"./Display.js\";\nimport type { SandboxError } from \"./errors.js\";\n\n/**\n * Formats a tagged SandboxError into a user-friendly message with\n * context-specific hints about what went wrong and how to recover.\n */\nexport const formatErrorMessage = (error: SandboxError): string => {\n switch (error._tag) {\n case \"ExecError\":\n return `Command failed in sandbox (${error.command}): ${error.message}`;\n case \"ExecHostError\":\n return `Command failed on host (${error.command}): ${error.message}`;\n case \"CopyError\":\n return `File copy failed: ${error.message}`;\n case \"DockerError\":\n return `Docker operation failed: ${error.message}. Is Docker running?`;\n case \"SyncError\":\n return `Git sync failed: ${error.message}`;\n case \"WorktreeError\":\n return `Git worktree operation failed: ${error.message}`;\n case \"PromptError\":\n return `Failed to resolve prompt: ${error.message}`;\n case \"AgentError\":\n return `Agent invocation failed: ${error.message}`;\n case \"ConfigDirError\":\n return `${error.message}`;\n case \"InitError\":\n return `${error.message}`;\n case \"AgentIdleTimeoutError\":\n case \"WorktreeTimeoutError\":\n case \"ContainerStartTimeoutError\":\n case \"CopyToWorktreeTimeoutError\":\n case \"CopyToWorktreeError\":\n case \"SyncInTimeoutError\":\n case \"HookTimeoutError\":\n case \"GitSetupTimeoutError\":\n case \"PromptExpansionTimeoutError\":\n case \"CommitCollectionTimeoutError\":\n case \"MergeToHostTimeoutError\":\n case \"SessionCaptureError\":\n case \"CwdError\":\n return error.message;\n }\n};\n\nconst showErrorAndExit = (error: SandboxError) =>\n Effect.gen(function* () {\n const d = yield* Display;\n yield* d.status(formatErrorMessage(error), \"error\");\n return yield* Effect.sync(() => process.exit(1) as never);\n });\n\n/**\n * Wraps an effect so that any SandboxError is caught, displayed via the\n * Display service as an error-severity status message, then exits the process\n * with code 1. Non-SandboxError errors pass through unchanged.\n */\nexport const withFriendlyErrors = <A, E, R>(\n effect: Effect.Effect<A, E, R>,\n): Effect.Effect<A, Exclude<E, SandboxError>, R | Display> =>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Effect.catchTags(effect as Effect.Effect<A, SandboxError, R>, {\n ExecError: showErrorAndExit,\n ExecHostError: showErrorAndExit,\n CopyError: showErrorAndExit,\n DockerError: showErrorAndExit,\n SyncError: showErrorAndExit,\n WorktreeError: showErrorAndExit,\n PromptError: showErrorAndExit,\n AgentError: showErrorAndExit,\n ConfigDirError: showErrorAndExit,\n InitError: showErrorAndExit,\n AgentIdleTimeoutError: showErrorAndExit,\n WorktreeTimeoutError: showErrorAndExit,\n ContainerStartTimeoutError: showErrorAndExit,\n CopyToWorktreeTimeoutError: showErrorAndExit,\n CopyToWorktreeError: showErrorAndExit,\n SyncInTimeoutError: showErrorAndExit,\n HookTimeoutError: showErrorAndExit,\n GitSetupTimeoutError: showErrorAndExit,\n PromptExpansionTimeoutError: showErrorAndExit,\n CommitCollectionTimeoutError: showErrorAndExit,\n MergeToHostTimeoutError: showErrorAndExit,\n SessionCaptureError: showErrorAndExit,\n CwdError: showErrorAndExit,\n }) as Effect.Effect<A, Exclude<E, SandboxError>, R | Display>;\n","/** Reasoning efforts accepted by the Codex CLI. */\nexport const CODEX_REASONING_EFFORTS = [\n \"low\",\n \"medium\",\n \"high\",\n \"xhigh\",\n \"max\",\n] as const;\n\nexport type CodexReasoningEffort = (typeof CODEX_REASONING_EFFORTS)[number];\n\n/** A model identifier plus the reasoning policy used for that model role. */\nexport interface CodexModelConfig {\n readonly model: string;\n readonly effort: CodexReasoningEffort;\n}\n\n/**\n * Default values for Shipyard's built-in Codex roles.\n *\n * Runtime environment variables override these defaults:\n * SHIPYARD_CODEX_ROUTINE_MODEL\n * SHIPYARD_CODEX_ROUTINE_REASONING_EFFORT\n * SHIPYARD_CODEX_STRONG_MODEL\n * SHIPYARD_CODEX_STRONG_REASONING_EFFORT\n *\n * Keep the defaults here so runtime providers, generated templates, and the\n * repository workflows all use the same role definitions.\n */\nconst DEFAULT_CODEX_MODELS = {\n routine: { model: \"gpt-5.6-luna\", effort: \"max\" },\n strong: { model: \"gpt-5.6-sol\", effort: \"max\" },\n} as const satisfies Record<string, CodexModelConfig>;\n\nconst readModel = (role: keyof typeof DEFAULT_CODEX_MODELS): string =>\n process.env[`SHIPYARD_CODEX_${role.toUpperCase()}_MODEL`]?.trim() ||\n DEFAULT_CODEX_MODELS[role].model;\n\nconst readEffort = (\n role: keyof typeof DEFAULT_CODEX_MODELS,\n): CodexReasoningEffort => {\n const envName = `SHIPYARD_CODEX_${role.toUpperCase()}_REASONING_EFFORT`;\n const value = process.env[envName]?.trim();\n if (!value) return DEFAULT_CODEX_MODELS[role].effort;\n if ((CODEX_REASONING_EFFORTS as readonly string[]).includes(value)) {\n return value as CodexReasoningEffort;\n }\n throw new Error(\n `${envName} must be one of ${CODEX_REASONING_EFFORTS.join(\", \")}; received \"${value}\"`,\n );\n};\n\nexport const CODEX_MODELS = {\n routine: {\n model: readModel(\"routine\"),\n effort: readEffort(\"routine\"),\n },\n strong: {\n model: readModel(\"strong\"),\n effort: readEffort(\"strong\"),\n },\n} as const satisfies Record<string, CodexModelConfig>;\n","import { FileSystem } from \"@effect/platform\";\nimport { Effect } from \"effect\";\nimport { join } from \"node:path\";\n\nimport { ConfigDirError } from \"./errors.js\";\nimport { assertNoSymlinkComponents } from \"./pathSecurity.js\";\nimport { CONFIG_DIR } from \"./runtimeNames.js\";\n\nconst parseEnvFile = (\n filePath: string,\n): Effect.Effect<Record<string, string>, never, FileSystem.FileSystem> =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const symlink = yield* fs.readLink(filePath).pipe(\n Effect.map(() => true),\n Effect.catchAll(() => Effect.succeed(false)),\n );\n // A repository-controlled symlink could redirect this read to a host\n // secret and then expose matching keys to the agent.\n if (symlink) return {};\n const content = yield* fs\n .readFileString(filePath)\n .pipe(Effect.catchAll(() => Effect.succeed(null)));\n if (content === null) return {};\n const vars: Record<string, string> = {};\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith(\"#\")) continue;\n const eqIndex = trimmed.indexOf(\"=\");\n if (eqIndex === -1) continue;\n const key = trimmed.slice(0, eqIndex).trim();\n let value = trimmed.slice(eqIndex + 1).trim();\n const isDoubleQuoted =\n value.length >= 2 &&\n value[0] === '\"' &&\n value[value.length - 1] === '\"';\n const isSingleQuoted =\n value.length >= 2 &&\n value[0] === \"'\" &&\n value[value.length - 1] === \"'\";\n if (isDoubleQuoted || isSingleQuoted) {\n value = value.slice(1, -1);\n }\n if (isDoubleQuoted) {\n value = value.replace(/\\\\([nrt\\\\])/g, (_, ch: string) => {\n const escapes: Record<string, string> = {\n n: \"\\n\",\n r: \"\\r\",\n t: \"\\t\",\n \"\\\\\": \"\\\\\",\n };\n return escapes[ch] ?? ch;\n });\n }\n vars[key] = value;\n }\n return vars;\n });\n\n/**\n * Resolve all env vars from .env files with process.env fallback.\n *\n * Precedence: .shipyard/.env > process.env\n * Only keys declared in .shipyard/.env are resolved from process.env.\n * Repo root .env is not part of the resolution chain.\n */\nexport const resolveEnv = (\n repoDir: string,\n): Effect.Effect<\n Record<string, string>,\n ConfigDirError,\n FileSystem.FileSystem\n> =>\n Effect.gen(function* () {\n const configDir = join(repoDir, CONFIG_DIR);\n const envPath = join(configDir, \".env\");\n yield* Effect.tryPromise({\n try: () =>\n assertNoSymlinkComponents(repoDir, envPath, \"environment file\"),\n catch: (e) =>\n new ConfigDirError({\n message: `Refusing symlinked environment path: ${e instanceof Error ? e.message : String(e)}`,\n }),\n });\n const shipyardEnv = yield* parseEnvFile(envPath);\n\n const result: Record<string, string> = {};\n for (const key of Object.keys(shipyardEnv)) {\n // A blank placeholder falls back to process.env, so callers can source\n // credentials from a host login for one invocation, e.g.\n // `GH_TOKEN=\"$(gh auth token)\" npx shipyard run`. Only keys declared in\n // .shipyard/.env are eligible for this fallback.\n const value = shipyardEnv[key] || process.env[key];\n if (value) {\n result[key] = value;\n }\n }\n\n return result;\n });\n","import { lstat, readdir, rm } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { CONFIG_DIR, LOGS_DIR } from \"./runtimeNames.js\";\n\n/** The default age threshold for automatic run-log purges. */\nexport const DEFAULT_LOG_RETENTION_DAYS = 8;\n\nconst LOG_DIRECTORY_PATTERN = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\n\n/** Build the local calendar date directory used for default run logs. */\nexport const buildLogDirectoryName = (date: Date = new Date()): string => {\n if (Number.isNaN(date.getTime())) {\n throw new Error(\"Cannot build a log directory name from an invalid date.\");\n }\n const pad = (value: number): string => String(value).padStart(2, \"0\");\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;\n};\n\nconst parseLogDirectoryDate = (name: string): Date | undefined => {\n const match = LOG_DIRECTORY_PATTERN.exec(name);\n if (!match) return undefined;\n\n const year = Number(match[1]);\n const month = Number(match[2]);\n const day = Number(match[3]);\n const date = new Date(year, month - 1, day);\n return date.getFullYear() === year &&\n date.getMonth() === month - 1 &&\n date.getDate() === day\n ? date\n : undefined;\n};\n\nconst validateRetentionDays = (retentionDays: number): void => {\n if (!Number.isSafeInteger(retentionDays) || retentionDays < 0) {\n throw new Error(\"Log retention days must be a non-negative integer.\");\n }\n};\n\nexport interface PurgeRunLogsOptions {\n /** Host repository containing `.shipyard/logs/`. */\n readonly repoDir: string;\n /** Remove run logs strictly older than this many calendar days. Omit to remove every default run log. */\n readonly retentionDays?: number;\n /** Local time used to calculate the cutoff. Primarily useful for tests. */\n readonly now?: Date;\n}\n\nexport interface PurgeRunLogsResult {\n readonly logsDir: string;\n readonly retentionDays?: number;\n /** Dated directories on or after this local date are retained when age-based purging is used. */\n readonly cutoffDate?: string;\n readonly scannedDirectories: number;\n readonly removedCount: number;\n /** Directory names removed from `logsDir`, without the parent path. */\n readonly removedDirectories: readonly string[];\n /** Root-level log filenames removed from `logsDir`. */\n readonly removedFiles: readonly string[];\n}\n\n/**\n * Remove default run logs, either all of them or only those older than an\n * explicit retention threshold.\n *\n * Dated default run-log directories and regular root-level `.log` files inside\n * the managed logs directory are considered. Other files, malformed directory\n * names, and symlink entries are left alone.\n */\nexport const purgeRunLogs = async (\n options: PurgeRunLogsOptions,\n): Promise<PurgeRunLogsResult> => {\n const retentionDays = options.retentionDays;\n if (retentionDays !== undefined) validateRetentionDays(retentionDays);\n\n const now = options.now ?? new Date();\n if (retentionDays !== undefined && Number.isNaN(now.getTime())) {\n throw new Error(\"Cannot purge logs using an invalid date.\");\n }\n const cutoff =\n retentionDays === undefined\n ? undefined\n : new Date(\n now.getFullYear(),\n now.getMonth(),\n now.getDate() - retentionDays,\n );\n const cutoffDate =\n cutoff === undefined ? undefined : buildLogDirectoryName(cutoff);\n const logsDir = join(options.repoDir, CONFIG_DIR, LOGS_DIR);\n\n let entries;\n try {\n entries = await readdir(logsDir, { withFileTypes: true });\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") {\n return {\n logsDir,\n ...(retentionDays === undefined ? {} : { retentionDays, cutoffDate }),\n scannedDirectories: 0,\n removedCount: 0,\n removedDirectories: [],\n removedFiles: [],\n };\n }\n throw error;\n }\n\n const removedDirectories: string[] = [];\n const removedFiles: string[] = [];\n let scannedDirectories = 0;\n for (const entry of entries) {\n const entryPath = join(logsDir, entry.name);\n if (entry.isFile() && entry.name.endsWith(\".log\")) {\n const file = await lstat(entryPath);\n if (file.isFile() && (cutoff === undefined || file.mtime < cutoff)) {\n await rm(entryPath, { force: true });\n removedFiles.push(entry.name);\n }\n continue;\n }\n if (!entry.isDirectory()) continue;\n const directoryDate = parseLogDirectoryDate(entry.name);\n if (directoryDate === undefined) continue;\n scannedDirectories += 1;\n if (cutoff !== undefined && directoryDate >= cutoff) continue;\n\n await rm(entryPath, { recursive: true, force: true });\n removedDirectories.push(entry.name);\n }\n\n return {\n logsDir,\n ...(retentionDays === undefined ? {} : { retentionDays, cutoffDate }),\n scannedDirectories,\n removedCount: removedDirectories.length + removedFiles.length,\n removedDirectories,\n removedFiles,\n };\n};\n"]}
1
+ {"version":3,"sources":["../src/ErrorHandler.ts","../src/modelConfig.ts","../src/EnvResolver.ts","../src/LogRetention.ts"],"names":["Effect","join"],"mappings":"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","file":"chunk-JI3HDDMS.js","sourcesContent":["import { Effect } from \"effect\";\nimport { Display } from \"./Display.js\";\nimport type { SandboxError } from \"./errors.js\";\n\n/**\n * Formats a tagged SandboxError into a user-friendly message with\n * context-specific hints about what went wrong and how to recover.\n */\nexport const formatErrorMessage = (error: SandboxError): string => {\n switch (error._tag) {\n case \"ExecError\":\n return `Command failed in sandbox (${error.command}): ${error.message}`;\n case \"ExecHostError\":\n return `Command failed on host (${error.command}): ${error.message}`;\n case \"CopyError\":\n return `File copy failed: ${error.message}`;\n case \"DockerError\":\n return `Docker operation failed: ${error.message}. Is Docker running?`;\n case \"SyncError\":\n return `Git sync failed: ${error.message}`;\n case \"WorktreeError\":\n return `Git worktree operation failed: ${error.message}`;\n case \"PromptError\":\n return `Failed to resolve prompt: ${error.message}`;\n case \"AgentError\":\n return `Agent invocation failed: ${error.message}`;\n case \"ConfigDirError\":\n return `${error.message}`;\n case \"InitError\":\n return `${error.message}`;\n case \"AgentIdleTimeoutError\":\n case \"WorktreeTimeoutError\":\n case \"ContainerStartTimeoutError\":\n case \"CopyToWorktreeTimeoutError\":\n case \"CopyToWorktreeError\":\n case \"SyncInTimeoutError\":\n case \"HookTimeoutError\":\n case \"GitSetupTimeoutError\":\n case \"PromptExpansionTimeoutError\":\n case \"CommitCollectionTimeoutError\":\n case \"MergeToHostTimeoutError\":\n case \"SessionCaptureError\":\n case \"CwdError\":\n return error.message;\n }\n};\n\nconst showErrorAndExit = (error: SandboxError) =>\n Effect.gen(function* () {\n const d = yield* Display;\n yield* d.status(formatErrorMessage(error), \"error\");\n return yield* Effect.sync(() => process.exit(1) as never);\n });\n\n/**\n * Wraps an effect so that any SandboxError is caught, displayed via the\n * Display service as an error-severity status message, then exits the process\n * with code 1. Non-SandboxError errors pass through unchanged.\n */\nexport const withFriendlyErrors = <A, E, R>(\n effect: Effect.Effect<A, E, R>,\n): Effect.Effect<A, Exclude<E, SandboxError>, R | Display> =>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Effect.catchTags(effect as Effect.Effect<A, SandboxError, R>, {\n ExecError: showErrorAndExit,\n ExecHostError: showErrorAndExit,\n CopyError: showErrorAndExit,\n DockerError: showErrorAndExit,\n SyncError: showErrorAndExit,\n WorktreeError: showErrorAndExit,\n PromptError: showErrorAndExit,\n AgentError: showErrorAndExit,\n ConfigDirError: showErrorAndExit,\n InitError: showErrorAndExit,\n AgentIdleTimeoutError: showErrorAndExit,\n WorktreeTimeoutError: showErrorAndExit,\n ContainerStartTimeoutError: showErrorAndExit,\n CopyToWorktreeTimeoutError: showErrorAndExit,\n CopyToWorktreeError: showErrorAndExit,\n SyncInTimeoutError: showErrorAndExit,\n HookTimeoutError: showErrorAndExit,\n GitSetupTimeoutError: showErrorAndExit,\n PromptExpansionTimeoutError: showErrorAndExit,\n CommitCollectionTimeoutError: showErrorAndExit,\n MergeToHostTimeoutError: showErrorAndExit,\n SessionCaptureError: showErrorAndExit,\n CwdError: showErrorAndExit,\n }) as Effect.Effect<A, Exclude<E, SandboxError>, R | Display>;\n","/** Reasoning efforts accepted by the Codex CLI. */\nexport const CODEX_REASONING_EFFORTS = [\n \"low\",\n \"medium\",\n \"high\",\n \"xhigh\",\n \"max\",\n] as const;\n\nexport type CodexReasoningEffort = (typeof CODEX_REASONING_EFFORTS)[number];\n\n/** A model identifier plus the reasoning policy used for that model role. */\nexport interface CodexModelConfig {\n readonly model: string;\n readonly effort: CodexReasoningEffort;\n}\n\n/**\n * Default values for Shipyard's built-in Codex roles.\n *\n * Runtime environment variables override these defaults:\n * SHIPYARD_CODEX_ROUTINE_MODEL\n * SHIPYARD_CODEX_ROUTINE_REASONING_EFFORT\n * SHIPYARD_CODEX_STRONG_MODEL\n * SHIPYARD_CODEX_STRONG_REASONING_EFFORT\n *\n * Keep the defaults here so runtime providers, generated templates, and the\n * repository workflows all use the same role definitions.\n */\nconst DEFAULT_CODEX_MODELS = {\n routine: { model: \"gpt-5.6-luna\", effort: \"max\" },\n strong: { model: \"gpt-5.6-sol\", effort: \"max\" },\n} as const satisfies Record<string, CodexModelConfig>;\n\nconst readModel = (role: keyof typeof DEFAULT_CODEX_MODELS): string =>\n process.env[`SHIPYARD_CODEX_${role.toUpperCase()}_MODEL`]?.trim() ||\n DEFAULT_CODEX_MODELS[role].model;\n\nconst readEffort = (\n role: keyof typeof DEFAULT_CODEX_MODELS,\n): CodexReasoningEffort => {\n const envName = `SHIPYARD_CODEX_${role.toUpperCase()}_REASONING_EFFORT`;\n const value = process.env[envName]?.trim();\n if (!value) return DEFAULT_CODEX_MODELS[role].effort;\n if ((CODEX_REASONING_EFFORTS as readonly string[]).includes(value)) {\n return value as CodexReasoningEffort;\n }\n throw new Error(\n `${envName} must be one of ${CODEX_REASONING_EFFORTS.join(\", \")}; received \"${value}\"`,\n );\n};\n\nexport const CODEX_MODELS = {\n routine: {\n model: readModel(\"routine\"),\n effort: readEffort(\"routine\"),\n },\n strong: {\n model: readModel(\"strong\"),\n effort: readEffort(\"strong\"),\n },\n} as const satisfies Record<string, CodexModelConfig>;\n","import { FileSystem } from \"@effect/platform\";\nimport { Effect } from \"effect\";\nimport { join } from \"node:path\";\n\nimport { ConfigDirError } from \"./errors.js\";\nimport { assertNoSymlinkComponents } from \"./pathSecurity.js\";\nimport { CONFIG_DIR } from \"./runtimeNames.js\";\n\nconst parseEnvFile = (\n filePath: string,\n): Effect.Effect<Record<string, string>, never, FileSystem.FileSystem> =>\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const symlink = yield* fs.readLink(filePath).pipe(\n Effect.map(() => true),\n Effect.catchAll(() => Effect.succeed(false)),\n );\n // A repository-controlled symlink could redirect this read to a host\n // secret and then expose matching keys to the agent.\n if (symlink) return {};\n const content = yield* fs\n .readFileString(filePath)\n .pipe(Effect.catchAll(() => Effect.succeed(null)));\n if (content === null) return {};\n const vars: Record<string, string> = {};\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith(\"#\")) continue;\n const eqIndex = trimmed.indexOf(\"=\");\n if (eqIndex === -1) continue;\n const key = trimmed.slice(0, eqIndex).trim();\n let value = trimmed.slice(eqIndex + 1).trim();\n const isDoubleQuoted =\n value.length >= 2 &&\n value[0] === '\"' &&\n value[value.length - 1] === '\"';\n const isSingleQuoted =\n value.length >= 2 &&\n value[0] === \"'\" &&\n value[value.length - 1] === \"'\";\n if (isDoubleQuoted || isSingleQuoted) {\n value = value.slice(1, -1);\n }\n if (isDoubleQuoted) {\n value = value.replace(/\\\\([nrt\\\\])/g, (_, ch: string) => {\n const escapes: Record<string, string> = {\n n: \"\\n\",\n r: \"\\r\",\n t: \"\\t\",\n \"\\\\\": \"\\\\\",\n };\n return escapes[ch] ?? ch;\n });\n }\n vars[key] = value;\n }\n return vars;\n });\n\n/**\n * Resolve all env vars from .env files with process.env fallback.\n *\n * Precedence: .shipyard/.env > process.env\n * Only keys declared in .shipyard/.env are resolved from process.env.\n * Repo root .env is not part of the resolution chain.\n */\nexport const resolveEnv = (\n repoDir: string,\n): Effect.Effect<\n Record<string, string>,\n ConfigDirError,\n FileSystem.FileSystem\n> =>\n Effect.gen(function* () {\n const configDir = join(repoDir, CONFIG_DIR);\n const envPath = join(configDir, \".env\");\n yield* Effect.tryPromise({\n try: () =>\n assertNoSymlinkComponents(repoDir, envPath, \"environment file\"),\n catch: (e) =>\n new ConfigDirError({\n message: `Refusing symlinked environment path: ${e instanceof Error ? e.message : String(e)}`,\n }),\n });\n const shipyardEnv = yield* parseEnvFile(envPath);\n\n const result: Record<string, string> = {};\n for (const key of Object.keys(shipyardEnv)) {\n // A blank placeholder falls back to process.env, so callers can source\n // credentials from a host login for one invocation, e.g.\n // `GH_TOKEN=\"$(gh auth token)\" npx shipyard run`. Only keys declared in\n // .shipyard/.env are eligible for this fallback.\n const value = shipyardEnv[key] || process.env[key];\n if (value) {\n result[key] = value;\n }\n }\n\n return result;\n });\n","import { lstat, readdir, rm } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { CONFIG_DIR, LOGS_DIR } from \"./runtimeNames.js\";\n\n/** The default age threshold for automatic run-log purges. */\nexport const DEFAULT_LOG_RETENTION_DAYS = 8;\n\nconst LOG_DIRECTORY_PATTERN = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\n\n/** Build the local calendar date directory used for default run logs. */\nexport const buildLogDirectoryName = (date: Date = new Date()): string => {\n if (Number.isNaN(date.getTime())) {\n throw new Error(\"Cannot build a log directory name from an invalid date.\");\n }\n const pad = (value: number): string => String(value).padStart(2, \"0\");\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;\n};\n\nconst parseLogDirectoryDate = (name: string): Date | undefined => {\n const match = LOG_DIRECTORY_PATTERN.exec(name);\n if (!match) return undefined;\n\n const year = Number(match[1]);\n const month = Number(match[2]);\n const day = Number(match[3]);\n const date = new Date(year, month - 1, day);\n return date.getFullYear() === year &&\n date.getMonth() === month - 1 &&\n date.getDate() === day\n ? date\n : undefined;\n};\n\nconst validateRetentionDays = (retentionDays: number): void => {\n if (!Number.isSafeInteger(retentionDays) || retentionDays < 0) {\n throw new Error(\"Log retention days must be a non-negative integer.\");\n }\n};\n\nexport interface PurgeRunLogsOptions {\n /** Host repository containing `.shipyard/logs/`. */\n readonly repoDir: string;\n /** Remove run logs strictly older than this many calendar days. Omit to remove every default run log. */\n readonly retentionDays?: number;\n /** Local time used to calculate the cutoff. Primarily useful for tests. */\n readonly now?: Date;\n}\n\nexport interface PurgeRunLogsResult {\n readonly logsDir: string;\n readonly retentionDays?: number;\n /** Dated directories on or after this local date are retained when age-based purging is used. */\n readonly cutoffDate?: string;\n readonly scannedDirectories: number;\n readonly removedCount: number;\n /** Directory names removed from `logsDir`, without the parent path. */\n readonly removedDirectories: readonly string[];\n /** Root-level log filenames removed from `logsDir`. */\n readonly removedFiles: readonly string[];\n}\n\n/**\n * Remove default run logs, either all of them or only those older than an\n * explicit retention threshold.\n *\n * Dated default run-log directories and regular root-level `.log` files inside\n * the managed logs directory are considered. Other files, malformed directory\n * names, and symlink entries are left alone.\n */\nexport const purgeRunLogs = async (\n options: PurgeRunLogsOptions,\n): Promise<PurgeRunLogsResult> => {\n const retentionDays = options.retentionDays;\n if (retentionDays !== undefined) validateRetentionDays(retentionDays);\n\n const now = options.now ?? new Date();\n if (retentionDays !== undefined && Number.isNaN(now.getTime())) {\n throw new Error(\"Cannot purge logs using an invalid date.\");\n }\n const cutoff =\n retentionDays === undefined\n ? undefined\n : new Date(\n now.getFullYear(),\n now.getMonth(),\n now.getDate() - retentionDays,\n );\n const cutoffDate =\n cutoff === undefined ? undefined : buildLogDirectoryName(cutoff);\n const logsDir = join(options.repoDir, CONFIG_DIR, LOGS_DIR);\n\n let entries;\n try {\n entries = await readdir(logsDir, { withFileTypes: true });\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") {\n return {\n logsDir,\n ...(retentionDays === undefined ? {} : { retentionDays, cutoffDate }),\n scannedDirectories: 0,\n removedCount: 0,\n removedDirectories: [],\n removedFiles: [],\n };\n }\n throw error;\n }\n\n const removedDirectories: string[] = [];\n const removedFiles: string[] = [];\n let scannedDirectories = 0;\n for (const entry of entries) {\n const entryPath = join(logsDir, entry.name);\n if (entry.isFile() && entry.name.endsWith(\".log\")) {\n const file = await lstat(entryPath);\n if (file.isFile() && (cutoff === undefined || file.mtime < cutoff)) {\n await rm(entryPath, { force: true });\n removedFiles.push(entry.name);\n }\n continue;\n }\n if (!entry.isDirectory()) continue;\n const directoryDate = parseLogDirectoryDate(entry.name);\n if (directoryDate === undefined) continue;\n scannedDirectories += 1;\n if (cutoff !== undefined && directoryDate >= cutoff) continue;\n\n await rm(entryPath, { recursive: true, force: true });\n removedDirectories.push(entry.name);\n }\n\n return {\n logsDir,\n ...(retentionDays === undefined ? {} : { retentionDays, cutoffDate }),\n scannedDirectories,\n removedCount: removedDirectories.length + removedFiles.length,\n removedDirectories,\n removedFiles,\n };\n};\n"]}