apphx 1.0.0 → 2.0.0
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 +52 -138
- package/benchmarks/peer-context-worker.mjs +186 -0
- package/benchmarks/peer-context.mjs +150 -0
- package/dist/apple-types.js.map +1 -1
- package/dist/cli.js +373 -121
- package/dist/cli.js.map +1 -1
- package/dist/config.js +42 -4
- package/dist/config.js.map +1 -1
- package/dist/dependencies.js +455 -16
- package/dist/dependencies.js.map +1 -1
- package/dist/export-options.js +44 -2
- package/dist/export-options.js.map +1 -1
- package/dist/flutter.js +13 -25
- package/dist/flutter.js.map +1 -1
- package/dist/go-dependencies.js +389 -0
- package/dist/go-dependencies.js.map +1 -0
- package/dist/inbox.js +7 -8
- package/dist/inbox.js.map +1 -1
- package/dist/integrations.js +29 -29
- package/dist/integrations.js.map +1 -1
- package/dist/isolation.js +190 -0
- package/dist/isolation.js.map +1 -0
- package/dist/macos.js +57 -0
- package/dist/macos.js.map +1 -0
- package/dist/mygo-build.js +55 -0
- package/dist/mygo-build.js.map +1 -0
- package/dist/policy.js +35 -0
- package/dist/policy.js.map +1 -0
- package/dist/preflight.js +1 -1
- package/dist/process.js +3 -3
- package/dist/project-profiles.js +163 -0
- package/dist/project-profiles.js.map +1 -0
- package/dist/proof.js +33 -0
- package/dist/proof.js.map +1 -0
- package/dist/remote.js +1 -1
- package/dist/runner.js +269 -287
- package/dist/runner.js.map +1 -1
- package/dist/scheduler.js +0 -3
- package/dist/scheduler.js.map +1 -1
- package/dist/schemas.js +156 -44
- package/dist/schemas.js.map +1 -1
- package/dist/store.js +166 -44
- package/dist/store.js.map +1 -1
- package/dist/vendor/obfuscator/dist/cli.js +72 -0
- package/dist/vendor/obfuscator/dist/cli.js.map +1 -0
- package/dist/vendor/obfuscator/dist/code.js +585 -0
- package/dist/vendor/obfuscator/dist/code.js.map +1 -0
- package/dist/vendor/obfuscator/dist/common.js +262 -0
- package/dist/vendor/obfuscator/dist/common.js.map +1 -0
- package/dist/vendor/obfuscator/dist/config.js +123 -0
- package/dist/vendor/obfuscator/dist/config.js.map +1 -0
- package/dist/vendor/obfuscator/dist/content.js +89 -0
- package/dist/vendor/obfuscator/dist/content.js.map +1 -0
- package/dist/vendor/obfuscator/dist/obfuscate.js +93 -0
- package/dist/vendor/obfuscator/dist/obfuscate.js.map +1 -0
- package/dist/vendor/obfuscator/dist/png.js +283 -0
- package/dist/vendor/obfuscator/dist/png.js.map +1 -0
- package/dist/vendor/obfuscator/dist/project.js +159 -0
- package/dist/vendor/obfuscator/dist/project.js.map +1 -0
- package/dist/vendor/obfuscator/dist/resources.js +335 -0
- package/dist/vendor/obfuscator/dist/resources.js.map +1 -0
- package/dist/vendor/obfuscator/package.json +22 -0
- package/dist/workspace.js +113 -0
- package/dist/workspace.js.map +1 -0
- package/evals/control.mjs +73 -0
- package/evals/expectations.mjs +37 -0
- package/evals/host.mjs +51 -0
- package/evals/oracle.mjs +80 -0
- package/evals/policy.mjs +268 -0
- package/examples/android-java.factory.json +18 -0
- package/examples/android-java.json +16 -0
- package/examples/existing-project.factory.json +18 -0
- package/examples/existing-project.json +17 -0
- package/examples/expo.eas.json +17 -0
- package/examples/expo.factory.json +18 -0
- package/examples/expo.json +16 -0
- package/examples/factory.json +0 -2
- package/examples/flutter.factory.json +13 -0
- package/examples/flutter.json +16 -0
- package/examples/luggage.json +5 -3
- package/examples/mygo-web.factory.json +18 -0
- package/examples/mygo-web.json +16 -0
- package/examples/mygo.factory.json +18 -0
- package/examples/mygo.json +16 -0
- package/examples/react-native.factory.json +18 -0
- package/examples/react-native.json +16 -0
- package/examples/remote.json +1 -1
- package/examples/runtime/android-java/app/build.gradle +7 -0
- package/examples/runtime/android-java/app/src/main/AndroidManifest.xml +8 -0
- package/examples/runtime/android-java/app/src/main/java/dev/apphx/runtime/MainActivity.java +44 -0
- package/examples/runtime/android-java/sdk-build.mjs +29 -0
- package/examples/runtime/android-java/settings.gradle +2 -0
- package/examples/runtime/android-ui.mjs +70 -0
- package/examples/runtime/mygo-native/go.mod +13 -0
- package/examples/runtime/mygo-native/go.sum +10 -0
- package/examples/runtime/mygo-native/main.go +173 -0
- package/examples/runtime/mygo-native/main_test.go +14 -0
- package/examples/runtime/mygo-native/mygo.json +1 -0
- package/examples/runtime/mygo-web/bun.lock +15 -0
- package/examples/runtime/mygo-web/go.mod +9 -0
- package/examples/runtime/mygo-web/go.sum +8 -0
- package/examples/runtime/mygo-web/index.html +1 -0
- package/examples/runtime/mygo-web/main.go +60 -0
- package/examples/runtime/mygo-web/mygo.config.ts +10 -0
- package/examples/runtime/mygo-web/package.json +1 -0
- package/examples/runtime/mygo-web/src/main.ts +23 -0
- package/examples/runtime/mygo-web/src/mygo.ts +14 -0
- package/examples/swift.factory.json +18 -0
- package/examples/swift.json +16 -0
- package/examples/uni-app.factory.json +18 -0
- package/examples/uni-app.json +16 -0
- package/package.json +12 -5
- package/scripts/bundle-obfuscator.mjs +19 -0
- package/scripts/runtime-smoke.mjs +209 -0
- package/skills/apphx/SKILL.md +180 -0
- package/skills/apphx/resources/google-play-research-result.json +6 -0
- package/skills/apphx/resources/local-research-result.json +6 -0
- package/skills/{apple-app-factory → apphx}/resources/requirement.json +5 -8
- package/skills/apphx/resources/research-result.json +12 -0
- package/skills/apphx/resources/review-result.json +7 -0
- package/dist/apple.js +0 -900
- package/dist/apple.js.map +0 -1
- package/skills/apple-app-factory/SKILL.md +0 -103
- package/skills/apple-app-factory/resources/research-result.json +0 -21
- package/skills/apple-app-factory/resources/review-result.json +0 -7
- /package/skills/{apple-app-factory → apphx}/LICENSE +0 -0
package/dist/schemas.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemas.js","names":[],"sources":["../src/schemas.ts"],"sourcesContent":["import { z } from 'zod';\nimport { AppleReceiptSchema } from './apple-types.js';\n\nconst text = z.string().min(1).refine(value => value.trim().length > 0 && !value.includes('\\0'), 'Expected non-empty text without NUL characters');\nconst count = z.number().int().nonnegative().safe();\nconst positive = z.number().positive().finite();\nconst command = z.array(text).min(1);\n\n\nexport const AppleSpecSchema = z.strictObject({\n appId: text.optional(), bundleId: text.optional(), version: text.optional(), buildNumber: text.optional(), locale: text.optional(),\n description: text.optional(), keywords: text.optional(), supportUrl: text.optional(), privacyPolicyUrl: text.optional(), reviewNotes: text.optional(),\n copyright: text.optional(), whatsNew: text.optional(), storefrontCountry: text.optional(), screenshotsDir: text.optional(), manualSetupConfirmed: z.boolean().optional(),\n contact: z.strictObject({ firstName: text.optional(), lastName: text.optional(), email: text.optional(), phone: text.optional() }).optional(),\n});\nexport type AppleSpec = z.infer<typeof AppleSpecSchema>;\nexport const SpecSchema = z.strictObject({\n id: text.regex(/^[a-z][a-z0-9-]{1,62}$/), name: text, purpose: text, audience: text,\n framework: z.literal('flutter'), differentiators: z.array(text).min(1), acceptance: z.array(text).min(1),\n constraints: z.array(text).optional(), apple: AppleSpecSchema.optional(),\n hiddenFeatures: z.literal(false).optional(), reviewBypass: z.literal(false).optional(),\n});\nexport type Spec = z.infer<typeof SpecSchema>;\nexport const RequirementSchema = SpecSchema.extend({ baseJobId: z.uuid().optional() });\n\nexport const ConfigSchema = z.strictObject({\n configPath: text.optional(), stateDir: text, workspaceRoot: text,\n allowLocalExecution: z.boolean().default(false), allowSubmit: z.boolean().default(false), allowRelease: z.boolean().default(false),\n executionEnv: z.array(text.regex(/^[A-Z][A-Z0-9_]*$/).refine(value => !/^(ASC_|APPLE_|FASTLANE_|MATCH_)/.test(value), 'Publisher credentials must not be passed to host or verification tools')).default([]),\n timeoutMs: positive.default(900000), maxAttempts: positive.int().default(3), maxHostTurns: positive.int().default(16), maxJobHours: positive.default(24),\n retryDelayMs: positive.default(30000), pollMs: positive.default(300000),\n inbox: z.strictObject({ directory: text, pollMs: positive.default(2000) }).optional(),\n verification: z.strictObject({ prerequisites: z.array(command).default([]), checks: z.array(command).min(1), runtime: z.array(command).min(1) }),\n toolchain: z.strictObject({ flutterSdk: text }).optional(),\n apple: z.strictObject({ exportOptionsPlist: text.optional() }).optional(),\n packageTarget: z.enum(['simulator', 'ipa']).optional(), executionWarning: text.optional(),\n}).transform(value => ({ ...value, packageTarget: value.packageTarget ?? (value.allowSubmit ? 'ipa' as const : 'simulator' as const) })).superRefine((value, context) => {\n if (value.allowSubmit && value.packageTarget !== 'ipa') context.addIssue({ code: 'custom', path: ['packageTarget'], message: 'Submission requires packageTarget=ipa; simulator builds cannot be uploaded' });\n if (value.allowRelease && !value.allowSubmit) context.addIssue({ code: 'custom', path: ['allowRelease'], message: 'allowRelease requires allowSubmit' });\n});\nexport type Config = z.infer<typeof ConfigSchema>;\nexport const StageSchema = z.enum(['research', 'build', 'verify', 'review', 'package', 'publish', 'monitor']);\nexport type Stage = z.infer<typeof StageSchema>;\nexport const StatusSchema = z.enum(['queued', 'running', 'waiting', 'blocked', 'failed', 'ready', 'built', 'approved', 'released']);\nexport type Status = z.infer<typeof StatusSchema>;\nexport const ToolchainSchema = z.strictObject({ source: text, frameworkRevision: text, engineRevision: text, ready: z.boolean() });\nexport type Toolchain = z.infer<typeof ToolchainSchema>;\nexport const ProcessIdentitySchema = z.strictObject({ token: text });\nexport type ProcessIdentity = z.infer<typeof ProcessIdentitySchema>;\nexport const CommandMetadataSchema = z.strictObject({ deadline: z.number().finite(), identity: ProcessIdentitySchema, termAt: z.number().finite().optional(), killAt: z.number().finite().optional() });\nexport type CommandMetadata = z.infer<typeof CommandMetadataSchema>;\nexport const PrerequisiteSchema = z.strictObject({ argv: z.array(text).optional(), reason: text, path: text.optional() });\nexport type Prerequisite = z.infer<typeof PrerequisiteSchema>;\nexport const ResearchSchema = z.strictObject({\n viable: z.boolean(), policySources: z.array(z.strictObject({ rule: text, url: z.url() })), distinctness: text, risks: z.array(text).optional(), plan: z.array(text).min(1),\n});\nexport type Research = z.infer<typeof ResearchSchema>;\nexport const ReviewSchema = z.strictObject({ approved: z.boolean(), findings: z.array(text), acceptanceEvidence: z.array(z.strictObject({ requirement: text, evidence: text })) });\nexport type Review = z.infer<typeof ReviewSchema>;\nexport const ArtifactSchema = z.strictObject({ kind: z.enum(['ios-simulator', 'ipa']), path: text, digest: text.regex(/^[a-f0-9]{64}$/), createdAt: z.iso.datetime() });\nexport type Artifact = z.infer<typeof ArtifactSchema>;\nexport const ApplePollResultSchema = z.strictObject({ status: z.enum(['waiting', 'approved', 'rejected']), detail: text, distributionReady: z.boolean().optional(), available: z.boolean().optional() });\nexport const InboxEntrySchema = z.strictObject({\n source: text, digest: text.nullable(), status: z.enum(['accepted', 'error']), jobId: text.nullable(),\n error: z.string().nullable(), observedAt: z.number().finite(),\n});\nexport type InboxEntry = z.infer<typeof InboxEntrySchema>;\nexport const HostStageSchema = z.enum(['research', 'build', 'review']);\nexport type HostStage = z.infer<typeof HostStageSchema>;\nexport const HostTurnSchema = z.strictObject({\n id: z.uuid(), stage: HostStageSchema, createdAt: z.number().finite(), contextDigest: text.regex(/^[a-f0-9]{64}$/),\n});\nexport type HostTurn = z.infer<typeof HostTurnSchema>;\nexport const JobSchema = z.object({\n id: text, spec: SpecSchema, requestSpec: SpecSchema.nullable(), requestSpecError: text.nullable().default(null), config: ConfigSchema, stage: StageSchema, status: StatusSchema,\n createdAt: z.number().finite(), updatedAt: z.number().finite(), nextAt: z.number().finite(),\n attempts: z.partialRecord(StageSchema, count), hostTurns: count, turn: HostTurnSchema.nullable().optional(), groups: z.array(z.number().int()),\n commands: z.record(z.string(), CommandMetadataSchema).default({}), receipt: AppleReceiptSchema, logs: z.array(text), workspace: text,\n baseJobId: z.uuid().optional(), baseDigest: text.regex(/^[a-f0-9]{64}$/).optional(), basePrepared: z.boolean().optional(),\n recoveryStage: StageSchema.optional(),\n blockedReason: z.strictObject({ kind: z.literal('prerequisite'), stage: StageSchema, prerequisite: PrerequisiteSchema }).nullable().optional(),\n manualRecovery: z.string().nullable().optional(), error: z.string().nullable().optional(), feedback: z.string().optional(),\n research: ResearchSchema.optional(), policyEvidence: z.strictObject({ url: z.url(), fetchedAt: text, sha256: text }).optional(),\n toolchain: ToolchainSchema.optional(), verifiedDigest: text.nullable().optional(), verifiedDependencyDigest: text.regex(/^[a-f0-9]{64}$/).nullable().optional(), screenshotDigest: text.nullable().optional(), verifiedAt: text.optional(),\n review: ReviewSchema.nullable().optional(), ipaPath: text.nullable().optional(), archiveDigest: text.nullable().optional(), artifact: ArtifactSchema.nullable().optional(),\n appleReview: ApplePollResultSchema.optional(), externalChecks: z.unknown().optional(),\n}).passthrough();\nexport type Job = z.infer<typeof JobSchema>;\n\nexport type FactoryError = Error & { code?: string; syscall?: string; prerequisite?: Prerequisite; httpStatus?: number | null; outcome?: string; transient?: boolean };\nexport function toError(value: unknown): FactoryError {\n return value instanceof Error ? value : new Error(String(value));\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"schemas.js","names":[],"sources":["../src/schemas.ts"],"sourcesContent":["import { z } from 'zod';\nimport { dirname, isAbsolute, resolve, win32 } from 'node:path';\nimport { lstatSync } from 'node:fs';\nimport { AppleReceiptSchema } from './apple-types.js';\nimport { validateMyGoPackaging } from './mygo-build.js';\n\nconst text = z.string().min(1).refine(value => value.trim().length > 0 && !value.includes('\\0'), 'Expected non-empty text without NUL characters');\nconst count = z.number().int().nonnegative().safe();\nconst positive = z.number().positive().finite();\nconst command = z.array(text).min(1);\n\nfunction relativeProjectPath(value: string, allowRoot = false): boolean {\n if (allowRoot && value === '.') return true;\n return !isAbsolute(value) && !win32.isAbsolute(value) && !/[\\\\:*?\\[\\]]/.test(value)\n && value.split('/').every(part => part !== '' && part !== '.' && part !== '..');\n}\n\nexport const FrameworkSchema = z.enum(['flutter', 'android-java', 'swift', 'react-native', 'expo', 'uni-app', 'mygo']);\nexport type Framework = z.infer<typeof FrameworkSchema>;\nexport const PlatformSchema = z.enum(['ios', 'android', 'macos']);\nexport type Platform = z.infer<typeof PlatformSchema>;\nexport const ChannelSchema = z.enum(['local', 'app-store', 'google-play']);\nexport type Channel = z.infer<typeof ChannelSchema>;\nexport const PackageTargetSchema = z.enum(['simulator', 'ipa', 'apk', 'aab', 'app', 'dmg']);\nexport type PackageTarget = z.infer<typeof PackageTargetSchema>;\nexport const AppleSpecSchema = z.strictObject({\n appId: text.optional(), bundleId: text.optional(), buildNumber: text.optional(), locale: text.optional(),\n description: text.optional(), keywords: text.optional(), supportUrl: text.optional(), privacyPolicyUrl: text.optional(), reviewNotes: text.optional(),\n copyright: text.optional(), whatsNew: text.optional(), storefrontCountry: text.optional(), manualSetupConfirmed: z.boolean().optional(),\n contact: z.strictObject({ firstName: text.optional(), lastName: text.optional(), email: text.optional(), phone: text.optional() }).optional(),\n});\nexport type AppleSpec = z.infer<typeof AppleSpecSchema>;\nconst SpecObject = z.strictObject({\n id: text.regex(/^[a-z][a-z0-9-]{1,62}$/), name: text, purpose: text, audience: text,\n framework: FrameworkSchema, platform: PlatformSchema, channel: ChannelSchema.default('local'), version: text.default('1.0.0'),\n project: z.strictObject({ sourceDir: text.optional(), directory: text.refine(value => relativeProjectPath(value, true), 'project.directory must be a relative in-root directory without traversal').default('.') }).optional(),\n screenshotsDir: text.optional(), differentiators: z.array(text).min(1), acceptance: z.array(text).min(1),\n constraints: z.array(text).optional(), apple: AppleSpecSchema.optional(),\n hiddenFeatures: z.literal(false).optional(), reviewBypass: z.literal(false).optional(),\n});\nfunction refineSpec(value: z.infer<typeof SpecObject>, context: z.RefinementCtx): void {\n if (value.framework === 'android-java' && value.platform !== 'android') context.addIssue({ code: 'custom', path: ['platform'], message: 'android-java requires platform=android' });\n if (value.framework === 'swift' && value.platform !== 'ios') context.addIssue({ code: 'custom', path: ['platform'], message: 'swift requires platform=ios' });\n if (value.framework === 'mygo' && value.platform !== 'macos') context.addIssue({ code: 'custom', path: ['platform'], message: 'mygo requires platform=macos' });\n if (value.platform === 'macos' && value.framework !== 'mygo') context.addIssue({ code: 'custom', path: ['framework'], message: 'macos currently requires framework=mygo' });\n if (value.platform === 'macos' && value.channel !== 'local') context.addIssue({ code: 'custom', path: ['channel'], message: 'macos currently supports local delivery only' });\n if (value.channel === 'app-store' && value.platform !== 'ios') context.addIssue({ code: 'custom', path: ['channel'], message: 'app-store requires platform=ios' });\n if (value.channel === 'google-play' && value.platform !== 'android') context.addIssue({ code: 'custom', path: ['channel'], message: 'google-play requires platform=android' });\n}\nexport const SpecSchema = SpecObject.superRefine(refineSpec);\nexport type Spec = z.infer<typeof SpecSchema>;\nexport const RequirementSchema = SpecObject.extend({ baseJobId: z.uuid().optional() }).superRefine((value, context) => {\n refineSpec(value, context);\n if (value.baseJobId && value.project?.sourceDir) context.addIssue({ code: 'custom', path: ['project', 'sourceDir'], message: 'project.sourceDir and baseJobId are mutually exclusive' });\n});\n\nexport const ObfuscationConfigSchema = z.strictObject({\n command: z.array(command.element).min(1).default(['obfuscator']),\n configPath: text,\n seed: text.optional(),\n});\nexport type ObfuscationConfig = z.infer<typeof ObfuscationConfigSchema>;\n\nexport const ConfigSchema = z.strictObject({\n configPath: text.optional(), stateDir: text, workspaceRoot: text,\n allowLocalExecution: z.boolean().default(false), allowCloudBuild: z.boolean().default(false),\n executionEnv: z.array(text.regex(/^[A-Z][A-Z0-9_]*$/).refine(value => !/^(ASC_|APPLE_|FASTLANE_|MATCH_)/.test(value), 'Publisher credentials must not be passed to host or verification tools')).default([]),\n isolation: z.strictObject({ mode: z.literal('macos-sandbox'), readOnlyPaths: z.array(text).default([]), network: z.enum(['deny', 'allow']).default('deny') }).optional(),\n timeoutMs: positive.default(900000), maxAttempts: positive.int().default(3), maxHostTurns: positive.int().default(16), maxJobHours: positive.default(24),\n retryDelayMs: positive.default(30000), pollMs: positive.default(300000),\n inbox: z.strictObject({ directory: text, pollMs: positive.default(2000) }).optional(),\n verification: z.strictObject({ prerequisites: z.array(command).default([]), checks: z.array(command).min(1), runtime: z.array(command).min(1) }),\n toolchain: z.strictObject({ flutterSdk: text }).optional(),\n apple: z.strictObject({ exportOptionsPlist: text.optional() }).optional(),\n packageTarget: PackageTargetSchema, executionWarning: text.optional(),\n obfuscation: ObfuscationConfigSchema.optional(),\n packaging: z.strictObject({ commands: z.array(command).min(1), artifactPath: text.refine(value => relativeProjectPath(value), 'artifactPath must be an exact project-relative file or directory without traversal or wildcards'), provider: z.enum(['local', 'cloud']).default('local') }).optional(),\n}).superRefine((value, context) => {\n if (value.packaging?.provider === 'cloud' && !value.allowCloudBuild) context.addIssue({ code: 'custom', path: ['allowCloudBuild'], message: 'Cloud packaging requires explicit allowCloudBuild=true' });\n});\nexport type Config = z.infer<typeof ConfigSchema>;\nexport function validateJobConfig(spec: Spec, config: Config): void {\n const targets: Record<Platform, readonly Config['packageTarget'][]> = { ios: ['simulator', 'ipa'], android: ['apk', 'aab'], macos: ['app', 'dmg'] };\n if (!targets[spec.platform].includes(config.packageTarget)) throw new Error(`packageTarget=${config.packageTarget} does not match platform=${spec.platform}`);\n if (spec.channel === 'google-play' && config.packageTarget !== 'aab') throw new Error('Google Play requires packageTarget=aab');\n if (config.toolchain && spec.framework !== 'flutter') throw new Error('toolchain.flutterSdk is only supported for framework=flutter');\n if (spec.framework !== 'flutter' && !config.packaging) throw new Error(`${spec.framework} requires owner-configured packaging.commands and packaging.artifactPath`);\n if (config.packaging?.provider === 'cloud' && !config.allowCloudBuild) throw new Error('Cloud packaging requires explicit allowCloudBuild=true');\n if (spec.platform === 'macos' && (config.allowCloudBuild || config.packaging?.provider === 'cloud')) throw new Error('macos currently supports local build-only delivery; notarization and uploads are not part of this tool');\n if (spec.framework === 'mygo') validateMyGoPackaging(config, spec.screenshotsDir);\n}\nexport const StageSchema = z.enum(['research', 'build', 'obfuscate', 'verify', 'review', 'package']);\nexport type Stage = z.infer<typeof StageSchema>;\nexport const StatusSchema = z.enum(['queued', 'running', 'waiting', 'blocked', 'failed', 'ready', 'built']);\nexport type Status = z.infer<typeof StatusSchema>;\nexport const ToolchainSchema = z.strictObject({ source: text, frameworkRevision: text, engineRevision: text, ready: z.boolean() });\nexport type Toolchain = z.infer<typeof ToolchainSchema>;\nexport const ProcessIdentitySchema = z.strictObject({ token: text });\nexport type ProcessIdentity = z.infer<typeof ProcessIdentitySchema>;\nexport const CommandMetadataSchema = z.strictObject({ deadline: z.number().finite(), identity: ProcessIdentitySchema, termAt: z.number().finite().optional(), killAt: z.number().finite().optional() });\nexport type CommandMetadata = z.infer<typeof CommandMetadataSchema>;\nexport const PrerequisiteSchema = z.strictObject({ argv: z.array(text).optional(), reason: text, path: text.optional() });\nexport type Prerequisite = z.infer<typeof PrerequisiteSchema>;\nexport const ResearchSchema = z.strictObject({\n viable: z.boolean(), distinctness: text, risks: z.array(text).optional(), plan: z.array(text).min(1),\n});\nexport type Research = z.infer<typeof ResearchSchema>;\nexport const ReviewSchema = z.strictObject({ approved: z.boolean(), findings: z.array(text), acceptanceEvidence: z.array(z.strictObject({ requirement: text, evidence: text })) });\nexport type Review = z.infer<typeof ReviewSchema>;\nexport const ArtifactSchema = z.strictObject({ kind: z.enum(['ios-simulator', 'ipa', 'apk', 'aab', 'macos-app', 'dmg']), path: text, digest: text.regex(/^[a-f0-9]{64}$/), createdAt: z.iso.datetime() });\nexport type Artifact = z.infer<typeof ArtifactSchema>;\nexport const InboxEntrySchema = z.strictObject({\n source: text, digest: text.nullable(), status: z.enum(['accepted', 'error']), jobId: text.nullable(),\n error: z.string().nullable(), observedAt: z.number().finite(),\n});\nexport type InboxEntry = z.infer<typeof InboxEntrySchema>;\nexport const HostStageSchema = z.enum(['research', 'build', 'review']);\nexport type HostStage = z.infer<typeof HostStageSchema>;\nexport const HostTurnSchema = z.strictObject({\n id: z.uuid(), stage: HostStageSchema, createdAt: z.number().finite(), contextDigest: text.regex(/^[a-f0-9]{64}$/),\n});\nexport type HostTurn = z.infer<typeof HostTurnSchema>;\nexport const JobSchema = z.object({\n id: text, spec: SpecSchema, requestSpec: SpecSchema.nullable(), requestSpecError: text.nullable().default(null), config: ConfigSchema, stage: StageSchema, status: StatusSchema,\n createdAt: z.number().finite(), updatedAt: z.number().finite(), nextAt: z.number().finite(),\n attempts: z.partialRecord(StageSchema, count), hostTurns: count, turn: HostTurnSchema.nullable().optional(), groups: z.array(z.number().int()),\n commands: z.record(z.string(), CommandMetadataSchema).default({}), receipt: AppleReceiptSchema, logs: z.array(text), workspace: text,\n baseJobId: z.uuid().optional(), baseDigest: text.regex(/^[a-f0-9]{64}$/).optional(), basePrepared: z.boolean().optional(),\n automaticBase: z.literal(true).optional(),\n sourceDirectory: text.refine(isAbsolute, 'sourceDirectory must be absolute').optional(), importDigest: text.regex(/^[a-f0-9]{64}$/).optional(), importPrepared: z.boolean().optional(), cloudBuildPending: z.boolean().optional(),\n recoveryStage: StageSchema.optional(),\n blockedReason: z.strictObject({ kind: z.literal('prerequisite'), stage: StageSchema, prerequisite: PrerequisiteSchema }).nullable().optional(),\n manualRecovery: z.string().nullable().optional(), error: z.string().nullable().optional(), feedback: z.string().optional(),\n research: ResearchSchema.optional(), policyEvidence: z.strictObject({ url: z.url(), fetchedAt: text, sha256: text }).optional(),\n toolchain: ToolchainSchema.optional(), verifiedDigest: text.nullable().optional(), verifiedDependencyDigest: text.regex(/^[a-f0-9]{64}$/).nullable().optional(), screenshotDigest: text.nullable().optional(), verifiedAt: text.optional(),\n obfuscationBase: z.strictObject({ digest: text.regex(/^[a-f0-9]{64}$/), path: text }).optional(),\n obfuscationDigest: text.regex(/^[a-f0-9]{64}$/).optional(),\n obfuscationReport: z.strictObject({ changedFiles: count, transforms: z.record(text, count), skipped: z.strictObject({ generated: count, unsupported: count }) }).optional(),\n review: ReviewSchema.nullable().optional(), ipaPath: text.nullable().optional(), archiveDigest: text.nullable().optional(), artifact: ArtifactSchema.nullable().optional(),\n externalChecks: z.unknown().optional(),\n}).passthrough();\nexport type Job = z.infer<typeof JobSchema>;\n\nexport type FactoryError = Error & { code?: string; syscall?: string; prerequisite?: Prerequisite; httpStatus?: number | null; outcome?: string; transient?: boolean };\nexport function toError(value: unknown): FactoryError {\n return value instanceof Error ? value : new Error(String(value));\n}\n"],"mappings":"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"}
|
package/dist/store.js
CHANGED
|
@@ -1,35 +1,71 @@
|
|
|
1
|
-
import { ConfigSchema, InboxEntrySchema, JobSchema, SpecSchema, toError } from "./schemas.js";
|
|
1
|
+
import { ConfigSchema, InboxEntrySchema, JobSchema, SpecSchema, toError, validateJobConfig } from "./schemas.js";
|
|
2
|
+
import { canonicalPath, normalizeIsolationPaths, validateProjectSource } from "./config.js";
|
|
2
3
|
import { TERMINATION_GRACE_MS, inspectProcessGroup, signalOwnedProcessGroup } from "./process.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
4
|
+
import { dependencyDigest } from "./dependencies.js";
|
|
5
|
+
import { projectDirectory, sourceDigest } from "./workspace.js";
|
|
5
6
|
import { chmodSync, mkdirSync } from "node:fs";
|
|
7
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
6
8
|
import { DatabaseSync } from "node:sqlite";
|
|
9
|
+
import { randomUUID } from "node:crypto";
|
|
7
10
|
// src/store.ts
|
|
8
11
|
function parseStoredJob(data) {
|
|
9
12
|
if (typeof data !== "string") throw new Error("Stored task data must be JSON text");
|
|
10
13
|
return JobSchema.parse(JSON.parse(data));
|
|
11
14
|
}
|
|
15
|
+
function sameIdentity(left, right) {
|
|
16
|
+
return left.id === right.id && left.platform === right.platform && left.channel === right.channel && left.version === right.version;
|
|
17
|
+
}
|
|
18
|
+
function overlaps(left, right) {
|
|
19
|
+
const contains = (root, path) => {
|
|
20
|
+
const child = relative(root, path);
|
|
21
|
+
return !child || child !== ".." && !child.startsWith(`..${sep}`) && !isAbsolute(child);
|
|
22
|
+
};
|
|
23
|
+
return contains(left, right) || contains(right, left);
|
|
24
|
+
}
|
|
25
|
+
function migrateSpec(value) {
|
|
26
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return SpecSchema.parse(value);
|
|
27
|
+
const saved = { ...value };
|
|
28
|
+
const apple = saved.apple && typeof saved.apple === "object" && !Array.isArray(saved.apple) ? { ...saved.apple } : void 0;
|
|
29
|
+
if (saved.platform === void 0) {
|
|
30
|
+
saved.framework = "flutter";
|
|
31
|
+
saved.platform = "ios";
|
|
32
|
+
saved.channel = "app-store";
|
|
33
|
+
}
|
|
34
|
+
if (apple) {
|
|
35
|
+
saved.version ??= apple.version;
|
|
36
|
+
saved.screenshotsDir ??= apple.screenshotsDir;
|
|
37
|
+
delete apple.version;
|
|
38
|
+
delete apple.screenshotsDir;
|
|
39
|
+
saved.apple = apple;
|
|
40
|
+
}
|
|
41
|
+
return SpecSchema.parse(saved);
|
|
42
|
+
}
|
|
12
43
|
var Store = class {
|
|
13
44
|
db;
|
|
45
|
+
directory;
|
|
14
46
|
constructor(directory) {
|
|
15
|
-
|
|
47
|
+
this.directory = canonicalPath(directory);
|
|
48
|
+
mkdirSync(this.directory, {
|
|
16
49
|
recursive: true,
|
|
17
50
|
mode: 448
|
|
18
51
|
});
|
|
19
|
-
this.db = new DatabaseSync(join(directory, "queue.sqlite"));
|
|
20
|
-
chmodSync(join(directory, "queue.sqlite"), 384);
|
|
21
|
-
this.db.exec(
|
|
22
|
-
CREATE TABLE IF NOT EXISTS jobs (id TEXT PRIMARY KEY, product TEXT NOT NULL, version TEXT NOT NULL, status TEXT NOT NULL, next_at INTEGER NOT NULL, data TEXT NOT NULL, UNIQUE(product, version));
|
|
23
|
-
CREATE TABLE IF NOT EXISTS events (seq INTEGER PRIMARY KEY, job TEXT NOT NULL, at INTEGER NOT NULL, data TEXT NOT NULL);
|
|
24
|
-
CREATE TABLE IF NOT EXISTS worker (id INTEGER PRIMARY KEY CHECK(id=1), pid INTEGER NOT NULL);
|
|
25
|
-
CREATE TABLE IF NOT EXISTS inbox (source TEXT PRIMARY KEY, digest TEXT, data TEXT NOT NULL);`);
|
|
52
|
+
this.db = new DatabaseSync(join(this.directory, "queue.sqlite"));
|
|
53
|
+
chmodSync(join(this.directory, "queue.sqlite"), 384);
|
|
54
|
+
this.db.exec("PRAGMA busy_timeout=5000;");
|
|
26
55
|
const version = Number(this.db.prepare("PRAGMA user_version").get()?.user_version);
|
|
27
|
-
if (version >
|
|
56
|
+
if (version > 3) {
|
|
28
57
|
this.db.close();
|
|
29
58
|
throw new Error(`Queue schema ${version} is newer than this factory supports; use the version that created it. No task data was changed.`);
|
|
30
59
|
}
|
|
31
|
-
|
|
60
|
+
this.db.exec("PRAGMA journal_mode=WAL;");
|
|
61
|
+
if (version < 3) try {
|
|
32
62
|
this.transaction(() => {
|
|
63
|
+
const lockedVersion = Number(this.db.prepare("PRAGMA user_version").get()?.user_version);
|
|
64
|
+
if (lockedVersion > 3) throw new Error(`Queue schema ${lockedVersion} is newer than this factory supports; use the version that created it. No task data was changed.`);
|
|
65
|
+
if (lockedVersion === 3) return;
|
|
66
|
+
this.db.exec(`CREATE TABLE IF NOT EXISTS events (seq INTEGER PRIMARY KEY, job TEXT NOT NULL, at INTEGER NOT NULL, data TEXT NOT NULL);
|
|
67
|
+
CREATE TABLE IF NOT EXISTS worker (id INTEGER PRIMARY KEY CHECK(id=1), pid INTEGER NOT NULL);
|
|
68
|
+
CREATE TABLE IF NOT EXISTS inbox (source TEXT PRIMARY KEY, digest TEXT, data TEXT NOT NULL);`);
|
|
33
69
|
const owner = this.db.prepare("SELECT pid FROM worker WHERE id=1").get();
|
|
34
70
|
if (owner) {
|
|
35
71
|
if (typeof owner.pid !== "number" || !Number.isSafeInteger(owner.pid) || owner.pid <= 1) throw new Error("Legacy queue has invalid execution ownership; inspect it with the previous factory version");
|
|
@@ -42,32 +78,77 @@ var Store = class {
|
|
|
42
78
|
if (alive) throw new Error(`Stop the previous factory execution (${owner.pid}) before migrating its queue; no process was signaled`);
|
|
43
79
|
}
|
|
44
80
|
this.db.exec("CREATE TABLE IF NOT EXISTS snapshot_migrations (job TEXT NOT NULL, version INTEGER NOT NULL, data TEXT NOT NULL, PRIMARY KEY(job,version));");
|
|
45
|
-
|
|
81
|
+
const hasJobs = this.db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='jobs'").get();
|
|
82
|
+
const rows = hasJobs ? this.db.prepare("SELECT id,data FROM jobs ORDER BY rowid").all() : [];
|
|
83
|
+
this.db.exec("CREATE TABLE jobs_v3 (id TEXT PRIMARY KEY, product TEXT NOT NULL, platform TEXT NOT NULL, channel TEXT NOT NULL, version TEXT NOT NULL, status TEXT NOT NULL, next_at INTEGER NOT NULL, data TEXT NOT NULL, UNIQUE(product,platform,channel,version));");
|
|
84
|
+
for (const row of rows) {
|
|
46
85
|
if (typeof row.data !== "string") throw new Error("Stored task data must be JSON text");
|
|
47
86
|
const saved = JSON.parse(row.data);
|
|
48
|
-
|
|
87
|
+
if (saved.turn) throw new Error(`Abandon the active host turn for task ${row.id} with the previous factory version before migrating; no host turn was changed`);
|
|
88
|
+
this.db.prepare("INSERT OR IGNORE INTO snapshot_migrations VALUES(?,?,?)").run(row.id, lockedVersion, row.data);
|
|
49
89
|
if (saved.requestSpec === void 0) {
|
|
50
90
|
const changed = this.db.prepare("SELECT 1 FROM events WHERE job=? AND json_type(data,'$.spec') IS NOT NULL LIMIT 1").get(row.id);
|
|
51
91
|
saved.requestSpec = changed ? null : saved.spec;
|
|
52
92
|
saved.requestSpecError = changed ? "Original intake identity cannot be proven after legacy requirement edits; use reconcile-intake with the original requirements" : null;
|
|
53
93
|
}
|
|
94
|
+
saved.spec = migrateSpec(saved.spec);
|
|
95
|
+
if (saved.requestSpec !== null) saved.requestSpec = migrateSpec(saved.requestSpec);
|
|
54
96
|
const config = saved.config;
|
|
55
97
|
config.executionEnv ??= config.agentEnv ?? [];
|
|
56
98
|
config.maxHostTurns ??= config.maxAgentCalls ?? 16;
|
|
99
|
+
config.packageTarget ??= saved.spec?.channel === "google-play" ? "aab" : "simulator";
|
|
57
100
|
for (const key of [
|
|
58
101
|
"builder",
|
|
59
102
|
"reviewer",
|
|
60
103
|
"researcher",
|
|
61
104
|
"agentEnv",
|
|
62
105
|
"maxAgentCalls",
|
|
63
|
-
"maxConcurrentJobs"
|
|
106
|
+
"maxConcurrentJobs",
|
|
107
|
+
"allowSubmit",
|
|
108
|
+
"allowRelease"
|
|
64
109
|
]) delete config[key];
|
|
65
110
|
saved.hostTurns ??= saved.agentCalls ?? 0;
|
|
66
111
|
delete saved.agentCalls;
|
|
112
|
+
const advanced = [
|
|
113
|
+
"review",
|
|
114
|
+
"package",
|
|
115
|
+
"publish",
|
|
116
|
+
"monitor"
|
|
117
|
+
].includes(saved.stage) || [
|
|
118
|
+
"built",
|
|
119
|
+
"ready",
|
|
120
|
+
"approved",
|
|
121
|
+
"released"
|
|
122
|
+
].includes(saved.status);
|
|
123
|
+
const published = saved.receipt && Object.keys(saved.receipt).length > 0;
|
|
124
|
+
saved.verifiedDigest = null;
|
|
125
|
+
saved.verifiedDependencyDigest = null;
|
|
126
|
+
saved.screenshotDigest = null;
|
|
127
|
+
delete saved.verifiedAt;
|
|
128
|
+
saved.review = null;
|
|
129
|
+
saved.artifact = null;
|
|
130
|
+
if (!published) {
|
|
131
|
+
saved.ipaPath = null;
|
|
132
|
+
saved.archiveDigest = null;
|
|
133
|
+
}
|
|
134
|
+
if (published) {
|
|
135
|
+
saved.stage = ["publish", "monitor"].includes(saved.stage) ? "package" : saved.stage;
|
|
136
|
+
saved.status = "blocked";
|
|
137
|
+
saved.blockedReason = null;
|
|
138
|
+
saved.error = "Automatic store publication has been removed from this tool. Store submission and review are manual human work; legacy publication receipts are retained only as records and will not be replayed.";
|
|
139
|
+
} else if (advanced) {
|
|
140
|
+
saved.stage = "verify";
|
|
141
|
+
saved.status = "blocked";
|
|
142
|
+
saved.blockedReason = null;
|
|
143
|
+
saved.error = "Snapshot fingerprint contract changed; retry to run fresh verification and review before packaging";
|
|
144
|
+
}
|
|
67
145
|
const job = JobSchema.parse(saved);
|
|
68
|
-
|
|
146
|
+
validateJobConfig(job.spec, job.config);
|
|
147
|
+
if (job.id !== row.id) throw new Error("Stored task ID does not match its queue row");
|
|
148
|
+
this.db.prepare("INSERT INTO jobs_v3 VALUES(?,?,?,?,?,?,?,?)").run(job.id, job.spec.id, job.spec.platform, job.spec.channel, job.spec.version, job.status, job.nextAt, JSON.stringify(job));
|
|
69
149
|
}
|
|
70
|
-
this.db.exec("
|
|
150
|
+
if (hasJobs) this.db.exec("DROP TABLE jobs;");
|
|
151
|
+
this.db.exec("ALTER TABLE jobs_v3 RENAME TO jobs; PRAGMA user_version=3;");
|
|
71
152
|
});
|
|
72
153
|
} catch (cause) {
|
|
73
154
|
this.db.close();
|
|
@@ -98,47 +179,80 @@ var Store = class {
|
|
|
98
179
|
}
|
|
99
180
|
enqueue(specValue, configValue, baseJobId) {
|
|
100
181
|
const spec = SpecSchema.parse(specValue);
|
|
101
|
-
const config =
|
|
182
|
+
const config = this.snapshotConfig(configValue);
|
|
183
|
+
validateJobConfig(spec, config);
|
|
102
184
|
return this.transaction(() => this.insertJob(spec, config, baseJobId));
|
|
103
185
|
}
|
|
104
186
|
checkIngest(specValue, baseJobId, pending = []) {
|
|
105
187
|
const spec = SpecSchema.parse(specValue);
|
|
106
|
-
|
|
188
|
+
if (baseJobId && spec.project?.sourceDir) throw new Error("project.sourceDir and baseJobId are mutually exclusive");
|
|
189
|
+
const row = this.db.prepare("SELECT data FROM jobs WHERE product=? AND platform=? AND channel=? AND version=?").get(spec.id, spec.platform, spec.channel, spec.version);
|
|
107
190
|
const existing = row ? parseStoredJob(row.data) : void 0;
|
|
108
191
|
if (existing?.requestSpec === null) throw new Error(existing.requestSpecError ?? "Original intake identity is unknown; use reconcile-intake with the original requirements");
|
|
109
|
-
const prospective = pending.find((item) =>
|
|
192
|
+
const prospective = pending.find((item) => sameIdentity(item.spec, spec));
|
|
110
193
|
const original = existing?.requestSpec ? {
|
|
111
194
|
spec: existing.requestSpec,
|
|
112
|
-
baseJobId: existing.baseJobId
|
|
195
|
+
baseJobId: existing.automaticBase ? void 0 : existing.baseJobId
|
|
113
196
|
} : void 0;
|
|
114
|
-
for (const candidate of [original, prospective]) if (candidate && (JSON.stringify(candidate.spec) !== JSON.stringify(spec) || candidate.baseJobId !== baseJobId)) throw new Error(`${spec.id} already has immutable requirements for this version; submit a new
|
|
115
|
-
if (existing) return existing;
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if (
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
197
|
+
for (const candidate of [original, prospective]) if (candidate && (JSON.stringify(candidate.spec) !== JSON.stringify(spec) || candidate.baseJobId !== baseJobId)) throw new Error(`${spec.id} already has immutable requirements for this platform, channel and version; submit a new version instead of editing its task`);
|
|
198
|
+
if (existing || prospective) return existing;
|
|
199
|
+
const base = this.selectBase(spec, baseJobId, pending);
|
|
200
|
+
if (base && (base.spec.id !== spec.id || base.spec.platform !== spec.platform || base.spec.channel !== spec.channel || base.spec.framework !== spec.framework || !["built", "ready"].includes(base.status) || !base.verifiedDigest || !base.verifiedDependencyDigest || base.turn || base.groups.length || base.manualRecovery)) throw new Error("baseJobId must identify a finished, verified task of the same product, platform, channel and framework with no active work");
|
|
201
|
+
if (base) this.predecessorSpec(spec, base);
|
|
202
|
+
if (base && sourceDigest(base.workspace, true, base.spec.framework, base.spec.project?.directory) !== base.verifiedDigest) throw new Error("baseJobId source changed after verification; verify the predecessor again before creating a successor");
|
|
203
|
+
if (base && dependencyDigest(base.workspace, base.spec.framework, base.spec.project?.directory) !== base.verifiedDependencyDigest) throw new Error("baseJobId dependency resolution changed after verification; verify the predecessor again before creating a successor");
|
|
204
|
+
}
|
|
205
|
+
selectBase(spec, baseJobId, pending = []) {
|
|
206
|
+
if (baseJobId !== void 0) return this.get(baseJobId);
|
|
207
|
+
if (spec.platform !== "ios" || spec.channel !== "app-store" || spec.project?.sourceDir) return void 0;
|
|
208
|
+
const row = this.db.prepare("SELECT data FROM jobs WHERE product=? AND platform=? AND channel=? AND status IN ('built','ready') ORDER BY rowid DESC LIMIT 1").get(spec.id, spec.platform, spec.channel);
|
|
209
|
+
if (row) return parseStoredJob(row.data);
|
|
210
|
+
if (this.db.prepare("SELECT 1 FROM jobs WHERE product=? AND platform=? AND channel=? LIMIT 1").get(spec.id, spec.platform, spec.channel) || pending.some((item) => item.spec.id === spec.id && item.spec.platform === spec.platform && item.spec.channel === spec.channel && !sameIdentity(item.spec, spec))) throw new Error("Previous App Store versions exist but none is finished and verified; finish or explicitly import the existing application before creating a successor");
|
|
211
|
+
}
|
|
212
|
+
predecessorSpec(spec, base) {
|
|
213
|
+
if (spec.platform !== "ios" || spec.channel !== "app-store") return spec;
|
|
214
|
+
const directory = base.spec.project?.directory ?? ".";
|
|
215
|
+
if (spec.project && spec.project.directory !== directory) throw new Error("project.directory must preserve the predecessor project directory");
|
|
216
|
+
return SpecSchema.parse({
|
|
217
|
+
...spec,
|
|
218
|
+
...base.spec.project || spec.project ? { project: { directory } } : {}
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
snapshotConfig(value) {
|
|
222
|
+
const config = ConfigSchema.parse(value);
|
|
223
|
+
const root = config.configPath ? dirname(resolve(config.configPath)) : process.cwd();
|
|
224
|
+
config.stateDir = canonicalPath(resolve(root, config.stateDir));
|
|
225
|
+
config.workspaceRoot = canonicalPath(resolve(root, config.workspaceRoot));
|
|
226
|
+
if (overlaps(config.stateDir, config.workspaceRoot) || overlaps(this.directory, config.workspaceRoot)) throw new Error("stateDir and workspaceRoot must not overlap in either direction");
|
|
227
|
+
normalizeIsolationPaths(config);
|
|
228
|
+
return config;
|
|
127
229
|
}
|
|
128
230
|
insertJob(spec, config, baseJobId) {
|
|
129
|
-
if (this.checkIngest(spec, baseJobId)) throw new Error(`${spec.id} ${spec.
|
|
130
|
-
const
|
|
131
|
-
const
|
|
231
|
+
if (this.checkIngest(spec, baseJobId)) throw new Error(`${spec.id} ${spec.platform} ${spec.channel} ${spec.version} is already queued; retry its task or use a new product version`);
|
|
232
|
+
const base = this.selectBase(spec, baseJobId);
|
|
233
|
+
const effectiveSpec = base ? this.predecessorSpec(spec, base) : spec;
|
|
234
|
+
const sourceDirectory = validateProjectSource(spec, config);
|
|
235
|
+
let importDigest;
|
|
236
|
+
if (sourceDirectory) {
|
|
237
|
+
if (overlaps(this.directory, sourceDirectory)) throw new Error("project.sourceDir must not overlap the queue directory in either direction");
|
|
238
|
+
importDigest = sourceDigest(sourceDirectory, true, spec.framework, spec.project?.directory);
|
|
239
|
+
}
|
|
132
240
|
const now = Date.now();
|
|
133
241
|
const id = randomUUID();
|
|
134
242
|
const job = JobSchema.parse({
|
|
135
243
|
id,
|
|
136
|
-
spec,
|
|
244
|
+
spec: effectiveSpec,
|
|
137
245
|
requestSpec: spec,
|
|
138
246
|
config,
|
|
139
247
|
...base ? {
|
|
140
248
|
baseJobId: base.id,
|
|
141
|
-
baseDigest: base.verifiedDigest
|
|
249
|
+
baseDigest: base.verifiedDigest,
|
|
250
|
+
...baseJobId === void 0 ? { automaticBase: true } : {}
|
|
251
|
+
} : {},
|
|
252
|
+
...sourceDirectory ? {
|
|
253
|
+
sourceDirectory,
|
|
254
|
+
importDigest,
|
|
255
|
+
importPrepared: false
|
|
142
256
|
} : {},
|
|
143
257
|
stage: "research",
|
|
144
258
|
status: "queued",
|
|
@@ -156,11 +270,12 @@ var Store = class {
|
|
|
156
270
|
logs: [],
|
|
157
271
|
workspace: join(config.workspaceRoot, id)
|
|
158
272
|
});
|
|
159
|
-
|
|
273
|
+
projectDirectory(job);
|
|
274
|
+
this.db.prepare("INSERT INTO jobs VALUES (?,?,?,?,?,?,?,?)").run(id, spec.id, spec.platform, spec.channel, spec.version, job.status, now, JSON.stringify(job));
|
|
160
275
|
this.event(id, {
|
|
161
276
|
stage: job.stage,
|
|
162
277
|
status: job.status,
|
|
163
|
-
baseJobId
|
|
278
|
+
baseJobId: job.baseJobId
|
|
164
279
|
});
|
|
165
280
|
return job;
|
|
166
281
|
}
|
|
@@ -188,7 +303,8 @@ var Store = class {
|
|
|
188
303
|
}
|
|
189
304
|
ingest(source, digest, specValue, configValue, baseJobId) {
|
|
190
305
|
const spec = SpecSchema.parse(specValue);
|
|
191
|
-
const config =
|
|
306
|
+
const config = this.snapshotConfig(configValue);
|
|
307
|
+
validateJobConfig(spec, config);
|
|
192
308
|
return this.transaction(() => {
|
|
193
309
|
const job = this.checkIngest(spec, baseJobId) ?? this.insertJob(spec, config, baseJobId);
|
|
194
310
|
return this.saveInbox(InboxEntrySchema.parse({
|
|
@@ -214,11 +330,17 @@ var Store = class {
|
|
|
214
330
|
});
|
|
215
331
|
}
|
|
216
332
|
saveJob(current, patch, reconcileIntake = false) {
|
|
333
|
+
const config = patch.config ? this.snapshotConfig(patch.config) : current.config;
|
|
334
|
+
if (current.sourceDirectory && [config.stateDir, config.workspaceRoot].some((path) => overlaps(path, current.sourceDirectory))) throw new Error("Pinned project source must not overlap stateDir or workspaceRoot after reconfiguration");
|
|
217
335
|
const job = JobSchema.parse({
|
|
218
336
|
...current,
|
|
219
337
|
...patch,
|
|
338
|
+
config,
|
|
220
339
|
updatedAt: Date.now()
|
|
221
340
|
});
|
|
341
|
+
validateJobConfig(job.spec, job.config);
|
|
342
|
+
if (job.id !== current.id || !sameIdentity(job.spec, current.spec) || job.spec.framework !== current.spec.framework) throw new Error("Task product, platform, channel, version and framework are immutable; enqueue a new task");
|
|
343
|
+
if (job.workspace !== current.workspace || job.sourceDirectory !== current.sourceDirectory || job.importDigest !== current.importDigest || job.baseJobId !== current.baseJobId || job.baseDigest !== current.baseDigest || job.automaticBase !== current.automaticBase || JSON.stringify(job.spec.project) !== JSON.stringify(current.spec.project)) throw new Error("Pinned project source and workspace identity cannot be changed by task updates");
|
|
222
344
|
if (!reconcileIntake && patch.requestSpec !== void 0 && JSON.stringify(job.requestSpec) !== JSON.stringify(current.requestSpec)) throw new Error("Original intake requirements cannot be changed by task updates");
|
|
223
345
|
this.db.prepare("UPDATE jobs SET status=?,next_at=?,data=? WHERE id=?").run(job.status, job.nextAt, JSON.stringify(job), job.id);
|
|
224
346
|
this.event(job.id, patch);
|
|
@@ -229,7 +351,7 @@ var Store = class {
|
|
|
229
351
|
return this.transaction(() => {
|
|
230
352
|
const current = this.get(id);
|
|
231
353
|
if (current.requestSpec !== null) throw new Error("This task already has a known intake identity; it cannot be replaced");
|
|
232
|
-
if (spec
|
|
354
|
+
if (!sameIdentity(spec, current.spec) || spec.framework !== current.spec.framework || baseJobId !== (current.automaticBase ? void 0 : current.baseJobId)) throw new Error("Original requirements must match this task product, platform, channel, framework, version and predecessor");
|
|
233
355
|
return this.saveJob(current, {
|
|
234
356
|
requestSpec: spec,
|
|
235
357
|
requestSpecError: null
|
package/dist/store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","names":[],"sources":["../src/store.ts"],"sourcesContent":["import { DatabaseSync } from 'node:sqlite';\nimport { mkdirSync, chmodSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { randomUUID } from 'node:crypto';\nimport { inspectProcessGroup, signalOwnedProcessGroup, TERMINATION_GRACE_MS } from './process.js';\nimport { ConfigSchema, JobSchema, SpecSchema, InboxEntrySchema, toError, type CommandMetadata, type Job, type Spec, type Config, type InboxEntry } from './schemas.js';\n\nfunction parseStoredJob(data: unknown): Job {\n if (typeof data !== 'string') throw new Error('Stored task data must be JSON text');\n return JobSchema.parse(JSON.parse(data));\n}\n\nexport class Store {\n readonly db: DatabaseSync;\n\n constructor(directory: string) {\n mkdirSync(directory, { recursive: true, mode: 0o700 });\n this.db = new DatabaseSync(join(directory, 'queue.sqlite'));\n chmodSync(join(directory, 'queue.sqlite'), 0o600);\n this.db.exec(`PRAGMA busy_timeout=5000; PRAGMA journal_mode=WAL;\n CREATE TABLE IF NOT EXISTS jobs (id TEXT PRIMARY KEY, product TEXT NOT NULL, version TEXT NOT NULL, status TEXT NOT NULL, next_at INTEGER NOT NULL, data TEXT NOT NULL, UNIQUE(product, version));\n CREATE TABLE IF NOT EXISTS events (seq INTEGER PRIMARY KEY, job TEXT NOT NULL, at INTEGER NOT NULL, data TEXT NOT NULL);\n CREATE TABLE IF NOT EXISTS worker (id INTEGER PRIMARY KEY CHECK(id=1), pid INTEGER NOT NULL);\n CREATE TABLE IF NOT EXISTS inbox (source TEXT PRIMARY KEY, digest TEXT, data TEXT NOT NULL);`);\n const version = Number(this.db.prepare('PRAGMA user_version').get()?.user_version);\n if (version > 2) { this.db.close(); throw new Error(`Queue schema ${version} is newer than this factory supports; use the version that created it. No task data was changed.`); }\n if (version < 2) {\n try {\n this.transaction(() => {\n const owner = this.db.prepare('SELECT pid FROM worker WHERE id=1').get();\n if (owner) {\n if (typeof owner.pid !== 'number' || !Number.isSafeInteger(owner.pid) || owner.pid <= 1) throw new Error('Legacy queue has invalid execution ownership; inspect it with the previous factory version');\n let alive = true;\n try { process.kill(owner.pid, 0); } catch (cause) { alive = toError(cause).code !== 'ESRCH'; }\n if (alive) throw new Error(`Stop the previous factory execution (${owner.pid}) before migrating its queue; no process was signaled`);\n }\n this.db.exec('CREATE TABLE IF NOT EXISTS snapshot_migrations (job TEXT NOT NULL, version INTEGER NOT NULL, data TEXT NOT NULL, PRIMARY KEY(job,version));');\n for (const row of this.db.prepare('SELECT id,data FROM jobs').all()) {\n if (typeof row.data !== 'string') throw new Error('Stored task data must be JSON text');\n const saved = JSON.parse(row.data);\n this.db.prepare('INSERT OR IGNORE INTO snapshot_migrations VALUES(?,?,?)').run(row.id, version, row.data);\n if (saved.requestSpec === undefined) {\n const changed = this.db.prepare(\"SELECT 1 FROM events WHERE job=? AND json_type(data,'$.spec') IS NOT NULL LIMIT 1\").get(row.id);\n saved.requestSpec = changed ? null : saved.spec;\n saved.requestSpecError = changed ? 'Original intake identity cannot be proven after legacy requirement edits; use reconcile-intake with the original requirements' : null;\n }\n const config = saved.config;\n config.executionEnv ??= config.agentEnv ?? [];\n config.maxHostTurns ??= config.maxAgentCalls ?? 16;\n for (const key of ['builder', 'reviewer', 'researcher', 'agentEnv', 'maxAgentCalls', 'maxConcurrentJobs']) delete config[key];\n saved.hostTurns ??= saved.agentCalls ?? 0;\n delete saved.agentCalls;\n const job = JobSchema.parse(saved);\n this.db.prepare('UPDATE jobs SET data=? WHERE id=?').run(JSON.stringify(job), job.id);\n }\n this.db.exec('PRAGMA user_version=2;');\n });\n } catch (cause) {\n this.db.close();\n throw new Error(`Cannot migrate saved factory snapshots: ${toError(cause).message}. No migration was committed. Preserve queue.sqlite and use the previous factory version to inspect or repair unsupported data.`);\n }\n }\n }\n close(): void { this.db.close(); }\n transaction<T>(action: () => T): T {\n this.db.exec('BEGIN IMMEDIATE');\n try { const result = action(); this.db.exec('COMMIT'); return result; }\n catch (error) { this.db.exec('ROLLBACK'); throw error; }\n }\n list(): Job[] { return this.db.prepare('SELECT data FROM jobs ORDER BY rowid').all().map(row => parseStoredJob(row.data)); }\n get(id: string): Job {\n const row = this.db.prepare('SELECT data FROM jobs WHERE id=?').get(id);\n if (!row) throw new Error(`Unknown task ${id}; use status to list task IDs`);\n return parseStoredJob(row.data);\n }\n enqueue(specValue: unknown, configValue: unknown, baseJobId?: string): Job {\n const spec = SpecSchema.parse(specValue);\n const config = ConfigSchema.parse(configValue);\n return this.transaction(() => this.insertJob(spec, config, baseJobId));\n }\n checkIngest(specValue: unknown, baseJobId?: string, pending: ReadonlyArray<{ spec: Spec; baseJobId?: string }> = []): Job | undefined {\n const spec = SpecSchema.parse(specValue);\n const row = this.db.prepare('SELECT data FROM jobs WHERE product=? AND version=?').get(spec.id, spec.apple?.version ?? '1.0.0');\n const existing = row ? parseStoredJob(row.data) : undefined;\n if (existing?.requestSpec === null) throw new Error(existing.requestSpecError ?? 'Original intake identity is unknown; use reconcile-intake with the original requirements');\n const prospective = pending.find(item => item.spec.id === spec.id && (item.spec.apple?.version ?? '1.0.0') === (spec.apple?.version ?? '1.0.0'));\n const original = existing?.requestSpec ? { spec: existing.requestSpec, baseJobId: existing.baseJobId } : undefined;\n for (const candidate of [original, prospective]) {\n if (candidate && (JSON.stringify(candidate.spec) !== JSON.stringify(spec) || candidate.baseJobId !== baseJobId)) throw new Error(`${spec.id} already has immutable requirements for this version; submit a new apple.version instead of editing its task`);\n }\n if (existing) return existing;\n const signature = (value: { purpose: string; audience: string }): string => `${value.purpose.trim().toLowerCase()}\\n${value.audience.trim().toLowerCase()}`;\n const duplicates = (job: { spec: Spec }): boolean => job.spec.id !== spec.id && signature(job.spec) === signature(spec);\n const duplicate = this.list().find(duplicates) ?? pending.find(duplicates);\n if (duplicate) throw new Error(`Product purpose and audience duplicate ${duplicate.spec.id}; differentiate actual utility, not names or code`);\n const base = baseJobId === undefined ? undefined : this.get(baseJobId);\n if (base && (base.spec.id !== spec.id || !['built', 'ready', 'approved', 'released'].includes(base.status) || !base.verifiedDigest || base.groups.length)) {\n throw new Error('baseJobId must identify a finished, verified task of the same product with no live command groups');\n }\n return undefined;\n }\n private insertJob(spec: Spec, config: Config, baseJobId?: string): Job {\n if (this.checkIngest(spec, baseJobId)) throw new Error(`${spec.id} ${spec.apple?.version ?? '1.0.0'} is already queued; retry its task or use a new product version`);\n const version = spec.apple?.version ?? '1.0.0';\n const base = baseJobId === undefined ? undefined : this.get(baseJobId);\n const now = Date.now();\n const id = randomUUID();\n const job = JobSchema.parse({ id, spec, requestSpec: spec, config, ...(base ? { baseJobId: base.id, baseDigest: base.verifiedDigest } : {}), stage: 'research', status: 'queued', blockedReason: null, manualRecovery: null, createdAt: now, updatedAt: now, nextAt: now, attempts: {}, hostTurns: 0, turn: null, groups: [], commands: {}, receipt: {}, logs: [], workspace: join(config.workspaceRoot, id) });\n this.db.prepare('INSERT INTO jobs VALUES (?,?,?,?,?,?)').run(id, spec.id, version, job.status, now, JSON.stringify(job));\n this.event(id, { stage: job.stage, status: job.status, baseJobId });\n return job;\n }\n inboxEntries(): InboxEntry[] {\n return this.db.prepare('SELECT data FROM inbox ORDER BY source').all().map(row => {\n if (typeof row.data !== 'string') throw new Error('Stored inbox data must be JSON text');\n return InboxEntrySchema.parse(JSON.parse(row.data));\n });\n }\n private saveInbox(entry: InboxEntry): InboxEntry {\n this.db.prepare('INSERT INTO inbox VALUES(?,?,?) ON CONFLICT(source) DO UPDATE SET digest=excluded.digest,data=excluded.data').run(entry.source, entry.digest, JSON.stringify(entry));\n return entry;\n }\n inboxError(source: string, digest: string | null, error: string): InboxEntry {\n const previous = this.inboxEntries().find(entry => entry.source === source);\n if (previous?.status === 'error' && previous.digest === digest && previous.error === error) return previous;\n return this.saveInbox(InboxEntrySchema.parse({ source, digest, status: 'error', jobId: previous?.jobId ?? null, error, observedAt: Date.now() }));\n }\n ingest(source: string, digest: string, specValue: unknown, configValue: unknown, baseJobId?: string): InboxEntry {\n const spec = SpecSchema.parse(specValue);\n const config = ConfigSchema.parse(configValue);\n return this.transaction(() => {\n const job = this.checkIngest(spec, baseJobId) ?? this.insertJob(spec, config, baseJobId);\n return this.saveInbox(InboxEntrySchema.parse({ source, digest, status: 'accepted', jobId: job.id, error: null, observedAt: Date.now() }));\n });\n }\n event(id: string, data: Record<string, unknown>): void { this.db.prepare('INSERT INTO events(job,at,data) VALUES (?,?,?)').run(id, Date.now(), JSON.stringify(data)); }\n update(id: string, patch: Partial<Job>): Job {\n return this.transition(id, () => patch);\n }\n transition(id: string, change: (current: Job) => Partial<Job>): Job {\n return this.transaction(() => {\n const current = this.get(id);\n return this.saveJob(current, change(current));\n });\n }\n private saveJob(current: Job, patch: Partial<Job>, reconcileIntake = false): Job {\n const job = JobSchema.parse({ ...current, ...patch, updatedAt: Date.now() });\n if (!reconcileIntake && patch.requestSpec !== undefined && JSON.stringify(job.requestSpec) !== JSON.stringify(current.requestSpec)) throw new Error('Original intake requirements cannot be changed by task updates');\n this.db.prepare('UPDATE jobs SET status=?,next_at=?,data=? WHERE id=?').run(job.status, job.nextAt, JSON.stringify(job), job.id);\n this.event(job.id, patch);\n return job;\n }\n reconcileIntake(id: string, specValue: unknown, baseJobId?: string): Job {\n const spec = SpecSchema.parse(specValue);\n return this.transaction(() => {\n const current = this.get(id);\n if (current.requestSpec !== null) throw new Error('This task already has a known intake identity; it cannot be replaced');\n if (spec.id !== current.spec.id || (spec.apple?.version ?? '1.0.0') !== (current.spec.apple?.version ?? '1.0.0') || baseJobId !== current.baseJobId) throw new Error('Original requirements must match this task product, version and predecessor');\n return this.saveJob(current, { requestSpec: spec, requestSpecError: null }, true);\n });\n }\n acquire(): void {\n const jobs = this.transaction(() => {\n const jobs = this.list();\n const owner = this.db.prepare('SELECT pid FROM worker WHERE id=1').get();\n if (owner) {\n if (typeof owner.pid !== 'number' || !Number.isSafeInteger(owner.pid) || owner.pid <= 1) throw new Error('Stored worker PID must be a valid process ID');\n let alive = true;\n try { process.kill(owner.pid, 0); } catch (error) { alive = toError(error).code !== 'ESRCH'; }\n if (alive) throw new Error(`Execution ${owner.pid} already owns this queue; wait for its command to finish`);\n }\n this.db.prepare('INSERT OR REPLACE INTO worker VALUES(1,?)').run(process.pid);\n return jobs;\n });\n for (const job of jobs) {\n if (job.status === 'running' && !job.turn) this.update(job.id, { status: 'waiting', blockedReason: null, nextAt: Date.now(), error: 'Execution stopped during a deterministic stage; recover its command groups before resuming' });\n }\n }\n release(): void {\n this.transaction(() => {\n this.db.prepare('DELETE FROM worker WHERE id=1 AND pid=?').run(process.pid);\n });\n }\n next(canClaim: (job: Job) => boolean = () => true, excludeIds: ReadonlySet<string> = new Set()): Job | undefined {\n const now = Date.now();\n const rows = this.db.prepare(\"SELECT data FROM jobs WHERE (status IN ('queued','waiting') OR (status='blocked' AND json_extract(data,'$.blockedReason.kind')='prerequisite')) AND next_at<=? ORDER BY next_at,rowid\").all(now);\n const jobs = rows.map(row => parseStoredJob(row.data));\n for (const job of jobs) {\n if (excludeIds.has(job.id)) continue;\n const groups: number[] = [], commands: Record<string, CommandMetadata> = {};\n let manualRecovery = job.manualRecovery ?? null, pending = false, nextAt = Infinity;\n for (const pid of job.groups) {\n const command = job.commands[pid];\n const ownership = inspectProcessGroup(pid, command?.identity);\n if (ownership === 'gone') continue;\n groups.push(pid);\n const saved = command ? { ...command } : undefined;\n if (saved) commands[pid] = saved;\n if (ownership !== 'owned' || !saved || !Number.isFinite(saved.deadline)) {\n manualRecovery ??= `Command group ${pid} has ${ownership === 'mismatch' ? 'a different process identity' : 'no verifiable ownership and deadline'}. It was not signaled. Inspect this task's recorded command ownership before retrying.`;\n continue;\n }\n try {\n if (!saved.termAt && now < saved.deadline) {\n nextAt = Math.min(nextAt, saved.deadline, now + job.config.pollMs);\n } else if (!saved.termAt) {\n signalOwnedProcessGroup(pid, saved.identity, 'SIGTERM');\n saved.termAt = Date.now();\n nextAt = Math.min(nextAt, saved.termAt + TERMINATION_GRACE_MS);\n } else if (now < saved.termAt + TERMINATION_GRACE_MS) {\n nextAt = Math.min(nextAt, saved.termAt + TERMINATION_GRACE_MS);\n } else if (!saved.killAt) {\n signalOwnedProcessGroup(pid, saved.identity, 'SIGKILL');\n saved.killAt = Date.now();\n nextAt = Math.min(nextAt, saved.killAt + TERMINATION_GRACE_MS);\n } else if (now < saved.killAt + TERMINATION_GRACE_MS) {\n nextAt = Math.min(nextAt, saved.killAt + TERMINATION_GRACE_MS);\n } else {\n manualRecovery ??= `Command group ${pid} is still active after SIGKILL. No replay is allowed. Inspect and stop the recorded group, then retry this task.`;\n continue;\n }\n pending = true;\n } catch (error) { manualRecovery ??= toError(error).message; }\n }\n if (!groups.length && manualRecovery === null) {\n if (job.groups.length) this.update(job.id, { groups: [], commands: {}, recoveryStage: undefined });\n const claimed = this.transaction(() => {\n const current = this.get(job.id);\n const eligible = current.status === 'queued' || current.status === 'waiting' || (current.status === 'blocked' && current.blockedReason?.kind === 'prerequisite');\n if (!eligible || current.turn || current.nextAt > Date.now() || current.groups.length || current.manualRecovery != null || !canClaim(current)) return undefined;\n return this.saveJob(current, { status: 'running', blockedReason: null, manualRecovery: null, groups: [], commands: {}, recoveryStage: undefined });\n });\n if (claimed) return claimed;\n continue;\n }\n if (pending) {\n this.update(job.id, { status: 'waiting', blockedReason: null, manualRecovery, groups, commands, nextAt, error: manualRecovery ?? 'Recovering an owned command group; waiting for its deadline and TERM-to-KILL cleanup before replay' });\n } else {\n this.update(job.id, { status: 'blocked', blockedReason: null, manualRecovery, groups, commands, error: manualRecovery });\n }\n }\n return undefined;\n }\n events(id: string) {\n this.get(id);\n return this.db.prepare('SELECT seq,at,data FROM events WHERE job=? ORDER BY seq').all(id).map(row => {\n if (typeof row.data !== 'string') throw new Error('Stored event data must be JSON text');\n const data: unknown = JSON.parse(row.data);\n return { ...row, data };\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"store.js","names":[],"sources":["../src/store.ts"],"sourcesContent":["import { DatabaseSync } from 'node:sqlite';\nimport { mkdirSync, chmodSync } from 'node:fs';\nimport { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';\nimport { randomUUID } from 'node:crypto';\nimport { inspectProcessGroup, signalOwnedProcessGroup, TERMINATION_GRACE_MS } from './process.js';\nimport { canonicalPath, normalizeIsolationPaths, validateProjectSource } from './config.js';\nimport { projectDirectory, sourceDigest } from './workspace.js';\nimport { dependencyDigest } from './dependencies.js';\nimport { ConfigSchema, JobSchema, SpecSchema, InboxEntrySchema, validateJobConfig, toError, type CommandMetadata, type Job, type Spec, type Config, type InboxEntry } from './schemas.js';\n\nfunction parseStoredJob(data: unknown): Job {\n if (typeof data !== 'string') throw new Error('Stored task data must be JSON text');\n return JobSchema.parse(JSON.parse(data));\n}\n\nfunction sameIdentity(left: Spec, right: Spec): boolean {\n return left.id === right.id && left.platform === right.platform && left.channel === right.channel && left.version === right.version;\n}\n\nfunction overlaps(left: string, right: string): boolean {\n const contains = (root: string, path: string): boolean => {\n const child = relative(root, path);\n return !child || (child !== '..' && !child.startsWith(`..${sep}`) && !isAbsolute(child));\n };\n return contains(left, right) || contains(right, left);\n}\n\nfunction migrateSpec(value: unknown): Spec {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return SpecSchema.parse(value);\n const saved = { ...value } as Record<string, unknown>;\n const apple = saved.apple && typeof saved.apple === 'object' && !Array.isArray(saved.apple) ? { ...saved.apple } as Record<string, unknown> : undefined;\n if (saved.platform === undefined) {\n saved.framework = 'flutter';\n saved.platform = 'ios';\n saved.channel = 'app-store';\n }\n if (apple) {\n saved.version ??= apple.version;\n saved.screenshotsDir ??= apple.screenshotsDir;\n delete apple.version;\n delete apple.screenshotsDir;\n saved.apple = apple;\n }\n return SpecSchema.parse(saved);\n}\n\nexport class Store {\n readonly db: DatabaseSync;\n readonly directory: string;\n\n constructor(directory: string) {\n this.directory = canonicalPath(directory);\n mkdirSync(this.directory, { recursive: true, mode: 0o700 });\n this.db = new DatabaseSync(join(this.directory, 'queue.sqlite'));\n chmodSync(join(this.directory, 'queue.sqlite'), 0o600);\n this.db.exec('PRAGMA busy_timeout=5000;');\n const version = Number(this.db.prepare('PRAGMA user_version').get()?.user_version);\n if (version > 3) { this.db.close(); throw new Error(`Queue schema ${version} is newer than this factory supports; use the version that created it. No task data was changed.`); }\n this.db.exec('PRAGMA journal_mode=WAL;');\n if (version < 3) {\n try {\n this.transaction(() => {\n const lockedVersion = Number(this.db.prepare('PRAGMA user_version').get()?.user_version);\n if (lockedVersion > 3) throw new Error(`Queue schema ${lockedVersion} is newer than this factory supports; use the version that created it. No task data was changed.`);\n if (lockedVersion === 3) return;\n this.db.exec(`CREATE TABLE IF NOT EXISTS events (seq INTEGER PRIMARY KEY, job TEXT NOT NULL, at INTEGER NOT NULL, data TEXT NOT NULL);\n CREATE TABLE IF NOT EXISTS worker (id INTEGER PRIMARY KEY CHECK(id=1), pid INTEGER NOT NULL);\n CREATE TABLE IF NOT EXISTS inbox (source TEXT PRIMARY KEY, digest TEXT, data TEXT NOT NULL);`);\n const owner = this.db.prepare('SELECT pid FROM worker WHERE id=1').get();\n if (owner) {\n if (typeof owner.pid !== 'number' || !Number.isSafeInteger(owner.pid) || owner.pid <= 1) throw new Error('Legacy queue has invalid execution ownership; inspect it with the previous factory version');\n let alive = true;\n try { process.kill(owner.pid, 0); } catch (cause) { alive = toError(cause).code !== 'ESRCH'; }\n if (alive) throw new Error(`Stop the previous factory execution (${owner.pid}) before migrating its queue; no process was signaled`);\n }\n this.db.exec('CREATE TABLE IF NOT EXISTS snapshot_migrations (job TEXT NOT NULL, version INTEGER NOT NULL, data TEXT NOT NULL, PRIMARY KEY(job,version));');\n const hasJobs = this.db.prepare(\"SELECT 1 FROM sqlite_master WHERE type='table' AND name='jobs'\").get();\n const rows = hasJobs ? this.db.prepare('SELECT id,data FROM jobs ORDER BY rowid').all() : [];\n this.db.exec('CREATE TABLE jobs_v3 (id TEXT PRIMARY KEY, product TEXT NOT NULL, platform TEXT NOT NULL, channel TEXT NOT NULL, version TEXT NOT NULL, status TEXT NOT NULL, next_at INTEGER NOT NULL, data TEXT NOT NULL, UNIQUE(product,platform,channel,version));');\n for (const row of rows) {\n if (typeof row.data !== 'string') throw new Error('Stored task data must be JSON text');\n const saved = JSON.parse(row.data);\n if (saved.turn) throw new Error(`Abandon the active host turn for task ${row.id} with the previous factory version before migrating; no host turn was changed`);\n this.db.prepare('INSERT OR IGNORE INTO snapshot_migrations VALUES(?,?,?)').run(row.id, lockedVersion, row.data);\n if (saved.requestSpec === undefined) {\n const changed = this.db.prepare(\"SELECT 1 FROM events WHERE job=? AND json_type(data,'$.spec') IS NOT NULL LIMIT 1\").get(row.id);\n saved.requestSpec = changed ? null : saved.spec;\n saved.requestSpecError = changed ? 'Original intake identity cannot be proven after legacy requirement edits; use reconcile-intake with the original requirements' : null;\n }\n saved.spec = migrateSpec(saved.spec);\n if (saved.requestSpec !== null) saved.requestSpec = migrateSpec(saved.requestSpec);\n const config = saved.config;\n config.executionEnv ??= config.agentEnv ?? [];\n config.maxHostTurns ??= config.maxAgentCalls ?? 16;\n config.packageTarget ??= saved.spec?.channel === 'google-play' ? 'aab' : 'simulator';\n for (const key of ['builder', 'reviewer', 'researcher', 'agentEnv', 'maxAgentCalls', 'maxConcurrentJobs', 'allowSubmit', 'allowRelease']) delete config[key];\n saved.hostTurns ??= saved.agentCalls ?? 0;\n delete saved.agentCalls;\n const advanced = ['review', 'package', 'publish', 'monitor'].includes(saved.stage) || ['built', 'ready', 'approved', 'released'].includes(saved.status);\n const published = saved.receipt && Object.keys(saved.receipt).length > 0;\n saved.verifiedDigest = null;\n saved.verifiedDependencyDigest = null;\n saved.screenshotDigest = null;\n delete saved.verifiedAt;\n saved.review = null;\n saved.artifact = null;\n if (!published) { saved.ipaPath = null; saved.archiveDigest = null; }\n if (published) {\n saved.stage = ['publish', 'monitor'].includes(saved.stage) ? 'package' : saved.stage;\n saved.status = 'blocked';\n saved.blockedReason = null;\n saved.error = 'Automatic store publication has been removed from this tool. Store submission and review are manual human work; legacy publication receipts are retained only as records and will not be replayed.';\n } else if (advanced) {\n saved.stage = 'verify';\n saved.status = 'blocked';\n saved.blockedReason = null;\n saved.error = 'Snapshot fingerprint contract changed; retry to run fresh verification and review before packaging';\n }\n const job = JobSchema.parse(saved);\n validateJobConfig(job.spec, job.config);\n if (job.id !== row.id) throw new Error('Stored task ID does not match its queue row');\n this.db.prepare('INSERT INTO jobs_v3 VALUES(?,?,?,?,?,?,?,?)').run(job.id, job.spec.id, job.spec.platform, job.spec.channel, job.spec.version, job.status, job.nextAt, JSON.stringify(job));\n }\n if (hasJobs) this.db.exec('DROP TABLE jobs;');\n this.db.exec('ALTER TABLE jobs_v3 RENAME TO jobs; PRAGMA user_version=3;');\n });\n } catch (cause) {\n this.db.close();\n throw new Error(`Cannot migrate saved factory snapshots: ${toError(cause).message}. No migration was committed. Preserve queue.sqlite and use the previous factory version to inspect or repair unsupported data.`);\n }\n }\n }\n close(): void { this.db.close(); }\n transaction<T>(action: () => T): T {\n this.db.exec('BEGIN IMMEDIATE');\n try { const result = action(); this.db.exec('COMMIT'); return result; }\n catch (error) { this.db.exec('ROLLBACK'); throw error; }\n }\n list(): Job[] { return this.db.prepare('SELECT data FROM jobs ORDER BY rowid').all().map(row => parseStoredJob(row.data)); }\n get(id: string): Job {\n const row = this.db.prepare('SELECT data FROM jobs WHERE id=?').get(id);\n if (!row) throw new Error(`Unknown task ${id}; use status to list task IDs`);\n return parseStoredJob(row.data);\n }\n enqueue(specValue: unknown, configValue: unknown, baseJobId?: string): Job {\n const spec = SpecSchema.parse(specValue);\n const config = this.snapshotConfig(configValue);\n validateJobConfig(spec, config);\n return this.transaction(() => this.insertJob(spec, config, baseJobId));\n }\n checkIngest(specValue: unknown, baseJobId?: string, pending: ReadonlyArray<{ spec: Spec; baseJobId?: string }> = []): Job | undefined {\n const spec = SpecSchema.parse(specValue);\n if (baseJobId && spec.project?.sourceDir) throw new Error('project.sourceDir and baseJobId are mutually exclusive');\n const row = this.db.prepare('SELECT data FROM jobs WHERE product=? AND platform=? AND channel=? AND version=?').get(spec.id, spec.platform, spec.channel, spec.version);\n const existing = row ? parseStoredJob(row.data) : undefined;\n if (existing?.requestSpec === null) throw new Error(existing.requestSpecError ?? 'Original intake identity is unknown; use reconcile-intake with the original requirements');\n const prospective = pending.find(item => sameIdentity(item.spec, spec));\n const original = existing?.requestSpec ? { spec: existing.requestSpec, baseJobId: existing.automaticBase ? undefined : existing.baseJobId } : undefined;\n for (const candidate of [original, prospective]) {\n if (candidate && (JSON.stringify(candidate.spec) !== JSON.stringify(spec) || candidate.baseJobId !== baseJobId)) throw new Error(`${spec.id} already has immutable requirements for this platform, channel and version; submit a new version instead of editing its task`);\n }\n if (existing || prospective) return existing;\n const base = this.selectBase(spec, baseJobId, pending);\n if (base && (base.spec.id !== spec.id || base.spec.platform !== spec.platform || base.spec.channel !== spec.channel || base.spec.framework !== spec.framework || !['built', 'ready'].includes(base.status) || !base.verifiedDigest || !base.verifiedDependencyDigest || base.turn || base.groups.length || base.manualRecovery)) {\n throw new Error('baseJobId must identify a finished, verified task of the same product, platform, channel and framework with no active work');\n }\n if (base) this.predecessorSpec(spec, base);\n if (base && sourceDigest(base.workspace, true, base.spec.framework, base.spec.project?.directory) !== base.verifiedDigest) throw new Error('baseJobId source changed after verification; verify the predecessor again before creating a successor');\n if (base && dependencyDigest(base.workspace, base.spec.framework, base.spec.project?.directory) !== base.verifiedDependencyDigest) throw new Error('baseJobId dependency resolution changed after verification; verify the predecessor again before creating a successor');\n return undefined;\n }\n private selectBase(spec: Spec, baseJobId?: string, pending: ReadonlyArray<{ spec: Spec; baseJobId?: string }> = []): Job | undefined {\n if (baseJobId !== undefined) return this.get(baseJobId);\n if (spec.platform !== 'ios' || spec.channel !== 'app-store' || spec.project?.sourceDir) return undefined;\n const row = this.db.prepare(\"SELECT data FROM jobs WHERE product=? AND platform=? AND channel=? AND status IN ('built','ready') ORDER BY rowid DESC LIMIT 1\").get(spec.id, spec.platform, spec.channel);\n if (row) return parseStoredJob(row.data);\n const history = this.db.prepare('SELECT 1 FROM jobs WHERE product=? AND platform=? AND channel=? LIMIT 1').get(spec.id, spec.platform, spec.channel);\n if (history || pending.some(item => item.spec.id === spec.id && item.spec.platform === spec.platform && item.spec.channel === spec.channel && !sameIdentity(item.spec, spec))) throw new Error('Previous App Store versions exist but none is finished and verified; finish or explicitly import the existing application before creating a successor');\n return undefined;\n }\n\n private predecessorSpec(spec: Spec, base: Job): Spec {\n if (spec.platform !== 'ios' || spec.channel !== 'app-store') return spec;\n const directory = base.spec.project?.directory ?? '.';\n if (spec.project && spec.project.directory !== directory) throw new Error('project.directory must preserve the predecessor project directory');\n return SpecSchema.parse({ ...spec, ...(base.spec.project || spec.project ? { project: { directory } } : {}) });\n }\n private snapshotConfig(value: unknown): Config {\n const config = ConfigSchema.parse(value);\n const root = config.configPath ? dirname(resolve(config.configPath)) : process.cwd();\n config.stateDir = canonicalPath(resolve(root, config.stateDir));\n config.workspaceRoot = canonicalPath(resolve(root, config.workspaceRoot));\n if (overlaps(config.stateDir, config.workspaceRoot) || overlaps(this.directory, config.workspaceRoot)) throw new Error('stateDir and workspaceRoot must not overlap in either direction');\n normalizeIsolationPaths(config);\n return config;\n }\n private insertJob(spec: Spec, config: Config, baseJobId?: string): Job {\n if (this.checkIngest(spec, baseJobId)) throw new Error(`${spec.id} ${spec.platform} ${spec.channel} ${spec.version} is already queued; retry its task or use a new product version`);\n const base = this.selectBase(spec, baseJobId);\n const effectiveSpec = base ? this.predecessorSpec(spec, base) : spec;\n const sourceDirectory = validateProjectSource(spec, config);\n let importDigest: string | undefined;\n if (sourceDirectory) {\n if (overlaps(this.directory, sourceDirectory)) throw new Error('project.sourceDir must not overlap the queue directory in either direction');\n importDigest = sourceDigest(sourceDirectory, true, spec.framework, spec.project?.directory);\n }\n const now = Date.now();\n const id = randomUUID();\n const job = JobSchema.parse({ id, spec: effectiveSpec, requestSpec: spec, config, ...(base ? { baseJobId: base.id, baseDigest: base.verifiedDigest, ...(baseJobId === undefined ? { automaticBase: true } : {}) } : {}), ...(sourceDirectory ? { sourceDirectory, importDigest, importPrepared: false } : {}), stage: 'research', status: 'queued', blockedReason: null, manualRecovery: null, createdAt: now, updatedAt: now, nextAt: now, attempts: {}, hostTurns: 0, turn: null, groups: [], commands: {}, receipt: {}, logs: [], workspace: join(config.workspaceRoot, id) });\n projectDirectory(job);\n this.db.prepare('INSERT INTO jobs VALUES (?,?,?,?,?,?,?,?)').run(id, spec.id, spec.platform, spec.channel, spec.version, job.status, now, JSON.stringify(job));\n this.event(id, { stage: job.stage, status: job.status, baseJobId: job.baseJobId });\n return job;\n }\n inboxEntries(): InboxEntry[] {\n return this.db.prepare('SELECT data FROM inbox ORDER BY source').all().map(row => {\n if (typeof row.data !== 'string') throw new Error('Stored inbox data must be JSON text');\n return InboxEntrySchema.parse(JSON.parse(row.data));\n });\n }\n private saveInbox(entry: InboxEntry): InboxEntry {\n this.db.prepare('INSERT INTO inbox VALUES(?,?,?) ON CONFLICT(source) DO UPDATE SET digest=excluded.digest,data=excluded.data').run(entry.source, entry.digest, JSON.stringify(entry));\n return entry;\n }\n inboxError(source: string, digest: string | null, error: string): InboxEntry {\n const previous = this.inboxEntries().find(entry => entry.source === source);\n if (previous?.status === 'error' && previous.digest === digest && previous.error === error) return previous;\n return this.saveInbox(InboxEntrySchema.parse({ source, digest, status: 'error', jobId: previous?.jobId ?? null, error, observedAt: Date.now() }));\n }\n ingest(source: string, digest: string, specValue: unknown, configValue: unknown, baseJobId?: string): InboxEntry {\n const spec = SpecSchema.parse(specValue);\n const config = this.snapshotConfig(configValue);\n validateJobConfig(spec, config);\n return this.transaction(() => {\n const job = this.checkIngest(spec, baseJobId) ?? this.insertJob(spec, config, baseJobId);\n return this.saveInbox(InboxEntrySchema.parse({ source, digest, status: 'accepted', jobId: job.id, error: null, observedAt: Date.now() }));\n });\n }\n event(id: string, data: Record<string, unknown>): void { this.db.prepare('INSERT INTO events(job,at,data) VALUES (?,?,?)').run(id, Date.now(), JSON.stringify(data)); }\n update(id: string, patch: Partial<Job>): Job {\n return this.transition(id, () => patch);\n }\n transition(id: string, change: (current: Job) => Partial<Job>): Job {\n return this.transaction(() => {\n const current = this.get(id);\n return this.saveJob(current, change(current));\n });\n }\n private saveJob(current: Job, patch: Partial<Job>, reconcileIntake = false): Job {\n const config = patch.config ? this.snapshotConfig(patch.config) : current.config;\n if (current.sourceDirectory && [config.stateDir, config.workspaceRoot].some(path => overlaps(path, current.sourceDirectory!))) throw new Error('Pinned project source must not overlap stateDir or workspaceRoot after reconfiguration');\n const job = JobSchema.parse({ ...current, ...patch, config, updatedAt: Date.now() });\n validateJobConfig(job.spec, job.config);\n if (job.id !== current.id || !sameIdentity(job.spec, current.spec) || job.spec.framework !== current.spec.framework) throw new Error('Task product, platform, channel, version and framework are immutable; enqueue a new task');\n if (job.workspace !== current.workspace || job.sourceDirectory !== current.sourceDirectory || job.importDigest !== current.importDigest || job.baseJobId !== current.baseJobId || job.baseDigest !== current.baseDigest || job.automaticBase !== current.automaticBase || JSON.stringify(job.spec.project) !== JSON.stringify(current.spec.project)) throw new Error('Pinned project source and workspace identity cannot be changed by task updates');\n if (!reconcileIntake && patch.requestSpec !== undefined && JSON.stringify(job.requestSpec) !== JSON.stringify(current.requestSpec)) throw new Error('Original intake requirements cannot be changed by task updates');\n this.db.prepare('UPDATE jobs SET status=?,next_at=?,data=? WHERE id=?').run(job.status, job.nextAt, JSON.stringify(job), job.id);\n this.event(job.id, patch);\n return job;\n }\n reconcileIntake(id: string, specValue: unknown, baseJobId?: string): Job {\n const spec = SpecSchema.parse(specValue);\n return this.transaction(() => {\n const current = this.get(id);\n if (current.requestSpec !== null) throw new Error('This task already has a known intake identity; it cannot be replaced');\n if (!sameIdentity(spec, current.spec) || spec.framework !== current.spec.framework || baseJobId !== (current.automaticBase ? undefined : current.baseJobId)) throw new Error('Original requirements must match this task product, platform, channel, framework, version and predecessor');\n return this.saveJob(current, { requestSpec: spec, requestSpecError: null }, true);\n });\n }\n acquire(): void {\n const jobs = this.transaction(() => {\n const jobs = this.list();\n const owner = this.db.prepare('SELECT pid FROM worker WHERE id=1').get();\n if (owner) {\n if (typeof owner.pid !== 'number' || !Number.isSafeInteger(owner.pid) || owner.pid <= 1) throw new Error('Stored worker PID must be a valid process ID');\n let alive = true;\n try { process.kill(owner.pid, 0); } catch (error) { alive = toError(error).code !== 'ESRCH'; }\n if (alive) throw new Error(`Execution ${owner.pid} already owns this queue; wait for its command to finish`);\n }\n this.db.prepare('INSERT OR REPLACE INTO worker VALUES(1,?)').run(process.pid);\n return jobs;\n });\n for (const job of jobs) {\n if (job.status === 'running' && !job.turn) this.update(job.id, { status: 'waiting', blockedReason: null, nextAt: Date.now(), error: 'Execution stopped during a deterministic stage; recover its command groups before resuming' });\n }\n }\n release(): void {\n this.transaction(() => {\n this.db.prepare('DELETE FROM worker WHERE id=1 AND pid=?').run(process.pid);\n });\n }\n next(canClaim: (job: Job) => boolean = () => true, excludeIds: ReadonlySet<string> = new Set()): Job | undefined {\n const now = Date.now();\n const rows = this.db.prepare(\"SELECT data FROM jobs WHERE (status IN ('queued','waiting') OR (status='blocked' AND json_extract(data,'$.blockedReason.kind')='prerequisite')) AND next_at<=? ORDER BY next_at,rowid\").all(now);\n const jobs = rows.map(row => parseStoredJob(row.data));\n for (const job of jobs) {\n if (excludeIds.has(job.id)) continue;\n const groups: number[] = [], commands: Record<string, CommandMetadata> = {};\n let manualRecovery = job.manualRecovery ?? null, pending = false, nextAt = Infinity;\n for (const pid of job.groups) {\n const command = job.commands[pid];\n const ownership = inspectProcessGroup(pid, command?.identity);\n if (ownership === 'gone') continue;\n groups.push(pid);\n const saved = command ? { ...command } : undefined;\n if (saved) commands[pid] = saved;\n if (ownership !== 'owned' || !saved || !Number.isFinite(saved.deadline)) {\n manualRecovery ??= `Command group ${pid} has ${ownership === 'mismatch' ? 'a different process identity' : 'no verifiable ownership and deadline'}. It was not signaled. Inspect this task's recorded command ownership before retrying.`;\n continue;\n }\n try {\n if (!saved.termAt && now < saved.deadline) {\n nextAt = Math.min(nextAt, saved.deadline, now + job.config.pollMs);\n } else if (!saved.termAt) {\n signalOwnedProcessGroup(pid, saved.identity, 'SIGTERM');\n saved.termAt = Date.now();\n nextAt = Math.min(nextAt, saved.termAt + TERMINATION_GRACE_MS);\n } else if (now < saved.termAt + TERMINATION_GRACE_MS) {\n nextAt = Math.min(nextAt, saved.termAt + TERMINATION_GRACE_MS);\n } else if (!saved.killAt) {\n signalOwnedProcessGroup(pid, saved.identity, 'SIGKILL');\n saved.killAt = Date.now();\n nextAt = Math.min(nextAt, saved.killAt + TERMINATION_GRACE_MS);\n } else if (now < saved.killAt + TERMINATION_GRACE_MS) {\n nextAt = Math.min(nextAt, saved.killAt + TERMINATION_GRACE_MS);\n } else {\n manualRecovery ??= `Command group ${pid} is still active after SIGKILL. No replay is allowed. Inspect and stop the recorded group, then retry this task.`;\n continue;\n }\n pending = true;\n } catch (error) { manualRecovery ??= toError(error).message; }\n }\n if (!groups.length && manualRecovery === null) {\n if (job.groups.length) this.update(job.id, { groups: [], commands: {}, recoveryStage: undefined });\n const claimed = this.transaction(() => {\n const current = this.get(job.id);\n const eligible = current.status === 'queued' || current.status === 'waiting' || (current.status === 'blocked' && current.blockedReason?.kind === 'prerequisite');\n if (!eligible || current.turn || current.nextAt > Date.now() || current.groups.length || current.manualRecovery != null || !canClaim(current)) return undefined;\n return this.saveJob(current, { status: 'running', blockedReason: null, manualRecovery: null, groups: [], commands: {}, recoveryStage: undefined });\n });\n if (claimed) return claimed;\n continue;\n }\n if (pending) {\n this.update(job.id, { status: 'waiting', blockedReason: null, manualRecovery, groups, commands, nextAt, error: manualRecovery ?? 'Recovering an owned command group; waiting for its deadline and TERM-to-KILL cleanup before replay' });\n } else {\n this.update(job.id, { status: 'blocked', blockedReason: null, manualRecovery, groups, commands, error: manualRecovery });\n }\n }\n return undefined;\n }\n events(id: string) {\n this.get(id);\n return this.db.prepare('SELECT seq,at,data FROM events WHERE job=? ORDER BY seq').all(id).map(row => {\n if (typeof row.data !== 'string') throw new Error('Stored event data must be JSON text');\n const data: unknown = JSON.parse(row.data);\n return { ...row, data };\n });\n }\n}\n"],"mappings":"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"}
|