apphx 1.1.0 → 2.0.1
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 +50 -182
- 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 +370 -118
- 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 +30 -3
- 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 +22 -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/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 +94 -17
- package/skills/apphx/resources/google-play-research-result.json +6 -0
- package/skills/apphx/resources/local-research-result.json +6 -0
- package/skills/apphx/resources/requirement.json +5 -8
- package/skills/apphx/resources/research-result.json +5 -14
- package/skills/apphx/resources/review-result.json +1 -1
- package/dist/apple.js +0 -900
- package/dist/apple.js.map +0 -1
package/dist/apple-types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apple-types.js","names":[],"sources":["../src/apple-types.ts"],"sourcesContent":["import { z } from 'zod';\n\nconst text = z.string().min(1);\nconst effect = z.strictObject({ id: text.optional() });\n\nexport const AppleReceiptSchema = z.strictObject({\n identity: z.strictObject({ appId: text, bundleId: text, version: text, buildNumber: text }).optional(),\n pending: z.strictObject({ key: text, path: text.optional(), method: z.enum(['POST', 'PATCH', 'PUT']).optional(), startedAt: z.iso.datetime().optional() }).nullable().optional(),\n effects: z.record(z.string(), effect).optional(),\n lastEffect: z.strictObject({ key: text, id: text.optional(), reconciled: z.boolean().optional(), completedAt: z.iso.datetime().optional() }).optional(),\n upload: z.strictObject({ status: z.enum(['intent', 'delivered', 'reconciled']), startedAt: z.iso.datetime().optional() }).optional(),\n phase: z.enum(['processing', 'submitted']).optional(),\n versionId: text.optional(),\n buildId: text.optional(),\n submissionId: text.optional(),\n assetParts: z.record(z.string(), z.number().int().nonnegative().safe()).optional(),\n});\n\nexport interface AppleReceipt extends z.infer<typeof AppleReceiptSchema> {}\n\
|
|
1
|
+
{"version":3,"file":"apple-types.js","names":[],"sources":["../src/apple-types.ts"],"sourcesContent":["import { z } from 'zod';\n\nconst text = z.string().min(1);\nconst effect = z.strictObject({ id: text.optional() });\n\nexport const AppleReceiptSchema = z.strictObject({\n identity: z.strictObject({ appId: text, bundleId: text, version: text, buildNumber: text }).optional(),\n pending: z.strictObject({ key: text, path: text.optional(), method: z.enum(['POST', 'PATCH', 'PUT']).optional(), startedAt: z.iso.datetime().optional() }).nullable().optional(),\n effects: z.record(z.string(), effect).optional(),\n lastEffect: z.strictObject({ key: text, id: text.optional(), reconciled: z.boolean().optional(), completedAt: z.iso.datetime().optional() }).optional(),\n upload: z.strictObject({ status: z.enum(['intent', 'delivered', 'reconciled']), startedAt: z.iso.datetime().optional() }).optional(),\n phase: z.enum(['processing', 'submitted']).optional(),\n versionId: text.optional(),\n buildId: text.optional(),\n submissionId: text.optional(),\n assetParts: z.record(z.string(), z.number().int().nonnegative().safe()).optional(),\n});\n\nexport interface AppleReceipt extends z.infer<typeof AppleReceiptSchema> {}\n\n"],"mappings":";;AAEA,MAAM,OAAO,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC;AAC7B,MAAM,SAAS,EAAE,aAAa,EAAE,IAAI,KAAK,SAAS,EAAE,CAAC;AAErD,MAAa,qBAAqB,EAAE,aAAa;CAC/C,UAAU,EAAE,aAAa;EAAE,OAAO;EAAM,UAAU;EAAM,SAAS;EAAM,aAAa;CAAK,CAAC,CAAC,CAAC,SAAS;CACrG,SAAS,EAAE,aAAa;EAAE,KAAK;EAAM,MAAM,KAAK,SAAS;EAAG,QAAQ,EAAE,KAAK;GAAC;GAAQ;GAAS;EAAK,CAAC,CAAC,CAAC,SAAS;EAAG,WAAW,EAAE,IAAI,SAAS,CAAC,CAAC,SAAS;CAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS;CAC/K,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,CAAC,SAAS;CAC/C,YAAY,EAAE,aAAa;EAAE,KAAK;EAAM,IAAI,KAAK,SAAS;EAAG,YAAY,EAAE,QAAQ,CAAC,CAAC,SAAS;EAAG,aAAa,EAAE,IAAI,SAAS,CAAC,CAAC,SAAS;CAAE,CAAC,CAAC,CAAC,SAAS;CACtJ,QAAQ,EAAE,aAAa;EAAE,QAAQ,EAAE,KAAK;GAAC;GAAU;GAAa;EAAY,CAAC;EAAG,WAAW,EAAE,IAAI,SAAS,CAAC,CAAC,SAAS;CAAE,CAAC,CAAC,CAAC,SAAS;CACnI,OAAO,EAAE,KAAK,CAAC,cAAc,WAAW,CAAC,CAAC,CAAC,SAAS;CACpD,WAAW,KAAK,SAAS;CACzB,SAAS,KAAK,SAAS;CACvB,cAAc,KAAK,SAAS;CAC5B,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;AACnF,CAAC"}
|
package/dist/cli.js
CHANGED
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { validateMyGoCommand } from "./mygo-build.js";
|
|
3
|
+
import { FrameworkSchema, PackageTargetSchema, PlatformSchema, toError, validateJobConfig } from "./schemas.js";
|
|
4
|
+
import { canonicalPath, expandArgv, loadConfig, loadJSON, normalizeIsolationPaths, validateProjectSource } from "./config.js";
|
|
3
5
|
import { executionEnvironment, run } from "./process.js";
|
|
4
|
-
import {
|
|
5
|
-
import { loadConfig, loadJSON } from "./config.js";
|
|
6
|
+
import { closestOwnedGoWorkspace } from "./go-dependencies.js";
|
|
6
7
|
import { Store } from "./store.js";
|
|
8
|
+
import { prepareIsolatedCommand, removeConfinedPath } from "./isolation.js";
|
|
9
|
+
import { assertProject, doctorCommands } from "./project-profiles.js";
|
|
10
|
+
import { invalidateVerification, verificationConfigChanged } from "./proof.js";
|
|
7
11
|
import { abandonTurn, completeTurn, nextTurn } from "./runner.js";
|
|
8
12
|
import { runStep } from "./scheduler.js";
|
|
9
13
|
import { hosts, inspectIntegration, installIntegration, uninstallIntegration, updateIntegration } from "./integrations.js";
|
|
10
14
|
import { MAX_INPUT_BYTES, parseRequirement, readInputFile } from "./requirements.js";
|
|
11
15
|
import { scanInbox, submitRequirement } from "./inbox.js";
|
|
12
16
|
import { dispatchRemote } from "./remote.js";
|
|
17
|
+
import { existsSync, mkdirSync, mkdtempSync, readFileSync, writeFileSync } from "node:fs";
|
|
18
|
+
import { spawnSync } from "node:child_process";
|
|
13
19
|
import { dirname, join, resolve } from "node:path";
|
|
14
|
-
import {
|
|
20
|
+
import { tmpdir } from "node:os";
|
|
15
21
|
import { fileURLToPath } from "node:url";
|
|
16
22
|
import { parseArgs } from "node:util";
|
|
17
23
|
// src/cli.ts
|
|
@@ -20,7 +26,10 @@ const print = (value) => console.log(JSON.stringify(value, null, 2));
|
|
|
20
26
|
const view = (job) => ({
|
|
21
27
|
id: job.id,
|
|
22
28
|
product: job.spec.id,
|
|
23
|
-
|
|
29
|
+
framework: job.spec.framework,
|
|
30
|
+
platform: job.spec.platform,
|
|
31
|
+
channel: job.spec.channel,
|
|
32
|
+
version: job.spec.version,
|
|
24
33
|
stage: job.stage,
|
|
25
34
|
status: job.status,
|
|
26
35
|
hostTurns: job.hostTurns,
|
|
@@ -41,10 +50,38 @@ function outcome(job) {
|
|
|
41
50
|
print(view(job));
|
|
42
51
|
if (job.status === "blocked" || job.status === "failed") process.exitCode = 2;
|
|
43
52
|
}
|
|
44
|
-
async function probe(argv, config) {
|
|
53
|
+
async function probe(argv, config, context) {
|
|
54
|
+
let temporary;
|
|
55
|
+
let isolated;
|
|
45
56
|
try {
|
|
46
|
-
const
|
|
47
|
-
|
|
57
|
+
const env = context?.env ?? executionEnvironment(config);
|
|
58
|
+
const expanded = expandArgv(argv, env);
|
|
59
|
+
validateMyGoCommand(config, expanded);
|
|
60
|
+
if (config.isolation) {
|
|
61
|
+
if (!config.allowLocalExecution) return {
|
|
62
|
+
available: false,
|
|
63
|
+
detail: "Owner must enable local execution before isolated probes run"
|
|
64
|
+
};
|
|
65
|
+
temporary = mkdtempSync(join(tmpdir(), "apphx-doctor-"));
|
|
66
|
+
const scoped = {
|
|
67
|
+
...config,
|
|
68
|
+
isolation: {
|
|
69
|
+
...config.isolation,
|
|
70
|
+
readOnlyPaths: [...config.isolation.readOnlyPaths, ...context?.sourceRoot ? [canonicalPath(context.sourceRoot)] : []]
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
normalizeIsolationPaths(scoped);
|
|
74
|
+
isolated = prepareIsolatedCommand(expanded, {
|
|
75
|
+
config: scoped,
|
|
76
|
+
workspace: temporary,
|
|
77
|
+
cwd: context?.cwd ?? temporary,
|
|
78
|
+
env,
|
|
79
|
+
scratchParent: temporary
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
const result = await run(isolated?.argv ?? expanded, {
|
|
83
|
+
cwd: context?.cwd ?? temporary,
|
|
84
|
+
env: isolated?.env ?? env,
|
|
48
85
|
timeoutMs: 3e4
|
|
49
86
|
});
|
|
50
87
|
return {
|
|
@@ -56,7 +93,195 @@ async function probe(argv, config) {
|
|
|
56
93
|
available: false,
|
|
57
94
|
detail: toError(error).message
|
|
58
95
|
};
|
|
96
|
+
} finally {
|
|
97
|
+
isolated?.cleanup();
|
|
98
|
+
if (temporary) removeConfinedPath(temporary, temporary);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const frameworks = FrameworkSchema.options;
|
|
102
|
+
const packageTargets = PackageTargetSchema.options;
|
|
103
|
+
function initialConfig(framework, platform, target) {
|
|
104
|
+
if (framework === "mygo" !== (platform === "macos")) throw new Error(`${framework} does not support ${platform}`);
|
|
105
|
+
if (framework === "android-java" && platform !== "android" || framework === "swift" && platform !== "ios") throw new Error(`${framework} does not support ${platform}`);
|
|
106
|
+
if (!(platform === "macos" ? ["app", "dmg"] : platform === "ios" ? ["simulator", "ipa"] : ["apk", "aab"]).includes(target)) throw new Error(`${target} does not match platform ${platform}`);
|
|
107
|
+
const template = JSON.parse(readFileSync(join(packageRoot, "examples", `${framework}.factory.json`), "utf8"));
|
|
108
|
+
template.packageTarget = target;
|
|
109
|
+
if (framework === "mygo") template.packaging = {
|
|
110
|
+
provider: "local",
|
|
111
|
+
commands: [[
|
|
112
|
+
"go",
|
|
113
|
+
"tool",
|
|
114
|
+
"mygo",
|
|
115
|
+
"build",
|
|
116
|
+
"-platform",
|
|
117
|
+
"darwin/arm64",
|
|
118
|
+
"-sign",
|
|
119
|
+
"-",
|
|
120
|
+
"-skip-notarize",
|
|
121
|
+
...target === "app" ? ["-skip-dmg"] : [],
|
|
122
|
+
"-o",
|
|
123
|
+
"build"
|
|
124
|
+
]],
|
|
125
|
+
artifactPath: target === "app" ? "build/darwin-arm64/MyGo App.app" : "build/darwin-arm64/MyGo App 0.1.0.dmg"
|
|
126
|
+
};
|
|
127
|
+
else if (framework === "flutter") {
|
|
128
|
+
template.executionEnv = platform === "ios" ? ["IOS_DEVICE_ID"] : ["ANDROID_DEVICE_ID"];
|
|
129
|
+
template.verification = {
|
|
130
|
+
prerequisites: platform === "ios" ? [["xcodebuild", "-version"]] : [["java", "-version"], ["adb", "version"]],
|
|
131
|
+
checks: [[
|
|
132
|
+
"flutter",
|
|
133
|
+
"analyze",
|
|
134
|
+
"--fatal-infos"
|
|
135
|
+
], ["flutter", "test"]],
|
|
136
|
+
runtime: [[
|
|
137
|
+
"flutter",
|
|
138
|
+
"drive",
|
|
139
|
+
"--driver",
|
|
140
|
+
"test_driver/integration_test.dart",
|
|
141
|
+
"--target",
|
|
142
|
+
"integration_test/app_test.dart",
|
|
143
|
+
"-d",
|
|
144
|
+
platform === "ios" ? "${IOS_DEVICE_ID}" : "${ANDROID_DEVICE_ID}",
|
|
145
|
+
"--no-pub"
|
|
146
|
+
]]
|
|
147
|
+
};
|
|
148
|
+
} else if (framework === "expo") {
|
|
149
|
+
const device = platform === "ios" ? "IOS_DEVICE_ID" : "ANDROID_DEVICE_ID";
|
|
150
|
+
const profile = target === "simulator" ? "simulator" : target === "apk" ? "apk" : "production";
|
|
151
|
+
const output = target === "simulator" ? "build/simulator.tar.gz" : `build/app.${target}`;
|
|
152
|
+
template.executionEnv = [device, ...platform === "android" ? ["ANDROID_HOME"] : []];
|
|
153
|
+
template.verification = {
|
|
154
|
+
prerequisites: [["node", "--version"], ["eas", "--version"]],
|
|
155
|
+
checks: [[
|
|
156
|
+
"npm",
|
|
157
|
+
"run",
|
|
158
|
+
"lint"
|
|
159
|
+
], [
|
|
160
|
+
"npm",
|
|
161
|
+
"test",
|
|
162
|
+
"--",
|
|
163
|
+
"--runInBand"
|
|
164
|
+
]],
|
|
165
|
+
runtime: [[
|
|
166
|
+
"npm",
|
|
167
|
+
"run",
|
|
168
|
+
"test:e2e",
|
|
169
|
+
"--",
|
|
170
|
+
"--platform",
|
|
171
|
+
platform,
|
|
172
|
+
"--device",
|
|
173
|
+
"${" + device + "}"
|
|
174
|
+
]]
|
|
175
|
+
};
|
|
176
|
+
template.packaging = {
|
|
177
|
+
provider: "local",
|
|
178
|
+
commands: [[
|
|
179
|
+
"eas",
|
|
180
|
+
"build",
|
|
181
|
+
"--platform",
|
|
182
|
+
platform,
|
|
183
|
+
"--profile",
|
|
184
|
+
profile,
|
|
185
|
+
"--local",
|
|
186
|
+
"--non-interactive",
|
|
187
|
+
"--output",
|
|
188
|
+
output
|
|
189
|
+
], ...target === "simulator" ? [[
|
|
190
|
+
"tar",
|
|
191
|
+
"-xzf",
|
|
192
|
+
output,
|
|
193
|
+
"-C",
|
|
194
|
+
"build"
|
|
195
|
+
]] : []],
|
|
196
|
+
artifactPath: target === "simulator" ? "build/App.app" : output
|
|
197
|
+
};
|
|
198
|
+
} else if (platform === "ios") {
|
|
199
|
+
const base = [
|
|
200
|
+
"xcodebuild",
|
|
201
|
+
...framework === "swift" ? ["-project", "App.xcodeproj"] : ["-workspace", `${framework === "swift" ? "." : framework === "uni-app" ? "native/ios" : "ios"}/App.xcworkspace`],
|
|
202
|
+
"-scheme",
|
|
203
|
+
"App"
|
|
204
|
+
];
|
|
205
|
+
template.executionEnv = ["IOS_DEVICE_ID"];
|
|
206
|
+
template.verification = {
|
|
207
|
+
prerequisites: [["xcodebuild", "-version"], ...framework === "swift" ? [] : [["node", "--version"], ["npm", "--version"]]],
|
|
208
|
+
checks: framework === "swift" ? [[
|
|
209
|
+
...base,
|
|
210
|
+
"build-for-testing",
|
|
211
|
+
"-destination",
|
|
212
|
+
"generic/platform=iOS Simulator",
|
|
213
|
+
"-derivedDataPath",
|
|
214
|
+
"build/DerivedData"
|
|
215
|
+
]] : [[
|
|
216
|
+
"npm",
|
|
217
|
+
"run",
|
|
218
|
+
"lint"
|
|
219
|
+
], [
|
|
220
|
+
"npm",
|
|
221
|
+
"test",
|
|
222
|
+
"--",
|
|
223
|
+
"--runInBand"
|
|
224
|
+
]],
|
|
225
|
+
runtime: framework === "swift" ? [[
|
|
226
|
+
...base,
|
|
227
|
+
"test",
|
|
228
|
+
"-destination",
|
|
229
|
+
"id=${IOS_DEVICE_ID}",
|
|
230
|
+
"-derivedDataPath",
|
|
231
|
+
"build/DerivedData"
|
|
232
|
+
]] : [[
|
|
233
|
+
"npm",
|
|
234
|
+
"run",
|
|
235
|
+
"test:e2e",
|
|
236
|
+
"--",
|
|
237
|
+
"--platform",
|
|
238
|
+
"ios",
|
|
239
|
+
"--device",
|
|
240
|
+
"${IOS_DEVICE_ID}"
|
|
241
|
+
]]
|
|
242
|
+
};
|
|
243
|
+
template.packaging = target === "simulator" ? {
|
|
244
|
+
commands: [[
|
|
245
|
+
...base,
|
|
246
|
+
"build",
|
|
247
|
+
"-configuration",
|
|
248
|
+
"Debug",
|
|
249
|
+
"-destination",
|
|
250
|
+
"generic/platform=iOS Simulator",
|
|
251
|
+
"-derivedDataPath",
|
|
252
|
+
"build/DerivedData"
|
|
253
|
+
]],
|
|
254
|
+
artifactPath: "build/DerivedData/Build/Products/Debug-iphonesimulator/App.app",
|
|
255
|
+
provider: "local"
|
|
256
|
+
} : {
|
|
257
|
+
commands: [[
|
|
258
|
+
...base,
|
|
259
|
+
"archive",
|
|
260
|
+
"-configuration",
|
|
261
|
+
"Release",
|
|
262
|
+
"-destination",
|
|
263
|
+
"generic/platform=iOS",
|
|
264
|
+
"-archivePath",
|
|
265
|
+
"build/App.xcarchive"
|
|
266
|
+
], [
|
|
267
|
+
"xcodebuild",
|
|
268
|
+
"-exportArchive",
|
|
269
|
+
"-archivePath",
|
|
270
|
+
"build/App.xcarchive",
|
|
271
|
+
"-exportPath",
|
|
272
|
+
"build/export",
|
|
273
|
+
"-exportOptionsPlist",
|
|
274
|
+
"ExportOptions.plist"
|
|
275
|
+
]],
|
|
276
|
+
artifactPath: "build/export/App.ipa",
|
|
277
|
+
provider: "local"
|
|
278
|
+
};
|
|
279
|
+
} else if (target === "apk") {
|
|
280
|
+
const packaging = template.packaging;
|
|
281
|
+
packaging.commands = packaging.commands.map((argv) => argv.map((arg) => arg === ":app:bundleRelease" ? ":app:assembleRelease" : arg));
|
|
282
|
+
packaging.artifactPath = packaging.artifactPath.replace("bundle/release/app-release.aab", "apk/release/app-release.apk");
|
|
59
283
|
}
|
|
284
|
+
return template;
|
|
60
285
|
}
|
|
61
286
|
const help = `apphx <command> [--config factory.json] [--build-only]
|
|
62
287
|
hosts List supported agent hosts and activation commands
|
|
@@ -66,28 +291,33 @@ const help = `apphx <command> [--config factory.json] [--build-only]
|
|
|
66
291
|
--project <directory> Select the project (default: current directory)
|
|
67
292
|
--global Use the host's user-level skill directory instead
|
|
68
293
|
doctor --host <host> Check installed workflow files; does not run the agent
|
|
69
|
-
init [--allow-local-execution] Create factory.json
|
|
70
|
-
|
|
294
|
+
init [--allow-local-execution] Create owner-editable factory.json; default Flutter/iOS
|
|
295
|
+
--framework <stack> flutter|android-java|swift|react-native|expo|uni-app|mygo
|
|
296
|
+
--platform <platform> ios|android|macos (mygo defaults macos; android-java android)
|
|
297
|
+
--package-target <target> simulator|ipa|apk|aab|app|dmg (MyGo app; Expo iOS ipa)
|
|
298
|
+
doctor [spec.json] Check configured prerequisites and optional stack tools
|
|
71
299
|
enqueue <spec.json|-> Persist requirements and return a task ID
|
|
72
300
|
next <id> Resume a host turn or show the next deterministic action
|
|
73
301
|
complete <id> <turn> [json|-] Record research/review, or finish the host's build turn
|
|
74
302
|
abandon <id> <turn> Abandon a host turn without resetting its budget
|
|
75
|
-
step <id> Execute one
|
|
303
|
+
step <id> Execute one obfuscation, verification or packaging stage
|
|
76
304
|
status [id] Read durable task state as JSON
|
|
77
305
|
events <id> Read task transitions and evidence
|
|
78
|
-
retry <id> Resume stopped work; preserve budgets and
|
|
306
|
+
retry <id> Resume stopped work; preserve budgets and proofs
|
|
79
307
|
submit <spec.json|-> Write requirements to the configured inbox
|
|
80
308
|
scan [--observe] Validate or ingest inbox files; never start an agent
|
|
81
309
|
inbox Read durable intake results
|
|
82
310
|
reconcile-intake <id> <json|-> Restore a legacy request identity from original input
|
|
83
|
-
authorize <id> --submit [--release] Explicitly grant publication permission
|
|
84
|
-
feedback <id> <file> Resume using actual App Review rejection feedback
|
|
85
311
|
remote <command> Call an installed Mac CLI over SSH (build-only)
|
|
312
|
+
obfuscator <project> Run the bundled deterministic obfuscator on a project copy
|
|
313
|
+
--config <file> Obfuscator options as JSON (required)
|
|
314
|
+
--framework <stack> flutter|android-java|swift|react-native|expo|uni-app|mygo
|
|
315
|
+
--seed <text> Determinism seed
|
|
86
316
|
--version Print the installed package version
|
|
87
317
|
|
|
88
318
|
Your agent supplies the model, session, tools and native delegation.
|
|
89
319
|
No coding-agent subprocess or autonomous daemon is started by this CLI.
|
|
90
|
-
Only verified local artifacts reach built
|
|
320
|
+
Only verified local artifacts reach built. Store submission and review are manual human work outside this tool.`;
|
|
91
321
|
async function main() {
|
|
92
322
|
const { values, positionals, tokens } = parseArgs({
|
|
93
323
|
allowPositionals: true,
|
|
@@ -105,9 +335,11 @@ async function main() {
|
|
|
105
335
|
global: { type: "boolean" },
|
|
106
336
|
host: { type: "string" },
|
|
107
337
|
"allow-local-execution": { type: "boolean" },
|
|
338
|
+
framework: { type: "string" },
|
|
339
|
+
seed: { type: "string" },
|
|
340
|
+
platform: { type: "string" },
|
|
341
|
+
"package-target": { type: "string" },
|
|
108
342
|
observe: { type: "boolean" },
|
|
109
|
-
submit: { type: "boolean" },
|
|
110
|
-
release: { type: "boolean" },
|
|
111
343
|
version: {
|
|
112
344
|
type: "boolean",
|
|
113
345
|
short: "v"
|
|
@@ -133,7 +365,13 @@ async function main() {
|
|
|
133
365
|
install: ["project", "global"],
|
|
134
366
|
update: ["project", "global"],
|
|
135
367
|
uninstall: ["project", "global"],
|
|
136
|
-
init: [
|
|
368
|
+
init: [
|
|
369
|
+
"config",
|
|
370
|
+
"allow-local-execution",
|
|
371
|
+
"framework",
|
|
372
|
+
"platform",
|
|
373
|
+
"package-target"
|
|
374
|
+
],
|
|
137
375
|
doctor: [
|
|
138
376
|
"config",
|
|
139
377
|
"build-only",
|
|
@@ -157,14 +395,12 @@ async function main() {
|
|
|
157
395
|
],
|
|
158
396
|
inbox: ["config", "build-only"],
|
|
159
397
|
"reconcile-intake": ["config", "build-only"],
|
|
160
|
-
|
|
398
|
+
remote: ["config", "observe"],
|
|
399
|
+
obfuscator: [
|
|
161
400
|
"config",
|
|
162
|
-
"
|
|
163
|
-
"
|
|
164
|
-
|
|
165
|
-
],
|
|
166
|
-
feedback: ["config", "build-only"],
|
|
167
|
-
remote: ["config", "observe"]
|
|
401
|
+
"framework",
|
|
402
|
+
"seed"
|
|
403
|
+
]
|
|
168
404
|
};
|
|
169
405
|
if (!(command in flags)) throw new Error(`Unknown command ${command}; run apphx --help`);
|
|
170
406
|
for (const token of tokens) if (token.kind === "option" && !flags[command].includes(token.name)) throw new Error(`${command} does not accept --${token.name}`);
|
|
@@ -175,6 +411,23 @@ async function main() {
|
|
|
175
411
|
project: values.project,
|
|
176
412
|
global: values.global
|
|
177
413
|
};
|
|
414
|
+
if (command === "obfuscator") {
|
|
415
|
+
arity(args, 1, 1, "obfuscator <project> --config <file> [--framework <stack>] [--seed <text>]");
|
|
416
|
+
const bundled = join(packageRoot, "dist", "vendor", "obfuscator", "dist", "cli.js");
|
|
417
|
+
if (!existsSync(bundled)) throw new Error(`Bundled obfuscator is missing at ${bundled}; reinstall the apphx package`);
|
|
418
|
+
const forward = [
|
|
419
|
+
bundled,
|
|
420
|
+
"--project",
|
|
421
|
+
resolve(args[0])
|
|
422
|
+
];
|
|
423
|
+
if (tokens.some((token) => token.kind === "option" && token.name === "config")) forward.push("--config", resolve(values.config));
|
|
424
|
+
if (values.framework !== void 0) forward.push("--framework", values.framework);
|
|
425
|
+
if (values.seed !== void 0) forward.push("--seed", values.seed);
|
|
426
|
+
const result = spawnSync(process.execPath, forward, { stdio: "inherit" });
|
|
427
|
+
if (result.error) throw result.error;
|
|
428
|
+
process.exitCode = result.status ?? 1;
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
178
431
|
if (command === "hosts") {
|
|
179
432
|
arity(args, 0, 0, "hosts");
|
|
180
433
|
print(hosts);
|
|
@@ -194,8 +447,13 @@ async function main() {
|
|
|
194
447
|
}
|
|
195
448
|
if (command === "doctor" && (values.project || values.global)) throw new Error("--project and --global require doctor --host <host>");
|
|
196
449
|
if (command === "init") {
|
|
197
|
-
arity(args, 0, 0, "init [--config <file>] [--allow-local-execution]");
|
|
198
|
-
const
|
|
450
|
+
arity(args, 0, 0, "init [--framework <stack>] [--platform ios|android|macos] [--package-target simulator|ipa|apk|aab|app|dmg] [--config <file>] [--allow-local-execution]");
|
|
451
|
+
const framework = values.framework ?? "flutter";
|
|
452
|
+
if (!frameworks.includes(framework)) throw new Error(`Unknown framework ${framework}; choose ${frameworks.join(", ")}`);
|
|
453
|
+
const platform = PlatformSchema.parse(values.platform ?? (framework === "mygo" ? "macos" : framework === "android-java" ? "android" : "ios"));
|
|
454
|
+
const target = values["package-target"] ?? (platform === "macos" ? "app" : platform === "ios" ? framework === "expo" ? "ipa" : "simulator" : "apk");
|
|
455
|
+
if (!packageTargets.includes(target)) throw new Error(`Unknown package target ${target}; choose ${packageTargets.join(", ")}`);
|
|
456
|
+
const template = initialConfig(framework, platform, target);
|
|
199
457
|
if (values["allow-local-execution"]) template.allowLocalExecution = true;
|
|
200
458
|
mkdirSync(dirname(resolve(configPath)), { recursive: true });
|
|
201
459
|
writeFileSync(configPath, `${JSON.stringify(template, null, 2)}\n`, {
|
|
@@ -204,8 +462,11 @@ async function main() {
|
|
|
204
462
|
});
|
|
205
463
|
print({
|
|
206
464
|
config: resolve(configPath),
|
|
465
|
+
framework,
|
|
466
|
+
platform,
|
|
467
|
+
packageTarget: target,
|
|
207
468
|
localExecution: template.allowLocalExecution,
|
|
208
|
-
next: "Configure
|
|
469
|
+
next: framework === "mygo" ? "Pin MyGo v0.3.0 in go.mod (Go 1.27.1), match app name/version/arch and artifact path, and implement real desktop UI acceptance in cmd/acceptance. Native UI needs no Bun. Local ad-hoc builds only; init creates configuration, not source." : framework === "expo" ? "Configure your existing eas.json production (store IPA/AAB), apk (Android buildType apk), or simulator (ios.simulator true) profile, real device acceptance, and exact app product/output path; no prebuild/eject is requested. Run apphx doctor <spec.json> --build-only." : "Adapt module/scheme, real device acceptance, signing and artifact path to your project; then run apphx doctor <spec.json> --build-only. init creates configuration, not app source."
|
|
209
470
|
});
|
|
210
471
|
return;
|
|
211
472
|
}
|
|
@@ -214,58 +475,106 @@ async function main() {
|
|
|
214
475
|
return;
|
|
215
476
|
}
|
|
216
477
|
const config = loadConfig(configPath);
|
|
217
|
-
if (buildOnly && (config.allowSubmit || config.allowRelease)) throw new Error("--build-only refuses configurations with upload or release enabled");
|
|
218
|
-
if (buildOnly && ["authorize", "feedback"].includes(command)) throw new Error("Publication commands are forbidden in --build-only mode");
|
|
219
478
|
if (command === "submit") {
|
|
220
479
|
arity(args, 1, 1, "submit <spec.json|->");
|
|
221
480
|
print(submitRequirement(config, inputJSON(args[0])));
|
|
222
481
|
return;
|
|
223
482
|
}
|
|
224
483
|
if (command === "doctor") {
|
|
225
|
-
arity(args, 0,
|
|
226
|
-
const
|
|
227
|
-
|
|
484
|
+
arity(args, 0, 1, "doctor [spec.json] [--build-only]");
|
|
485
|
+
const spec = args[0] ? parseRequirement(inputJSON(args[0])).spec : void 0;
|
|
486
|
+
let prerequisiteContext;
|
|
487
|
+
if (spec) {
|
|
488
|
+
validateJobConfig(spec, config);
|
|
489
|
+
let source;
|
|
490
|
+
try {
|
|
491
|
+
source = validateProjectSource(spec, config);
|
|
492
|
+
} catch (error) {
|
|
493
|
+
if (spec.framework !== "mygo" || error.code !== "ENOENT") throw error;
|
|
494
|
+
}
|
|
495
|
+
const directory = spec.project?.directory ?? ".";
|
|
496
|
+
const project = source ? resolve(source, directory) : void 0;
|
|
497
|
+
if (source && project && (spec.framework !== "mygo" || existsSync(project))) {
|
|
498
|
+
assertProject(project, spec);
|
|
499
|
+
if (spec.framework === "mygo" || config.isolation) prerequisiteContext = {
|
|
500
|
+
cwd: project,
|
|
501
|
+
sourceRoot: source,
|
|
502
|
+
env: {
|
|
503
|
+
...executionEnvironment(config),
|
|
504
|
+
...spec.framework === "mygo" ? {
|
|
505
|
+
GOWORK: closestOwnedGoWorkspace(source, directory) ?? "off",
|
|
506
|
+
GOENV: "off",
|
|
507
|
+
GOTOOLCHAIN: "local",
|
|
508
|
+
GOFLAGS: "-mod=readonly"
|
|
509
|
+
} : {}
|
|
510
|
+
}
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
const commands = spec && config.packaging?.provider !== "cloud" ? doctorCommands(spec.framework, spec.platform) : [];
|
|
515
|
+
const tools = await Promise.all(commands.map(async ({ name, argv }) => ({
|
|
516
|
+
name,
|
|
517
|
+
...await probe(argv[0] === "flutter" && config.toolchain ? [join(config.toolchain.flutterSdk, "bin", "flutter"), ...argv.slice(1)] : argv, config)
|
|
518
|
+
})));
|
|
519
|
+
const prerequisites = await Promise.all(config.verification.prerequisites.map(async (argv, index) => ({
|
|
520
|
+
name: `configured-prerequisite-${index + 1}`,
|
|
521
|
+
...!config.allowLocalExecution ? {
|
|
522
|
+
available: false,
|
|
523
|
+
detail: "Owner must enable allowLocalExecution before configured prerequisite commands run"
|
|
524
|
+
} : spec?.framework === "mygo" && !prerequisiteContext ? {
|
|
525
|
+
available: false,
|
|
526
|
+
detail: "Project-scoped prerequisite cannot be checked yet: select an existing MyGo source app with project.sourceDir and project.directory; doctor does not create source or use the control module"
|
|
527
|
+
} : await probe(argv, config, prerequisiteContext)
|
|
528
|
+
})));
|
|
228
529
|
const environment = executionEnvironment(config);
|
|
229
|
-
const
|
|
530
|
+
const configuredCommands = [
|
|
230
531
|
...config.verification.prerequisites,
|
|
231
532
|
...config.verification.checks,
|
|
232
|
-
...config.verification.runtime
|
|
233
|
-
|
|
533
|
+
...config.verification.runtime,
|
|
534
|
+
...config.packaging?.commands ?? []
|
|
535
|
+
];
|
|
536
|
+
const neededEnv = [...new Set(configuredCommands.flat().flatMap((arg) => [...arg.matchAll(/\$\{([A-Z][A-Z0-9_]*)\}/g)].map((match) => match[1])))];
|
|
234
537
|
const checks = [
|
|
235
538
|
{
|
|
236
539
|
name: "local-execution-permission",
|
|
237
540
|
available: config.allowLocalExecution,
|
|
238
541
|
detail: config.executionWarning ?? "Trusted local commands permitted; host tools remain under the host permission policy"
|
|
239
542
|
},
|
|
240
|
-
{
|
|
241
|
-
name: "
|
|
242
|
-
...
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
543
|
+
...config.isolation ? [{
|
|
544
|
+
name: "subprocess-isolation",
|
|
545
|
+
...await probe(["/usr/bin/true"], config),
|
|
546
|
+
mode: config.isolation.mode,
|
|
547
|
+
network: config.isolation.network
|
|
548
|
+
}] : [],
|
|
549
|
+
...tools,
|
|
550
|
+
...prerequisites,
|
|
248
551
|
...neededEnv.map((name) => ({
|
|
249
552
|
name,
|
|
250
553
|
available: Boolean(environment[name]),
|
|
251
554
|
detail: environment[name] ? "Available in the configured execution environment; value not printed" : `Set ${name} and include its name in executionEnv`
|
|
252
555
|
}))
|
|
253
556
|
];
|
|
254
|
-
if (config.allowSubmit) checks.push(...await appleDoctor());
|
|
255
557
|
print({
|
|
558
|
+
framework: spec?.framework ?? null,
|
|
559
|
+
platform: spec?.platform ?? null,
|
|
256
560
|
checks,
|
|
257
|
-
|
|
561
|
+
note: spec ? "Tool availability is not runtime acceptance; configured checks run in the task workspace during verify" : "No stack assumed; pass spec.json for profile-specific probes and compatibility checks",
|
|
258
562
|
model: "Provided by your agent host; no separate model authentication is configured here"
|
|
259
563
|
});
|
|
260
564
|
if (checks.some((check) => !check.available)) process.exitCode = 2;
|
|
261
565
|
return;
|
|
262
566
|
}
|
|
567
|
+
const queuedRequirement = command === "enqueue" ? (() => {
|
|
568
|
+
arity(args, 1, 1, "enqueue <spec.json|->");
|
|
569
|
+
const requirement = parseRequirement(inputJSON(args[0]));
|
|
570
|
+
validateJobConfig(requirement.spec, config);
|
|
571
|
+
validateProjectSource(requirement.spec, config);
|
|
572
|
+
return requirement;
|
|
573
|
+
})() : void 0;
|
|
263
574
|
const store = new Store(config.stateDir);
|
|
264
575
|
try {
|
|
265
576
|
if (command === "enqueue") {
|
|
266
|
-
|
|
267
|
-
const { spec, baseJobId } = parseRequirement(inputJSON(args[0]));
|
|
268
|
-
if (config.allowSubmit) validateAppleSpec(spec);
|
|
577
|
+
const { spec, baseJobId } = queuedRequirement;
|
|
269
578
|
print(view(store.enqueue(spec, config, baseJobId)));
|
|
270
579
|
} else if (command === "scan") {
|
|
271
580
|
arity(args, 0, 0, "scan [--observe]");
|
|
@@ -314,28 +623,26 @@ async function main() {
|
|
|
314
623
|
} else if (command === "retry") {
|
|
315
624
|
arity(args, 1, 1, "retry <id>");
|
|
316
625
|
print(view(store.transition(args[0], (job) => {
|
|
317
|
-
if (buildOnly && (job.config.allowSubmit || job.config.allowRelease)) throw new Error("--build-only refuses a task with snapshotted publication permission");
|
|
318
626
|
if (![
|
|
319
627
|
"blocked",
|
|
320
628
|
"ready",
|
|
321
629
|
"built"
|
|
322
630
|
].includes(job.status)) throw new Error(`Cannot retry ${job.status}; budgets and active work cannot be reset by retry`);
|
|
323
631
|
if (job.turn) throw new Error("Abandon the active host turn before changing task configuration");
|
|
324
|
-
|
|
325
|
-
if (proofChanged && Object.keys(job.receipt).length) throw new Error("Verification proof is no longer valid after publication began; reconcile the existing upload before creating a new version");
|
|
326
|
-
const patch = proofChanged && job.verifiedDigest ? {
|
|
327
|
-
stage: "verify",
|
|
328
|
-
verifiedDigest: null,
|
|
329
|
-
verifiedDependencyDigest: null,
|
|
330
|
-
review: null,
|
|
331
|
-
artifact: null
|
|
332
|
-
} : {};
|
|
632
|
+
if (job.cloudBuildPending) throw new Error("Cloud packaging outcome is uncertain; reconcile the existing provider run rather than replaying it with retry");
|
|
333
633
|
const resumedConfig = {
|
|
334
634
|
...config,
|
|
335
|
-
packageTarget:
|
|
336
|
-
allowSubmit: job.config.allowSubmit,
|
|
337
|
-
allowRelease: job.config.allowRelease
|
|
635
|
+
packageTarget: config.packageTarget
|
|
338
636
|
};
|
|
637
|
+
const patch = verificationConfigChanged(job, resumedConfig) ? {
|
|
638
|
+
...invalidateVerification(),
|
|
639
|
+
stage: [
|
|
640
|
+
"verify",
|
|
641
|
+
"review",
|
|
642
|
+
"package"
|
|
643
|
+
].includes(job.stage) ? "verify" : job.stage
|
|
644
|
+
} : {};
|
|
645
|
+
validateJobConfig(job.spec, resumedConfig);
|
|
339
646
|
return {
|
|
340
647
|
...patch,
|
|
341
648
|
config: resumedConfig,
|
|
@@ -345,62 +652,7 @@ async function main() {
|
|
|
345
652
|
error: null
|
|
346
653
|
};
|
|
347
654
|
})));
|
|
348
|
-
} else
|
|
349
|
-
arity(args, 1, 1, "authorize <id> --submit [--release]");
|
|
350
|
-
if (!values.submit) throw new Error("authorize requires --submit");
|
|
351
|
-
print(view(store.transition(args[0], (job) => {
|
|
352
|
-
if (job.turn || ![
|
|
353
|
-
"ready",
|
|
354
|
-
"blocked",
|
|
355
|
-
"built"
|
|
356
|
-
].includes(job.status) || Object.keys(job.receipt).length || job.stage === "monitor") throw new Error("Publication permission can change only on stopped work before any remote intent");
|
|
357
|
-
const publishing = validateAppleSpec(job.spec);
|
|
358
|
-
if (values.release && !/^[A-Za-z]{2}$/.test(publishing.storefrontCountry ?? "")) throw new Error("--release requires apple.storefrontCountry in the immutable product specification");
|
|
359
|
-
return {
|
|
360
|
-
config: {
|
|
361
|
-
...job.config,
|
|
362
|
-
packageTarget: "ipa",
|
|
363
|
-
allowSubmit: true,
|
|
364
|
-
allowRelease: Boolean(values.release)
|
|
365
|
-
},
|
|
366
|
-
status: ["ready", "built"].includes(job.status) ? "queued" : "blocked",
|
|
367
|
-
nextAt: Date.now()
|
|
368
|
-
};
|
|
369
|
-
})));
|
|
370
|
-
} else if (command === "feedback") {
|
|
371
|
-
arity(args, 2, 2, "feedback <id> <file>");
|
|
372
|
-
const feedback = readInputFile(args[1], "App Review feedback").toString("utf8").trim();
|
|
373
|
-
if (!feedback) throw new Error("App Review feedback file is empty");
|
|
374
|
-
print(view(store.transition(args[0], (job) => {
|
|
375
|
-
if (job.turn || job.stage !== "monitor" || job.appleReview?.status !== "rejected" || job.status !== "blocked") throw new Error("feedback is only allowed for an observed App Review rejection");
|
|
376
|
-
const spec = structuredClone(job.spec);
|
|
377
|
-
if (!spec.apple?.buildNumber || !/^\d+$/.test(spec.apple.buildNumber)) throw new Error("A numeric apple.buildNumber is required to prepare a replacement build");
|
|
378
|
-
spec.apple.buildNumber = String(BigInt(spec.apple.buildNumber) + 1n);
|
|
379
|
-
return {
|
|
380
|
-
spec,
|
|
381
|
-
config: {
|
|
382
|
-
...config,
|
|
383
|
-
packageTarget: job.config.allowSubmit ? "ipa" : config.packageTarget,
|
|
384
|
-
allowSubmit: job.config.allowSubmit,
|
|
385
|
-
allowRelease: job.config.allowRelease
|
|
386
|
-
},
|
|
387
|
-
feedback,
|
|
388
|
-
status: "queued",
|
|
389
|
-
stage: "build",
|
|
390
|
-
createdAt: Date.now(),
|
|
391
|
-
attempts: {},
|
|
392
|
-
hostTurns: 0,
|
|
393
|
-
nextAt: Date.now(),
|
|
394
|
-
receipt: {},
|
|
395
|
-
ipaPath: null,
|
|
396
|
-
archiveDigest: null,
|
|
397
|
-
verifiedDigest: null,
|
|
398
|
-
verifiedDependencyDigest: null,
|
|
399
|
-
review: null,
|
|
400
|
-
error: null
|
|
401
|
-
};
|
|
402
|
-
})));
|
|
403
|
-
}
|
|
655
|
+
} else throw new Error(`Unknown command ${command}; use --help`);
|
|
404
656
|
} finally {
|
|
405
657
|
store.close();
|
|
406
658
|
}
|