fengming 0.3.10 → 0.3.11
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/dist/build-info.json +2 -2
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/cli-startup-metadata.json +8 -8
- package/dist/control-ui/assets/{activity-D-mnRThU.js → activity-wgT0-JR0.js} +2 -2
- package/dist/control-ui/assets/{agents-U_KSP5I_.js → agents-DG5PobrT.js} +2 -2
- package/dist/control-ui/assets/{channels-ohK9_G1O.js → channels-CX28oM42.js} +2 -2
- package/dist/control-ui/assets/{cron-6ZCzfU29.js → cron-B8ixwBqU.js} +2 -2
- package/dist/control-ui/assets/{debug-CSsDLg_s.js → debug-CnkYZUXy.js} +2 -2
- package/dist/control-ui/assets/{index-jUDczxhd.js → index-DQRZJKbO.js} +4 -4
- package/dist/control-ui/assets/{instances-782ZoDT4.js → instances-BE3mV1JC.js} +2 -2
- package/dist/control-ui/assets/{nodes-BMX16BKM.js → nodes-Cou4PWRX.js} +2 -2
- package/dist/control-ui/assets/{sessions-jLGSApYa.js → sessions-DpAaBT21.js} +2 -2
- package/dist/control-ui/assets/{skills-DweBwUhs.js → skills-DjA_j_20.js} +2 -2
- package/dist/control-ui/assets/{workboard-BsU-FXIo.js → workboard-BFnvbS0k.js} +2 -2
- package/dist/control-ui/index.html +1 -1
- package/dist/control-ui/sw.js +1 -1
- package/dist/gateway/protocol/index.d.ts +1 -1
- package/dist/{index-AZzJCgph.d.ts → index-DuDY3bCZ.d.ts} +2 -2
- package/dist/plugin-sdk/.boundary-entry-shims.stamp +1 -1
- package/dist/plugin-sdk/agent-config-primitives.d.ts +1 -1
- package/dist/plugin-sdk/{bundled-channel-config-schema-Dfn3b8sF.d.ts → bundled-channel-config-schema-BPFNnbwu.d.ts} +23 -23
- package/dist/plugin-sdk/bundled-channel-config-schema.d.ts +3 -3
- package/dist/plugin-sdk/channel-config-primitives.d.ts +2 -2
- package/dist/plugin-sdk/channel-config-schema-legacy.d.ts +3 -3
- package/dist/plugin-sdk/channel-config-schema.d.ts +2 -2
- package/dist/plugin-sdk/channel-core.d.ts +1 -1
- package/dist/plugin-sdk/channel-plugin-common.d.ts +1 -1
- package/dist/plugin-sdk/compat.d.ts +2 -2
- package/dist/plugin-sdk/{config-schema-DUddICQM.d.ts → config-schema-D7cABQ6o.d.ts} +1 -1
- package/dist/plugin-sdk/config-schema.d.ts +2 -2
- package/dist/plugin-sdk/core.d.ts +1 -1
- package/dist/plugin-sdk/discord.d.ts +2 -2
- package/dist/plugin-sdk/tts-runtime.d.ts +1 -1
- package/dist/plugin-sdk/{zod-schema.core-B4_b2R5K.d.ts → zod-schema.core-CwBNqcXp.d.ts} +1 -1
- package/package.json +4 -409
- package/CHANGELOG.md +0 -42
- package/THIRD_PARTY_NOTICES.md +0 -37
- package/docs/.i18n/README.md +0 -81
- package/docs/.i18n/ar-navigation.json +0 -18
- package/docs/.i18n/de-navigation.json +0 -18
- package/docs/.i18n/es-navigation.json +0 -18
- package/docs/.i18n/fr-navigation.json +0 -18
- package/docs/.i18n/glossary.ar.json +0 -78
- package/docs/.i18n/glossary.de.json +0 -78
- package/docs/.i18n/glossary.es.json +0 -78
- package/docs/.i18n/glossary.fa.json +0 -78
- package/docs/.i18n/glossary.fr.json +0 -78
- package/docs/.i18n/glossary.id.json +0 -78
- package/docs/.i18n/glossary.it.json +0 -78
- package/docs/.i18n/glossary.ja-JP.json +0 -98
- package/docs/.i18n/glossary.ko.json +0 -78
- package/docs/.i18n/glossary.nl.json +0 -78
- package/docs/.i18n/glossary.pl.json +0 -78
- package/docs/.i18n/glossary.pt-BR.json +0 -78
- package/docs/.i18n/glossary.th.json +0 -78
- package/docs/.i18n/glossary.tr.json +0 -78
- package/docs/.i18n/glossary.uk.json +0 -78
- package/docs/.i18n/glossary.vi.json +0 -78
- package/docs/.i18n/glossary.zh-CN.json +0 -1122
- package/docs/.i18n/glossary.zh-TW.json +0 -78
- package/docs/.i18n/id-navigation.json +0 -18
- package/docs/.i18n/it-navigation.json +0 -18
- package/docs/.i18n/ja-navigation.json +0 -18
- package/docs/.i18n/ko-navigation.json +0 -18
- package/docs/.i18n/pl-navigation.json +0 -18
- package/docs/.i18n/pt-BR-navigation.json +0 -18
- package/docs/.i18n/tr-navigation.json +0 -18
- package/docs/.i18n/translation-workflow.md +0 -111
- package/docs/.i18n/zh-Hans-navigation.json +0 -552
- package/docs/AGENTS.md +0 -36
- package/docs/CLAUDE.md +0 -1
- package/docs/agent-runtime-architecture.md +0 -48
- package/docs/announcements/bluebubbles-imessage.md +0 -79
- package/docs/auth-credential-semantics.md +0 -124
- package/docs/automation/auth-monitoring.md +0 -11
- package/docs/automation/clawflow.md +0 -12
- package/docs/automation/cron-jobs.md +0 -534
- package/docs/automation/cron-vs-heartbeat.md +0 -11
- package/docs/automation/gmail-pubsub.md +0 -11
- package/docs/automation/hooks.md +0 -387
- package/docs/automation/index.md +0 -135
- package/docs/automation/poll.md +0 -12
- package/docs/automation/standing-orders.md +0 -250
- package/docs/automation/taskflow.md +0 -155
- package/docs/automation/tasks.md +0 -374
- package/docs/automation/troubleshooting.md +0 -12
- package/docs/automation/webhook.md +0 -12
- package/docs/brave-search.md +0 -11
- package/docs/channels/access-groups.md +0 -201
- package/docs/channels/ambient-room-events.md +0 -214
- package/docs/channels/bot-loop-protection.md +0 -131
- package/docs/channels/broadcast-groups.md +0 -472
- package/docs/channels/channel-routing.md +0 -162
- package/docs/channels/clickclack.md +0 -138
- package/docs/channels/discord.md +0 -1758
- package/docs/channels/feishu.md +0 -650
- package/docs/channels/googlechat.md +0 -284
- package/docs/channels/group-messages.md +0 -95
- package/docs/channels/groups.md +0 -524
- package/docs/channels/imessage-from-bluebubbles.md +0 -259
- package/docs/channels/imessage.md +0 -839
- package/docs/channels/index.md +0 -64
- package/docs/channels/irc.md +0 -253
- package/docs/channels/line.md +0 -243
- package/docs/channels/location.md +0 -71
- package/docs/channels/matrix-migration.md +0 -370
- package/docs/channels/matrix-presentation.md +0 -77
- package/docs/channels/matrix-push-rules.md +0 -150
- package/docs/channels/matrix.md +0 -921
- package/docs/channels/mattermost.md +0 -542
- package/docs/channels/msteams.md +0 -1096
- package/docs/channels/nextcloud-talk.md +0 -176
- package/docs/channels/nostr.md +0 -253
- package/docs/channels/pairing.md +0 -214
- package/docs/channels/qqbot.md +0 -314
- package/docs/channels/signal.md +0 -417
- package/docs/channels/slack.md +0 -1623
- package/docs/channels/synology-chat.md +0 -187
- package/docs/channels/telegram.md +0 -1124
- package/docs/channels/tlon.md +0 -296
- package/docs/channels/troubleshooting.md +0 -162
- package/docs/channels/twitch.md +0 -431
- package/docs/channels/wechat.md +0 -171
- package/docs/channels/whatsapp.md +0 -796
- package/docs/channels/yuanbao.md +0 -416
- package/docs/channels/zalo.md +0 -253
- package/docs/channels/zalouser.md +0 -217
- package/docs/ci.md +0 -657
- package/docs/clawhub/publishing.md +0 -96
- package/docs/cli/acp.md +0 -370
- package/docs/cli/agent.md +0 -109
- package/docs/cli/agents.md +0 -253
- package/docs/cli/approvals.md +0 -190
- package/docs/cli/backup.md +0 -98
- package/docs/cli/browser.md +0 -307
- package/docs/cli/channels.md +0 -154
- package/docs/cli/clawbot.md +0 -25
- package/docs/cli/commitments.md +0 -90
- package/docs/cli/completion.md +0 -39
- package/docs/cli/config.md +0 -504
- package/docs/cli/configure.md +0 -77
- package/docs/cli/crestodian.md +0 -337
- package/docs/cli/cron.md +0 -304
- package/docs/cli/daemon.md +0 -67
- package/docs/cli/dashboard.md +0 -33
- package/docs/cli/devices.md +0 -240
- package/docs/cli/directory.md +0 -68
- package/docs/cli/dns.md +0 -53
- package/docs/cli/docs.md +0 -63
- package/docs/cli/doctor.md +0 -241
- package/docs/cli/flows.md +0 -52
- package/docs/cli/gateway.md +0 -572
- package/docs/cli/health.md +0 -43
- package/docs/cli/hooks.md +0 -345
- package/docs/cli/index.md +0 -400
- package/docs/cli/infer.md +0 -364
- package/docs/cli/logs.md +0 -68
- package/docs/cli/mcp.md +0 -529
- package/docs/cli/memory.md +0 -183
- package/docs/cli/message.md +0 -317
- package/docs/cli/migrate.md +0 -334
- package/docs/cli/models.md +0 -239
- package/docs/cli/node.md +0 -177
- package/docs/cli/nodes.md +0 -76
- package/docs/cli/onboard.md +0 -250
- package/docs/cli/pairing.md +0 -77
- package/docs/cli/path.md +0 -511
- package/docs/cli/plugins.md +0 -459
- package/docs/cli/policy.md +0 -886
- package/docs/cli/proxy.md +0 -89
- package/docs/cli/qr.md +0 -56
- package/docs/cli/reset.md +0 -39
- package/docs/cli/sandbox.md +0 -208
- package/docs/cli/secrets.md +0 -202
- package/docs/cli/security.md +0 -136
- package/docs/cli/sessions.md +0 -164
- package/docs/cli/setup.md +0 -59
- package/docs/cli/skills.md +0 -122
- package/docs/cli/status.md +0 -45
- package/docs/cli/system.md +0 -89
- package/docs/cli/tasks.md +0 -111
- package/docs/cli/transcripts.md +0 -151
- package/docs/cli/tui.md +0 -91
- package/docs/cli/uninstall.md +0 -44
- package/docs/cli/update.md +0 -243
- package/docs/cli/voicecall.md +0 -204
- package/docs/cli/webhooks.md +0 -117
- package/docs/cli/wiki.md +0 -256
- package/docs/concepts/active-memory.md +0 -856
- package/docs/concepts/agent-loop.md +0 -185
- package/docs/concepts/agent-runtimes.md +0 -276
- package/docs/concepts/agent-workspace.md +0 -230
- package/docs/concepts/agent.md +0 -140
- package/docs/concepts/architecture.md +0 -154
- package/docs/concepts/channel-docking.md +0 -145
- package/docs/concepts/commitments.md +0 -150
- package/docs/concepts/compaction.md +0 -203
- package/docs/concepts/context-engine.md +0 -347
- package/docs/concepts/context.md +0 -199
- package/docs/concepts/delegate-architecture.md +0 -319
- package/docs/concepts/dreaming.md +0 -264
- package/docs/concepts/experimental-features.md +0 -109
- package/docs/concepts/features.md +0 -91
- package/docs/concepts/fengming-sdk.md +0 -323
- package/docs/concepts/mantis-slack-desktop-runbook.md +0 -231
- package/docs/concepts/mantis.md +0 -744
- package/docs/concepts/markdown-formatting.md +0 -139
- package/docs/concepts/memory-builtin.md +0 -148
- package/docs/concepts/memory-honcho.md +0 -144
- package/docs/concepts/memory-qmd.md +0 -271
- package/docs/concepts/memory-search.md +0 -167
- package/docs/concepts/memory.md +0 -299
- package/docs/concepts/message-lifecycle-refactor.md +0 -1126
- package/docs/concepts/messages.md +0 -214
- package/docs/concepts/model-failover.md +0 -384
- package/docs/concepts/model-providers.md +0 -719
- package/docs/concepts/models.md +0 -371
- package/docs/concepts/multi-agent.md +0 -625
- package/docs/concepts/oauth.md +0 -198
- package/docs/concepts/parallel-specialist-lanes.md +0 -127
- package/docs/concepts/personal-agent-benchmark-pack.md +0 -74
- package/docs/concepts/presence.md +0 -117
- package/docs/concepts/progress-drafts.md +0 -406
- package/docs/concepts/qa-e2e-automation.md +0 -947
- package/docs/concepts/qa-matrix.md +0 -139
- package/docs/concepts/queue-steering.md +0 -90
- package/docs/concepts/queue.md +0 -136
- package/docs/concepts/retry.md +0 -86
- package/docs/concepts/session-pruning.md +0 -104
- package/docs/concepts/session-tool.md +0 -188
- package/docs/concepts/session.md +0 -164
- package/docs/concepts/soul.md +0 -116
- package/docs/concepts/streaming.md +0 -257
- package/docs/concepts/system-prompt.md +0 -328
- package/docs/concepts/timezone.md +0 -47
- package/docs/concepts/typebox.md +0 -309
- package/docs/concepts/typing-indicators.md +0 -88
- package/docs/concepts/usage-tracking.md +0 -66
- package/docs/date-time.md +0 -126
- package/docs/debug/node-issue.md +0 -90
- package/docs/diagnostics/flags.md +0 -182
- package/docs/docs.json +0 -1862
- package/docs/fengming-agent-runtime.md +0 -82
- package/docs/gateway/authentication.md +0 -256
- package/docs/gateway/background-process.md +0 -147
- package/docs/gateway/bonjour.md +0 -303
- package/docs/gateway/bridge-protocol.md +0 -97
- package/docs/gateway/cli-backends.md +0 -439
- package/docs/gateway/config-agents.md +0 -1525
- package/docs/gateway/config-channels.md +0 -945
- package/docs/gateway/config-tools.md +0 -774
- package/docs/gateway/configuration-examples.md +0 -704
- package/docs/gateway/configuration-reference.md +0 -1391
- package/docs/gateway/configuration.md +0 -739
- package/docs/gateway/diagnostics.md +0 -213
- package/docs/gateway/discovery.md +0 -154
- package/docs/gateway/doctor.md +0 -575
- package/docs/gateway/gateway-lock.md +0 -37
- package/docs/gateway/health.md +0 -73
- package/docs/gateway/heartbeat.md +0 -498
- package/docs/gateway/index.md +0 -383
- package/docs/gateway/local-model-services.md +0 -205
- package/docs/gateway/local-models.md +0 -355
- package/docs/gateway/logging.md +0 -149
- package/docs/gateway/multiple-gateways.md +0 -178
- package/docs/gateway/network-model.md +0 -15
- package/docs/gateway/openai-http-api.md +0 -378
- package/docs/gateway/openresponses-http-api.md +0 -347
- package/docs/gateway/openshell.md +0 -316
- package/docs/gateway/opentelemetry.md +0 -433
- package/docs/gateway/operator-scopes.md +0 -119
- package/docs/gateway/pairing.md +0 -207
- package/docs/gateway/prometheus.md +0 -249
- package/docs/gateway/protocol.md +0 -826
- package/docs/gateway/remote-gateway-readme.md +0 -169
- package/docs/gateway/remote.md +0 -280
- package/docs/gateway/sandbox-vs-tool-policy-vs-elevated.md +0 -148
- package/docs/gateway/sandboxing.md +0 -546
- package/docs/gateway/secrets-plan-contract.md +0 -159
- package/docs/gateway/secrets.md +0 -805
- package/docs/gateway/security/audit-checks.md +0 -127
- package/docs/gateway/security/exposure-runbook.md +0 -212
- package/docs/gateway/security/index.md +0 -1343
- package/docs/gateway/security/secure-file-operations.md +0 -76
- package/docs/gateway/security/shrinkwrap.md +0 -111
- package/docs/gateway/tailscale.md +0 -156
- package/docs/gateway/tools-invoke-http-api.md +0 -169
- package/docs/gateway/troubleshooting.md +0 -877
- package/docs/gateway/trusted-proxy-auth.md +0 -483
- package/docs/help/debugging.md +0 -341
- package/docs/help/environment.md +0 -233
- package/docs/help/faq-first-run.md +0 -870
- package/docs/help/faq-models.md +0 -556
- package/docs/help/faq.md +0 -2041
- package/docs/help/index.md +0 -39
- package/docs/help/scripts.md +0 -56
- package/docs/help/testing-live.md +0 -587
- package/docs/help/testing-updates-plugins.md +0 -299
- package/docs/help/testing.md +0 -977
- package/docs/help/troubleshooting.md +0 -449
- package/docs/index.md +0 -196
- package/docs/install/ansible.md +0 -233
- package/docs/install/azure.md +0 -315
- package/docs/install/bun.md +0 -59
- package/docs/install/clawdock.md +0 -112
- package/docs/install/development-channels.md +0 -148
- package/docs/install/digitalocean.md +0 -174
- package/docs/install/docker-vm-runtime.md +0 -154
- package/docs/install/docker.md +0 -564
- package/docs/install/exe-dev.md +0 -201
- package/docs/install/fly.md +0 -524
- package/docs/install/gcp.md +0 -418
- package/docs/install/hetzner.md +0 -285
- package/docs/install/hostinger.md +0 -98
- package/docs/install/index.md +0 -232
- package/docs/install/installer.md +0 -447
- package/docs/install/kubernetes.md +0 -196
- package/docs/install/macos-vm.md +0 -281
- package/docs/install/migrating-claude.md +0 -165
- package/docs/install/migrating-hermes.md +0 -178
- package/docs/install/migrating.md +0 -137
- package/docs/install/nix.md +0 -112
- package/docs/install/node.md +0 -142
- package/docs/install/northflank.mdx +0 -44
- package/docs/install/oracle.md +0 -218
- package/docs/install/podman.md +0 -216
- package/docs/install/railway.mdx +0 -92
- package/docs/install/raspberry-pi.md +0 -234
- package/docs/install/render.mdx +0 -167
- package/docs/install/uninstall.md +0 -131
- package/docs/install/updating.md +0 -284
- package/docs/install/upstash.md +0 -96
- package/docs/logging.md +0 -320
- package/docs/nav-tabs-underline.js +0 -100
- package/docs/network.md +0 -72
- package/docs/nodes/audio.md +0 -216
- package/docs/nodes/camera.md +0 -166
- package/docs/nodes/images.md +0 -77
- package/docs/nodes/index.md +0 -439
- package/docs/nodes/location-command.md +0 -102
- package/docs/nodes/media-understanding.md +0 -495
- package/docs/nodes/talk.md +0 -160
- package/docs/nodes/troubleshooting.md +0 -123
- package/docs/nodes/voicewake.md +0 -93
- package/docs/perplexity.md +0 -11
- package/docs/plan/codex-context-engine-harness.md +0 -624
- package/docs/plan/ui-channels.md +0 -284
- package/docs/platforms/digitalocean.md +0 -12
- package/docs/platforms/easyrunner.md +0 -109
- package/docs/platforms/index.md +0 -51
- package/docs/platforms/linux.md +0 -141
- package/docs/platforms/mac/bundled-gateway.md +0 -79
- package/docs/platforms/mac/canvas.md +0 -128
- package/docs/platforms/mac/child-process.md +0 -72
- package/docs/platforms/mac/dev-setup.md +0 -112
- package/docs/platforms/mac/health.md +0 -39
- package/docs/platforms/mac/icon.md +0 -36
- package/docs/platforms/mac/logging.md +0 -62
- package/docs/platforms/mac/menu-bar.md +0 -93
- package/docs/platforms/mac/peekaboo.md +0 -96
- package/docs/platforms/mac/permissions.md +0 -73
- package/docs/platforms/mac/remote.md +0 -123
- package/docs/platforms/mac/signing.md +0 -52
- package/docs/platforms/mac/skills.md +0 -43
- package/docs/platforms/mac/voice-overlay.md +0 -66
- package/docs/platforms/mac/voicewake.md +0 -73
- package/docs/platforms/mac/webchat.md +0 -54
- package/docs/platforms/mac/xpc.md +0 -66
- package/docs/platforms/oracle.md +0 -12
- package/docs/platforms/raspberry-pi.md +0 -13
- package/docs/platforms/windows.md +0 -286
- package/docs/plugins/adding-capabilities.md +0 -146
- package/docs/plugins/admin-http-rpc.md +0 -216
- package/docs/plugins/agent-tools.md +0 -13
- package/docs/plugins/architecture-internals.md +0 -1196
- package/docs/plugins/architecture.md +0 -483
- package/docs/plugins/building-extensions.md +0 -13
- package/docs/plugins/building-plugins.md +0 -335
- package/docs/plugins/bundles.md +0 -310
- package/docs/plugins/cli-backend-plugins.md +0 -310
- package/docs/plugins/codex-computer-use.md +0 -297
- package/docs/plugins/codex-harness-reference.md +0 -470
- package/docs/plugins/codex-harness-runtime.md +0 -268
- package/docs/plugins/codex-harness.md +0 -780
- package/docs/plugins/codex-native-plugins.md +0 -276
- package/docs/plugins/community.md +0 -77
- package/docs/plugins/compatibility.md +0 -167
- package/docs/plugins/copilot.md +0 -356
- package/docs/plugins/dependency-resolution.md +0 -176
- package/docs/plugins/google-meet.md +0 -1737
- package/docs/plugins/hooks.md +0 -484
- package/docs/plugins/install-overrides.md +0 -80
- package/docs/plugins/manage-plugins.md +0 -210
- package/docs/plugins/manifest.md +0 -1457
- package/docs/plugins/memory-lancedb.md +0 -385
- package/docs/plugins/memory-wiki.md +0 -529
- package/docs/plugins/message-presentation.md +0 -473
- package/docs/plugins/oc-path.md +0 -166
- package/docs/plugins/plugin-inventory.md +0 -189
- package/docs/plugins/plugin-permission-requests.md +0 -193
- package/docs/plugins/reference/acpx.md +0 -23
- package/docs/plugins/reference/admin-http-rpc.md +0 -23
- package/docs/plugins/reference/alibaba.md +0 -23
- package/docs/plugins/reference/amazon-bedrock-mantle.md +0 -23
- package/docs/plugins/reference/amazon-bedrock.md +0 -23
- package/docs/plugins/reference/anthropic-vertex.md +0 -19
- package/docs/plugins/reference/anthropic.md +0 -23
- package/docs/plugins/reference/arcee.md +0 -23
- package/docs/plugins/reference/azure-speech.md +0 -23
- package/docs/plugins/reference/bonjour.md +0 -19
- package/docs/plugins/reference/brave.md +0 -23
- package/docs/plugins/reference/browser.md +0 -23
- package/docs/plugins/reference/byteplus.md +0 -19
- package/docs/plugins/reference/canvas.md +0 -19
- package/docs/plugins/reference/cerebras.md +0 -23
- package/docs/plugins/reference/chutes.md +0 -23
- package/docs/plugins/reference/clickclack.md +0 -23
- package/docs/plugins/reference/cloudflare-ai-gateway.md +0 -23
- package/docs/plugins/reference/codex-supervisor.md +0 -27
- package/docs/plugins/reference/codex.md +0 -23
- package/docs/plugins/reference/comfy.md +0 -23
- package/docs/plugins/reference/copilot-proxy.md +0 -19
- package/docs/plugins/reference/copilot.md +0 -23
- package/docs/plugins/reference/deepgram.md +0 -23
- package/docs/plugins/reference/deepinfra.md +0 -23
- package/docs/plugins/reference/deepseek.md +0 -23
- package/docs/plugins/reference/diagnostics-otel.md +0 -19
- package/docs/plugins/reference/diagnostics-prometheus.md +0 -19
- package/docs/plugins/reference/diffs-language-pack.md +0 -19
- package/docs/plugins/reference/diffs.md +0 -19
- package/docs/plugins/reference/discord.md +0 -23
- package/docs/plugins/reference/document-extract.md +0 -23
- package/docs/plugins/reference/duckduckgo.md +0 -23
- package/docs/plugins/reference/elevenlabs.md +0 -23
- package/docs/plugins/reference/exa.md +0 -23
- package/docs/plugins/reference/fal.md +0 -23
- package/docs/plugins/reference/feishu.md +0 -23
- package/docs/plugins/reference/file-transfer.md +0 -19
- package/docs/plugins/reference/firecrawl.md +0 -23
- package/docs/plugins/reference/fireworks.md +0 -23
- package/docs/plugins/reference/github-copilot.md +0 -23
- package/docs/plugins/reference/gmi.md +0 -23
- package/docs/plugins/reference/google-meet.md +0 -23
- package/docs/plugins/reference/google.md +0 -23
- package/docs/plugins/reference/googlechat.md +0 -23
- package/docs/plugins/reference/gradium.md +0 -23
- package/docs/plugins/reference/groq.md +0 -23
- package/docs/plugins/reference/huggingface.md +0 -23
- package/docs/plugins/reference/imessage.md +0 -23
- package/docs/plugins/reference/inworld.md +0 -23
- package/docs/plugins/reference/irc.md +0 -23
- package/docs/plugins/reference/kilocode.md +0 -23
- package/docs/plugins/reference/kimi.md +0 -23
- package/docs/plugins/reference/line.md +0 -23
- package/docs/plugins/reference/litellm.md +0 -23
- package/docs/plugins/reference/llm-task.md +0 -19
- package/docs/plugins/reference/lmstudio.md +0 -23
- package/docs/plugins/reference/lobster.md +0 -19
- package/docs/plugins/reference/matrix.md +0 -23
- package/docs/plugins/reference/mattermost.md +0 -23
- package/docs/plugins/reference/memory-core.md +0 -19
- package/docs/plugins/reference/memory-lancedb.md +0 -23
- package/docs/plugins/reference/memory-wiki.md +0 -23
- package/docs/plugins/reference/microsoft-foundry.md +0 -19
- package/docs/plugins/reference/microsoft.md +0 -19
- package/docs/plugins/reference/migrate-claude.md +0 -19
- package/docs/plugins/reference/migrate-hermes.md +0 -19
- package/docs/plugins/reference/minimax.md +0 -23
- package/docs/plugins/reference/mistral.md +0 -23
- package/docs/plugins/reference/moonshot.md +0 -23
- package/docs/plugins/reference/msteams.md +0 -23
- package/docs/plugins/reference/nextcloud-talk.md +0 -23
- package/docs/plugins/reference/nostr.md +0 -23
- package/docs/plugins/reference/novita.md +0 -23
- package/docs/plugins/reference/nvidia.md +0 -23
- package/docs/plugins/reference/oc-path.md +0 -23
- package/docs/plugins/reference/ollama.md +0 -23
- package/docs/plugins/reference/open-prose.md +0 -19
- package/docs/plugins/reference/openai.md +0 -23
- package/docs/plugins/reference/opencode-go.md +0 -23
- package/docs/plugins/reference/opencode.md +0 -23
- package/docs/plugins/reference/openrouter.md +0 -23
- package/docs/plugins/reference/openshell.md +0 -19
- package/docs/plugins/reference/perplexity.md +0 -23
- package/docs/plugins/reference/pixverse.md +0 -23
- package/docs/plugins/reference/policy.md +0 -72
- package/docs/plugins/reference/qa-channel.md +0 -23
- package/docs/plugins/reference/qa-lab.md +0 -19
- package/docs/plugins/reference/qa-matrix.md +0 -19
- package/docs/plugins/reference/qianfan.md +0 -23
- package/docs/plugins/reference/qqbot.md +0 -23
- package/docs/plugins/reference/qwen.md +0 -23
- package/docs/plugins/reference/runway.md +0 -23
- package/docs/plugins/reference/searxng.md +0 -19
- package/docs/plugins/reference/senseaudio.md +0 -23
- package/docs/plugins/reference/sglang.md +0 -23
- package/docs/plugins/reference/signal.md +0 -23
- package/docs/plugins/reference/skill-workshop.md +0 -23
- package/docs/plugins/reference/slack.md +0 -23
- package/docs/plugins/reference/stepfun.md +0 -23
- package/docs/plugins/reference/synology-chat.md +0 -23
- package/docs/plugins/reference/synthetic.md +0 -23
- package/docs/plugins/reference/tavily.md +0 -23
- package/docs/plugins/reference/telegram.md +0 -23
- package/docs/plugins/reference/tencent.md +0 -23
- package/docs/plugins/reference/tlon.md +0 -23
- package/docs/plugins/reference/together.md +0 -23
- package/docs/plugins/reference/tokenjuice.md +0 -23
- package/docs/plugins/reference/tts-local-cli.md +0 -19
- package/docs/plugins/reference/twitch.md +0 -23
- package/docs/plugins/reference/venice.md +0 -23
- package/docs/plugins/reference/vercel-ai-gateway.md +0 -23
- package/docs/plugins/reference/vllm.md +0 -23
- package/docs/plugins/reference/voice-call.md +0 -23
- package/docs/plugins/reference/volcengine.md +0 -23
- package/docs/plugins/reference/voyage.md +0 -19
- package/docs/plugins/reference/vydra.md +0 -23
- package/docs/plugins/reference/web-readability.md +0 -19
- package/docs/plugins/reference/webhooks.md +0 -23
- package/docs/plugins/reference/whatsapp.md +0 -23
- package/docs/plugins/reference/workboard.md +0 -23
- package/docs/plugins/reference/xai.md +0 -23
- package/docs/plugins/reference/xiaomi.md +0 -23
- package/docs/plugins/reference/zai.md +0 -23
- package/docs/plugins/reference/zalo.md +0 -23
- package/docs/plugins/reference/zalouser.md +0 -24
- package/docs/plugins/reference.md +0 -145
- package/docs/plugins/sdk-agent-harness.md +0 -338
- package/docs/plugins/sdk-channel-inbound.md +0 -70
- package/docs/plugins/sdk-channel-ingress.md +0 -137
- package/docs/plugins/sdk-channel-message.md +0 -18
- package/docs/plugins/sdk-channel-outbound.md +0 -113
- package/docs/plugins/sdk-channel-plugins.md +0 -765
- package/docs/plugins/sdk-channel-turn.md +0 -9
- package/docs/plugins/sdk-entrypoints.md +0 -344
- package/docs/plugins/sdk-migration.md +0 -979
- package/docs/plugins/sdk-overview.md +0 -511
- package/docs/plugins/sdk-provider-plugins.md +0 -846
- package/docs/plugins/sdk-runtime.md +0 -676
- package/docs/plugins/sdk-setup.md +0 -550
- package/docs/plugins/sdk-subpaths.md +0 -391
- package/docs/plugins/sdk-testing.md +0 -403
- package/docs/plugins/skill-workshop.md +0 -713
- package/docs/plugins/tool-plugins.md +0 -411
- package/docs/plugins/voice-call.md +0 -942
- package/docs/plugins/webhooks.md +0 -192
- package/docs/plugins/workboard.md +0 -252
- package/docs/plugins/zalouser.md +0 -86
- package/docs/prose.md +0 -137
- package/docs/providers/alibaba.md +0 -158
- package/docs/providers/anthropic.md +0 -381
- package/docs/providers/arcee.md +0 -144
- package/docs/providers/azure-speech.md +0 -119
- package/docs/providers/bedrock-mantle.md +0 -211
- package/docs/providers/bedrock.md +0 -414
- package/docs/providers/cerebras.md +0 -130
- package/docs/providers/chutes.md +0 -153
- package/docs/providers/claude-max-api-proxy.md +0 -191
- package/docs/providers/cloudflare-ai-gateway.md +0 -119
- package/docs/providers/comfy.md +0 -362
- package/docs/providers/deepgram.md +0 -184
- package/docs/providers/deepinfra.md +0 -92
- package/docs/providers/deepseek.md +0 -146
- package/docs/providers/ds4.md +0 -309
- package/docs/providers/elevenlabs.md +0 -130
- package/docs/providers/fal.md +0 -240
- package/docs/providers/fireworks.md +0 -144
- package/docs/providers/github-copilot.md +0 -257
- package/docs/providers/gmi.md +0 -92
- package/docs/providers/google.md +0 -472
- package/docs/providers/gradium.md +0 -123
- package/docs/providers/groq.md +0 -171
- package/docs/providers/huggingface.md +0 -235
- package/docs/providers/index.md +0 -105
- package/docs/providers/inferrs.md +0 -272
- package/docs/providers/inworld.md +0 -120
- package/docs/providers/kilocode.md +0 -135
- package/docs/providers/litellm.md +0 -234
- package/docs/providers/lmstudio.md +0 -224
- package/docs/providers/minimax.md +0 -505
- package/docs/providers/mistral.md +0 -235
- package/docs/providers/models.md +0 -64
- package/docs/providers/moonshot.md +0 -413
- package/docs/providers/novita.md +0 -92
- package/docs/providers/nvidia.md +0 -158
- package/docs/providers/ollama-cloud.md +0 -115
- package/docs/providers/ollama.md +0 -1225
- package/docs/providers/openai.md +0 -1093
- package/docs/providers/opencode-go.md +0 -123
- package/docs/providers/opencode.md +0 -149
- package/docs/providers/openrouter.md +0 -349
- package/docs/providers/perplexity-provider.md +0 -123
- package/docs/providers/pixverse.md +0 -165
- package/docs/providers/qianfan.md +0 -132
- package/docs/providers/qwen-oauth.md +0 -115
- package/docs/providers/qwen.md +0 -364
- package/docs/providers/runway.md +0 -103
- package/docs/providers/senseaudio.md +0 -68
- package/docs/providers/sglang.md +0 -161
- package/docs/providers/stepfun.md +0 -229
- package/docs/providers/synthetic.md +0 -154
- package/docs/providers/tencent.md +0 -130
- package/docs/providers/together.md +0 -140
- package/docs/providers/venice.md +0 -312
- package/docs/providers/vercel-ai-gateway.md +0 -128
- package/docs/providers/vllm.md +0 -407
- package/docs/providers/volcengine.md +0 -199
- package/docs/providers/vydra.md +0 -180
- package/docs/providers/xai.md +0 -571
- package/docs/providers/xiaomi.md +0 -262
- package/docs/providers/zai.md +0 -224
- package/docs/refactor/access.md +0 -9
- package/docs/refactor/acp.md +0 -298
- package/docs/refactor/canvas.md +0 -131
- package/docs/refactor/database-first.md +0 -2256
- package/docs/refactor/ingress-core.md +0 -341
- package/docs/reference/AGENTS.default.md +0 -131
- package/docs/reference/RELEASING.md +0 -799
- package/docs/reference/api-usage-costs.md +0 -208
- package/docs/reference/application-modernization-plan.md +0 -208
- package/docs/reference/code-mode.md +0 -773
- package/docs/reference/credits.md +0 -33
- package/docs/reference/device-models.md +0 -50
- package/docs/reference/fengming-sdk-api-design.md +0 -390
- package/docs/reference/full-release-validation.md +0 -202
- package/docs/reference/memory-config.md +0 -604
- package/docs/reference/prompt-caching.md +0 -358
- package/docs/reference/release-performance-sweep.md +0 -360
- package/docs/reference/rich-output-protocol.md +0 -101
- package/docs/reference/rpc.md +0 -43
- package/docs/reference/secret-placeholder-conventions.md +0 -33
- package/docs/reference/secretref-credential-surface.md +0 -159
- package/docs/reference/secretref-user-supplied-credentials-matrix.json +0 -663
- package/docs/reference/session-management-compaction.md +0 -474
- package/docs/reference/templates/AGENTS.dev.md +0 -90
- package/docs/reference/templates/AGENTS.md +0 -227
- package/docs/reference/templates/BOOT.md +0 -16
- package/docs/reference/templates/BOOTSTRAP.md +0 -66
- package/docs/reference/templates/CLAUDE.md +0 -1
- package/docs/reference/templates/HEARTBEAT.md +0 -24
- package/docs/reference/templates/IDENTITY.dev.md +0 -52
- package/docs/reference/templates/IDENTITY.md +0 -34
- package/docs/reference/templates/SOUL.dev.md +0 -82
- package/docs/reference/templates/SOUL.md +0 -49
- package/docs/reference/templates/TOOLS.dev.md +0 -29
- package/docs/reference/templates/TOOLS.md +0 -51
- package/docs/reference/templates/USER.dev.md +0 -23
- package/docs/reference/templates/USER.md +0 -28
- package/docs/reference/test.md +0 -247
- package/docs/reference/token-use.md +0 -246
- package/docs/reference/transcript-hygiene.md +0 -214
- package/docs/reference/wizard.md +0 -252
- package/docs/security/CONTRIBUTING-THREAT-MODEL.md +0 -101
- package/docs/security/THREAT-MODEL-ATLAS.md +0 -611
- package/docs/security/formal-verification.md +0 -170
- package/docs/security/incident-response.md +0 -59
- package/docs/security/network-proxy.md +0 -268
- package/docs/snippets/plugin-publish/minimal-fengming.plugin.json +0 -12
- package/docs/snippets/plugin-publish/minimal-package.json +0 -16
- package/docs/specs/claw-supervisor.md +0 -247
- package/docs/start/bootstrapping.md +0 -49
- package/docs/start/docs-directory.md +0 -69
- package/docs/start/fengming.md +0 -252
- package/docs/start/getting-started.md +0 -152
- package/docs/start/hubs.md +0 -201
- package/docs/start/lore.md +0 -223
- package/docs/start/onboarding-overview.md +0 -72
- package/docs/start/onboarding.md +0 -98
- package/docs/start/quickstart.md +0 -25
- package/docs/start/setup.md +0 -178
- package/docs/start/showcase.md +0 -363
- package/docs/start/wizard-cli-automation.md +0 -232
- package/docs/start/wizard-cli-reference.md +0 -331
- package/docs/start/wizard.md +0 -141
- package/docs/style.css +0 -137
- package/docs/superpowers/specs/2026-04-22-tweakcn-custom-theme-import-design.md +0 -316
- package/docs/tools/acp-agents-setup.md +0 -351
- package/docs/tools/acp-agents.md +0 -854
- package/docs/tools/agent-send.md +0 -130
- package/docs/tools/apply-patch.md +0 -64
- package/docs/tools/brave-search.md +0 -139
- package/docs/tools/browser-control.md +0 -391
- package/docs/tools/browser-linux-troubleshooting.md +0 -173
- package/docs/tools/browser-login.md +0 -77
- package/docs/tools/browser-wsl2-windows-remote-cdp-troubleshooting.md +0 -219
- package/docs/tools/browser.md +0 -810
- package/docs/tools/btw.md +0 -159
- package/docs/tools/capability-cookbook.md +0 -12
- package/docs/tools/clawhub.md +0 -5
- package/docs/tools/code-execution.md +0 -173
- package/docs/tools/creating-skills.md +0 -158
- package/docs/tools/diffs.md +0 -525
- package/docs/tools/duckduckgo-search.md +0 -109
- package/docs/tools/elevated.md +0 -128
- package/docs/tools/exa-search.md +0 -152
- package/docs/tools/exec-approvals-advanced.md +0 -444
- package/docs/tools/exec-approvals.md +0 -494
- package/docs/tools/exec.md +0 -285
- package/docs/tools/firecrawl.md +0 -155
- package/docs/tools/gemini-search.md +0 -114
- package/docs/tools/goal.md +0 -217
- package/docs/tools/grok-search.md +0 -129
- package/docs/tools/image-generation.md +0 -493
- package/docs/tools/index.md +0 -178
- package/docs/tools/kimi-search.md +0 -105
- package/docs/tools/llm-task.md +0 -137
- package/docs/tools/lobster.md +0 -365
- package/docs/tools/loop-detection.md +0 -154
- package/docs/tools/media-overview.md +0 -160
- package/docs/tools/minimax-search.md +0 -102
- package/docs/tools/multi-agent-sandbox-tools.md +0 -409
- package/docs/tools/music-generation.md +0 -372
- package/docs/tools/ollama-search.md +0 -153
- package/docs/tools/pdf.md +0 -213
- package/docs/tools/perplexity-search.md +0 -220
- package/docs/tools/plugin.md +0 -363
- package/docs/tools/reactions.md +0 -100
- package/docs/tools/searxng-search.md +0 -141
- package/docs/tools/skills-config.md +0 -195
- package/docs/tools/skills.md +0 -569
- package/docs/tools/slash-commands.md +0 -487
- package/docs/tools/steer.md +0 -77
- package/docs/tools/subagents.md +0 -651
- package/docs/tools/tavily.md +0 -162
- package/docs/tools/thinking.md +0 -142
- package/docs/tools/tokenjuice.md +0 -84
- package/docs/tools/tool-search.md +0 -269
- package/docs/tools/trajectory.md +0 -229
- package/docs/tools/tts.md +0 -1009
- package/docs/tools/video-generation.md +0 -555
- package/docs/tools/web-fetch.md +0 -210
- package/docs/tools/web.md +0 -461
- package/docs/tts.md +0 -11
- package/docs/vps.md +0 -139
- package/docs/web/control-ui.md +0 -512
- package/docs/web/dashboard.md +0 -107
- package/docs/web/index.md +0 -133
- package/docs/web/tui.md +0 -250
- package/docs/web/webchat.md +0 -102
- package/npm-shrinkwrap.json +0 -12861
- package/patches/.gitkeep +0 -0
- package/patches/@agentclientprotocol__claude-agent-acp@0.37.0.patch +0 -41
- package/pnpm-workspace.yaml +0 -120
- package/scripts/crabbox-wrapper.mjs +0 -2004
- package/scripts/lib/official-external-channel-catalog.json +0 -560
- package/scripts/lib/official-external-plugin-catalog.json +0 -264
- package/scripts/lib/official-external-provider-catalog.json +0 -158
- package/scripts/lib/package-dist-imports.mjs +0 -171
- package/scripts/npm-runner.mjs +0 -91
- package/scripts/postinstall-bundled-plugins.mjs +0 -978
- package/scripts/preinstall-package-manager-warning.mjs +0 -64
- package/scripts/prepare-git-hooks.mjs +0 -72
- package/scripts/windows-cmd-helpers.mjs +0 -22
- package/skills/batch/SKILL.md +0 -118
- package/skills/code-review/SKILL.md +0 -107
- package/skills/debug/SKILL.md +0 -83
- package/skills/loop/SKILL.md +0 -118
- package/skills/run/SKILL.md +0 -79
- package/skills/run-skill-generator/SKILL.md +0 -179
- package/skills/verify/SKILL.md +0 -103
- package/src/agents/templates/HEARTBEAT.md +0 -3
|
@@ -1,2004 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { spawn, spawnSync } from "node:child_process";
|
|
3
|
-
import {
|
|
4
|
-
accessSync,
|
|
5
|
-
chmodSync,
|
|
6
|
-
constants,
|
|
7
|
-
cpSync,
|
|
8
|
-
mkdirSync,
|
|
9
|
-
mkdtempSync,
|
|
10
|
-
readFileSync,
|
|
11
|
-
readdirSync,
|
|
12
|
-
rmSync,
|
|
13
|
-
statSync,
|
|
14
|
-
writeFileSync,
|
|
15
|
-
} from "node:fs";
|
|
16
|
-
import { tmpdir } from "node:os";
|
|
17
|
-
import { delimiter, dirname, extname, isAbsolute, relative, resolve } from "node:path";
|
|
18
|
-
import { fileURLToPath } from "node:url";
|
|
19
|
-
import { resolvePathEnvKey } from "./windows-cmd-helpers.mjs";
|
|
20
|
-
|
|
21
|
-
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
22
|
-
const ignoreRepoBinary = process.env.FENGMING_CRABBOX_WRAPPER_IGNORE_REPO_BINARY === "1";
|
|
23
|
-
const repoLocal = ignoreRepoBinary ? null : resolveCrabboxBinary(process.env, process.platform);
|
|
24
|
-
const pathLocal = resolvePathBinary("crabbox", process.env, process.platform);
|
|
25
|
-
const binary =
|
|
26
|
-
repoLocal ??
|
|
27
|
-
pathLocal ??
|
|
28
|
-
resolveGitCommonCrabboxBinary(process.env, process.platform) ??
|
|
29
|
-
"crabbox";
|
|
30
|
-
const args = process.argv.slice(2);
|
|
31
|
-
|
|
32
|
-
if (args[0] === "--") {
|
|
33
|
-
args.shift();
|
|
34
|
-
}
|
|
35
|
-
const userArgStart = args[0] === "actions" && args[1] === "hydrate" ? 2 : 1;
|
|
36
|
-
if (args[userArgStart] === "--") {
|
|
37
|
-
args.splice(userArgStart, 1);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function commandCandidates(command, platform) {
|
|
41
|
-
if (platform !== "win32") {
|
|
42
|
-
return [command];
|
|
43
|
-
}
|
|
44
|
-
if (extname(command)) {
|
|
45
|
-
return [command];
|
|
46
|
-
}
|
|
47
|
-
return [`${command}.exe`, `${command}.cmd`, `${command}.bat`, `${command}.com`, command];
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function resolveCrabboxBinary(env, platform) {
|
|
51
|
-
const base = resolve(repoRoot, "../crabbox/bin/crabbox");
|
|
52
|
-
for (const candidate of commandCandidates(base, platform)) {
|
|
53
|
-
if (isExecutableFile(candidate, platform)) {
|
|
54
|
-
return candidate;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function resolvePathBinary(command, env, platform) {
|
|
61
|
-
const pathValue = env[resolvePathEnvKey(env)] ?? "";
|
|
62
|
-
for (const dir of pathValue.split(delimiter).filter(Boolean)) {
|
|
63
|
-
for (const candidate of commandCandidates(command, platform)) {
|
|
64
|
-
const fullPath = resolve(dir, candidate);
|
|
65
|
-
if (isExecutableFile(fullPath, platform)) {
|
|
66
|
-
return fullPath;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
return null;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function resolveGitCommonCrabboxBinary(env, platform) {
|
|
74
|
-
const gitBinary = resolvePathBinary("git", env, platform) ?? "git";
|
|
75
|
-
const invocation = spawnInvocation(gitBinary, ["rev-parse", "--git-common-dir"], env, platform);
|
|
76
|
-
const result = spawnSync(invocation.command, invocation.args, {
|
|
77
|
-
cwd: repoRoot,
|
|
78
|
-
encoding: "utf8",
|
|
79
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
80
|
-
windowsVerbatimArguments: invocation.windowsVerbatimArguments,
|
|
81
|
-
});
|
|
82
|
-
if ((result.status ?? 1) !== 0) {
|
|
83
|
-
return null;
|
|
84
|
-
}
|
|
85
|
-
const gitCommonDir = result.stdout.trim();
|
|
86
|
-
if (!gitCommonDir) {
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
const absoluteGitCommonDir = isAbsolute(gitCommonDir)
|
|
90
|
-
? gitCommonDir
|
|
91
|
-
: resolve(repoRoot, gitCommonDir);
|
|
92
|
-
const base = resolve(absoluteGitCommonDir, "../..", "crabbox/bin/crabbox");
|
|
93
|
-
for (const candidate of commandCandidates(base, platform)) {
|
|
94
|
-
if (isExecutableFile(candidate, platform)) {
|
|
95
|
-
return candidate;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
return null;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function isExecutableFile(path, platform) {
|
|
102
|
-
try {
|
|
103
|
-
if (!statSync(path).isFile()) {
|
|
104
|
-
return false;
|
|
105
|
-
}
|
|
106
|
-
if (platform !== "win32") {
|
|
107
|
-
accessSync(path, constants.X_OK);
|
|
108
|
-
}
|
|
109
|
-
return true;
|
|
110
|
-
} catch {
|
|
111
|
-
return false;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function spawnInvocation(command, commandArgs, env, platform) {
|
|
116
|
-
const extension = extname(command).toLowerCase();
|
|
117
|
-
if (platform === "win32" && (extension === ".cmd" || extension === ".bat")) {
|
|
118
|
-
return {
|
|
119
|
-
command: env.ComSpec ?? "cmd.exe",
|
|
120
|
-
args: ["/d", "/s", "/c", buildBatchCommandLine(command, commandArgs)],
|
|
121
|
-
windowsVerbatimArguments: true,
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
return { command, args: commandArgs };
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const cmdMetaCharactersRe = /([()\][%!^"`<>&|;, *?])/g;
|
|
128
|
-
const jsRuntimeEntrypoints = new Set(["pnpm", "npm", "npx", "corepack", "node", "yarn", "bun"]);
|
|
129
|
-
const awsMacosCorepackEntrypoints = new Set(["pnpm", "yarn", "corepack"]);
|
|
130
|
-
const shellControlCommandPrefixes = new Set([
|
|
131
|
-
"if",
|
|
132
|
-
"while",
|
|
133
|
-
"until",
|
|
134
|
-
"then",
|
|
135
|
-
"do",
|
|
136
|
-
"else",
|
|
137
|
-
"elif",
|
|
138
|
-
"!",
|
|
139
|
-
]);
|
|
140
|
-
const shellCommandExecutionPrefixes = new Set(["exec"]);
|
|
141
|
-
const shellInlineCommandInterpreters = new Set(["bash", "dash", "ksh", "sh", "zsh"]);
|
|
142
|
-
const shellInlineCommandOptionsWithNextValue = new Set([
|
|
143
|
-
"+O",
|
|
144
|
-
"+o",
|
|
145
|
-
"-O",
|
|
146
|
-
"-o",
|
|
147
|
-
"--init-file",
|
|
148
|
-
"--rcfile",
|
|
149
|
-
]);
|
|
150
|
-
|
|
151
|
-
function escapeBatchCommand(command) {
|
|
152
|
-
return `${command}`.replace(cmdMetaCharactersRe, "^$1");
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function escapeBatchArgument(arg) {
|
|
156
|
-
let escaped = `${arg}`;
|
|
157
|
-
escaped = escaped.replace(/(?=(\\+?)?)\1"/g, '$1$1\\"');
|
|
158
|
-
escaped = escaped.replace(/(?=(\\+?)?)\1$/, "$1$1");
|
|
159
|
-
escaped = `"${escaped}"`;
|
|
160
|
-
escaped = escaped.replace(cmdMetaCharactersRe, "^$1");
|
|
161
|
-
return escaped.replace(cmdMetaCharactersRe, "^$1");
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
function buildBatchCommandLine(command, commandArgs) {
|
|
165
|
-
const escapedCommand = escapeBatchCommand(command);
|
|
166
|
-
const escapedArgs = commandArgs.map(escapeBatchArgument);
|
|
167
|
-
return `"${[escapedCommand, ...escapedArgs].join(" ")}"`;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
function checkedOutput(command, commandArgs) {
|
|
171
|
-
const invocation = spawnInvocation(command, commandArgs, process.env, process.platform);
|
|
172
|
-
const result = spawnSync(invocation.command, invocation.args, {
|
|
173
|
-
cwd: repoRoot,
|
|
174
|
-
encoding: "utf8",
|
|
175
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
176
|
-
windowsVerbatimArguments: invocation.windowsVerbatimArguments,
|
|
177
|
-
});
|
|
178
|
-
return {
|
|
179
|
-
status: result.status ?? 1,
|
|
180
|
-
text: `${result.stdout ?? ""}${result.stderr ?? ""}`.trim(),
|
|
181
|
-
stdout: (result.stdout ?? "").trim(),
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
function gitOutput(commandArgs) {
|
|
186
|
-
const gitBinary = resolvePathBinary("git", process.env, process.platform) ?? "git";
|
|
187
|
-
const invocation = spawnInvocation(gitBinary, commandArgs, process.env, process.platform);
|
|
188
|
-
const result = spawnSync(invocation.command, invocation.args, {
|
|
189
|
-
cwd: repoRoot,
|
|
190
|
-
encoding: "utf8",
|
|
191
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
192
|
-
windowsVerbatimArguments: invocation.windowsVerbatimArguments,
|
|
193
|
-
});
|
|
194
|
-
return {
|
|
195
|
-
status: result.status ?? 1,
|
|
196
|
-
text: `${result.stdout ?? ""}${result.stderr ?? ""}`.trim(),
|
|
197
|
-
stdout: (result.stdout ?? "").trim(),
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
function envProvider() {
|
|
202
|
-
const envProvider = process.env.CRABBOX_PROVIDER?.trim();
|
|
203
|
-
if (envProvider) {
|
|
204
|
-
return envProvider;
|
|
205
|
-
}
|
|
206
|
-
return "";
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
function configProvider() {
|
|
210
|
-
try {
|
|
211
|
-
const config = readFileSync(resolve(repoRoot, ".crabbox.yaml"), "utf8");
|
|
212
|
-
const match = config.match(/^provider:\s*([^\s#]+)/m);
|
|
213
|
-
return match?.[1] ?? "aws";
|
|
214
|
-
} catch {
|
|
215
|
-
return "aws";
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
function configuredProvider() {
|
|
220
|
-
return envProvider() || configProvider();
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
const runValueOptions = new Set([
|
|
224
|
-
"allow-env",
|
|
225
|
-
"artifact-glob",
|
|
226
|
-
"azure-location",
|
|
227
|
-
"azure-os-disk",
|
|
228
|
-
"azure-resource-group",
|
|
229
|
-
"azure-subnet",
|
|
230
|
-
"azure-vnet",
|
|
231
|
-
"blacksmith-job",
|
|
232
|
-
"blacksmith-org",
|
|
233
|
-
"blacksmith-ref",
|
|
234
|
-
"blacksmith-workflow",
|
|
235
|
-
"capture-stderr",
|
|
236
|
-
"capture-stdout",
|
|
237
|
-
"class",
|
|
238
|
-
"cloudflare-url",
|
|
239
|
-
"cloudflare-workdir",
|
|
240
|
-
"daytona-api-url",
|
|
241
|
-
"daytona-snapshot",
|
|
242
|
-
"daytona-ssh-access-minutes",
|
|
243
|
-
"daytona-ssh-gateway-host",
|
|
244
|
-
"daytona-target",
|
|
245
|
-
"daytona-user",
|
|
246
|
-
"daytona-work-root",
|
|
247
|
-
"download",
|
|
248
|
-
"env-from-profile",
|
|
249
|
-
"env-helper",
|
|
250
|
-
"e2b-api-url",
|
|
251
|
-
"e2b-domain",
|
|
252
|
-
"e2b-template",
|
|
253
|
-
"e2b-user",
|
|
254
|
-
"e2b-workdir",
|
|
255
|
-
"fresh-pr",
|
|
256
|
-
"id",
|
|
257
|
-
"idle-timeout",
|
|
258
|
-
"islo-base-url",
|
|
259
|
-
"islo-disk-gb",
|
|
260
|
-
"islo-gateway-profile",
|
|
261
|
-
"islo-image",
|
|
262
|
-
"islo-memory-mb",
|
|
263
|
-
"islo-snapshot-name",
|
|
264
|
-
"islo-vcpus",
|
|
265
|
-
"islo-workdir",
|
|
266
|
-
"junit",
|
|
267
|
-
"label",
|
|
268
|
-
"market",
|
|
269
|
-
"modal-app",
|
|
270
|
-
"modal-image",
|
|
271
|
-
"modal-python",
|
|
272
|
-
"modal-workdir",
|
|
273
|
-
"namespace-auto-stop-idle-timeout",
|
|
274
|
-
"namespace-image",
|
|
275
|
-
"namespace-repository",
|
|
276
|
-
"namespace-site",
|
|
277
|
-
"namespace-size",
|
|
278
|
-
"namespace-volume-size-gb",
|
|
279
|
-
"namespace-work-root",
|
|
280
|
-
"network",
|
|
281
|
-
"preflight-tools",
|
|
282
|
-
"profile",
|
|
283
|
-
"proof-template",
|
|
284
|
-
"provider",
|
|
285
|
-
"proxmox-api-url",
|
|
286
|
-
"proxmox-bridge",
|
|
287
|
-
"proxmox-node",
|
|
288
|
-
"proxmox-pool",
|
|
289
|
-
"proxmox-storage",
|
|
290
|
-
"proxmox-template-id",
|
|
291
|
-
"proxmox-user",
|
|
292
|
-
"proxmox-work-root",
|
|
293
|
-
"script",
|
|
294
|
-
"scenario",
|
|
295
|
-
"semaphore-host",
|
|
296
|
-
"semaphore-idle-timeout",
|
|
297
|
-
"semaphore-machine",
|
|
298
|
-
"semaphore-os-image",
|
|
299
|
-
"semaphore-project",
|
|
300
|
-
"sprites-api-url",
|
|
301
|
-
"sprites-work-root",
|
|
302
|
-
"static-host",
|
|
303
|
-
"static-port",
|
|
304
|
-
"static-user",
|
|
305
|
-
"static-work-root",
|
|
306
|
-
"stop-after",
|
|
307
|
-
"tailscale-auth-key-env",
|
|
308
|
-
"tailscale-exit-node",
|
|
309
|
-
"tailscale-hostname-template",
|
|
310
|
-
"tailscale-tags",
|
|
311
|
-
"target",
|
|
312
|
-
"tensorlake-api-url",
|
|
313
|
-
"tensorlake-cli",
|
|
314
|
-
"tensorlake-cpus",
|
|
315
|
-
"tensorlake-disk-mb",
|
|
316
|
-
"tensorlake-image",
|
|
317
|
-
"tensorlake-memory-mb",
|
|
318
|
-
"tensorlake-namespace",
|
|
319
|
-
"tensorlake-organization-id",
|
|
320
|
-
"tensorlake-project-id",
|
|
321
|
-
"tensorlake-snapshot",
|
|
322
|
-
"tensorlake-timeout-secs",
|
|
323
|
-
"tensorlake-workdir",
|
|
324
|
-
"ttl",
|
|
325
|
-
"type",
|
|
326
|
-
"emit-proof",
|
|
327
|
-
"preset",
|
|
328
|
-
"preset-var",
|
|
329
|
-
"windows-mode",
|
|
330
|
-
]);
|
|
331
|
-
|
|
332
|
-
let runValueOptionsFromHelp;
|
|
333
|
-
|
|
334
|
-
function parseRunValueOptionsFromHelp(text) {
|
|
335
|
-
const names = new Set();
|
|
336
|
-
for (const line of text.split(/\r?\n/u)) {
|
|
337
|
-
const match = line.match(
|
|
338
|
-
/^\s+-{1,2}([a-z0-9][a-z0-9-]*)\s+(?:string|duration|int|float|value)\b/u,
|
|
339
|
-
);
|
|
340
|
-
if (match) {
|
|
341
|
-
names.add(match[1]);
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
return names;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
function currentRunValueOptions() {
|
|
348
|
-
if (!runValueOptionsFromHelp) {
|
|
349
|
-
runValueOptionsFromHelp = new Set([
|
|
350
|
-
...runValueOptions,
|
|
351
|
-
...parseRunValueOptionsFromHelp(help.text),
|
|
352
|
-
]);
|
|
353
|
-
}
|
|
354
|
-
return runValueOptionsFromHelp;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
function runOptionName(arg) {
|
|
358
|
-
return arg.replace(/^-+/u, "").split("=", 1)[0];
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
function runCommandBounds(commandArgs) {
|
|
362
|
-
if (commandArgs[0] !== "run") {
|
|
363
|
-
return { start: -1, optionEnd: commandArgs.length };
|
|
364
|
-
}
|
|
365
|
-
for (let index = 1; index < commandArgs.length; index += 1) {
|
|
366
|
-
const arg = commandArgs[index];
|
|
367
|
-
if (arg === "--") {
|
|
368
|
-
return { start: index + 1, optionEnd: index };
|
|
369
|
-
}
|
|
370
|
-
if (!arg.startsWith("-")) {
|
|
371
|
-
return { start: index, optionEnd: index };
|
|
372
|
-
}
|
|
373
|
-
if (!arg.includes("=") && currentRunValueOptions().has(runOptionName(arg))) {
|
|
374
|
-
index += 1;
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
return { start: -1, optionEnd: commandArgs.length };
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
function crabboxOptionArgs(commandArgs) {
|
|
381
|
-
const bounds = runCommandBounds(commandArgs);
|
|
382
|
-
if (commandArgs[0] === "run") {
|
|
383
|
-
return commandArgs.slice(0, bounds.optionEnd);
|
|
384
|
-
}
|
|
385
|
-
const delimiter = commandArgs.indexOf("--");
|
|
386
|
-
return delimiter >= 0 ? commandArgs.slice(0, delimiter) : commandArgs;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
function commandProvider(commandArgs) {
|
|
390
|
-
commandArgs = crabboxOptionArgs(commandArgs);
|
|
391
|
-
for (let index = 0; index < commandArgs.length; index += 1) {
|
|
392
|
-
const arg = commandArgs[index];
|
|
393
|
-
if (arg === "--provider" || arg === "-provider") {
|
|
394
|
-
return commandArgs[index + 1] ?? "";
|
|
395
|
-
}
|
|
396
|
-
if (arg.startsWith("--provider=") || arg.startsWith("-provider=")) {
|
|
397
|
-
return arg.slice(arg.indexOf("=") + 1);
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
return "";
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
function selectedProvider(commandArgs, advertisedProviders = []) {
|
|
404
|
-
const explicitProvider = commandProvider(commandArgs);
|
|
405
|
-
if (explicitProvider) {
|
|
406
|
-
return explicitProvider;
|
|
407
|
-
}
|
|
408
|
-
if (shouldPreferAzureForWindows(commandArgs, advertisedProviders)) {
|
|
409
|
-
return "azure";
|
|
410
|
-
}
|
|
411
|
-
return configuredProvider();
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
function shouldRequireBrokeredAws(commandArgs, providerName) {
|
|
415
|
-
if (process.env.FENGMING_CRABBOX_ALLOW_DIRECT_AWS === "1") {
|
|
416
|
-
return false;
|
|
417
|
-
}
|
|
418
|
-
const canonicalProvider = providerAliases.get(providerName) ?? providerName;
|
|
419
|
-
if (canonicalProvider !== "aws") {
|
|
420
|
-
return false;
|
|
421
|
-
}
|
|
422
|
-
if (commandArgs[0] === "run" || commandArgs[0] === "warmup") {
|
|
423
|
-
return true;
|
|
424
|
-
}
|
|
425
|
-
return commandArgs[0] === "actions" && commandArgs[1] === "hydrate";
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
function brokerAuthConfigured() {
|
|
429
|
-
const config = checkedOutput(binary, ["config", "show", "--json"]);
|
|
430
|
-
if (config.status !== 0) {
|
|
431
|
-
return false;
|
|
432
|
-
}
|
|
433
|
-
let parsed;
|
|
434
|
-
try {
|
|
435
|
-
parsed = JSON.parse(config.stdout || config.text);
|
|
436
|
-
} catch {
|
|
437
|
-
return false;
|
|
438
|
-
}
|
|
439
|
-
return Boolean(parsed?.coordinator && parsed?.brokerAuth === "configured");
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
function enforceBrokeredAws(commandArgs, providerName) {
|
|
443
|
-
if (!shouldRequireBrokeredAws(commandArgs, providerName) || brokerAuthConfigured()) {
|
|
444
|
-
return;
|
|
445
|
-
}
|
|
446
|
-
console.error(
|
|
447
|
-
[
|
|
448
|
-
"[crabbox] provider=aws requires a configured Crabbox broker for FengMing proof.",
|
|
449
|
-
"[crabbox] run `crabbox login --url https://crabbox.fengming.ai --provider aws`, then retry.",
|
|
450
|
-
"[crabbox] for intentional direct AWS provider debugging, set FENGMING_CRABBOX_ALLOW_DIRECT_AWS=1.",
|
|
451
|
-
].join("\n"),
|
|
452
|
-
);
|
|
453
|
-
process.exit(2);
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
function optionValue(commandArgs, name) {
|
|
457
|
-
commandArgs = crabboxOptionArgs(commandArgs);
|
|
458
|
-
for (let index = 0; index < commandArgs.length; index += 1) {
|
|
459
|
-
const arg = commandArgs[index];
|
|
460
|
-
if (arg === name || arg === name.replace(/^--/u, "-")) {
|
|
461
|
-
return commandArgs[index + 1] ?? "";
|
|
462
|
-
}
|
|
463
|
-
if (arg.startsWith(`${name}=`) || arg.startsWith(`${name.replace(/^--/u, "-")}=`)) {
|
|
464
|
-
return arg.slice(arg.indexOf("=") + 1);
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
return "";
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
function hasOption(commandArgs, name) {
|
|
471
|
-
commandArgs = crabboxOptionArgs(commandArgs);
|
|
472
|
-
const shortName = name.replace(/^--/u, "-");
|
|
473
|
-
for (const arg of commandArgs) {
|
|
474
|
-
if (
|
|
475
|
-
arg === name ||
|
|
476
|
-
arg === shortName ||
|
|
477
|
-
arg.startsWith(`${name}=`) ||
|
|
478
|
-
arg.startsWith(`${shortName}=`)
|
|
479
|
-
) {
|
|
480
|
-
return true;
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
return false;
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
function commandOptionEnd(commandArgs) {
|
|
487
|
-
if (commandArgs[0] === "run") {
|
|
488
|
-
return runCommandBounds(commandArgs).optionEnd;
|
|
489
|
-
}
|
|
490
|
-
const delimiter = commandArgs.indexOf("--");
|
|
491
|
-
return delimiter >= 0 ? delimiter : commandArgs.length;
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
function shouldPreferAzureForWindows(commandArgs, advertisedProviders = []) {
|
|
495
|
-
return (
|
|
496
|
-
["run", "warmup"].includes(commandArgs[0]) &&
|
|
497
|
-
isWindowsRemoteTarget(commandArgs) &&
|
|
498
|
-
!commandProvider(commandArgs) &&
|
|
499
|
-
!envProvider() &&
|
|
500
|
-
!hasOption(commandArgs, "--id") &&
|
|
501
|
-
advertisedProviders.includes("azure")
|
|
502
|
-
);
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
function ensureAzureWindowsProvider(commandArgs, providerName, advertisedProviders = []) {
|
|
506
|
-
if (providerName !== "azure" || !shouldPreferAzureForWindows(commandArgs, advertisedProviders)) {
|
|
507
|
-
return commandArgs;
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
const optionEnd = commandOptionEnd(commandArgs);
|
|
511
|
-
const normalizedArgs = [...commandArgs];
|
|
512
|
-
normalizedArgs.splice(optionEnd, 0, "--provider", "azure");
|
|
513
|
-
return normalizedArgs;
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
function ensureAwsMacOnDemandMarket(commandArgs, providerName) {
|
|
517
|
-
if (
|
|
518
|
-
!["run", "warmup"].includes(commandArgs[0]) ||
|
|
519
|
-
providerName !== "aws" ||
|
|
520
|
-
optionValue(commandArgs, "--target") !== "macos" ||
|
|
521
|
-
hasOption(commandArgs, "--market") ||
|
|
522
|
-
hasOption(commandArgs, "--id")
|
|
523
|
-
) {
|
|
524
|
-
return commandArgs;
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
const optionEnd = commandOptionEnd(commandArgs);
|
|
528
|
-
const normalizedArgs = [...commandArgs];
|
|
529
|
-
normalizedArgs.splice(optionEnd, 0, "--market", "on-demand");
|
|
530
|
-
return normalizedArgs;
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
const localPathRunOptions = new Set([
|
|
534
|
-
"capture-stderr",
|
|
535
|
-
"capture-stdout",
|
|
536
|
-
"emit-proof",
|
|
537
|
-
"env-from-profile",
|
|
538
|
-
"script",
|
|
539
|
-
]);
|
|
540
|
-
|
|
541
|
-
function repoRelativePath(value) {
|
|
542
|
-
if (!value || value === "-" || isAbsolute(value)) {
|
|
543
|
-
return value;
|
|
544
|
-
}
|
|
545
|
-
return resolve(repoRoot, value);
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
function repoRelativeDownload(value) {
|
|
549
|
-
const split = value.indexOf("=");
|
|
550
|
-
if (split < 0) {
|
|
551
|
-
return value;
|
|
552
|
-
}
|
|
553
|
-
const remote = value.slice(0, split + 1);
|
|
554
|
-
const local = value.slice(split + 1);
|
|
555
|
-
return `${remote}${repoRelativePath(local)}`;
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
function absolutizeLocalRunPaths(commandArgs) {
|
|
559
|
-
if (commandArgs[0] !== "run") {
|
|
560
|
-
return commandArgs;
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
const normalizedArgs = [...commandArgs];
|
|
564
|
-
const { optionEnd } = runCommandBounds(normalizedArgs);
|
|
565
|
-
for (let index = 1; index < optionEnd; index += 1) {
|
|
566
|
-
const arg = normalizedArgs[index];
|
|
567
|
-
if (!arg.startsWith("-")) {
|
|
568
|
-
continue;
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
const optionName = runOptionName(arg);
|
|
572
|
-
const absolutize = optionName === "download" ? repoRelativeDownload : repoRelativePath;
|
|
573
|
-
if (localPathRunOptions.has(optionName) || optionName === "download") {
|
|
574
|
-
const equals = arg.indexOf("=");
|
|
575
|
-
if (equals >= 0) {
|
|
576
|
-
normalizedArgs[index] = `${arg.slice(0, equals + 1)}${absolutize(arg.slice(equals + 1))}`;
|
|
577
|
-
} else if (index + 1 < optionEnd) {
|
|
578
|
-
normalizedArgs[index + 1] = absolutize(normalizedArgs[index + 1]);
|
|
579
|
-
index += 1;
|
|
580
|
-
}
|
|
581
|
-
continue;
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
if (!arg.includes("=") && currentRunValueOptions().has(optionName)) {
|
|
585
|
-
index += 1;
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
return normalizedArgs;
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
function pathExists(path) {
|
|
592
|
-
try {
|
|
593
|
-
statSync(path);
|
|
594
|
-
return true;
|
|
595
|
-
} catch {
|
|
596
|
-
return false;
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
function preserveTemporaryCrabboxRuns() {
|
|
601
|
-
if (childCwd === repoRoot) {
|
|
602
|
-
return;
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
const sourceRuns = resolve(childCwd, ".crabbox", "runs");
|
|
606
|
-
if (!pathExists(sourceRuns)) {
|
|
607
|
-
return;
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
const targetRuns = resolve(repoRoot, ".crabbox", "runs");
|
|
611
|
-
mkdirSync(targetRuns, { recursive: true });
|
|
612
|
-
let preserved = 0;
|
|
613
|
-
for (const entry of readdirSync(sourceRuns)) {
|
|
614
|
-
cpSync(resolve(sourceRuns, entry), resolve(targetRuns, entry), {
|
|
615
|
-
recursive: true,
|
|
616
|
-
force: true,
|
|
617
|
-
});
|
|
618
|
-
preserved += 1;
|
|
619
|
-
}
|
|
620
|
-
if (preserved > 0) {
|
|
621
|
-
console.error(
|
|
622
|
-
`[crabbox] preserved ${preserved} temporary run artifact ${preserved === 1 ? "directory" : "directories"} under ${relative(repoRoot, targetRuns)}`,
|
|
623
|
-
);
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
function shellQuote(value) {
|
|
628
|
-
const text = `${value}`;
|
|
629
|
-
if (text === "") {
|
|
630
|
-
return "''";
|
|
631
|
-
}
|
|
632
|
-
if (/^[A-Za-z0-9_./:=@%+-]+$/u.test(text)) {
|
|
633
|
-
return text;
|
|
634
|
-
}
|
|
635
|
-
return `'${text.replaceAll("'", "'\\''")}'`;
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
function shellJoin(commandArgs) {
|
|
639
|
-
return commandArgs.map(shellQuote).join(" ");
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
function isLocalContainerProvider(providerName) {
|
|
643
|
-
return ["local-container", "docker", "container", "local-docker"].includes(providerName);
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
function runCommandArgs(commandArgs) {
|
|
647
|
-
const { start } = runCommandBounds(commandArgs);
|
|
648
|
-
return start >= 0 ? commandArgs.slice(start) : [];
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
function normalizedCommandWords(commandArgs) {
|
|
652
|
-
const words = commandArgs.length === 1 ? commandArgs[0].split(/\s+/u) : [...commandArgs];
|
|
653
|
-
while (/^[A-Za-z_][A-Za-z0-9_]*=/.test(words[0] ?? "")) {
|
|
654
|
-
words.shift();
|
|
655
|
-
}
|
|
656
|
-
return words.map((word) => word.replace(/^['"]|['";|&()]+$/g, ""));
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
function commandRuntimeEntrypoint(commandArgs) {
|
|
660
|
-
if (commandArgs.length === 1) {
|
|
661
|
-
for (const candidateWords of shellCommandWordCandidates(commandArgs[0])) {
|
|
662
|
-
const shellRuntime = commandWordsRuntimeEntrypoint(candidateWords);
|
|
663
|
-
if (shellRuntime) {
|
|
664
|
-
return shellRuntime;
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
return "";
|
|
668
|
-
}
|
|
669
|
-
const words = normalizedCommandWords(commandArgs);
|
|
670
|
-
const directRuntime = commandWordsRuntimeEntrypoint(words);
|
|
671
|
-
if (directRuntime) {
|
|
672
|
-
return directRuntime;
|
|
673
|
-
}
|
|
674
|
-
return "";
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
function commandWordsRuntimeEntrypoint(words) {
|
|
678
|
-
words = normalizeExecutableWords(words);
|
|
679
|
-
const first = (words[0] ?? "").split("/").pop();
|
|
680
|
-
if (jsRuntimeEntrypoints.has(first)) {
|
|
681
|
-
return first;
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
const inlineCommand = shellInlineCommand(words);
|
|
685
|
-
if (!inlineCommand) {
|
|
686
|
-
return "";
|
|
687
|
-
}
|
|
688
|
-
for (const candidateWords of shellCommandWordCandidates(inlineCommand)) {
|
|
689
|
-
const shellRuntime = commandWordsRuntimeEntrypoint(candidateWords);
|
|
690
|
-
if (shellRuntime) {
|
|
691
|
-
return shellRuntime;
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
return "";
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
function commandNeedsAwsMacosPackageManager(commandArgs) {
|
|
698
|
-
if (isChangedGateCommand(commandArgs)) {
|
|
699
|
-
return true;
|
|
700
|
-
}
|
|
701
|
-
if (commandArgs.length === 1) {
|
|
702
|
-
return shellCommandWordCandidates(commandArgs[0]).some(commandWordsNeedAwsMacosPackageManager);
|
|
703
|
-
}
|
|
704
|
-
return commandWordsNeedAwsMacosPackageManager(normalizedCommandWords(commandArgs));
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
function commandWordsNeedAwsMacosPackageManager(words) {
|
|
708
|
-
words = normalizeExecutableWords(words);
|
|
709
|
-
const first = (words[0] ?? "").split("/").pop();
|
|
710
|
-
if (awsMacosCorepackEntrypoints.has(first)) {
|
|
711
|
-
return true;
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
const inlineCommand = shellInlineCommand(words);
|
|
715
|
-
if (!inlineCommand) {
|
|
716
|
-
return false;
|
|
717
|
-
}
|
|
718
|
-
return shellCommandWordCandidates(inlineCommand).some(commandWordsNeedAwsMacosPackageManager);
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
function isChangedGateCommand(commandArgs) {
|
|
722
|
-
if (commandArgs.length === 1) {
|
|
723
|
-
return shellCommandWordCandidates(commandArgs[0]).some(isChangedGateCommandWords);
|
|
724
|
-
}
|
|
725
|
-
const words = normalizedCommandWords(commandArgs);
|
|
726
|
-
return isChangedGateCommandWords(words);
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
function isChangedGateCommandWords(words) {
|
|
730
|
-
words = normalizeExecutableWords(words);
|
|
731
|
-
if (isChangedGateWords(words)) {
|
|
732
|
-
return true;
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
const inlineCommand = shellInlineCommand(words);
|
|
736
|
-
return inlineCommand
|
|
737
|
-
? shellCommandWordCandidates(inlineCommand).some(isChangedGateCommandWords)
|
|
738
|
-
: false;
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
function isChangedGateWords(words) {
|
|
742
|
-
words = normalizeExecutableWords(words);
|
|
743
|
-
if (words[0] === "corepack") {
|
|
744
|
-
words.shift();
|
|
745
|
-
}
|
|
746
|
-
return (
|
|
747
|
-
(words[0] === "pnpm" && words[1] === "check:changed") ||
|
|
748
|
-
(words[0] === "pnpm" && words[1] === "run" && words[2] === "check:changed") ||
|
|
749
|
-
(words[0] === "node" && (words[1] ?? "").endsWith("scripts/check-changed.mjs"))
|
|
750
|
-
);
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
function shellInlineCommand(words) {
|
|
754
|
-
const command = shellWordBasename(words[0]);
|
|
755
|
-
if (!shellInlineCommandInterpreters.has(command)) {
|
|
756
|
-
return "";
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
for (let index = 1; index < words.length; index += 1) {
|
|
760
|
-
const word = words[index];
|
|
761
|
-
if (word === "--") {
|
|
762
|
-
return "";
|
|
763
|
-
}
|
|
764
|
-
if (!word.startsWith("-") && !word.startsWith("+")) {
|
|
765
|
-
return "";
|
|
766
|
-
}
|
|
767
|
-
if (word === "-c" || /^-[^-]*c/u.test(word)) {
|
|
768
|
-
return words[index + 1] ?? "";
|
|
769
|
-
}
|
|
770
|
-
if (shellInlineCommandOptionConsumesNextValue(word)) {
|
|
771
|
-
index += 1;
|
|
772
|
-
}
|
|
773
|
-
}
|
|
774
|
-
return "";
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
function shellInlineCommandOptionConsumesNextValue(word) {
|
|
778
|
-
return shellInlineCommandOptionsWithNextValue.has(word) || /^[+-][^-+]*[oO]$/u.test(word);
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
function shellCommandWordCandidates(command) {
|
|
782
|
-
return shellCommandSegments(stripHeredocBodies(command.replace(/\\\r?\n/gu, " ")));
|
|
783
|
-
}
|
|
784
|
-
|
|
785
|
-
function pushShellCandidate(candidates, segment) {
|
|
786
|
-
const words = normalizedShellSegmentWords(segment);
|
|
787
|
-
if (words.length > 0) {
|
|
788
|
-
candidates.push(words);
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
function normalizedShellSegmentWords(segment) {
|
|
793
|
-
const trimmed = segment.trim().replace(/^[({]\s*/u, "");
|
|
794
|
-
if (!trimmed || trimmed.startsWith("#")) {
|
|
795
|
-
return [];
|
|
796
|
-
}
|
|
797
|
-
const words = normalizedCommandWords(splitShellWords(trimmed));
|
|
798
|
-
while (shellControlCommandPrefixes.has(words[0])) {
|
|
799
|
-
words.shift();
|
|
800
|
-
}
|
|
801
|
-
const normalizedWords = normalizedCommandWords(words);
|
|
802
|
-
return normalizedCommandWords(stripShellExecutionPrefixes(normalizedWords));
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
function normalizeExecutableWords(words) {
|
|
806
|
-
return normalizedCommandWords(stripShellExecutionPrefixes(words));
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
function stripShellExecutionPrefixes(words) {
|
|
810
|
-
words = [...words];
|
|
811
|
-
for (;;) {
|
|
812
|
-
const first = shellWordBasename(words[0]);
|
|
813
|
-
if (shellCommandExecutionPrefixes.has(first)) {
|
|
814
|
-
words.shift();
|
|
815
|
-
continue;
|
|
816
|
-
}
|
|
817
|
-
if (first === "command") {
|
|
818
|
-
words.shift();
|
|
819
|
-
if (!stripCommandBuiltinOptions(words)) {
|
|
820
|
-
return words;
|
|
821
|
-
}
|
|
822
|
-
continue;
|
|
823
|
-
}
|
|
824
|
-
if (first === "env") {
|
|
825
|
-
if (!stripEnvCommandOptions(words, { canShimIgnoreEnvironment: false })) {
|
|
826
|
-
return words;
|
|
827
|
-
}
|
|
828
|
-
continue;
|
|
829
|
-
}
|
|
830
|
-
if (first === "time") {
|
|
831
|
-
words.shift();
|
|
832
|
-
stripTimeOptions(words);
|
|
833
|
-
continue;
|
|
834
|
-
}
|
|
835
|
-
if (first === "timeout") {
|
|
836
|
-
stripTimeoutOptions(words);
|
|
837
|
-
continue;
|
|
838
|
-
}
|
|
839
|
-
return words;
|
|
840
|
-
}
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
function stripEnvCommandOptions(words, { canShimIgnoreEnvironment = true } = {}) {
|
|
844
|
-
const originalWords = [...words];
|
|
845
|
-
const envCommand = words.shift() ?? "";
|
|
846
|
-
let ignoresEnvironment = false;
|
|
847
|
-
for (;;) {
|
|
848
|
-
const word = words[0] ?? "";
|
|
849
|
-
if (!word) {
|
|
850
|
-
words.splice(0, words.length, ...originalWords);
|
|
851
|
-
return false;
|
|
852
|
-
}
|
|
853
|
-
if (word === "--") {
|
|
854
|
-
words.shift();
|
|
855
|
-
return true;
|
|
856
|
-
}
|
|
857
|
-
if (/^[A-Za-z_][A-Za-z0-9_]*=/.test(word)) {
|
|
858
|
-
words.shift();
|
|
859
|
-
continue;
|
|
860
|
-
}
|
|
861
|
-
if (word === "-S" || word === "--split-string") {
|
|
862
|
-
if (ignoresEnvironment) {
|
|
863
|
-
words.splice(0, words.length, ...originalWords);
|
|
864
|
-
return false;
|
|
865
|
-
}
|
|
866
|
-
words.shift();
|
|
867
|
-
const split = splitShellWords(words.shift() ?? "");
|
|
868
|
-
words.unshift(...split);
|
|
869
|
-
return words.length > 0;
|
|
870
|
-
}
|
|
871
|
-
if (word.startsWith("-S") && word !== "-S") {
|
|
872
|
-
if (ignoresEnvironment) {
|
|
873
|
-
words.splice(0, words.length, ...originalWords);
|
|
874
|
-
return false;
|
|
875
|
-
}
|
|
876
|
-
words.shift();
|
|
877
|
-
words.unshift(...splitShellWords(word.slice(2)));
|
|
878
|
-
return words.length > 0;
|
|
879
|
-
}
|
|
880
|
-
if (word.startsWith("--split-string=")) {
|
|
881
|
-
if (ignoresEnvironment) {
|
|
882
|
-
words.splice(0, words.length, ...originalWords);
|
|
883
|
-
return false;
|
|
884
|
-
}
|
|
885
|
-
words.shift();
|
|
886
|
-
words.unshift(...splitShellWords(word.slice("--split-string=".length)));
|
|
887
|
-
return words.length > 0;
|
|
888
|
-
}
|
|
889
|
-
if (word === "-i" || word === "--ignore-environment") {
|
|
890
|
-
if (!canShimIgnoreEnvironment || envCommand.includes("/")) {
|
|
891
|
-
words.splice(0, words.length, ...originalWords);
|
|
892
|
-
return false;
|
|
893
|
-
}
|
|
894
|
-
ignoresEnvironment = true;
|
|
895
|
-
words.shift();
|
|
896
|
-
continue;
|
|
897
|
-
}
|
|
898
|
-
if (word === "-u" || word === "--unset" || word === "-C" || word === "--chdir") {
|
|
899
|
-
words.shift();
|
|
900
|
-
if (words[0]) {
|
|
901
|
-
words.shift();
|
|
902
|
-
}
|
|
903
|
-
continue;
|
|
904
|
-
}
|
|
905
|
-
if (word.startsWith("--unset=") || word.startsWith("--chdir=")) {
|
|
906
|
-
words.shift();
|
|
907
|
-
continue;
|
|
908
|
-
}
|
|
909
|
-
if (word.startsWith("-") && word !== "-") {
|
|
910
|
-
if (word.includes("i")) {
|
|
911
|
-
if (!canShimIgnoreEnvironment || envCommand.includes("/")) {
|
|
912
|
-
words.splice(0, words.length, ...originalWords);
|
|
913
|
-
return false;
|
|
914
|
-
}
|
|
915
|
-
ignoresEnvironment = true;
|
|
916
|
-
}
|
|
917
|
-
words.shift();
|
|
918
|
-
continue;
|
|
919
|
-
}
|
|
920
|
-
if (ignoresEnvironment && (!canShimIgnoreEnvironment || envCommand.includes("/"))) {
|
|
921
|
-
words.splice(0, words.length, ...originalWords);
|
|
922
|
-
return false;
|
|
923
|
-
}
|
|
924
|
-
return true;
|
|
925
|
-
}
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
function shellWordBasename(word) {
|
|
929
|
-
return (word ?? "").split("/").pop() ?? "";
|
|
930
|
-
}
|
|
931
|
-
|
|
932
|
-
function stripCommandBuiltinOptions(words) {
|
|
933
|
-
for (;;) {
|
|
934
|
-
if (words[0] === "--") {
|
|
935
|
-
words.shift();
|
|
936
|
-
return true;
|
|
937
|
-
}
|
|
938
|
-
if (words[0] === "-p") {
|
|
939
|
-
words.shift();
|
|
940
|
-
continue;
|
|
941
|
-
}
|
|
942
|
-
return words[0] !== "-v" && words[0] !== "-V";
|
|
943
|
-
}
|
|
944
|
-
}
|
|
945
|
-
|
|
946
|
-
function stripTimeOptions(words) {
|
|
947
|
-
while ((words[0] ?? "").startsWith("-")) {
|
|
948
|
-
if (words[0] === "--") {
|
|
949
|
-
words.shift();
|
|
950
|
-
return;
|
|
951
|
-
}
|
|
952
|
-
words.shift();
|
|
953
|
-
}
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
function stripTimeoutOptions(words) {
|
|
957
|
-
words.shift();
|
|
958
|
-
for (;;) {
|
|
959
|
-
const word = words[0] ?? "";
|
|
960
|
-
if (!word) {
|
|
961
|
-
return;
|
|
962
|
-
}
|
|
963
|
-
if (word === "--") {
|
|
964
|
-
words.shift();
|
|
965
|
-
break;
|
|
966
|
-
}
|
|
967
|
-
if (word === "-k" || word === "--kill-after" || word === "-s" || word === "--signal") {
|
|
968
|
-
words.shift();
|
|
969
|
-
if (words[0]) {
|
|
970
|
-
words.shift();
|
|
971
|
-
}
|
|
972
|
-
continue;
|
|
973
|
-
}
|
|
974
|
-
if (word.startsWith("--kill-after=") || word.startsWith("--signal=")) {
|
|
975
|
-
words.shift();
|
|
976
|
-
continue;
|
|
977
|
-
}
|
|
978
|
-
if (word.startsWith("-") && word !== "-") {
|
|
979
|
-
words.shift();
|
|
980
|
-
continue;
|
|
981
|
-
}
|
|
982
|
-
break;
|
|
983
|
-
}
|
|
984
|
-
if (words[0]) {
|
|
985
|
-
words.shift();
|
|
986
|
-
}
|
|
987
|
-
}
|
|
988
|
-
|
|
989
|
-
function splitShellWords(value) {
|
|
990
|
-
const words = [];
|
|
991
|
-
let word = "";
|
|
992
|
-
let quote = "";
|
|
993
|
-
let escaped = false;
|
|
994
|
-
for (const char of value) {
|
|
995
|
-
if (escaped) {
|
|
996
|
-
word += char;
|
|
997
|
-
escaped = false;
|
|
998
|
-
continue;
|
|
999
|
-
}
|
|
1000
|
-
if (char === "\\" && quote !== "'") {
|
|
1001
|
-
escaped = true;
|
|
1002
|
-
continue;
|
|
1003
|
-
}
|
|
1004
|
-
if (quote) {
|
|
1005
|
-
if (char === quote) {
|
|
1006
|
-
quote = "";
|
|
1007
|
-
} else {
|
|
1008
|
-
word += char;
|
|
1009
|
-
}
|
|
1010
|
-
continue;
|
|
1011
|
-
}
|
|
1012
|
-
if (char === "'" || char === '"') {
|
|
1013
|
-
quote = char;
|
|
1014
|
-
continue;
|
|
1015
|
-
}
|
|
1016
|
-
if (/\s/u.test(char)) {
|
|
1017
|
-
if (word) {
|
|
1018
|
-
words.push(word);
|
|
1019
|
-
word = "";
|
|
1020
|
-
}
|
|
1021
|
-
continue;
|
|
1022
|
-
}
|
|
1023
|
-
word += char;
|
|
1024
|
-
}
|
|
1025
|
-
if (word) {
|
|
1026
|
-
words.push(word);
|
|
1027
|
-
}
|
|
1028
|
-
return words;
|
|
1029
|
-
}
|
|
1030
|
-
|
|
1031
|
-
function stripHeredocBodies(command) {
|
|
1032
|
-
const lines = command.split("\n");
|
|
1033
|
-
const kept = [];
|
|
1034
|
-
const pendingDelimiters = [];
|
|
1035
|
-
for (const line of lines) {
|
|
1036
|
-
if (pendingDelimiters.length > 0) {
|
|
1037
|
-
const current = pendingDelimiters[0];
|
|
1038
|
-
const candidate = current.stripTabs ? line.replace(/^\t+/u, "") : line;
|
|
1039
|
-
if (candidate === current.delimiter) {
|
|
1040
|
-
pendingDelimiters.shift();
|
|
1041
|
-
} else if (current.expand) {
|
|
1042
|
-
kept.push(...extractCommandSubstitutionBodies(line));
|
|
1043
|
-
}
|
|
1044
|
-
continue;
|
|
1045
|
-
}
|
|
1046
|
-
kept.push(line);
|
|
1047
|
-
pendingDelimiters.push(...lineHeredocDelimiters(line));
|
|
1048
|
-
}
|
|
1049
|
-
return kept.join("\n");
|
|
1050
|
-
}
|
|
1051
|
-
|
|
1052
|
-
function lineHeredocDelimiters(line) {
|
|
1053
|
-
const delimiters = [];
|
|
1054
|
-
let quote = "";
|
|
1055
|
-
let escaped = false;
|
|
1056
|
-
for (let index = 0; index < line.length; index += 1) {
|
|
1057
|
-
const char = line[index];
|
|
1058
|
-
const next = line[index + 1] ?? "";
|
|
1059
|
-
if (escaped) {
|
|
1060
|
-
escaped = false;
|
|
1061
|
-
continue;
|
|
1062
|
-
}
|
|
1063
|
-
if (char === "\\" && quote !== "'") {
|
|
1064
|
-
escaped = true;
|
|
1065
|
-
continue;
|
|
1066
|
-
}
|
|
1067
|
-
if (quote) {
|
|
1068
|
-
if (char === quote) {
|
|
1069
|
-
quote = "";
|
|
1070
|
-
}
|
|
1071
|
-
continue;
|
|
1072
|
-
}
|
|
1073
|
-
if (char === "'" || char === '"') {
|
|
1074
|
-
quote = char;
|
|
1075
|
-
continue;
|
|
1076
|
-
}
|
|
1077
|
-
if (char !== "<" || next !== "<" || line[index + 2] === "<") {
|
|
1078
|
-
continue;
|
|
1079
|
-
}
|
|
1080
|
-
let delimiterStart = index + 2;
|
|
1081
|
-
const stripTabs = line[delimiterStart] === "-";
|
|
1082
|
-
if (stripTabs) {
|
|
1083
|
-
delimiterStart += 1;
|
|
1084
|
-
}
|
|
1085
|
-
while (/\s/u.test(line[delimiterStart] ?? "")) {
|
|
1086
|
-
delimiterStart += 1;
|
|
1087
|
-
}
|
|
1088
|
-
const parsed = readHeredocDelimiter(line, delimiterStart);
|
|
1089
|
-
if (parsed.delimiter) {
|
|
1090
|
-
delimiters.push({ delimiter: parsed.delimiter, stripTabs, expand: !parsed.quoted });
|
|
1091
|
-
index = parsed.endIndex;
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1094
|
-
return delimiters;
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
function readHeredocDelimiter(line, startIndex) {
|
|
1098
|
-
let delimiter = "";
|
|
1099
|
-
let quote = "";
|
|
1100
|
-
let escaped = false;
|
|
1101
|
-
let quoted = false;
|
|
1102
|
-
let index = startIndex;
|
|
1103
|
-
for (; index < line.length; index += 1) {
|
|
1104
|
-
const char = line[index];
|
|
1105
|
-
if (escaped) {
|
|
1106
|
-
delimiter += char;
|
|
1107
|
-
escaped = false;
|
|
1108
|
-
continue;
|
|
1109
|
-
}
|
|
1110
|
-
if (char === "\\" && quote !== "'") {
|
|
1111
|
-
quoted = true;
|
|
1112
|
-
escaped = true;
|
|
1113
|
-
continue;
|
|
1114
|
-
}
|
|
1115
|
-
if (quote) {
|
|
1116
|
-
if (char === quote) {
|
|
1117
|
-
quote = "";
|
|
1118
|
-
} else {
|
|
1119
|
-
delimiter += char;
|
|
1120
|
-
}
|
|
1121
|
-
continue;
|
|
1122
|
-
}
|
|
1123
|
-
if (char === "'" || char === '"') {
|
|
1124
|
-
quoted = true;
|
|
1125
|
-
quote = char;
|
|
1126
|
-
continue;
|
|
1127
|
-
}
|
|
1128
|
-
if (/\s/u.test(char) || /[;&|()<>]/u.test(char)) {
|
|
1129
|
-
break;
|
|
1130
|
-
}
|
|
1131
|
-
delimiter += char;
|
|
1132
|
-
}
|
|
1133
|
-
return { delimiter, endIndex: Math.max(startIndex, index), quoted };
|
|
1134
|
-
}
|
|
1135
|
-
|
|
1136
|
-
function extractCommandSubstitutionBodies(line) {
|
|
1137
|
-
const substitutions = [];
|
|
1138
|
-
let escaped = false;
|
|
1139
|
-
for (let index = 0; index < line.length; index += 1) {
|
|
1140
|
-
const char = line[index];
|
|
1141
|
-
const next = line[index + 1] ?? "";
|
|
1142
|
-
if (escaped) {
|
|
1143
|
-
escaped = false;
|
|
1144
|
-
continue;
|
|
1145
|
-
}
|
|
1146
|
-
if (char === "\\") {
|
|
1147
|
-
escaped = true;
|
|
1148
|
-
continue;
|
|
1149
|
-
}
|
|
1150
|
-
if (char === "$" && next === "(" && line[index + 2] !== "(") {
|
|
1151
|
-
const substitution = readCommandSubstitution(line, index + 2);
|
|
1152
|
-
substitutions.push(substitution.content);
|
|
1153
|
-
index = substitution.endIndex;
|
|
1154
|
-
}
|
|
1155
|
-
}
|
|
1156
|
-
return substitutions;
|
|
1157
|
-
}
|
|
1158
|
-
|
|
1159
|
-
function shellCommandSegments(command) {
|
|
1160
|
-
const segments = [];
|
|
1161
|
-
let segment = "";
|
|
1162
|
-
let quote = "";
|
|
1163
|
-
let escaped = false;
|
|
1164
|
-
let inCase = false;
|
|
1165
|
-
let readingCasePattern = false;
|
|
1166
|
-
for (let index = 0; index < command.length; index += 1) {
|
|
1167
|
-
const char = command[index];
|
|
1168
|
-
const next = command[index + 1] ?? "";
|
|
1169
|
-
if (escaped) {
|
|
1170
|
-
segment += char;
|
|
1171
|
-
escaped = false;
|
|
1172
|
-
continue;
|
|
1173
|
-
}
|
|
1174
|
-
if (char === "\\" && quote !== "'") {
|
|
1175
|
-
segment += char;
|
|
1176
|
-
escaped = true;
|
|
1177
|
-
continue;
|
|
1178
|
-
}
|
|
1179
|
-
if (quote) {
|
|
1180
|
-
if (quote === '"' && char === "$" && next === "(" && command[index + 2] !== "(") {
|
|
1181
|
-
const substitution = readCommandSubstitution(command, index + 2);
|
|
1182
|
-
segments.push(...shellCommandWordCandidates(substitution.content));
|
|
1183
|
-
index = substitution.endIndex;
|
|
1184
|
-
segment += "$()";
|
|
1185
|
-
continue;
|
|
1186
|
-
}
|
|
1187
|
-
if (char === quote) {
|
|
1188
|
-
quote = "";
|
|
1189
|
-
}
|
|
1190
|
-
segment += char;
|
|
1191
|
-
continue;
|
|
1192
|
-
}
|
|
1193
|
-
if (char === "'" || char === '"') {
|
|
1194
|
-
quote = char;
|
|
1195
|
-
segment += char;
|
|
1196
|
-
continue;
|
|
1197
|
-
}
|
|
1198
|
-
if (char === "#" && (segment.trim() === "" || /\s$/u.test(segment))) {
|
|
1199
|
-
index = skipUntilNewline(command, index);
|
|
1200
|
-
pushShellCandidate(segments, segment);
|
|
1201
|
-
segment = "";
|
|
1202
|
-
continue;
|
|
1203
|
-
}
|
|
1204
|
-
if (char === "$" && next === "(" && command[index + 2] !== "(") {
|
|
1205
|
-
const substitution = readCommandSubstitution(command, index + 2);
|
|
1206
|
-
segments.push(...shellCommandWordCandidates(substitution.content));
|
|
1207
|
-
index = substitution.endIndex;
|
|
1208
|
-
segment += "$()";
|
|
1209
|
-
continue;
|
|
1210
|
-
}
|
|
1211
|
-
if (segment.trim() === "" && startsShellReservedWord(command, index, "case")) {
|
|
1212
|
-
pushShellCandidate(segments, segment);
|
|
1213
|
-
segment = "";
|
|
1214
|
-
inCase = true;
|
|
1215
|
-
readingCasePattern = true;
|
|
1216
|
-
index += "case".length - 1;
|
|
1217
|
-
continue;
|
|
1218
|
-
}
|
|
1219
|
-
if (inCase && segment.trim() === "" && startsShellReservedWord(command, index, "esac")) {
|
|
1220
|
-
pushShellCandidate(segments, segment);
|
|
1221
|
-
segment = "";
|
|
1222
|
-
inCase = false;
|
|
1223
|
-
readingCasePattern = false;
|
|
1224
|
-
index += "esac".length - 1;
|
|
1225
|
-
continue;
|
|
1226
|
-
}
|
|
1227
|
-
if (inCase && readingCasePattern) {
|
|
1228
|
-
if (char === ")") {
|
|
1229
|
-
segment = "";
|
|
1230
|
-
readingCasePattern = false;
|
|
1231
|
-
continue;
|
|
1232
|
-
}
|
|
1233
|
-
segment += char;
|
|
1234
|
-
continue;
|
|
1235
|
-
}
|
|
1236
|
-
if (inCase && char === ";" && next === ";") {
|
|
1237
|
-
pushShellCandidate(segments, segment);
|
|
1238
|
-
segment = "";
|
|
1239
|
-
readingCasePattern = true;
|
|
1240
|
-
index += 1;
|
|
1241
|
-
continue;
|
|
1242
|
-
}
|
|
1243
|
-
if (char === "\n" || char === ";" || char === ")") {
|
|
1244
|
-
pushShellCandidate(segments, segment);
|
|
1245
|
-
segment = "";
|
|
1246
|
-
continue;
|
|
1247
|
-
}
|
|
1248
|
-
if ((char === "&" && next === "&") || (char === "|" && next === "|")) {
|
|
1249
|
-
pushShellCandidate(segments, segment);
|
|
1250
|
-
segment = "";
|
|
1251
|
-
index += 1;
|
|
1252
|
-
continue;
|
|
1253
|
-
}
|
|
1254
|
-
if (char === "&" && next !== ">" && command[index - 1] !== ">") {
|
|
1255
|
-
pushShellCandidate(segments, segment);
|
|
1256
|
-
segment = "";
|
|
1257
|
-
continue;
|
|
1258
|
-
}
|
|
1259
|
-
if (char === "|") {
|
|
1260
|
-
pushShellCandidate(segments, segment);
|
|
1261
|
-
segment = "";
|
|
1262
|
-
if (next === "&") {
|
|
1263
|
-
index += 1;
|
|
1264
|
-
}
|
|
1265
|
-
continue;
|
|
1266
|
-
}
|
|
1267
|
-
segment += char;
|
|
1268
|
-
}
|
|
1269
|
-
pushShellCandidate(segments, segment);
|
|
1270
|
-
return segments;
|
|
1271
|
-
}
|
|
1272
|
-
|
|
1273
|
-
function readCommandSubstitution(command, startIndex) {
|
|
1274
|
-
let depth = 1;
|
|
1275
|
-
let quote = "";
|
|
1276
|
-
let escaped = false;
|
|
1277
|
-
let inCase = false;
|
|
1278
|
-
let readingCasePattern = false;
|
|
1279
|
-
let content = "";
|
|
1280
|
-
for (let index = startIndex; index < command.length; index += 1) {
|
|
1281
|
-
const char = command[index];
|
|
1282
|
-
const next = command[index + 1] ?? "";
|
|
1283
|
-
if (escaped) {
|
|
1284
|
-
content += char;
|
|
1285
|
-
escaped = false;
|
|
1286
|
-
continue;
|
|
1287
|
-
}
|
|
1288
|
-
if (char === "\\" && quote !== "'") {
|
|
1289
|
-
content += char;
|
|
1290
|
-
escaped = true;
|
|
1291
|
-
continue;
|
|
1292
|
-
}
|
|
1293
|
-
if (quote) {
|
|
1294
|
-
if (char === quote) {
|
|
1295
|
-
quote = "";
|
|
1296
|
-
}
|
|
1297
|
-
content += char;
|
|
1298
|
-
continue;
|
|
1299
|
-
}
|
|
1300
|
-
if (char === "'" || char === '"') {
|
|
1301
|
-
quote = char;
|
|
1302
|
-
content += char;
|
|
1303
|
-
continue;
|
|
1304
|
-
}
|
|
1305
|
-
if (!inCase && startsShellToken(command, index, "case")) {
|
|
1306
|
-
inCase = true;
|
|
1307
|
-
readingCasePattern = true;
|
|
1308
|
-
} else if (inCase && startsShellToken(command, index, "esac")) {
|
|
1309
|
-
inCase = false;
|
|
1310
|
-
readingCasePattern = false;
|
|
1311
|
-
}
|
|
1312
|
-
if (char === "$" && next === "(") {
|
|
1313
|
-
depth += 1;
|
|
1314
|
-
content += "$(";
|
|
1315
|
-
index += 1;
|
|
1316
|
-
continue;
|
|
1317
|
-
}
|
|
1318
|
-
if (char === "(") {
|
|
1319
|
-
depth += 1;
|
|
1320
|
-
content += char;
|
|
1321
|
-
continue;
|
|
1322
|
-
}
|
|
1323
|
-
if (inCase && char === ";" && next === ";") {
|
|
1324
|
-
readingCasePattern = true;
|
|
1325
|
-
content += ";;";
|
|
1326
|
-
index += 1;
|
|
1327
|
-
continue;
|
|
1328
|
-
}
|
|
1329
|
-
if (inCase && readingCasePattern && depth === 1 && char === ")") {
|
|
1330
|
-
readingCasePattern = false;
|
|
1331
|
-
content += char;
|
|
1332
|
-
continue;
|
|
1333
|
-
}
|
|
1334
|
-
if (char === ")") {
|
|
1335
|
-
depth -= 1;
|
|
1336
|
-
if (depth === 0) {
|
|
1337
|
-
return { content, endIndex: index };
|
|
1338
|
-
}
|
|
1339
|
-
}
|
|
1340
|
-
content += char;
|
|
1341
|
-
}
|
|
1342
|
-
return { content, endIndex: command.length - 1 };
|
|
1343
|
-
}
|
|
1344
|
-
|
|
1345
|
-
function startsShellReservedWord(command, index, word) {
|
|
1346
|
-
if (!command.startsWith(word, index)) {
|
|
1347
|
-
return false;
|
|
1348
|
-
}
|
|
1349
|
-
const after = command[index + word.length] ?? "";
|
|
1350
|
-
return !after || /\s|[;&|()<>]/u.test(after);
|
|
1351
|
-
}
|
|
1352
|
-
|
|
1353
|
-
function startsShellToken(command, index, word) {
|
|
1354
|
-
if (!command.startsWith(word, index)) {
|
|
1355
|
-
return false;
|
|
1356
|
-
}
|
|
1357
|
-
const before = command[index - 1] ?? "";
|
|
1358
|
-
const after = command[index + word.length] ?? "";
|
|
1359
|
-
return (!before || /\s|[;&|()<>]/u.test(before)) && (!after || /\s|[;&|()<>]/u.test(after));
|
|
1360
|
-
}
|
|
1361
|
-
|
|
1362
|
-
function skipUntilNewline(command, index) {
|
|
1363
|
-
const newlineIndex = command.indexOf("\n", index);
|
|
1364
|
-
return newlineIndex < 0 ? command.length - 1 : newlineIndex;
|
|
1365
|
-
}
|
|
1366
|
-
|
|
1367
|
-
function mergeBaseForChangedGate() {
|
|
1368
|
-
const base = gitOutput(["merge-base", "origin/main", "HEAD"]);
|
|
1369
|
-
return base.status === 0 && base.stdout ? base.stdout : "origin/main";
|
|
1370
|
-
}
|
|
1371
|
-
|
|
1372
|
-
function remoteGitBootstrapForChangedGate(changedGateBase) {
|
|
1373
|
-
const quotedBase = shellQuote(changedGateBase);
|
|
1374
|
-
return [
|
|
1375
|
-
"if ! git status --short >/dev/null 2>&1; then",
|
|
1376
|
-
"rm -rf .git;",
|
|
1377
|
-
"git init -q;",
|
|
1378
|
-
"git remote add origin https://github.com/fengming/fengming.git 2>/dev/null || git remote set-url origin https://github.com/fengming/fengming.git;",
|
|
1379
|
-
`git fetch -q --depth=1 origin ${quotedBase}:refs/remotes/origin/main;`,
|
|
1380
|
-
"git reset --mixed --quiet refs/remotes/origin/main;",
|
|
1381
|
-
"git add -A;",
|
|
1382
|
-
"if ! git diff --cached --quiet; then git -c user.name=FengMing -c user.email=ci@fengming.local commit -q --no-gpg-sign -m remote-changed-gate-tree; fi;",
|
|
1383
|
-
"fi",
|
|
1384
|
-
].join(" ");
|
|
1385
|
-
}
|
|
1386
|
-
|
|
1387
|
-
function isWindowsRemoteTarget(commandArgs) {
|
|
1388
|
-
return (
|
|
1389
|
-
optionValue(commandArgs, "--target") === "windows" || hasOption(commandArgs, "--windows-mode")
|
|
1390
|
-
);
|
|
1391
|
-
}
|
|
1392
|
-
|
|
1393
|
-
function isAwsMacosRemoteTarget(commandArgs, providerName) {
|
|
1394
|
-
return (
|
|
1395
|
-
commandArgs[0] === "run" &&
|
|
1396
|
-
providerName === "aws" &&
|
|
1397
|
-
optionValue(commandArgs, "--target") === "macos"
|
|
1398
|
-
);
|
|
1399
|
-
}
|
|
1400
|
-
|
|
1401
|
-
function injectRemoteChangedGateGitBootstrap(commandArgs, changedGateBase) {
|
|
1402
|
-
if (!changedGateBase || commandArgs[0] !== "run" || isWindowsRemoteTarget(commandArgs)) {
|
|
1403
|
-
return commandArgs;
|
|
1404
|
-
}
|
|
1405
|
-
|
|
1406
|
-
const { start, optionEnd } = runCommandBounds(commandArgs);
|
|
1407
|
-
if (start < 0) {
|
|
1408
|
-
return commandArgs;
|
|
1409
|
-
}
|
|
1410
|
-
|
|
1411
|
-
const normalizedArgs = [...commandArgs];
|
|
1412
|
-
const remoteCommand = normalizedArgs.slice(start);
|
|
1413
|
-
const originalShellCommand =
|
|
1414
|
-
hasOption(normalizedArgs, "--shell") && remoteCommand.length === 1
|
|
1415
|
-
? remoteCommand[0]
|
|
1416
|
-
: shellJoin(remoteCommand);
|
|
1417
|
-
const shellCommand = `${remoteGitBootstrapForChangedGate(changedGateBase)} && ${originalShellCommand}`;
|
|
1418
|
-
|
|
1419
|
-
if (!hasOption(normalizedArgs, "--shell")) {
|
|
1420
|
-
normalizedArgs.splice(optionEnd, 0, "--shell");
|
|
1421
|
-
}
|
|
1422
|
-
|
|
1423
|
-
const updatedBounds = runCommandBounds(normalizedArgs);
|
|
1424
|
-
normalizedArgs.splice(
|
|
1425
|
-
updatedBounds.start,
|
|
1426
|
-
normalizedArgs.length - updatedBounds.start,
|
|
1427
|
-
shellCommand,
|
|
1428
|
-
);
|
|
1429
|
-
return normalizedArgs;
|
|
1430
|
-
}
|
|
1431
|
-
|
|
1432
|
-
function remoteAwsMacosJsBootstrap({ packageManager = false } = {}) {
|
|
1433
|
-
const nodeVersion = process.env.FENGMING_CRABBOX_MACOS_NODE_VERSION?.trim() || "24.15.0";
|
|
1434
|
-
const bootstrap = [
|
|
1435
|
-
"fengming_crabbox_bootstrap_macos_js() {",
|
|
1436
|
-
'tool_root="${FENGMING_CRABBOX_MACOS_TOOLCHAIN_DIR:-$HOME/.fengming-crabbox-toolchain}";',
|
|
1437
|
-
`node_version=${shellQuote(nodeVersion)};`,
|
|
1438
|
-
'arch="$(uname -m)";',
|
|
1439
|
-
'case "$arch" in arm64) node_arch=arm64 ;; x86_64) node_arch=x64 ;; *) echo "unsupported macOS arch: $arch" >&2; return 2 ;; esac;',
|
|
1440
|
-
'if [ -z "${TMPDIR:-}" ]; then export TMPDIR="/tmp"; fi;',
|
|
1441
|
-
'if [ ! -d "$TMPDIR" ]; then mkdir -p "$TMPDIR" 2>/dev/null || export TMPDIR="/tmp"; fi;',
|
|
1442
|
-
'if [ ! -d "$TMPDIR" ]; then echo "usable TMPDIR not found: $TMPDIR" >&2; return 1; fi;',
|
|
1443
|
-
'node_dir="$tool_root/node-v${node_version}-darwin-${node_arch}";',
|
|
1444
|
-
'export PATH="$node_dir/bin:$PATH";',
|
|
1445
|
-
'if [ ! -x "$node_dir/bin/node" ]; then',
|
|
1446
|
-
'tmp_dir="$(mktemp -d)" || return 1;',
|
|
1447
|
-
'pkg="node-v${node_version}-darwin-${node_arch}.tar.gz";',
|
|
1448
|
-
'base_url="https://nodejs.org/dist/v${node_version}";',
|
|
1449
|
-
'mkdir -p "$tool_root" || { status=$?; rm -rf "$tmp_dir"; return "$status"; };',
|
|
1450
|
-
'curl -fsSLo "$tmp_dir/$pkg" "$base_url/$pkg" || { status=$?; rm -rf "$tmp_dir"; return "$status"; };',
|
|
1451
|
-
'curl -fsSLo "$tmp_dir/SHASUMS256.txt" "$base_url/SHASUMS256.txt" || { status=$?; rm -rf "$tmp_dir"; return "$status"; };',
|
|
1452
|
-
'(cd "$tmp_dir" && grep " $pkg$" SHASUMS256.txt | shasum -a 256 -c -) || { status=$?; rm -rf "$tmp_dir"; return "$status"; };',
|
|
1453
|
-
'rm -rf "$node_dir" || { status=$?; rm -rf "$tmp_dir"; return "$status"; };',
|
|
1454
|
-
'tar -xzf "$tmp_dir/$pkg" -C "$tool_root" || { status=$?; rm -rf "$tmp_dir"; return "$status"; };',
|
|
1455
|
-
'rm -rf "$tmp_dir";',
|
|
1456
|
-
"fi;",
|
|
1457
|
-
"node --version >&2 || return 1;",
|
|
1458
|
-
"fengming_crabbox_env() {",
|
|
1459
|
-
"fengming_env_args=();",
|
|
1460
|
-
"fengming_env_ignore=0;",
|
|
1461
|
-
"fengming_env_path_seen=0;",
|
|
1462
|
-
'while [ "$#" -gt 0 ]; do',
|
|
1463
|
-
'case "$1" in',
|
|
1464
|
-
'-i|--ignore-environment) fengming_env_ignore=1; fengming_env_args+=("$1"); shift ;;',
|
|
1465
|
-
'-S|--split-string|-S*|--split-string=*) command env "${fengming_env_args[@]}" "$@"; return ;;',
|
|
1466
|
-
'-[!-]*i*) fengming_env_ignore=1; fengming_env_args+=("$1"); shift ;;',
|
|
1467
|
-
'-u|--unset|-C|--chdir) fengming_env_args+=("$1"); shift; if [ "$#" -gt 0 ]; then fengming_env_args+=("$1"); shift; fi ;;',
|
|
1468
|
-
'--unset=*|--chdir=*) fengming_env_args+=("$1"); shift ;;',
|
|
1469
|
-
'PATH=*) if [ "$fengming_env_ignore" = "1" ]; then fengming_env_args+=("PATH=$PATH:${1#PATH=}"); else fengming_env_args+=("$1"); fi; fengming_env_path_seen=1; shift ;;',
|
|
1470
|
-
'[A-Za-z_]*=*) fengming_env_args+=("$1"); shift ;;',
|
|
1471
|
-
'--) fengming_env_args+=("--"); shift; break ;;',
|
|
1472
|
-
"*) break ;;",
|
|
1473
|
-
"esac;",
|
|
1474
|
-
"done;",
|
|
1475
|
-
'if [ "$fengming_env_ignore" = "1" ] && [ "$fengming_env_path_seen" = "0" ]; then fengming_env_args+=("PATH=$PATH"); fi;',
|
|
1476
|
-
'command env "${fengming_env_args[@]}" "$@";',
|
|
1477
|
-
"};",
|
|
1478
|
-
];
|
|
1479
|
-
if (packageManager) {
|
|
1480
|
-
bootstrap.push(
|
|
1481
|
-
'export COREPACK_HOME="${COREPACK_HOME:-$tool_root/corepack}";',
|
|
1482
|
-
'export PNPM_HOME="${PNPM_HOME:-$tool_root/pnpm-home}";',
|
|
1483
|
-
'mkdir -p "$COREPACK_HOME" "$PNPM_HOME" || return 1;',
|
|
1484
|
-
'export PATH="$PNPM_HOME:$PATH";',
|
|
1485
|
-
'corepack enable --install-directory "$PNPM_HOME" || return 1;',
|
|
1486
|
-
"pnpm --version >&2;",
|
|
1487
|
-
);
|
|
1488
|
-
}
|
|
1489
|
-
bootstrap.push("};", "fengming_crabbox_bootstrap_macos_js");
|
|
1490
|
-
return bootstrap.join(" ");
|
|
1491
|
-
}
|
|
1492
|
-
|
|
1493
|
-
function scopedAwsMacosEnvCommand(commandArgs) {
|
|
1494
|
-
if (
|
|
1495
|
-
commandArgs.length <= 1 ||
|
|
1496
|
-
shellWordBasename(commandArgs[0]) !== "env" ||
|
|
1497
|
-
commandArgs[0].includes("/")
|
|
1498
|
-
) {
|
|
1499
|
-
return null;
|
|
1500
|
-
}
|
|
1501
|
-
|
|
1502
|
-
const targetWords = [...commandArgs];
|
|
1503
|
-
if (!stripEnvCommandOptions(targetWords, { canShimIgnoreEnvironment: true })) {
|
|
1504
|
-
return null;
|
|
1505
|
-
}
|
|
1506
|
-
|
|
1507
|
-
const targetEntrypoint = shellWordBasename(targetWords[0]);
|
|
1508
|
-
if (
|
|
1509
|
-
!jsRuntimeEntrypoints.has(targetEntrypoint) &&
|
|
1510
|
-
!awsMacosCorepackEntrypoints.has(targetEntrypoint)
|
|
1511
|
-
) {
|
|
1512
|
-
return null;
|
|
1513
|
-
}
|
|
1514
|
-
|
|
1515
|
-
return {
|
|
1516
|
-
runtimeEntrypoint: targetEntrypoint,
|
|
1517
|
-
packageManager: awsMacosCorepackEntrypoints.has(targetEntrypoint),
|
|
1518
|
-
shellCommand: `fengming_crabbox_env ${shellJoin(commandArgs.slice(1))}`,
|
|
1519
|
-
};
|
|
1520
|
-
}
|
|
1521
|
-
|
|
1522
|
-
function injectRemoteAwsMacosJsBootstrap(commandArgs, providerName) {
|
|
1523
|
-
const runArgs = runCommandArgs(commandArgs);
|
|
1524
|
-
const directScopedEnvCommand = hasOption(commandArgs, "--shell")
|
|
1525
|
-
? null
|
|
1526
|
-
: scopedAwsMacosEnvCommand(runArgs);
|
|
1527
|
-
const runtimeEntrypoint =
|
|
1528
|
-
directScopedEnvCommand?.runtimeEntrypoint || commandRuntimeEntrypoint(runArgs);
|
|
1529
|
-
if (!isAwsMacosRemoteTarget(commandArgs, providerName) || !runtimeEntrypoint) {
|
|
1530
|
-
return commandArgs;
|
|
1531
|
-
}
|
|
1532
|
-
|
|
1533
|
-
const { start, optionEnd } = runCommandBounds(commandArgs);
|
|
1534
|
-
if (start < 0) {
|
|
1535
|
-
return commandArgs;
|
|
1536
|
-
}
|
|
1537
|
-
|
|
1538
|
-
const normalizedArgs = [...commandArgs];
|
|
1539
|
-
const remoteCommand = normalizedArgs.slice(start);
|
|
1540
|
-
const originalShellCommand =
|
|
1541
|
-
directScopedEnvCommand?.shellCommand ??
|
|
1542
|
-
(hasOption(normalizedArgs, "--shell") && remoteCommand.length === 1
|
|
1543
|
-
? remoteCommand[0]
|
|
1544
|
-
: shellJoin(remoteCommand));
|
|
1545
|
-
const shellCommand = `${remoteAwsMacosJsBootstrap({
|
|
1546
|
-
packageManager:
|
|
1547
|
-
directScopedEnvCommand?.packageManager || commandNeedsAwsMacosPackageManager(runArgs),
|
|
1548
|
-
})} && { ${originalShellCommand}\n}`;
|
|
1549
|
-
|
|
1550
|
-
if (!hasOption(normalizedArgs, "--shell")) {
|
|
1551
|
-
normalizedArgs.splice(optionEnd, 0, "--shell");
|
|
1552
|
-
}
|
|
1553
|
-
|
|
1554
|
-
const updatedBounds = runCommandBounds(normalizedArgs);
|
|
1555
|
-
normalizedArgs.splice(
|
|
1556
|
-
updatedBounds.start,
|
|
1557
|
-
normalizedArgs.length - updatedBounds.start,
|
|
1558
|
-
shellCommand,
|
|
1559
|
-
);
|
|
1560
|
-
return normalizedArgs;
|
|
1561
|
-
}
|
|
1562
|
-
|
|
1563
|
-
function hasRunOption(commandArgs, name) {
|
|
1564
|
-
if (commandArgs[0] !== "run") {
|
|
1565
|
-
return false;
|
|
1566
|
-
}
|
|
1567
|
-
const { optionEnd } = runCommandBounds(commandArgs);
|
|
1568
|
-
const normalizedName = name.replace(/^-+/u, "");
|
|
1569
|
-
for (let index = 1; index < optionEnd; index += 1) {
|
|
1570
|
-
const arg = commandArgs[index];
|
|
1571
|
-
if (arg.startsWith("-") && runOptionName(arg) === normalizedName) {
|
|
1572
|
-
return true;
|
|
1573
|
-
}
|
|
1574
|
-
if (!arg.includes("=") && currentRunValueOptions().has(runOptionName(arg))) {
|
|
1575
|
-
index += 1;
|
|
1576
|
-
}
|
|
1577
|
-
}
|
|
1578
|
-
return false;
|
|
1579
|
-
}
|
|
1580
|
-
|
|
1581
|
-
function replaceRunFlagWithScript(commandArgs, flagName, scriptPath) {
|
|
1582
|
-
const { optionEnd } = runCommandBounds(commandArgs);
|
|
1583
|
-
const normalizedName = flagName.replace(/^-+/u, "");
|
|
1584
|
-
const normalizedArgs = [...commandArgs];
|
|
1585
|
-
for (let index = 1; index < optionEnd; index += 1) {
|
|
1586
|
-
const arg = normalizedArgs[index];
|
|
1587
|
-
if (arg.startsWith("-") && runOptionName(arg) === normalizedName) {
|
|
1588
|
-
normalizedArgs.splice(index, 1, "--script", scriptPath);
|
|
1589
|
-
return normalizedArgs;
|
|
1590
|
-
}
|
|
1591
|
-
if (!arg.includes("=") && currentRunValueOptions().has(runOptionName(arg))) {
|
|
1592
|
-
index += 1;
|
|
1593
|
-
}
|
|
1594
|
-
}
|
|
1595
|
-
return normalizedArgs;
|
|
1596
|
-
}
|
|
1597
|
-
|
|
1598
|
-
function prepareAwsMacosScriptStdinBootstrap(commandArgs, providerName) {
|
|
1599
|
-
if (
|
|
1600
|
-
!isAwsMacosRemoteTarget(commandArgs, providerName) ||
|
|
1601
|
-
!hasRunOption(commandArgs, "--script-stdin")
|
|
1602
|
-
) {
|
|
1603
|
-
return { args: commandArgs, cleanup: () => {}, prepared: false };
|
|
1604
|
-
}
|
|
1605
|
-
|
|
1606
|
-
const scriptRoot = mkdtempSync(resolve(tmpdir(), "fengming-crabbox-macos-script-"));
|
|
1607
|
-
const scriptPath = resolve(scriptRoot, "script.sh");
|
|
1608
|
-
const script = readFileSync(0, "utf8");
|
|
1609
|
-
writeFileSync(scriptPath, createAwsMacosScriptStdinWrapper(script), "utf8");
|
|
1610
|
-
chmodSync(scriptPath, 0o700);
|
|
1611
|
-
return {
|
|
1612
|
-
args: replaceRunFlagWithScript(commandArgs, "--script-stdin", scriptPath),
|
|
1613
|
-
cleanup: () => rmSync(scriptRoot, { recursive: true, force: true }),
|
|
1614
|
-
prepared: true,
|
|
1615
|
-
};
|
|
1616
|
-
}
|
|
1617
|
-
|
|
1618
|
-
function createAwsMacosScriptStdinWrapper(script) {
|
|
1619
|
-
const packageManager = scriptNeedsAwsMacosPackageManager(script);
|
|
1620
|
-
if (!script.startsWith("#!")) {
|
|
1621
|
-
return `${remoteAwsMacosJsBootstrap({ packageManager })} || exit $?\n${script}`;
|
|
1622
|
-
}
|
|
1623
|
-
const delimiter = uniqueHereDocDelimiter(script);
|
|
1624
|
-
return [
|
|
1625
|
-
`${remoteAwsMacosJsBootstrap({ packageManager })} || exit $?`,
|
|
1626
|
-
'tmp_script="$(mktemp "${TMPDIR:-/tmp}/fengming-crabbox-script.XXXXXX")" || exit $?',
|
|
1627
|
-
'cleanup_fengming_crabbox_script() { rm -f "$tmp_script"; }',
|
|
1628
|
-
"trap cleanup_fengming_crabbox_script EXIT",
|
|
1629
|
-
`cat >"$tmp_script" <<'${delimiter}'`,
|
|
1630
|
-
script.endsWith("\n") ? script.slice(0, -1) : script,
|
|
1631
|
-
delimiter,
|
|
1632
|
-
'chmod 700 "$tmp_script" || exit $?',
|
|
1633
|
-
'"$tmp_script" "$@"',
|
|
1634
|
-
"",
|
|
1635
|
-
].join("\n");
|
|
1636
|
-
}
|
|
1637
|
-
|
|
1638
|
-
function scriptNeedsAwsMacosPackageManager(script) {
|
|
1639
|
-
const firstLine = script.match(/^[^\r\n]*/u)?.[0] ?? "";
|
|
1640
|
-
if (firstLine.startsWith("#!")) {
|
|
1641
|
-
let words = firstLine.slice(2).trim().split(/\s+/u).filter(Boolean);
|
|
1642
|
-
if ((words[0] ?? "").split("/").pop() === "env") {
|
|
1643
|
-
words = words.slice(1);
|
|
1644
|
-
while ((words[0] ?? "").startsWith("-")) {
|
|
1645
|
-
words = words.slice(1);
|
|
1646
|
-
}
|
|
1647
|
-
}
|
|
1648
|
-
if (commandWordsNeedAwsMacosPackageManager(words)) {
|
|
1649
|
-
return true;
|
|
1650
|
-
}
|
|
1651
|
-
}
|
|
1652
|
-
return commandNeedsAwsMacosPackageManager([script]);
|
|
1653
|
-
}
|
|
1654
|
-
|
|
1655
|
-
function uniqueHereDocDelimiter(script) {
|
|
1656
|
-
let index = 0;
|
|
1657
|
-
for (;;) {
|
|
1658
|
-
const delimiter = `FENGMING_CRABBOX_SCRIPT_${index}`;
|
|
1659
|
-
if (!new RegExp(`^${delimiter}$`, "mu").test(script)) {
|
|
1660
|
-
return delimiter;
|
|
1661
|
-
}
|
|
1662
|
-
index += 1;
|
|
1663
|
-
}
|
|
1664
|
-
}
|
|
1665
|
-
|
|
1666
|
-
function isSparseCheckout() {
|
|
1667
|
-
const config = gitOutput(["config", "--bool", "core.sparseCheckout"]);
|
|
1668
|
-
if (config.status === 0 && config.stdout === "true") {
|
|
1669
|
-
return true;
|
|
1670
|
-
}
|
|
1671
|
-
const patterns = gitOutput(["sparse-checkout", "list"]);
|
|
1672
|
-
return patterns.status === 0 && patterns.stdout.length > 0;
|
|
1673
|
-
}
|
|
1674
|
-
|
|
1675
|
-
function isWorktreeClean() {
|
|
1676
|
-
return gitOutput(["status", "--porcelain=v1"]).stdout === "";
|
|
1677
|
-
}
|
|
1678
|
-
|
|
1679
|
-
function shouldUseFullCheckoutForCleanSparseRemoteSync(commandArgs, providerName) {
|
|
1680
|
-
if (commandArgs[0] !== "run") {
|
|
1681
|
-
return false;
|
|
1682
|
-
}
|
|
1683
|
-
if (hasOption(commandArgs, "--no-sync")) {
|
|
1684
|
-
return false;
|
|
1685
|
-
}
|
|
1686
|
-
|
|
1687
|
-
return isSparseCheckout() && isWorktreeClean();
|
|
1688
|
-
}
|
|
1689
|
-
|
|
1690
|
-
function prepareFullCheckoutForSync(options = {}) {
|
|
1691
|
-
const dir = mkdtempSync(resolve(tmpdir(), "fengming-crabbox-sync-"));
|
|
1692
|
-
let active = false;
|
|
1693
|
-
const add = gitOutput(["worktree", "add", "--detach", dir, "HEAD"]);
|
|
1694
|
-
if (add.status !== 0) {
|
|
1695
|
-
rmSync(dir, { recursive: true, force: true });
|
|
1696
|
-
throw new Error(`git worktree add failed: ${add.text}`);
|
|
1697
|
-
}
|
|
1698
|
-
active = true;
|
|
1699
|
-
|
|
1700
|
-
const disableSparse = gitOutput(["-C", dir, "sparse-checkout", "disable"]);
|
|
1701
|
-
if (disableSparse.status !== 0) {
|
|
1702
|
-
cleanupFullCheckout(dir, active);
|
|
1703
|
-
throw new Error(`git sparse-checkout disable failed: ${disableSparse.text}`);
|
|
1704
|
-
}
|
|
1705
|
-
|
|
1706
|
-
if (options.changedGateBase) {
|
|
1707
|
-
const reset = gitOutput(["-C", dir, "reset", "--mixed", "--quiet", options.changedGateBase]);
|
|
1708
|
-
if (reset.status !== 0) {
|
|
1709
|
-
cleanupFullCheckout(dir, active);
|
|
1710
|
-
throw new Error(`git reset for changed-gate sync failed: ${reset.text}`);
|
|
1711
|
-
}
|
|
1712
|
-
}
|
|
1713
|
-
|
|
1714
|
-
return {
|
|
1715
|
-
dir,
|
|
1716
|
-
changedGateBase: options.changedGateBase ?? "",
|
|
1717
|
-
cleanup() {
|
|
1718
|
-
cleanupFullCheckout(dir, active);
|
|
1719
|
-
active = false;
|
|
1720
|
-
},
|
|
1721
|
-
};
|
|
1722
|
-
}
|
|
1723
|
-
|
|
1724
|
-
function cleanupFullCheckout(dir, active) {
|
|
1725
|
-
if (active) {
|
|
1726
|
-
const remove = gitOutput(["worktree", "remove", "--force", dir]);
|
|
1727
|
-
if (remove.status === 0) {
|
|
1728
|
-
return;
|
|
1729
|
-
}
|
|
1730
|
-
console.error(`[crabbox] warning: git worktree remove failed for ${dir}: ${remove.text}`);
|
|
1731
|
-
}
|
|
1732
|
-
rmSync(dir, { recursive: true, force: true });
|
|
1733
|
-
}
|
|
1734
|
-
|
|
1735
|
-
const version = checkedOutput(binary, ["--version"]);
|
|
1736
|
-
const help = checkedOutput(binary, ["run", "--help"]);
|
|
1737
|
-
const providerAliases = new Map([
|
|
1738
|
-
["blacksmith", "blacksmith-testbox"],
|
|
1739
|
-
["cf", "cloudflare"],
|
|
1740
|
-
["container", "local-container"],
|
|
1741
|
-
["docker", "local-container"],
|
|
1742
|
-
["exe", "exe-dev"],
|
|
1743
|
-
["exedev", "exe-dev"],
|
|
1744
|
-
["google", "gcp"],
|
|
1745
|
-
["google-cloud", "gcp"],
|
|
1746
|
-
["local-docker", "local-container"],
|
|
1747
|
-
["namespace", "namespace-devbox"],
|
|
1748
|
-
["namespace-devboxes", "namespace-devbox"],
|
|
1749
|
-
["rail", "railway"],
|
|
1750
|
-
["railwayapp", "railway"],
|
|
1751
|
-
["run-pod", "runpod"],
|
|
1752
|
-
["runpodio", "runpod"],
|
|
1753
|
-
["sem", "semaphore"],
|
|
1754
|
-
["static", "ssh"],
|
|
1755
|
-
["static-ssh", "ssh"],
|
|
1756
|
-
["tensorlake-sbx", "tensorlake"],
|
|
1757
|
-
["tl", "tensorlake"],
|
|
1758
|
-
]);
|
|
1759
|
-
// Crabbox providerHelpAll can omit Tensorlake even when the binary accepts it.
|
|
1760
|
-
const providerHelpOmissions = new Set(["tensorlake"]);
|
|
1761
|
-
|
|
1762
|
-
function addProviderNames(names, text) {
|
|
1763
|
-
for (const name of text
|
|
1764
|
-
.replace(/\s+\(default\b.*$/u, "")
|
|
1765
|
-
.split(/\s*(?:,|\||\bor\b)\s*/u)
|
|
1766
|
-
.map((s) => s.trim())
|
|
1767
|
-
.filter(Boolean)) {
|
|
1768
|
-
if (/^[a-z0-9][a-z0-9-]*$/u.test(name)) {
|
|
1769
|
-
names.add(name);
|
|
1770
|
-
}
|
|
1771
|
-
}
|
|
1772
|
-
}
|
|
1773
|
-
|
|
1774
|
-
function providerListContinuation(line, previousText) {
|
|
1775
|
-
const match = line.match(
|
|
1776
|
-
/^\s*((?:or\s+)?[a-z0-9][a-z0-9-]*(?:\s*(?:,|\||\bor\b)\s*(?:or\s+)?[a-z0-9][a-z0-9-]*)*\s*(?:,|\|)?)(?:\s+\(default\b.*)?\s*$/u,
|
|
1777
|
-
);
|
|
1778
|
-
if (!match) {
|
|
1779
|
-
return "";
|
|
1780
|
-
}
|
|
1781
|
-
if (/[,|]\s*$/u.test(previousText) || /[,|]|\bor\b|\(default\b/u.test(line)) {
|
|
1782
|
-
return match[1];
|
|
1783
|
-
}
|
|
1784
|
-
return "";
|
|
1785
|
-
}
|
|
1786
|
-
|
|
1787
|
-
function parseProvidersFromHelp(text) {
|
|
1788
|
-
const names = new Set();
|
|
1789
|
-
const lines = text.split(/\r?\n/u);
|
|
1790
|
-
for (let index = 0; index < lines.length; index += 1) {
|
|
1791
|
-
const line = lines[index];
|
|
1792
|
-
const providerMatch = line.match(/provider:\s*([a-z0-9][a-z0-9, -]*)(?:\s*\(default\b|$)/u);
|
|
1793
|
-
if (providerMatch) {
|
|
1794
|
-
let providerText = providerMatch[1];
|
|
1795
|
-
while (!/\(default\b/u.test(lines[index]) && index + 1 < lines.length) {
|
|
1796
|
-
const continuation = providerListContinuation(lines[index + 1], providerText);
|
|
1797
|
-
if (!continuation) {
|
|
1798
|
-
break;
|
|
1799
|
-
}
|
|
1800
|
-
index += 1;
|
|
1801
|
-
providerText = `${providerText} ${continuation}`;
|
|
1802
|
-
}
|
|
1803
|
-
addProviderNames(names, providerText);
|
|
1804
|
-
continue;
|
|
1805
|
-
}
|
|
1806
|
-
|
|
1807
|
-
const flagMatch = line.match(
|
|
1808
|
-
/^\s+-{1,2}provider(?:[=\s]+)([a-z0-9][a-z0-9|, -]*)(?:\s{2,}|\s+\(|$)/u,
|
|
1809
|
-
);
|
|
1810
|
-
if (flagMatch && /[,|]|\bor\b/u.test(flagMatch[1])) {
|
|
1811
|
-
addProviderNames(names, flagMatch[1]);
|
|
1812
|
-
}
|
|
1813
|
-
}
|
|
1814
|
-
return [...names];
|
|
1815
|
-
}
|
|
1816
|
-
|
|
1817
|
-
function isProviderAdvertised(provider, advertisedProviders) {
|
|
1818
|
-
const canonicalProvider = providerAliases.get(provider) ?? provider;
|
|
1819
|
-
return (
|
|
1820
|
-
advertisedProviders.includes(provider) ||
|
|
1821
|
-
advertisedProviders.includes(canonicalProvider) ||
|
|
1822
|
-
providerHelpOmissions.has(canonicalProvider)
|
|
1823
|
-
);
|
|
1824
|
-
}
|
|
1825
|
-
|
|
1826
|
-
const providers = parseProvidersFromHelp(help.text);
|
|
1827
|
-
const displayBinary = binary === "crabbox" ? "crabbox" : relative(repoRoot, binary);
|
|
1828
|
-
const provider = selectedProvider(args, providers);
|
|
1829
|
-
const commandProviderValue = commandProvider(args);
|
|
1830
|
-
let normalizedArgs = ensureAwsMacOnDemandMarket(
|
|
1831
|
-
ensureAzureWindowsProvider(args, provider, providers),
|
|
1832
|
-
provider,
|
|
1833
|
-
);
|
|
1834
|
-
|
|
1835
|
-
console.error(
|
|
1836
|
-
`[crabbox] bin=${displayBinary} version=${version.text || "unknown"} provider=${provider || "unknown"} providers=${providers.join(",") || "unknown"}`,
|
|
1837
|
-
);
|
|
1838
|
-
|
|
1839
|
-
if (version.status !== 0 || help.status !== 0) {
|
|
1840
|
-
console.error("[crabbox] selected binary failed basic --version/--help sanity checks");
|
|
1841
|
-
process.exit(2);
|
|
1842
|
-
}
|
|
1843
|
-
|
|
1844
|
-
if (provider && !isProviderAdvertised(provider, providers)) {
|
|
1845
|
-
if (providers.length === 0) {
|
|
1846
|
-
console.error(
|
|
1847
|
-
"[crabbox] could not parse provider list from --help; refusing to run with --provider without validation",
|
|
1848
|
-
);
|
|
1849
|
-
process.exit(2);
|
|
1850
|
-
}
|
|
1851
|
-
console.error(
|
|
1852
|
-
`[crabbox] selected binary does not advertise provider ${provider}; update Crabbox or choose a supported provider`,
|
|
1853
|
-
);
|
|
1854
|
-
process.exit(2);
|
|
1855
|
-
}
|
|
1856
|
-
|
|
1857
|
-
enforceBrokeredAws(normalizedArgs, provider);
|
|
1858
|
-
|
|
1859
|
-
if (provider === "blacksmith-testbox") {
|
|
1860
|
-
const envProvider = process.env.CRABBOX_PROVIDER?.trim();
|
|
1861
|
-
const source = commandProviderValue
|
|
1862
|
-
? "explicit"
|
|
1863
|
-
: envProvider
|
|
1864
|
-
? "from CRABBOX_PROVIDER"
|
|
1865
|
-
: "from config";
|
|
1866
|
-
const fallback = commandProviderValue
|
|
1867
|
-
? "rerun without --provider to use .crabbox.yaml"
|
|
1868
|
-
: envProvider
|
|
1869
|
-
? "unset CRABBOX_PROVIDER to use .crabbox.yaml"
|
|
1870
|
-
: "pass another --provider to override it";
|
|
1871
|
-
console.error(
|
|
1872
|
-
`[crabbox] provider=blacksmith-testbox ${source}; if Testbox is queued or down, ${fallback}`,
|
|
1873
|
-
);
|
|
1874
|
-
}
|
|
1875
|
-
|
|
1876
|
-
let childCwd = repoRoot;
|
|
1877
|
-
let cleanupChildCwd = () => {};
|
|
1878
|
-
let cleanupDone = false;
|
|
1879
|
-
let remoteChangedGateBase = "";
|
|
1880
|
-
let scriptStdinPrepared = false;
|
|
1881
|
-
const scriptBootstrap = prepareAwsMacosScriptStdinBootstrap(normalizedArgs, provider);
|
|
1882
|
-
normalizedArgs = scriptBootstrap.args;
|
|
1883
|
-
scriptStdinPrepared = scriptBootstrap.prepared;
|
|
1884
|
-
try {
|
|
1885
|
-
if (shouldUseFullCheckoutForCleanSparseRemoteSync(normalizedArgs, provider)) {
|
|
1886
|
-
const runWords = runCommandArgs(normalizedArgs);
|
|
1887
|
-
const changedGateBase = isChangedGateCommand(runWords) ? mergeBaseForChangedGate() : "";
|
|
1888
|
-
const checkout = prepareFullCheckoutForSync({ changedGateBase });
|
|
1889
|
-
childCwd = checkout.dir;
|
|
1890
|
-
cleanupChildCwd = () => checkout.cleanup();
|
|
1891
|
-
remoteChangedGateBase = checkout.changedGateBase;
|
|
1892
|
-
console.error(
|
|
1893
|
-
`[crabbox] sparse clean checkout detected; syncing from temporary full checkout ${checkout.dir}`,
|
|
1894
|
-
);
|
|
1895
|
-
if (checkout.changedGateBase) {
|
|
1896
|
-
console.error(
|
|
1897
|
-
`[crabbox] remote changed gate detected; overlaying local HEAD as worktree changes from ${checkout.changedGateBase}`,
|
|
1898
|
-
);
|
|
1899
|
-
}
|
|
1900
|
-
}
|
|
1901
|
-
} catch (error) {
|
|
1902
|
-
scriptBootstrap.cleanup();
|
|
1903
|
-
throw error;
|
|
1904
|
-
}
|
|
1905
|
-
|
|
1906
|
-
function cleanupOnce() {
|
|
1907
|
-
if (cleanupDone) {
|
|
1908
|
-
return;
|
|
1909
|
-
}
|
|
1910
|
-
cleanupDone = true;
|
|
1911
|
-
scriptBootstrap.cleanup();
|
|
1912
|
-
preserveTemporaryCrabboxRuns();
|
|
1913
|
-
cleanupChildCwd();
|
|
1914
|
-
}
|
|
1915
|
-
|
|
1916
|
-
const runtimeEntrypoint = commandRuntimeEntrypoint(runCommandArgs(normalizedArgs));
|
|
1917
|
-
if (
|
|
1918
|
-
normalizedArgs[0] === "run" &&
|
|
1919
|
-
provider === "aws" &&
|
|
1920
|
-
(runtimeEntrypoint || scriptStdinPrepared)
|
|
1921
|
-
) {
|
|
1922
|
-
if (isAwsMacosRemoteTarget(normalizedArgs, provider)) {
|
|
1923
|
-
console.error(
|
|
1924
|
-
`[crabbox] provider=aws macOS raw boxes may lack Node/Corepack/pnpm for ${runtimeEntrypoint || "--script-stdin"}; bootstrapping a pinned user-local Node toolchain before the command`,
|
|
1925
|
-
);
|
|
1926
|
-
} else {
|
|
1927
|
-
const id = optionValue(normalizedArgs, "--id");
|
|
1928
|
-
const hydrate = id
|
|
1929
|
-
? `pnpm crabbox:hydrate -- --id ${id}`
|
|
1930
|
-
: "pnpm crabbox:warmup, then pnpm crabbox:hydrate -- --id <id>";
|
|
1931
|
-
console.error(
|
|
1932
|
-
`[crabbox] warning: provider=aws raw boxes may lack Node/Corepack/pnpm for ${runtimeEntrypoint}; hydrate first (${hydrate}) or pass --provider blacksmith-testbox for FengMing CI-like proof; not switching providers automatically`,
|
|
1933
|
-
);
|
|
1934
|
-
}
|
|
1935
|
-
}
|
|
1936
|
-
|
|
1937
|
-
const childEnv = { ...process.env };
|
|
1938
|
-
if (
|
|
1939
|
-
isLocalContainerProvider(provider) &&
|
|
1940
|
-
!childEnv.CRABBOX_LOCAL_CONTAINER_DOCKER_SOCKET &&
|
|
1941
|
-
!hasOption(normalizedArgs, "--local-container-docker-socket")
|
|
1942
|
-
) {
|
|
1943
|
-
childEnv.CRABBOX_LOCAL_CONTAINER_DOCKER_SOCKET = "1";
|
|
1944
|
-
console.error(
|
|
1945
|
-
"[crabbox] provider=docker enabling host Docker socket pass-through for FengMing Docker tests",
|
|
1946
|
-
);
|
|
1947
|
-
}
|
|
1948
|
-
if (
|
|
1949
|
-
isLocalContainerProvider(provider) &&
|
|
1950
|
-
process.platform === "linux" &&
|
|
1951
|
-
!childEnv.CRABBOX_LOCAL_CONTAINER_WORK_ROOT &&
|
|
1952
|
-
!hasOption(normalizedArgs, "--local-container-work-root")
|
|
1953
|
-
) {
|
|
1954
|
-
childEnv.CRABBOX_LOCAL_CONTAINER_WORK_ROOT = "/tmp/fengming-crabbox-docker-work";
|
|
1955
|
-
console.error(
|
|
1956
|
-
"[crabbox] provider=docker using short host-visible work root for FengMing Docker tests",
|
|
1957
|
-
);
|
|
1958
|
-
}
|
|
1959
|
-
|
|
1960
|
-
const childArgs =
|
|
1961
|
-
childCwd === repoRoot
|
|
1962
|
-
? injectRemoteAwsMacosJsBootstrap(normalizedArgs, provider)
|
|
1963
|
-
: injectRemoteChangedGateGitBootstrap(
|
|
1964
|
-
injectRemoteAwsMacosJsBootstrap(absolutizeLocalRunPaths(normalizedArgs), provider),
|
|
1965
|
-
remoteChangedGateBase,
|
|
1966
|
-
);
|
|
1967
|
-
const childInvocation = spawnInvocation(binary, childArgs, childEnv, process.platform);
|
|
1968
|
-
const child = spawn(childInvocation.command, childInvocation.args, {
|
|
1969
|
-
cwd: childCwd,
|
|
1970
|
-
stdio: "inherit",
|
|
1971
|
-
env: childEnv,
|
|
1972
|
-
windowsVerbatimArguments: childInvocation.windowsVerbatimArguments,
|
|
1973
|
-
});
|
|
1974
|
-
|
|
1975
|
-
const signalExitCodes = new Map([
|
|
1976
|
-
["SIGHUP", 129],
|
|
1977
|
-
["SIGINT", 130],
|
|
1978
|
-
["SIGTERM", 143],
|
|
1979
|
-
]);
|
|
1980
|
-
for (const signal of signalExitCodes.keys()) {
|
|
1981
|
-
process.once(signal, () => {
|
|
1982
|
-
if (!child.killed) {
|
|
1983
|
-
child.kill(signal);
|
|
1984
|
-
}
|
|
1985
|
-
cleanupOnce();
|
|
1986
|
-
process.exit(signalExitCodes.get(signal) ?? 1);
|
|
1987
|
-
});
|
|
1988
|
-
}
|
|
1989
|
-
process.once("exit", cleanupOnce);
|
|
1990
|
-
|
|
1991
|
-
child.on("exit", (code, signal) => {
|
|
1992
|
-
cleanupOnce();
|
|
1993
|
-
if (signal) {
|
|
1994
|
-
process.exit(signalExitCodes.get(signal) ?? 1);
|
|
1995
|
-
return;
|
|
1996
|
-
}
|
|
1997
|
-
process.exit(code ?? 1);
|
|
1998
|
-
});
|
|
1999
|
-
|
|
2000
|
-
child.on("error", (error) => {
|
|
2001
|
-
cleanupOnce();
|
|
2002
|
-
console.error(`[crabbox] failed to execute ${displayBinary}: ${error.message}`);
|
|
2003
|
-
process.exit(2);
|
|
2004
|
-
});
|