forgeos 0.1.0-alpha.7 → 0.1.0-alpha.71
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/.agents/skills/forge-agent-fabric/SKILL.md +178 -0
- package/.agents/skills/forge-agent-fabric/references/managed-workflows.md +95 -0
- package/.agents/skills/forge-agent-fabric/references/repository-analysis.md +102 -0
- package/.agents/skills/forge-agent-fabric/scripts/fabric.mjs +46 -0
- package/.agents/skills/forge-agent-fabric/scripts/repository.mjs +44 -0
- package/.npmignore +10 -0
- package/AGENTS.md +142 -90
- package/CHANGELOG.md +870 -9
- package/LICENSE +21 -0
- package/README.md +121 -6
- package/adapters/go/README.md +23 -0
- package/adapters/go/go.mod +3 -0
- package/adapters/go/http.go +149 -0
- package/adapters/go/registry.go +234 -0
- package/adapters/go/types.go +136 -0
- package/adapters/java/README.md +68 -0
- package/adapters/java/pom.xml +47 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Auth.java +20 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Diagnostic.java +16 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Entry.java +38 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/EntryKind.java +16 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ErrorInfo.java +4 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Forge.java +94 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeCall.java +12 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeContext.java +11 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeHandler.java +8 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeHttpHandler.java +179 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeRegistry.java +121 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Json.java +14 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Manifest.java +14 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/RequestEnvelope.java +6 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ResponseEnvelope.java +25 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Risk.java +18 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Schemas.java +36 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Service.java +65 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/TransactionMode.java +18 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/TypedForgeHandler.java +6 -0
- package/adapters/java-spring-boot-starter/README.md +32 -0
- package/adapters/java-spring-boot-starter/pom.xml +49 -0
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeCommand.java +22 -0
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeExternalService.java +15 -0
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeQuery.java +16 -0
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeServiceBeanCondition.java +18 -0
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeSpringAutoConfiguration.java +16 -0
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeSpringRuntime.java +104 -0
- package/adapters/java-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +1 -0
- package/bin/forge.mjs +18 -0
- package/docs/agent-fabric-programs.md +151 -0
- package/docs/agent-fabric.md +582 -0
- package/docs/architecture/agent-fabric/PORTABLE_PROJECTS_PLAN.md +136 -0
- package/docs/architecture/agent-fabric/README.md +180 -0
- package/docs/architecture/agent-fabric/REPOSITORY_MANIFEST_PLAN.md +284 -0
- package/docs/architecture/agent-fabric/WORKFLOW_PROGRAM_V2_ADR.md +81 -0
- package/docs/architecture/agent-fabric/WORKFLOW_PROGRAM_V2_CORRECTIONS.md +39 -0
- package/docs/architecture/agent-fabric/WORKFLOW_PROGRAM_V2_CORRECTIONS_EVIDENCE.md +53 -0
- package/docs/architecture/agent-fabric/WORKFLOW_PROGRAM_V2_EVIDENCE.md +49 -0
- package/docs/architecture/agent-fabric/WORKFLOW_PROGRAM_V2_PLAN.md +590 -0
- package/docs/cair-protocol.md +103 -0
- package/docs/changelog.md +1070 -0
- package/docs/forge-protocol.md +189 -0
- package/docs/repository-agent-benchmark.md +179 -0
- package/docs/repository-analysis.md +139 -0
- package/docs/repository-context-quality.md +179 -0
- package/docs/repository-runtime-observation.md +82 -0
- package/examples/agent-fabric-v2/README.md +70 -0
- package/examples/agent-fabric-v2/item-child.workflow.ts +11 -0
- package/examples/agent-fabric-v2/make-request.mjs +4 -0
- package/examples/agent-fabric-v2/map-child.workflow.ts +10 -0
- package/examples/agent-fabric-v2/migrate.workflow.ts +35 -0
- package/examples/agent-fabric-v2/registry.example.json +256 -0
- package/examples/agent-fabric-v2/run-ui-fixture.ts +48 -0
- package/examples/agent-fabric-v2/ui-audit.workflow.ts +28 -0
- package/examples/agent-fabric-v2/ui-fixture-worker.cjs +36 -0
- package/examples/agent-fabric-v2/visual-population.json +13 -0
- package/examples/agent-fabric-v2/workers/check.mjs +2 -0
- package/examples/agent-fabric-v2/workers/common.mjs +7 -0
- package/examples/agent-fabric-v2/workers/discover.mjs +2 -0
- package/examples/agent-fabric-v2/workers/migrate.mjs +4 -0
- package/examples/agent-fabric-v2/workers/review.mjs +3 -0
- package/examples/go-billing/go.mod +7 -0
- package/examples/go-billing/main.go +120 -0
- package/examples/java-billing/pom.xml +60 -0
- package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/CreateInvoiceInput.java +4 -0
- package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/Invoice.java +11 -0
- package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/Main.java +127 -0
- package/package.json +60 -5
- package/schemas/agent-fabric/v0.1/control-event.schema.json +281 -0
- package/schemas/forge-manifest.schema.json +389 -0
- package/scripts/field-test-forgeos.mjs +1021 -0
- package/scripts/install-agent-fabric-skill.mjs +105 -0
- package/src/forge/_generated/releaseManifest.json +1 -2
- package/src/forge/_generated/releaseManifest.ts +3 -3
- package/src/forge/agent-adapters/index.ts +1592 -125
- package/src/forge/agent-adapters/types.ts +225 -1
- package/src/forge/agent-fabric/adapter.ts +131 -0
- package/src/forge/agent-fabric/attached-snapshot.ts +55 -0
- package/src/forge/agent-fabric/attached-task-contract.ts +105 -0
- package/src/forge/agent-fabric/attached-task-service.ts +127 -0
- package/src/forge/agent-fabric/attached-task-store.ts +109 -0
- package/src/forge/agent-fabric/authority.ts +298 -0
- package/src/forge/agent-fabric/canonical.ts +135 -0
- package/src/forge/agent-fabric/codex-adversarial-review.ts +229 -0
- package/src/forge/agent-fabric/codex-sdk-worker.ts +203 -0
- package/src/forge/agent-fabric/conductor.ts +754 -0
- package/src/forge/agent-fabric/dictionary.ts +12 -0
- package/src/forge/agent-fabric/errors.ts +32 -0
- package/src/forge/agent-fabric/hardened-conductor.ts +485 -0
- package/src/forge/agent-fabric/hardened-reducer.ts +211 -0
- package/src/forge/agent-fabric/index.ts +48 -0
- package/src/forge/agent-fabric/journal.ts +116 -0
- package/src/forge/agent-fabric/local-adaptive-digest-worker.mjs +26 -0
- package/src/forge/agent-fabric/local-adaptive-harness.ts +343 -0
- package/src/forge/agent-fabric/local-adaptive-service.ts +398 -0
- package/src/forge/agent-fabric/local-adaptive-worker.ts +146 -0
- package/src/forge/agent-fabric/local-approval-window.ts +211 -0
- package/src/forge/agent-fabric/local-change-review-service.ts +374 -0
- package/src/forge/agent-fabric/local-coding-worker.ts +285 -0
- package/src/forge/agent-fabric/local-control-store.ts +239 -0
- package/src/forge/agent-fabric/local-effect-broker.ts +348 -0
- package/src/forge/agent-fabric/local-evolution-approval.ts +81 -0
- package/src/forge/agent-fabric/local-evolution-profile.ts +87 -0
- package/src/forge/agent-fabric/local-evolution-registry.ts +427 -0
- package/src/forge/agent-fabric/local-evolution-service.ts +200 -0
- package/src/forge/agent-fabric/local-intelligence.ts +281 -0
- package/src/forge/agent-fabric/local-paths.ts +18 -0
- package/src/forge/agent-fabric/local-task-contract.ts +203 -0
- package/src/forge/agent-fabric/local-task-inbox.ts +543 -0
- package/src/forge/agent-fabric/local-task-server.ts +374 -0
- package/src/forge/agent-fabric/local-task-service.ts +982 -0
- package/src/forge/agent-fabric/local-verification.ts +551 -0
- package/src/forge/agent-fabric/managed-environment.ts +205 -0
- package/src/forge/agent-fabric/managed-run-contract.ts +103 -0
- package/src/forge/agent-fabric/managed-run-service.ts +401 -0
- package/src/forge/agent-fabric/managed-run-store.ts +165 -0
- package/src/forge/agent-fabric/managed-workspace.ts +253 -0
- package/src/forge/agent-fabric/p0a.ts +104 -0
- package/src/forge/agent-fabric/p0b-model-adapter.ts +434 -0
- package/src/forge/agent-fabric/planning.ts +155 -0
- package/src/forge/agent-fabric/program-api.ts +37 -0
- package/src/forge/agent-fabric/program-contract.ts +283 -0
- package/src/forge/agent-fabric/program-dsl.ts +126 -0
- package/src/forge/agent-fabric/program-evidence.ts +22 -0
- package/src/forge/agent-fabric/program-image.ts +15 -0
- package/src/forge/agent-fabric/program-lock.ts +50 -0
- package/src/forge/agent-fabric/program-owner.ts +16 -0
- package/src/forge/agent-fabric/program-scheduler.ts +38 -0
- package/src/forge/agent-fabric/program-service.ts +793 -0
- package/src/forge/agent-fabric/program-store.ts +142 -0
- package/src/forge/agent-fabric/program-structure.ts +65 -0
- package/src/forge/agent-fabric/program-types.ts +110 -0
- package/src/forge/agent-fabric/program-view.ts +12 -0
- package/src/forge/agent-fabric/program-worker.ts +108 -0
- package/src/forge/agent-fabric/project-profile.ts +50 -0
- package/src/forge/agent-fabric/project-registry.ts +120 -0
- package/src/forge/agent-fabric/project-runtime.ts +85 -0
- package/src/forge/agent-fabric/readiness.ts +26 -0
- package/src/forge/agent-fabric/reducer.ts +863 -0
- package/src/forge/agent-fabric/repository-context.ts +83 -0
- package/src/forge/agent-fabric/resource-ledger.ts +266 -0
- package/src/forge/agent-fabric/serialized-local-adapter.ts +60 -0
- package/src/forge/agent-fabric/types.ts +424 -0
- package/src/forge/agent-fabric/validation.ts +500 -0
- package/src/forge/agent-fabric/workflow-engine.ts +218 -0
- package/src/forge/agent-fabric/workflow-task-actions.ts +104 -0
- package/src/forge/agent-fabric/workflow-templates.ts +11 -0
- package/src/forge/agent-memory/bridge.ts +1728 -0
- package/src/forge/agent-memory/context-pack.ts +284 -0
- package/src/forge/agent-memory/hook-runner.ts +331 -0
- package/src/forge/agent-memory/mcp.ts +597 -0
- package/src/forge/agent-memory/normalize.ts +498 -0
- package/src/forge/agent-memory/redaction.ts +103 -0
- package/src/forge/agent-memory/sources/claude-code.ts +51 -0
- package/src/forge/agent-memory/sources/codex-hook-runner.mjs +343 -0
- package/src/forge/agent-memory/sources/codex.ts +161 -0
- package/src/forge/agent-memory/sources/cursor.ts +35 -0
- package/src/forge/agent-memory/types.ts +215 -0
- package/src/forge/bench.ts +248 -0
- package/src/forge/brownfield-import/index.ts +896 -0
- package/src/forge/brownfield-import/types.ts +127 -0
- package/src/forge/cair/action-journal.ts +61 -0
- package/src/forge/cair/action-parser.ts +314 -0
- package/src/forge/cair/action-validator.ts +40 -0
- package/src/forge/cair/actions.ts +1818 -0
- package/src/forge/cair/format.ts +77 -0
- package/src/forge/cair/index.ts +118 -0
- package/src/forge/cair/query.ts +478 -0
- package/src/forge/cair/snapshot.ts +315 -0
- package/src/forge/cair/types.ts +255 -0
- package/src/forge/cli/adaptive.ts +51 -0
- package/src/forge/cli/ai.ts +16 -1
- package/src/forge/cli/auth.ts +459 -15
- package/src/forge/cli/authmd.ts +441 -0
- package/src/forge/cli/baseline.ts +112 -0
- package/src/forge/cli/build.ts +20 -4
- package/src/forge/cli/changed.ts +418 -0
- package/src/forge/cli/codex-app-server.ts +877 -0
- package/src/forge/cli/commands.ts +1859 -20
- package/src/forge/cli/db.ts +209 -2
- package/src/forge/cli/deploy.ts +1339 -0
- package/src/forge/cli/deps.ts +150 -23
- package/src/forge/cli/dev.ts +1137 -53
- package/src/forge/cli/docs.ts +265 -0
- package/src/forge/cli/doctor.ts +297 -0
- package/src/forge/cli/env-placeholders.ts +62 -0
- package/src/forge/cli/evolution.ts +40 -0
- package/src/forge/cli/fabric.ts +253 -0
- package/src/forge/cli/field-test.ts +568 -0
- package/src/forge/cli/golden-path.ts +487 -0
- package/src/forge/cli/handoff.ts +336 -0
- package/src/forge/cli/index.ts +1 -0
- package/src/forge/cli/last-run.ts +84 -0
- package/src/forge/cli/main.ts +196 -3
- package/src/forge/cli/new.ts +169 -17
- package/src/forge/cli/next-actions.ts +23 -0
- package/src/forge/cli/output.ts +398 -6
- package/src/forge/cli/parse.ts +1377 -38
- package/src/forge/cli/progress.ts +51 -0
- package/src/forge/cli/query.ts +32 -0
- package/src/forge/cli/release.ts +35 -11
- package/src/forge/cli/repository.ts +151 -0
- package/src/forge/cli/run.ts +42 -0
- package/src/forge/cli/secrets.ts +137 -1
- package/src/forge/cli/seed.ts +581 -0
- package/src/forge/cli/self-host.ts +56 -14
- package/src/forge/cli/studio.ts +2282 -0
- package/src/forge/cli/verify.ts +1458 -32
- package/src/forge/cli/windows.ts +23 -0
- package/src/forge/cli/workos.ts +3509 -0
- package/src/forge/compiler/agent-contract/build.ts +728 -64
- package/src/forge/compiler/agent-contract/types.ts +45 -2
- package/src/forge/compiler/ai-registry/parse.ts +71 -2
- package/src/forge/compiler/api-surface/build.ts +47 -0
- package/src/forge/compiler/app-graph/build.ts +112 -9
- package/src/forge/compiler/app-graph/extract.ts +107 -0
- package/src/forge/compiler/app-graph/module-graph.ts +73 -78
- package/src/forge/compiler/app-graph/parser.ts +24 -24
- package/src/forge/compiler/app-graph/profile.ts +26 -0
- package/src/forge/compiler/app-graph/tsconfig-hash.ts +41 -4
- package/src/forge/compiler/app-graph/versions.ts +1 -1
- package/src/forge/compiler/classifier/capabilities.ts +3 -2
- package/src/forge/compiler/classifier/classify.ts +32 -8
- package/src/forge/compiler/classifier/secrets.ts +3 -2
- package/src/forge/compiler/classifier/signals.ts +91 -1
- package/src/forge/compiler/client-sdk/build-manifest.ts +59 -0
- package/src/forge/compiler/client-sdk/render-client.ts +295 -13
- package/src/forge/compiler/data-graph/build.ts +29 -1
- package/src/forge/compiler/data-graph/parse.ts +20 -4
- package/src/forge/compiler/data-graph/sql/ddl.ts +144 -31
- package/src/forge/compiler/data-graph/sql/serialize.ts +4 -0
- package/src/forge/compiler/data-graph/sql/types.ts +1 -0
- package/src/forge/compiler/diagnostics/codes.ts +38 -0
- package/src/forge/compiler/diagnostics/create.ts +28 -2
- package/src/forge/compiler/diagnostics/index.ts +2 -0
- package/src/forge/compiler/emitter/barrel.ts +3 -0
- package/src/forge/compiler/emitter/render.ts +9 -0
- package/src/forge/compiler/external-manifest/registry.ts +217 -0
- package/src/forge/compiler/external-manifest/types.ts +91 -0
- package/src/forge/compiler/external-manifest/validate.ts +373 -0
- package/src/forge/compiler/frontend-graph/build.ts +142 -14
- package/src/forge/compiler/integration/add.ts +991 -33
- package/src/forge/compiler/integration/plan.ts +43 -12
- package/src/forge/compiler/integration/render.ts +29 -0
- package/src/forge/compiler/integration/snapshot.ts +2 -0
- package/src/forge/compiler/integration/templates/convex.ts +70 -0
- package/src/forge/compiler/integration/templates/index.ts +1 -0
- package/src/forge/compiler/integration/templates/render.ts +38 -0
- package/src/forge/compiler/integration/templates/types.ts +3 -0
- package/src/forge/compiler/integration/templates/workos.ts +1439 -0
- package/src/forge/compiler/make-registry/build.ts +8 -9
- package/src/forge/compiler/orchestrator/fast-check.ts +4 -0
- package/src/forge/compiler/orchestrator/generate-lock.ts +14 -3
- package/src/forge/compiler/orchestrator/manifest.ts +1 -1
- package/src/forge/compiler/orchestrator/plan-profile.ts +23 -0
- package/src/forge/compiler/orchestrator/plan.ts +249 -10
- package/src/forge/compiler/orchestrator/profile.ts +65 -0
- package/src/forge/compiler/orchestrator/run.ts +101 -33
- package/src/forge/compiler/orchestrator/serialize.ts +33 -8
- package/src/forge/compiler/orchestrator/types.ts +1 -1
- package/src/forge/compiler/package-graph/compiler.ts +3 -1
- package/src/forge/compiler/package-graph/constants.ts +1 -1
- package/src/forge/compiler/package-graph/dts-extractor.ts +14 -1
- package/src/forge/compiler/package-manager/adapter.ts +4 -1
- package/src/forge/compiler/package-manager/commands.ts +4 -0
- package/src/forge/compiler/package-manager/executor.ts +30 -1
- package/src/forge/compiler/package-manager/version.ts +36 -12
- package/src/forge/compiler/package-upgrades/planner.ts +155 -18
- package/src/forge/compiler/package-upgrades/types.ts +2 -0
- package/src/forge/compiler/policy-registry/build.ts +47 -2
- package/src/forge/compiler/policy-registry/parse.ts +32 -2
- package/src/forge/compiler/recipes/definitions.ts +63 -0
- package/src/forge/compiler/recipes/index.ts +2 -0
- package/src/forge/compiler/recipes/profiles.ts +81 -0
- package/src/forge/compiler/recipes/registry.ts +6 -0
- package/src/forge/compiler/test-graph/build.ts +11 -3
- package/src/forge/compiler/types/app-graph.ts +8 -2
- package/src/forge/compiler/types/cli.ts +76 -1
- package/src/forge/compiler/types/dev-manifest.ts +4 -0
- package/src/forge/compiler/types/emit.ts +2 -0
- package/src/forge/compiler/types/frontend-graph.ts +2 -2
- package/src/forge/compiler/types/integration.ts +1 -0
- package/src/forge/compiler/types/package-graph.ts +6 -0
- package/src/forge/compiler/types/policy-registry.ts +3 -1
- package/src/forge/delta/broker-runner.mjs +5 -0
- package/src/forge/delta/broker.ts +429 -0
- package/src/forge/delta/classifier.ts +52 -0
- package/src/forge/delta/explain.ts +238 -0
- package/src/forge/delta/git-observer.ts +67 -0
- package/src/forge/delta/ids.ts +44 -0
- package/src/forge/delta/index.ts +25 -0
- package/src/forge/delta/process-identity.ts +37 -0
- package/src/forge/delta/queue-status.ts +190 -0
- package/src/forge/delta/recorder.ts +540 -0
- package/src/forge/delta/redaction.ts +50 -0
- package/src/forge/delta/schema.ts +240 -0
- package/src/forge/delta/session.ts +142 -0
- package/src/forge/delta/status.ts +1139 -0
- package/src/forge/delta/store.ts +3329 -0
- package/src/forge/delta/timeline.ts +178 -0
- package/src/forge/dev/server.ts +1061 -22
- package/src/forge/dev/types.ts +15 -1
- package/src/forge/dev/watch.ts +17 -7
- package/src/forge/dev-console/cycle.ts +285 -33
- package/src/forge/dev-console/types.ts +47 -1
- package/src/forge/impact/index.ts +222 -30
- package/src/forge/impact/types.ts +33 -1
- package/src/forge/intent/index.ts +35 -16
- package/src/forge/make/fields.ts +26 -0
- package/src/forge/make/index.ts +42 -6
- package/src/forge/make/templates.ts +211 -4
- package/src/forge/make/types.ts +2 -1
- package/src/forge/policy.ts +1 -1
- package/src/forge/react/index.ts +160 -2
- package/src/forge/refactor/index.ts +1 -0
- package/src/forge/repair/rules/index.ts +2 -2
- package/src/forge/repository-analysis/adapters/common.ts +72 -0
- package/src/forge/repository-analysis/adapters/docker.ts +185 -0
- package/src/forge/repository-analysis/adapters/java.ts +133 -0
- package/src/forge/repository-analysis/adapters/typescript.ts +350 -0
- package/src/forge/repository-analysis/adapters/vue.ts +71 -0
- package/src/forge/repository-analysis/analyze.ts +434 -0
- package/src/forge/repository-analysis/benchmark.ts +336 -0
- package/src/forge/repository-analysis/cache-gc.ts +154 -0
- package/src/forge/repository-analysis/check-selection.ts +123 -0
- package/src/forge/repository-analysis/context-node.ts +17 -0
- package/src/forge/repository-analysis/context.ts +456 -0
- package/src/forge/repository-analysis/http-resolution.ts +135 -0
- package/src/forge/repository-analysis/identity.ts +45 -0
- package/src/forge/repository-analysis/index.ts +18 -0
- package/src/forge/repository-analysis/nuxt-resolution.ts +188 -0
- package/src/forge/repository-analysis/quality.ts +60 -0
- package/src/forge/repository-analysis/retrieval.ts +309 -0
- package/src/forge/repository-analysis/runtime-artifacts.ts +195 -0
- package/src/forge/repository-analysis/runtime-observation.ts +325 -0
- package/src/forge/repository-analysis/scanner.ts +174 -0
- package/src/forge/repository-analysis/storage.ts +193 -0
- package/src/forge/repository-analysis/test-associations.ts +59 -0
- package/src/forge/repository-analysis/types.ts +99 -0
- package/src/forge/repository-manifest/index.ts +178 -0
- package/src/forge/repository-manifest/types.ts +63 -0
- package/src/forge/review/index.ts +162 -12
- package/src/forge/review/types.ts +15 -0
- package/src/forge/runtime/ai/providers.ts +19 -4
- package/src/forge/runtime/auth/config.ts +17 -0
- package/src/forge/runtime/auth/evaluate.ts +15 -2
- package/src/forge/runtime/auth/resolve.ts +61 -6
- package/src/forge/runtime/auth/types.ts +1 -0
- package/src/forge/runtime/db/factory.ts +1 -3
- package/src/forge/runtime/db/generated-client.ts +13 -2
- package/src/forge/runtime/db/memory-adapter.ts +139 -32
- package/src/forge/runtime/db/pglite-adapter.ts +285 -2
- package/src/forge/runtime/executor.ts +129 -16
- package/src/forge/runtime/external/bridge.ts +663 -0
- package/src/forge/runtime/runner/run-entry.ts +16 -7
- package/src/forge/runtime/telemetry/buffer.ts +4 -1
- package/src/forge/runtime/telemetry/scrubber.ts +35 -5
- package/src/forge/runtime/webhooks/security.ts +12 -7
- package/src/forge/server.ts +71 -7
- package/src/forge/ui/index.ts +831 -19
- package/src/forge/ui/types.ts +3 -1
- package/src/forge/version.ts +1 -1
- package/src/forge/vue/index.ts +422 -0
- package/src/forge/workspace/baseline.ts +112 -0
- package/src/forge/workspace/change-summary.ts +292 -0
- package/src/forge/workspace/forge-cli.ts +42 -0
- package/src/forge/workspace/git-summary.ts +393 -0
- package/templates/agent-workroom/AGENTS.md +29 -0
- package/templates/agent-workroom/README.md +34 -0
- package/templates/agent-workroom/forge.config.ts +3 -0
- package/templates/agent-workroom/package.json +34 -0
- package/templates/agent-workroom/pnpm-workspace.yaml +2 -0
- package/templates/agent-workroom/src/actions/indexAgentSignal.ts +10 -0
- package/templates/agent-workroom/src/commands/openWorkroom.ts +61 -0
- package/templates/agent-workroom/src/commands/recordAgentSignal.ts +119 -0
- package/templates/agent-workroom/src/commands/recordCheckRun.ts +52 -0
- package/templates/agent-workroom/src/forge/schema.ts +54 -0
- package/templates/agent-workroom/src/policies.ts +6 -0
- package/templates/agent-workroom/src/queries/listWorkrooms.ts +11 -0
- package/templates/agent-workroom/src/queries/liveWorkroom.ts +63 -0
- package/templates/agent-workroom/tsconfig.json +16 -0
- package/templates/agent-workroom/web/index.html +13 -0
- package/templates/agent-workroom/web/package.json +21 -0
- package/templates/agent-workroom/web/src/App.tsx +345 -0
- package/templates/agent-workroom/web/src/lib/forge.ts +20 -0
- package/templates/agent-workroom/web/src/main.tsx +13 -0
- package/templates/agent-workroom/web/src/styles.css +545 -0
- package/templates/agent-workroom/web/tsconfig.json +27 -0
- package/templates/agent-workroom/web/vite.config.ts +36 -0
- package/templates/b2b-support-web/package.json +2 -0
- package/templates/b2b-support-web/pnpm-workspace.yaml +2 -0
- package/templates/b2b-support-web/web/app/page.tsx +2 -2
- package/templates/b2b-support-web/web/lib/forge.ts +9 -2
- package/templates/b2b-support-web/web/next.config.ts +24 -0
- package/templates/b2b-support-web/web/package.json +1 -1
- package/templates/minimal-web/package.json +2 -1
- package/templates/minimal-web/pnpm-workspace.yaml +2 -0
- package/templates/minimal-web/web/index.html +1 -0
- package/templates/minimal-web/web/src/App.tsx +12 -6
- package/templates/minimal-web/web/src/lib/forge.ts +9 -2
- package/templates/minimal-web/web/src/styles.css +34 -0
- package/templates/minimal-web/web/vite.config.ts +36 -0
- package/templates/nuxt-web/.vscode/settings.json +14 -0
- package/templates/nuxt-web/.yarnrc.yml +1 -0
- package/templates/nuxt-web/README.md +30 -0
- package/templates/nuxt-web/forge.config.ts +3 -0
- package/templates/nuxt-web/package.json +37 -0
- package/templates/nuxt-web/pnpm-workspace.yaml +2 -0
- package/templates/nuxt-web/src/actions/logNoteCreated.ts +11 -0
- package/templates/nuxt-web/src/commands/createNote.ts +26 -0
- package/templates/nuxt-web/src/forge/schema.ts +12 -0
- package/templates/nuxt-web/src/policies.ts +6 -0
- package/templates/nuxt-web/src/queries/listNotes.ts +8 -0
- package/templates/nuxt-web/src/queries/liveNotes.ts +8 -0
- package/templates/nuxt-web/tsconfig.json +17 -0
- package/templates/nuxt-web/web/app.vue +67 -0
- package/templates/nuxt-web/web/components/LiveNotes.vue +89 -0
- package/templates/nuxt-web/web/components/NoteComposer.vue +100 -0
- package/templates/nuxt-web/web/composables/forge.ts +13 -0
- package/templates/nuxt-web/web/composables/useNotes.ts +24 -0
- package/templates/nuxt-web/web/nuxt.config.ts +11 -0
- package/templates/nuxt-web/web/package.json +22 -0
- package/templates/nuxt-web/web/plugins/forge.client.ts +10 -0
- package/templates/nuxt-web/web/plugins/forge.server.ts +10 -0
- package/templates/nuxt-web/web/server/api/forge-health.get.ts +7 -0
- package/templates/nuxt-web/web/tsconfig.json +6 -0
- package/templates/vendor-access/.vscode/settings.json +14 -0
- package/templates/vendor-access/README.md +30 -0
- package/templates/vendor-access/forge.config.ts +3 -0
- package/templates/vendor-access/package.json +35 -0
- package/templates/vendor-access/pnpm-workspace.yaml +2 -0
- package/templates/vendor-access/src/commands/addEvidence.ts +42 -0
- package/templates/vendor-access/src/commands/approveAccessRequest.ts +43 -0
- package/templates/vendor-access/src/commands/createAccessRequest.ts +49 -0
- package/templates/vendor-access/src/commands/seedVendorAccessDemo.ts +200 -0
- package/templates/vendor-access/src/forge/schema.ts +74 -0
- package/templates/vendor-access/src/policies.ts +11 -0
- package/templates/vendor-access/src/queries/listVendorAccessDashboard.ts +24 -0
- package/templates/vendor-access/src/queries/liveVendorAccessDashboard.ts +24 -0
- package/templates/vendor-access/tsconfig.json +17 -0
- package/templates/vendor-access/web/index.html +13 -0
- package/templates/vendor-access/web/package.json +21 -0
- package/templates/vendor-access/web/src/App.tsx +573 -0
- package/templates/vendor-access/web/src/lib/forge.ts +20 -0
- package/templates/vendor-access/web/src/main.tsx +205 -0
- package/templates/vendor-access/web/src/styles.css +682 -0
- package/templates/vendor-access/web/tsconfig.json +18 -0
- package/templates/vendor-access/web/vite.config.ts +36 -0
- package/src/forge/_generated/actionSubscriptions.json +0 -2
- package/src/forge/_generated/actionSubscriptions.ts +0 -10
- package/src/forge/_generated/agentAdapterManifest.json +0 -2
- package/src/forge/_generated/agentAdapterManifest.ts +0 -73
- package/src/forge/_generated/agentContract.json +0 -2
- package/src/forge/_generated/agentContract.ts +0 -7829
- package/src/forge/_generated/agentQuickstart.md +0 -34
- package/src/forge/_generated/agentTools.json +0 -2
- package/src/forge/_generated/agentTools.md +0 -16
- package/src/forge/_generated/agentTools.ts +0 -12
- package/src/forge/_generated/aiContext.ts +0 -125
- package/src/forge/_generated/aiModels.json +0 -2
- package/src/forge/_generated/aiModels.ts +0 -51
- package/src/forge/_generated/aiProviders.json +0 -2
- package/src/forge/_generated/aiProviders.ts +0 -23
- package/src/forge/_generated/aiRegistry.json +0 -2
- package/src/forge/_generated/aiRegistry.ts +0 -31
- package/src/forge/_generated/api.json +0 -2
- package/src/forge/_generated/api.ts +0 -8
- package/src/forge/_generated/appGraph.json +0 -2
- package/src/forge/_generated/appGraph.ts +0 -14937
- package/src/forge/_generated/appMap.md +0 -55
- package/src/forge/_generated/artifactManifest.json +0 -2
- package/src/forge/_generated/artifactManifest.ts +0 -7
- package/src/forge/_generated/authClaims.json +0 -2
- package/src/forge/_generated/authClaims.ts +0 -13
- package/src/forge/_generated/authConfig.json +0 -2
- package/src/forge/_generated/authConfig.ts +0 -17
- package/src/forge/_generated/authContext.ts +0 -23
- package/src/forge/_generated/authRegistry.json +0 -2
- package/src/forge/_generated/authRegistry.ts +0 -25
- package/src/forge/_generated/buildInfo.json +0 -2
- package/src/forge/_generated/buildInfo.ts +0 -9
- package/src/forge/_generated/capabilityMap.json +0 -2
- package/src/forge/_generated/capabilityMap.md +0 -15
- package/src/forge/_generated/capabilityMap.ts +0 -17
- package/src/forge/_generated/client.ts +0 -282
- package/src/forge/_generated/clientApi.ts +0 -9
- package/src/forge/_generated/clientManifest.json +0 -2
- package/src/forge/_generated/clientManifest.ts +0 -39
- package/src/forge/_generated/clientTypes.ts +0 -78
- package/src/forge/_generated/configRegistry.json +0 -2
- package/src/forge/_generated/configRegistry.ts +0 -4
- package/src/forge/_generated/dataGraph.json +0 -2
- package/src/forge/_generated/dataGraph.ts +0 -8
- package/src/forge/_generated/db.json +0 -2
- package/src/forge/_generated/db.ts +0 -2
- package/src/forge/_generated/dbSecurityManifest.json +0 -2
- package/src/forge/_generated/dbSecurityManifest.ts +0 -15
- package/src/forge/_generated/dbSessionContext.json +0 -2
- package/src/forge/_generated/dbSessionContext.ts +0 -39
- package/src/forge/_generated/deployManifest.json +0 -2
- package/src/forge/_generated/deployManifest.ts +0 -14
- package/src/forge/_generated/devManifest.json +0 -2
- package/src/forge/_generated/devManifest.ts +0 -62
- package/src/forge/_generated/envSchema.json +0 -2
- package/src/forge/_generated/envSchema.ts +0 -59
- package/src/forge/_generated/frontendGraph.json +0 -2
- package/src/forge/_generated/frontendGraph.ts +0 -27
- package/src/forge/_generated/importGuards.json +0 -2
- package/src/forge/_generated/importGuards.ts +0 -686
- package/src/forge/_generated/index.ts +0 -68
- package/src/forge/_generated/liveProductionManifest.json +0 -2
- package/src/forge/_generated/liveProductionManifest.ts +0 -23
- package/src/forge/_generated/liveProtocol.json +0 -2
- package/src/forge/_generated/liveProtocol.ts +0 -21
- package/src/forge/_generated/liveQueryRegistry.json +0 -2
- package/src/forge/_generated/liveQueryRegistry.ts +0 -9
- package/src/forge/_generated/liveTransportConfig.json +0 -2
- package/src/forge/_generated/liveTransportConfig.ts +0 -19
- package/src/forge/_generated/makeRegistry.json +0 -2
- package/src/forge/_generated/makeRegistry.ts +0 -177
- package/src/forge/_generated/makeTemplates.json +0 -2
- package/src/forge/_generated/makeTemplates.ts +0 -66
- package/src/forge/_generated/mockMap.json +0 -2
- package/src/forge/_generated/mockMap.ts +0 -7
- package/src/forge/_generated/operationPlaybooks.md +0 -167
- package/src/forge/_generated/packageGraph.json +0 -2
- package/src/forge/_generated/packageGraph.ts +0 -249334
- package/src/forge/_generated/packageUpgradeRegistry.json +0 -2
- package/src/forge/_generated/packageUpgradeRegistry.ts +0 -15
- package/src/forge/_generated/permissionMatrix.json +0 -2
- package/src/forge/_generated/permissionMatrix.ts +0 -7
- package/src/forge/_generated/policyRegistry.json +0 -2
- package/src/forge/_generated/policyRegistry.ts +0 -11
- package/src/forge/_generated/queryRegistry.json +0 -2
- package/src/forge/_generated/queryRegistry.ts +0 -9
- package/src/forge/_generated/react.d.ts +0 -22
- package/src/forge/_generated/react.ts +0 -29
- package/src/forge/_generated/reactManifest.json +0 -2
- package/src/forge/_generated/reactManifest.ts +0 -19
- package/src/forge/_generated/rlsPolicies.json +0 -2
- package/src/forge/_generated/rlsPolicies.sql +0 -34
- package/src/forge/_generated/rlsPolicies.ts +0 -6
- package/src/forge/_generated/runtimeGraph.json +0 -2
- package/src/forge/_generated/runtimeGraph.ts +0 -8
- package/src/forge/_generated/runtimeMatrix.json +0 -2
- package/src/forge/_generated/runtimeMatrix.ts +0 -334130
- package/src/forge/_generated/runtimeRegistry.ts +0 -2
- package/src/forge/_generated/runtimeRules.md +0 -91
- package/src/forge/_generated/secretRegistry.json +0 -2
- package/src/forge/_generated/secretRegistry.ts +0 -50
- package/src/forge/_generated/secretsContext.ts +0 -11
- package/src/forge/_generated/serverApi.ts +0 -10
- package/src/forge/_generated/sourceMapManifest.json +0 -2
- package/src/forge/_generated/sourceMapManifest.ts +0 -7
- package/src/forge/_generated/sqlPlan.json +0 -2
- package/src/forge/_generated/sqlPlan.ts +0 -88
- package/src/forge/_generated/subscriptionManifest.json +0 -2
- package/src/forge/_generated/subscriptionManifest.ts +0 -7
- package/src/forge/_generated/symbolicationManifest.json +0 -2
- package/src/forge/_generated/symbolicationManifest.ts +0 -17
- package/src/forge/_generated/telemetryRegistry.json +0 -2
- package/src/forge/_generated/telemetryRegistry.ts +0 -9
- package/src/forge/_generated/telemetrySinks.json +0 -2
- package/src/forge/_generated/telemetrySinks.ts +0 -11
- package/src/forge/_generated/tenantScope.json +0 -2
- package/src/forge/_generated/tenantScope.ts +0 -8
- package/src/forge/_generated/testGraph.json +0 -2
- package/src/forge/_generated/testGraph.ts +0 -3452
- package/src/forge/_generated/testPlanRegistry.json +0 -2
- package/src/forge/_generated/testPlanRegistry.ts +0 -33
- package/src/forge/_generated/uiRoutes.json +0 -2
- package/src/forge/_generated/uiRoutes.ts +0 -16
- package/src/forge/_generated/uiScenarios.json +0 -2
- package/src/forge/_generated/uiScenarios.ts +0 -30
- package/src/forge/_generated/uiTestManifest.json +0 -2
- package/src/forge/_generated/uiTestManifest.ts +0 -27
- package/src/forge/_generated/workflowRegistry.json +0 -2
- package/src/forge/_generated/workflowRegistry.ts +0 -9
- package/src/forge/_generated/workflowSubscriptions.json +0 -2
- package/src/forge/_generated/workflowSubscriptions.ts +0 -10
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { join } from "node:path";
|
|
1
|
+
import { join, relative, resolve } from "node:path";
|
|
2
2
|
import { nodeFileSystem } from "../fs/index.ts";
|
|
3
3
|
import type { AddOptions } from "../types/cli.ts";
|
|
4
4
|
import type { Diagnostic } from "../types/diagnostic.ts";
|
|
5
5
|
import type { Dependency } from "../types/package-graph.ts";
|
|
6
|
+
import type { IntegrationRecipe } from "../types/integration.ts";
|
|
6
7
|
import type { ClassifiedPackage } from "../classifier/runtime-matrix.ts";
|
|
7
8
|
import { buildAppGraph } from "../app-graph/build.ts";
|
|
8
9
|
import { classify } from "../classifier/classify.ts";
|
|
@@ -16,17 +17,21 @@ import { PACKAGE_ANALYZER_VERSION } from "../package-graph/constants.ts";
|
|
|
16
17
|
import { renderBody } from "../emitter/render.ts";
|
|
17
18
|
import { hashStable } from "../primitives/hash.ts";
|
|
18
19
|
import { PackageGraphCompiler } from "../package-graph/compiler.ts";
|
|
20
|
+
import { run as runGenerate } from "../orchestrator/run.ts";
|
|
19
21
|
import {
|
|
22
|
+
buildAddCommand,
|
|
20
23
|
detectAndCreatePackageManagerAdapter,
|
|
21
24
|
dryRunRecipeFallbackMessage,
|
|
22
25
|
type PackageManagerAdapter,
|
|
23
26
|
} from "../package-manager/adapter.ts";
|
|
27
|
+
import { parsePackageName } from "../package-manager/parse-spec.ts";
|
|
24
28
|
import { PackageManagerCommandError } from "../package-manager/executor.ts";
|
|
25
29
|
import {
|
|
26
30
|
isReferenceAlias,
|
|
27
31
|
resolveByPackageName,
|
|
28
32
|
resolveRecipe,
|
|
29
33
|
} from "../recipes/registry.ts";
|
|
34
|
+
import { applyWorkOSRecipeProfile } from "../recipes/profiles.ts";
|
|
30
35
|
import { discover } from "../orchestrator/discover.ts";
|
|
31
36
|
import {
|
|
32
37
|
loadManifest,
|
|
@@ -50,6 +55,24 @@ export interface ForgeAddOptions extends AddOptions {
|
|
|
50
55
|
|
|
51
56
|
export interface ForgeAddResult {
|
|
52
57
|
alias: string;
|
|
58
|
+
mode?: "integration" | "package";
|
|
59
|
+
targetKind?: "forge-integration" | "npm-package";
|
|
60
|
+
target?: string;
|
|
61
|
+
packageTarget?: "root" | "frontend" | "backend" | "workspace";
|
|
62
|
+
packageTargetReason?: string;
|
|
63
|
+
explanation?: string;
|
|
64
|
+
recipeVersion?: string;
|
|
65
|
+
recipePackages?: string[];
|
|
66
|
+
requiredSecrets?: string[];
|
|
67
|
+
optionalSecrets?: string[];
|
|
68
|
+
packageSpec?: string;
|
|
69
|
+
packageName?: string;
|
|
70
|
+
packageManager?: string;
|
|
71
|
+
installCommand?: string[];
|
|
72
|
+
nativeInstallCommand?: string[];
|
|
73
|
+
avoidedManualCommand?: string;
|
|
74
|
+
installCwd?: string;
|
|
75
|
+
installWorkspace?: string;
|
|
53
76
|
changed: string[];
|
|
54
77
|
unchanged: string[];
|
|
55
78
|
warnings: Diagnostic[];
|
|
@@ -58,6 +81,337 @@ export interface ForgeAddResult {
|
|
|
58
81
|
failureKind?: string;
|
|
59
82
|
}
|
|
60
83
|
|
|
84
|
+
function recipeResultMetadata(recipe: IntegrationRecipe): Pick<
|
|
85
|
+
ForgeAddResult,
|
|
86
|
+
"recipeVersion" | "recipePackages" | "requiredSecrets" | "optionalSecrets"
|
|
87
|
+
> {
|
|
88
|
+
return {
|
|
89
|
+
recipeVersion: recipe.recipeVersion,
|
|
90
|
+
recipePackages: recipe.packages.map((pkg) => pkg.packageName),
|
|
91
|
+
requiredSecrets: recipe.secrets.filter((secret) => secret.required !== false).map((secret) => secret.envVar),
|
|
92
|
+
optionalSecrets: recipe.secrets.filter((secret) => secret.required === false).map((secret) => secret.envVar),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function addExplanation(result: ForgeAddResult): string {
|
|
97
|
+
if (result.mode === "package") {
|
|
98
|
+
const location = result.target && result.target !== "root" ? `${result.target}/package.json` : "package.json";
|
|
99
|
+
const command = result.installCommand?.join(" ") ?? `package manager add ${result.packageSpec ?? result.alias}`;
|
|
100
|
+
const target = result.packageTarget && result.packageTarget !== "root" ? ` (${result.packageTarget})` : "";
|
|
101
|
+
return `Adds npm package '${result.packageSpec ?? result.alias}' to ${location}${target}, then refreshes Forge package evidence. Forge runs the native install command for you: ${command}.`;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (result.failureKind === "unknown_alias") {
|
|
105
|
+
return `No Forge integration recipe exists for '${result.alias}'. Use 'forge add ${result.alias}' or 'forge add package ${result.alias}' for a normal npm package, or choose a supported integration alias.`;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return `Applies the Forge integration recipe '${result.alias}', including package install, generated adapters, secret-name metadata, runtime guards, and Forge lock evidence.`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function finalizeAddResult(result: Omit<ForgeAddResult, "targetKind" | "explanation">): ForgeAddResult {
|
|
112
|
+
const mode = result.mode ?? "integration";
|
|
113
|
+
const withMode: ForgeAddResult = {
|
|
114
|
+
...result,
|
|
115
|
+
mode,
|
|
116
|
+
targetKind: mode === "package" ? "npm-package" : "forge-integration",
|
|
117
|
+
};
|
|
118
|
+
return {
|
|
119
|
+
...withMode,
|
|
120
|
+
explanation: addExplanation(withMode),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function packageJsonRelativeFor(workspace?: string): string {
|
|
125
|
+
return workspace ? `${workspace.replace(/\\/g, "/")}/package.json` : "package.json";
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function readPackageJsonDependencies(packageJsonPath: string): Record<string, string> {
|
|
129
|
+
if (!nodeFileSystem.exists(packageJsonPath)) {
|
|
130
|
+
return {};
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
const parsed = JSON.parse(nodeFileSystem.readText(packageJsonPath) ?? "{}") as {
|
|
134
|
+
dependencies?: Record<string, string>;
|
|
135
|
+
devDependencies?: Record<string, string>;
|
|
136
|
+
peerDependencies?: Record<string, string>;
|
|
137
|
+
optionalDependencies?: Record<string, string>;
|
|
138
|
+
};
|
|
139
|
+
return {
|
|
140
|
+
...(parsed.dependencies ?? {}),
|
|
141
|
+
...(parsed.devDependencies ?? {}),
|
|
142
|
+
...(parsed.peerDependencies ?? {}),
|
|
143
|
+
...(parsed.optionalDependencies ?? {}),
|
|
144
|
+
};
|
|
145
|
+
} catch {
|
|
146
|
+
return {};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function packageJsonDeclares(packageJsonPath: string, packageName: string): boolean {
|
|
151
|
+
return Object.prototype.hasOwnProperty.call(readPackageJsonDependencies(packageJsonPath), packageName);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function packageInstallEvidence(installRoot: string, packageName: string): {
|
|
155
|
+
installPath: string;
|
|
156
|
+
version: string;
|
|
157
|
+
} | null {
|
|
158
|
+
const installPath = join(installRoot, "node_modules", ...packageName.split("/"));
|
|
159
|
+
const packageJsonPath = join(installPath, "package.json");
|
|
160
|
+
if (!nodeFileSystem.exists(packageJsonPath)) {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
try {
|
|
164
|
+
const parsed = JSON.parse(nodeFileSystem.readText(packageJsonPath) ?? "{}") as {
|
|
165
|
+
version?: unknown;
|
|
166
|
+
};
|
|
167
|
+
return {
|
|
168
|
+
installPath,
|
|
169
|
+
version: typeof parsed.version === "string" && parsed.version.length > 0 ? parsed.version : "0.0.0",
|
|
170
|
+
};
|
|
171
|
+
} catch {
|
|
172
|
+
return {
|
|
173
|
+
installPath,
|
|
174
|
+
version: "0.0.0",
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function dependencyRangeFromInstalledVersion(version: string): string {
|
|
180
|
+
if (/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(version)) {
|
|
181
|
+
return `^${version}`;
|
|
182
|
+
}
|
|
183
|
+
return version && version !== "0.0.0" ? version : "*";
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function ensurePackageJsonDependency(packageJsonPath: string, packageName: string, version: string): boolean {
|
|
187
|
+
if (!nodeFileSystem.exists(packageJsonPath) || packageJsonDeclares(packageJsonPath, packageName)) {
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
const parsed = JSON.parse(nodeFileSystem.readText(packageJsonPath) ?? "{}") as {
|
|
191
|
+
dependencies?: Record<string, string>;
|
|
192
|
+
};
|
|
193
|
+
parsed.dependencies = {
|
|
194
|
+
...(parsed.dependencies ?? {}),
|
|
195
|
+
[packageName]: dependencyRangeFromInstalledVersion(version),
|
|
196
|
+
};
|
|
197
|
+
parsed.dependencies = Object.fromEntries(
|
|
198
|
+
Object.entries(parsed.dependencies).sort(([left], [right]) => left.localeCompare(right)),
|
|
199
|
+
);
|
|
200
|
+
nodeFileSystem.writeText(packageJsonPath, `${JSON.stringify(parsed, null, 2)}\n`);
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async function addPackageOrContinueIfInstalled(input: {
|
|
205
|
+
pm: PackageManagerAdapter;
|
|
206
|
+
packageName: string;
|
|
207
|
+
workspaceRoot: string;
|
|
208
|
+
installRoot: string;
|
|
209
|
+
packageJsonPath: string;
|
|
210
|
+
ignoreScripts: boolean;
|
|
211
|
+
warnings: Diagnostic[];
|
|
212
|
+
doctorCommand: string;
|
|
213
|
+
allowInstalledFallback: boolean;
|
|
214
|
+
}): Promise<void> {
|
|
215
|
+
if (packageJsonDeclares(input.packageJsonPath, input.packageName)) {
|
|
216
|
+
input.warnings.push(
|
|
217
|
+
createDiagnostic({
|
|
218
|
+
severity: "warning",
|
|
219
|
+
code: "FORGE_ADD_PACKAGE_ALREADY_DECLARED",
|
|
220
|
+
message: `${input.packageName} is already declared in ${relative(input.workspaceRoot, input.packageJsonPath).replace(/\\/g, "/")}; skipped package-manager install and continued recipe generation.`,
|
|
221
|
+
fixHint: `Run your package manager install if node_modules is missing, then rerun ${input.doctorCommand}.`,
|
|
222
|
+
suggestedCommands: [input.doctorCommand],
|
|
223
|
+
}),
|
|
224
|
+
);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
try {
|
|
229
|
+
await input.pm.add(input.packageName, {
|
|
230
|
+
cwd: input.installRoot,
|
|
231
|
+
ignoreScripts: input.ignoreScripts,
|
|
232
|
+
});
|
|
233
|
+
return;
|
|
234
|
+
} catch (error) {
|
|
235
|
+
if (!input.allowInstalledFallback) {
|
|
236
|
+
throw error;
|
|
237
|
+
}
|
|
238
|
+
const evidence = packageInstallEvidence(input.installRoot, input.packageName);
|
|
239
|
+
if (!evidence) {
|
|
240
|
+
throw error;
|
|
241
|
+
}
|
|
242
|
+
const declared = ensurePackageJsonDependency(input.packageJsonPath, input.packageName, evidence.version);
|
|
243
|
+
input.warnings.push(
|
|
244
|
+
createDiagnostic({
|
|
245
|
+
severity: "warning",
|
|
246
|
+
code: "FORGE_ADD_PACKAGE_ALREADY_INSTALLED",
|
|
247
|
+
message: `package-manager install for ${input.packageName} failed, but the package is already installed at ${relative(input.workspaceRoot, evidence.installPath).replace(/\\/g, "/")}; ${declared ? "recorded it in package.json and continued" : "continued recipe generation"}.`,
|
|
248
|
+
fixHint: `Rerun ${input.doctorCommand}; if node_modules was restored from cache, this is expected.`,
|
|
249
|
+
suggestedCommands: [input.doctorCommand],
|
|
250
|
+
}),
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
type PackageAddScope = "root" | "frontend" | "backend" | "workspace";
|
|
256
|
+
|
|
257
|
+
interface NormalizedPackageRequest {
|
|
258
|
+
spec: string;
|
|
259
|
+
packageTarget: PackageAddScope;
|
|
260
|
+
packageTargetReason: string;
|
|
261
|
+
installWorkspace?: string;
|
|
262
|
+
forcePackageMode: boolean;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function parseScopedPackageSpec(spec: string): {
|
|
266
|
+
spec: string;
|
|
267
|
+
target?: "frontend" | "backend";
|
|
268
|
+
forcePackageMode: boolean;
|
|
269
|
+
} {
|
|
270
|
+
const trimmed = spec.trim();
|
|
271
|
+
const match = /^(frontend|front|web|client|backend|back|server|api|root):(.+)$/i.exec(trimmed);
|
|
272
|
+
if (!match) {
|
|
273
|
+
return { spec: trimmed, forcePackageMode: false };
|
|
274
|
+
}
|
|
275
|
+
const scope = match[1]!.toLowerCase();
|
|
276
|
+
return {
|
|
277
|
+
spec: match[2]!.trim(),
|
|
278
|
+
target: scope === "frontend" || scope === "front" || scope === "web" || scope === "client"
|
|
279
|
+
? "frontend"
|
|
280
|
+
: "backend",
|
|
281
|
+
forcePackageMode: true,
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function findFrontendWorkspace(workspaceRoot: string): string | undefined {
|
|
286
|
+
for (const candidate of ["web", "frontend", "client", "apps/web", "packages/web"]) {
|
|
287
|
+
if (nodeFileSystem.exists(join(workspaceRoot, candidate, "package.json"))) {
|
|
288
|
+
return candidate;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return undefined;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function normalizePackageRequest(
|
|
295
|
+
spec: string,
|
|
296
|
+
options: ForgeAddOptions,
|
|
297
|
+
): { request: NormalizedPackageRequest; error?: Diagnostic } {
|
|
298
|
+
const scoped = parseScopedPackageSpec(spec);
|
|
299
|
+
const requestedTarget = options.packageTarget ?? scoped.target;
|
|
300
|
+
if (options.installWorkspace?.trim()) {
|
|
301
|
+
return {
|
|
302
|
+
request: {
|
|
303
|
+
spec: scoped.spec,
|
|
304
|
+
packageTarget: "workspace",
|
|
305
|
+
packageTargetReason: `explicit --workspace ${options.installWorkspace.trim()}`,
|
|
306
|
+
installWorkspace: options.installWorkspace.trim(),
|
|
307
|
+
forcePackageMode: scoped.forcePackageMode,
|
|
308
|
+
},
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
if (requestedTarget === "frontend") {
|
|
312
|
+
const workspace = findFrontendWorkspace(options.workspaceRoot);
|
|
313
|
+
if (!workspace) {
|
|
314
|
+
return {
|
|
315
|
+
request: {
|
|
316
|
+
spec: scoped.spec,
|
|
317
|
+
packageTarget: "frontend",
|
|
318
|
+
packageTargetReason: "frontend target requested, but no frontend package.json was detected",
|
|
319
|
+
forcePackageMode: true,
|
|
320
|
+
},
|
|
321
|
+
error: createDiagnostic({
|
|
322
|
+
severity: "error",
|
|
323
|
+
code: "FORGE_ADD_FRONTEND_WORKSPACE_MISSING",
|
|
324
|
+
message: "frontend package target requested, but no frontend package.json was found under web, frontend, client, apps/web, or packages/web",
|
|
325
|
+
fixHint: "Create a frontend with forge make ui, pass --workspace <path>, or install as a backend/root package.",
|
|
326
|
+
suggestedCommands: [
|
|
327
|
+
"forge make ui --framework vite --dry-run --json",
|
|
328
|
+
`forge add ${scoped.spec} --workspace web --dry-run --json`,
|
|
329
|
+
`forge add backend:${scoped.spec} --dry-run --json`,
|
|
330
|
+
],
|
|
331
|
+
}),
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
return {
|
|
335
|
+
request: {
|
|
336
|
+
spec: scoped.spec,
|
|
337
|
+
packageTarget: "frontend",
|
|
338
|
+
packageTargetReason: `frontend target resolved to ${workspace}/package.json`,
|
|
339
|
+
installWorkspace: workspace,
|
|
340
|
+
forcePackageMode: true,
|
|
341
|
+
},
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
if (requestedTarget === "backend") {
|
|
345
|
+
return {
|
|
346
|
+
request: {
|
|
347
|
+
spec: scoped.spec,
|
|
348
|
+
packageTarget: "backend",
|
|
349
|
+
packageTargetReason: "backend target resolves to the Forge app root package.json",
|
|
350
|
+
forcePackageMode: true,
|
|
351
|
+
},
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
return {
|
|
355
|
+
request: {
|
|
356
|
+
spec: scoped.spec,
|
|
357
|
+
packageTarget: "root",
|
|
358
|
+
packageTargetReason: "default package target resolves to the Forge app root package.json",
|
|
359
|
+
forcePackageMode: scoped.forcePackageMode,
|
|
360
|
+
},
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function resolveInstallRoot(options: ForgeAddOptions): {
|
|
365
|
+
installRoot: string;
|
|
366
|
+
target: string;
|
|
367
|
+
extraSnapshotPaths: string[];
|
|
368
|
+
error?: Diagnostic;
|
|
369
|
+
} {
|
|
370
|
+
const workspace = options.installWorkspace?.trim();
|
|
371
|
+
if (!workspace) {
|
|
372
|
+
return {
|
|
373
|
+
installRoot: options.workspaceRoot,
|
|
374
|
+
target: "root",
|
|
375
|
+
extraSnapshotPaths: [],
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const workspaceRoot = resolve(options.workspaceRoot);
|
|
380
|
+
const installRoot = resolve(workspaceRoot, workspace);
|
|
381
|
+
const rel = relative(workspaceRoot, installRoot).replace(/\\/g, "/");
|
|
382
|
+
if (rel.startsWith("..") || rel === "") {
|
|
383
|
+
return {
|
|
384
|
+
installRoot,
|
|
385
|
+
target: workspace,
|
|
386
|
+
extraSnapshotPaths: [],
|
|
387
|
+
error: createDiagnostic({
|
|
388
|
+
severity: "error",
|
|
389
|
+
code: "FORGE_ADD_INVALID_WORKSPACE",
|
|
390
|
+
message: `workspace '${workspace}' must resolve inside the Forge app`,
|
|
391
|
+
}),
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
if (!nodeFileSystem.exists(join(installRoot, "package.json"))) {
|
|
396
|
+
return {
|
|
397
|
+
installRoot,
|
|
398
|
+
target: rel,
|
|
399
|
+
extraSnapshotPaths: [],
|
|
400
|
+
error: createDiagnostic({
|
|
401
|
+
severity: "error",
|
|
402
|
+
code: "FORGE_ADD_INVALID_WORKSPACE",
|
|
403
|
+
message: `workspace '${workspace}' does not contain a package.json`,
|
|
404
|
+
}),
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
return {
|
|
409
|
+
installRoot,
|
|
410
|
+
target: rel,
|
|
411
|
+
extraSnapshotPaths: [packageJsonRelativeFor(rel)],
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
|
|
61
415
|
function failureKind(errors: Diagnostic[]): string | undefined {
|
|
62
416
|
if (errors.length === 0) {
|
|
63
417
|
return undefined;
|
|
@@ -119,8 +473,318 @@ function dependencyFromInstall(
|
|
|
119
473
|
};
|
|
120
474
|
}
|
|
121
475
|
|
|
476
|
+
function fileHashOrNull(path: string): string | null {
|
|
477
|
+
if (!nodeFileSystem.exists(path)) {
|
|
478
|
+
return null;
|
|
479
|
+
}
|
|
480
|
+
return hashStable(nodeFileSystem.readText(path) ?? "");
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
function snapshotPackageManagerFiles(
|
|
484
|
+
workspaceRoot: string,
|
|
485
|
+
pm: PackageManagerAdapter,
|
|
486
|
+
extraPaths: string[] = [],
|
|
487
|
+
): Map<string, string | null> {
|
|
488
|
+
const paths = [...new Set(["package.json", pm.lockfile, ...extraPaths])];
|
|
489
|
+
return new Map(
|
|
490
|
+
paths.map((path) => [
|
|
491
|
+
path,
|
|
492
|
+
fileHashOrNull(join(workspaceRoot, path)),
|
|
493
|
+
]),
|
|
494
|
+
);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
function changedPackageManagerFiles(
|
|
498
|
+
workspaceRoot: string,
|
|
499
|
+
before: Map<string, string | null>,
|
|
500
|
+
): string[] {
|
|
501
|
+
const changed: string[] = [];
|
|
502
|
+
for (const [path, previousHash] of before) {
|
|
503
|
+
if (fileHashOrNull(join(workspaceRoot, path)) !== previousHash) {
|
|
504
|
+
changed.push(path);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
return changed.sort();
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
function workosFrontendWorkspace(workspaceRoot: string): string | undefined {
|
|
511
|
+
return findFrontendWorkspace(workspaceRoot);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
function parseDotEnv(text: string | null): Record<string, string> {
|
|
515
|
+
const result: Record<string, string> = {};
|
|
516
|
+
for (const line of (text ?? "").split(/\r?\n/)) {
|
|
517
|
+
const trimmed = line.trim();
|
|
518
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
519
|
+
const match = trimmed.match(/^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/);
|
|
520
|
+
if (!match) continue;
|
|
521
|
+
result[match[1]!] = match[2]!.replace(/^["']|["']$/g, "");
|
|
522
|
+
}
|
|
523
|
+
return result;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
function renderMergedDotEnv(current: string | null, values: Record<string, string>): string {
|
|
527
|
+
const lines = (current ?? "").split(/\r?\n/);
|
|
528
|
+
const seen = new Set<string>();
|
|
529
|
+
const next = lines.map((line) => {
|
|
530
|
+
const match = line.match(/^([A-Za-z_][A-Za-z0-9_]*)=/);
|
|
531
|
+
if (!match || !(match[1]! in values)) {
|
|
532
|
+
return line;
|
|
533
|
+
}
|
|
534
|
+
seen.add(match[1]!);
|
|
535
|
+
return `${match[1]}=${values[match[1]!]}`;
|
|
536
|
+
});
|
|
537
|
+
for (const [key, value] of Object.entries(values)) {
|
|
538
|
+
if (!seen.has(key)) {
|
|
539
|
+
next.push(`${key}=${value}`);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
return `${next.filter((line, index, all) => line.length > 0 || index < all.length - 1).join("\n").trimEnd()}\n`;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
function syncWorkOSPublicWebEnv(workspaceRoot: string, frontendWorkspace: string): { changed: string[] } {
|
|
546
|
+
const rootLocal = parseDotEnv(nodeFileSystem.readText(join(workspaceRoot, ".env.local")));
|
|
547
|
+
const rootExample = parseDotEnv(nodeFileSystem.readText(join(workspaceRoot, ".env.example")));
|
|
548
|
+
const source = { ...rootExample, ...rootLocal };
|
|
549
|
+
const clientId = source.VITE_WORKOS_CLIENT_ID || source.WORKOS_CLIENT_ID || "";
|
|
550
|
+
const redirectUri = source.VITE_WORKOS_REDIRECT_URI || source.WORKOS_REDIRECT_URI || "http://localhost:5173/callback";
|
|
551
|
+
const values: Record<string, string> = {
|
|
552
|
+
VITE_FORGE_URL: source.VITE_FORGE_URL || "http://localhost:3765",
|
|
553
|
+
VITE_WORKOS_CLIENT_ID: clientId,
|
|
554
|
+
VITE_WORKOS_REDIRECT_URI: redirectUri,
|
|
555
|
+
VITE_FORGE_WORKOS_TENANT_MAP: source.VITE_FORGE_WORKOS_TENANT_MAP || "",
|
|
556
|
+
VITE_FORGE_WORKOS_TENANT_ID_FALLBACK: source.VITE_FORGE_WORKOS_TENANT_ID_FALLBACK || "",
|
|
557
|
+
};
|
|
558
|
+
const envRel = `${frontendWorkspace}/.env.local`;
|
|
559
|
+
const envPath = join(workspaceRoot, envRel);
|
|
560
|
+
const current = nodeFileSystem.readText(envPath);
|
|
561
|
+
const next = renderMergedDotEnv(current, values);
|
|
562
|
+
if (current === next) {
|
|
563
|
+
return { changed: [] };
|
|
564
|
+
}
|
|
565
|
+
nodeFileSystem.mkdirp(join(workspaceRoot, frontendWorkspace));
|
|
566
|
+
nodeFileSystem.writeText(envPath, next);
|
|
567
|
+
return { changed: [envRel] };
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
function connectWorkOSReactRoot(workspaceRoot: string, frontendWorkspace: string): {
|
|
571
|
+
changed: string[];
|
|
572
|
+
warnings: Diagnostic[];
|
|
573
|
+
} {
|
|
574
|
+
const mainRel = `${frontendWorkspace}/src/main.tsx`;
|
|
575
|
+
const mainPath = join(workspaceRoot, mainRel);
|
|
576
|
+
const current = nodeFileSystem.readText(mainPath);
|
|
577
|
+
if (current === null) {
|
|
578
|
+
return {
|
|
579
|
+
changed: [],
|
|
580
|
+
warnings: [
|
|
581
|
+
createDiagnostic({
|
|
582
|
+
severity: "warning",
|
|
583
|
+
code: "FORGE_WORKOS_AUTHKIT_ROOT_NOT_FOUND",
|
|
584
|
+
message: `generated WorkOS AuthKit bridge, but ${mainRel} was not found`,
|
|
585
|
+
fixHint: "Wrap the web app root with ForgeWorkOSAuthProvider from ./lib/workos-auth.",
|
|
586
|
+
suggestedCommands: ["forge workos doctor --json", "forge inspect ui --json"],
|
|
587
|
+
}),
|
|
588
|
+
],
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
if (current.includes("ForgeWorkOSAuthProvider")) {
|
|
592
|
+
return { changed: [], warnings: [] };
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
const canRewriteVendorAccessRoot =
|
|
596
|
+
current.includes('import { ForgeProvider, forgeUrl } from "./lib/forge";') &&
|
|
597
|
+
current.includes("function LocalForgeProvider") &&
|
|
598
|
+
(
|
|
599
|
+
current.includes("<LocalForgeProvider persona={persona}>{app}</LocalForgeProvider>") ||
|
|
600
|
+
current.includes("<LocalForgeProvider persona={signedInPersona}>")
|
|
601
|
+
);
|
|
602
|
+
|
|
603
|
+
if (canRewriteVendorAccessRoot) {
|
|
604
|
+
const personaType = current.includes("LocalPersona") ? "LocalPersona" : "DemoPersona";
|
|
605
|
+
const withWorkOSImport = current.replace(
|
|
606
|
+
'import { ForgeProvider, forgeUrl } from "./lib/forge";',
|
|
607
|
+
[
|
|
608
|
+
'import { ForgeProvider, forgeUrl } from "./lib/forge";',
|
|
609
|
+
'import { ForgeWorkOSAuthProvider, hasWorkOSBrowserConfig, useForgeWorkOSSession, useWorkOSAuth } from "./lib/workos-auth";',
|
|
610
|
+
].join("\n"),
|
|
611
|
+
);
|
|
612
|
+
if (withWorkOSImport.includes("function LoginScreen(") && !withWorkOSImport.includes("function WorkOSVendorAccessRoot()")) {
|
|
613
|
+
const withWorkOSEntry = withWorkOSImport.replace(
|
|
614
|
+
"function Root() {\n",
|
|
615
|
+
[
|
|
616
|
+
"function Root() {",
|
|
617
|
+
" if (hasWorkOSBrowserConfig()) {",
|
|
618
|
+
" return (",
|
|
619
|
+
" <ForgeWorkOSAuthProvider>",
|
|
620
|
+
" <WorkOSVendorAccessRoot />",
|
|
621
|
+
" </ForgeWorkOSAuthProvider>",
|
|
622
|
+
" );",
|
|
623
|
+
" }",
|
|
624
|
+
"",
|
|
625
|
+
].join("\n"),
|
|
626
|
+
);
|
|
627
|
+
const workOSRoot = [
|
|
628
|
+
"function WorkOSVendorAccessRoot() {",
|
|
629
|
+
" const auth = useWorkOSAuth();",
|
|
630
|
+
" const workosSession = useForgeWorkOSSession();",
|
|
631
|
+
"",
|
|
632
|
+
" if (auth.isLoading || (auth.user && workosSession.loading)) {",
|
|
633
|
+
" return (",
|
|
634
|
+
" <main className=\"login-shell\">",
|
|
635
|
+
" <section className=\"login-panel\">",
|
|
636
|
+
" <p className=\"eyebrow\">Secure workspace</p>",
|
|
637
|
+
" <h1>Checking your session</h1>",
|
|
638
|
+
" </section>",
|
|
639
|
+
" </main>",
|
|
640
|
+
" );",
|
|
641
|
+
" }",
|
|
642
|
+
"",
|
|
643
|
+
" if (auth.user && workosSession.error) {",
|
|
644
|
+
" return (",
|
|
645
|
+
" <main className=\"login-shell\">",
|
|
646
|
+
" <section className=\"login-panel\">",
|
|
647
|
+
" <p className=\"eyebrow\">Identity provider</p>",
|
|
648
|
+
" <h1>Session unavailable</h1>",
|
|
649
|
+
" <p className=\"notice error\">{workosSession.error.message}</p>",
|
|
650
|
+
" <div className=\"login-form\">",
|
|
651
|
+
" <button type=\"button\" onClick={() => void workosSession.refresh()}>Retry session</button>",
|
|
652
|
+
" <button className=\"secondary\" type=\"button\" onClick={() => auth.signOut()}>Sign out</button>",
|
|
653
|
+
" </div>",
|
|
654
|
+
" </section>",
|
|
655
|
+
" </main>",
|
|
656
|
+
" );",
|
|
657
|
+
" }",
|
|
658
|
+
"",
|
|
659
|
+
" if (!auth.user) {",
|
|
660
|
+
" return (",
|
|
661
|
+
" <main className=\"login-shell\">",
|
|
662
|
+
" <section className=\"login-panel\">",
|
|
663
|
+
" <div className=\"brand login-brand\">",
|
|
664
|
+
" <span className=\"brand-mark\">VA</span>",
|
|
665
|
+
" <div>",
|
|
666
|
+
" <strong>Vendor Access</strong>",
|
|
667
|
+
" <span>Risk operations</span>",
|
|
668
|
+
" </div>",
|
|
669
|
+
" </div>",
|
|
670
|
+
" <p className=\"eyebrow\">WorkOS AuthKit</p>",
|
|
671
|
+
" <h1>Sign in to review vendor access</h1>",
|
|
672
|
+
" <div className=\"login-form\">",
|
|
673
|
+
" <button type=\"button\" onClick={() => auth.signIn()}>Sign in with WorkOS</button>",
|
|
674
|
+
" <button className=\"secondary\" type=\"button\" onClick={() => auth.signUp()}>Create account</button>",
|
|
675
|
+
" </div>",
|
|
676
|
+
" </section>",
|
|
677
|
+
" <aside className=\"login-context\">",
|
|
678
|
+
" <span>Identity provider</span>",
|
|
679
|
+
" <strong>AuthKit session required</strong>",
|
|
680
|
+
" <p>Organization, role, and permissions come from your signed-in workspace session.</p>",
|
|
681
|
+
" </aside>",
|
|
682
|
+
" </main>",
|
|
683
|
+
" );",
|
|
684
|
+
" }",
|
|
685
|
+
"",
|
|
686
|
+
" const claims = workosSession.session?.claims;",
|
|
687
|
+
" const email = workosSession.session?.user?.email ?? auth.user.email ?? claims?.email ?? \"workos-user@example.com\";",
|
|
688
|
+
" const organizationId = claims?.organization_id ?? \"workos-organization\";",
|
|
689
|
+
" const role = claims?.role ?? claims?.roles?.[0] ?? \"member\";",
|
|
690
|
+
" const permissions = claims?.permissions ?? [];",
|
|
691
|
+
` const persona: ${personaType} = {`,
|
|
692
|
+
" id: `workos:${organizationId}:${email}`,",
|
|
693
|
+
" label: email,",
|
|
694
|
+
" email,",
|
|
695
|
+
" organizationId,",
|
|
696
|
+
" organizationName: organizationId,",
|
|
697
|
+
" role,",
|
|
698
|
+
" permissions,",
|
|
699
|
+
" };",
|
|
700
|
+
"",
|
|
701
|
+
" return (",
|
|
702
|
+
" <App",
|
|
703
|
+
" persona={persona}",
|
|
704
|
+
" personas={[persona]}",
|
|
705
|
+
" onPersonaChange={() => undefined}",
|
|
706
|
+
" onSignOut={() => auth.signOut()}",
|
|
707
|
+
" />",
|
|
708
|
+
" );",
|
|
709
|
+
"}",
|
|
710
|
+
"",
|
|
711
|
+
].join("\n");
|
|
712
|
+
const next = withWorkOSEntry.replace("function LoginScreen(", `${workOSRoot}function LoginScreen(`);
|
|
713
|
+
if (next !== current) {
|
|
714
|
+
nodeFileSystem.writeText(mainPath, next);
|
|
715
|
+
return { changed: [mainRel], warnings: [] };
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
let next = withWorkOSImport.replace(
|
|
719
|
+
"<LocalForgeProvider persona={persona}>{app}</LocalForgeProvider>",
|
|
720
|
+
[
|
|
721
|
+
"hasWorkOSBrowserConfig() ? (",
|
|
722
|
+
" <ForgeWorkOSAuthProvider>{app}</ForgeWorkOSAuthProvider>",
|
|
723
|
+
" ) : (",
|
|
724
|
+
" <LocalForgeProvider persona={persona}>{app}</LocalForgeProvider>",
|
|
725
|
+
" )",
|
|
726
|
+
].join("\n "),
|
|
727
|
+
);
|
|
728
|
+
if (next === withWorkOSImport) {
|
|
729
|
+
const rootReturn = / return \(\n <LocalForgeProvider persona=\{signedInPersona\}>\n([\s\S]*?) <\/LocalForgeProvider>\n \);/m;
|
|
730
|
+
next = withWorkOSImport.replace(rootReturn, (_match, appBody: string) => {
|
|
731
|
+
const app = String(appBody).replace(/^ /gm, " ");
|
|
732
|
+
return [
|
|
733
|
+
" const app = (",
|
|
734
|
+
app.trimEnd(),
|
|
735
|
+
" );",
|
|
736
|
+
"",
|
|
737
|
+
" return hasWorkOSBrowserConfig() ? (",
|
|
738
|
+
" <ForgeWorkOSAuthProvider>{app}</ForgeWorkOSAuthProvider>",
|
|
739
|
+
" ) : (",
|
|
740
|
+
" <LocalForgeProvider persona={signedInPersona}>{app}</LocalForgeProvider>",
|
|
741
|
+
" );",
|
|
742
|
+
].join("\n");
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
if (next !== current) {
|
|
746
|
+
nodeFileSystem.writeText(mainPath, next);
|
|
747
|
+
return { changed: [mainRel], warnings: [] };
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
const canRewriteDefaultViteRoot =
|
|
752
|
+
current.includes('import { ForgeProvider, forgeUrl } from "./lib/forge";') &&
|
|
753
|
+
current.includes("<ForgeProvider url={forgeUrl} devAuth>") &&
|
|
754
|
+
current.includes("</ForgeProvider>");
|
|
755
|
+
|
|
756
|
+
if (!canRewriteDefaultViteRoot) {
|
|
757
|
+
return {
|
|
758
|
+
changed: [],
|
|
759
|
+
warnings: [
|
|
760
|
+
createDiagnostic({
|
|
761
|
+
severity: "warning",
|
|
762
|
+
code: "FORGE_WORKOS_AUTHKIT_ROOT_CUSTOM",
|
|
763
|
+
message: `generated WorkOS AuthKit bridge, but ${mainRel} is custom and was not rewritten automatically`,
|
|
764
|
+
fixHint: "Import ForgeWorkOSAuthProvider from ./lib/workos-auth and wrap the app root with it so AuthKit tokens are passed to ForgeProvider.",
|
|
765
|
+
suggestedCommands: ["forge workos doctor --json", "forge inspect ui --json"],
|
|
766
|
+
}),
|
|
767
|
+
],
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
const next = current
|
|
772
|
+
.replace(
|
|
773
|
+
'import { ForgeProvider, forgeUrl } from "./lib/forge";',
|
|
774
|
+
'import { ForgeWorkOSAuthProvider } from "./lib/workos-auth";',
|
|
775
|
+
)
|
|
776
|
+
.replace("<ForgeProvider url={forgeUrl} devAuth>", "<ForgeWorkOSAuthProvider>")
|
|
777
|
+
.replace("</ForgeProvider>", "</ForgeWorkOSAuthProvider>");
|
|
778
|
+
|
|
779
|
+
if (next !== current) {
|
|
780
|
+
nodeFileSystem.writeText(mainPath, next);
|
|
781
|
+
return { changed: [mainRel], warnings: [] };
|
|
782
|
+
}
|
|
783
|
+
return { changed: [], warnings: [] };
|
|
784
|
+
}
|
|
785
|
+
|
|
122
786
|
async function analyzeRecipePackages(
|
|
123
|
-
recipe:
|
|
787
|
+
recipe: IntegrationRecipe,
|
|
124
788
|
ctx: ReturnType<typeof discover>,
|
|
125
789
|
installRoot: string,
|
|
126
790
|
options: ForgeAddOptions,
|
|
@@ -177,7 +841,7 @@ async function analyzeRecipePackages(
|
|
|
177
841
|
|
|
178
842
|
async function buildAddPlan(
|
|
179
843
|
alias: string,
|
|
180
|
-
recipe:
|
|
844
|
+
recipe: IntegrationRecipe,
|
|
181
845
|
ctx: ReturnType<typeof discover>,
|
|
182
846
|
installRoot: string,
|
|
183
847
|
options: ForgeAddOptions,
|
|
@@ -258,37 +922,100 @@ export async function forgeAdd(
|
|
|
258
922
|
alias: string,
|
|
259
923
|
options: ForgeAddOptions,
|
|
260
924
|
): Promise<ForgeAddResult> {
|
|
261
|
-
const
|
|
925
|
+
const packageRequestResult = normalizePackageRequest(alias, options);
|
|
926
|
+
const packageRequest = packageRequestResult.request;
|
|
927
|
+
const effectiveOptions: ForgeAddOptions = {
|
|
928
|
+
...options,
|
|
929
|
+
installWorkspace: packageRequest.installWorkspace,
|
|
930
|
+
};
|
|
931
|
+
const packageModeRequested =
|
|
932
|
+
options.mode === "package" ||
|
|
933
|
+
packageRequest.forcePackageMode ||
|
|
934
|
+
options.packageTarget !== undefined;
|
|
935
|
+
if (packageRequestResult.error && packageModeRequested) {
|
|
936
|
+
return finalizeAddResult({
|
|
937
|
+
alias: packageRequest.spec,
|
|
938
|
+
mode: "package",
|
|
939
|
+
target: packageRequest.installWorkspace ?? packageRequest.packageTarget,
|
|
940
|
+
packageTarget: packageRequest.packageTarget,
|
|
941
|
+
packageTargetReason: packageRequest.packageTargetReason,
|
|
942
|
+
packageSpec: packageRequest.spec,
|
|
943
|
+
packageName: parsePackageName(packageRequest.spec),
|
|
944
|
+
changed: [],
|
|
945
|
+
unchanged: [],
|
|
946
|
+
warnings: [],
|
|
947
|
+
errors: [packageRequestResult.error],
|
|
948
|
+
exitCode: 1,
|
|
949
|
+
failureKind: "invalid_workspace",
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
if (options.mode === "integration" && (packageRequest.forcePackageMode || options.packageTarget)) {
|
|
953
|
+
const error = createDiagnostic({
|
|
954
|
+
severity: "error",
|
|
955
|
+
code: "FORGE_ADD_SCOPED_INTEGRATION",
|
|
956
|
+
message: "frontend/backend package targets only apply to normal npm package installs, not explicit integration recipes",
|
|
957
|
+
fixHint: "Use forge add package <spec> --frontend, forge add frontend:<spec>, or remove the frontend/backend target for an integration recipe.",
|
|
958
|
+
suggestedCommands: [
|
|
959
|
+
`forge add package ${packageRequest.spec} --frontend --dry-run --json`,
|
|
960
|
+
`forge add integration ${packageRequest.spec} --dry-run --json`,
|
|
961
|
+
],
|
|
962
|
+
});
|
|
963
|
+
return finalizeAddResult({
|
|
964
|
+
alias: packageRequest.spec,
|
|
965
|
+
mode: "integration",
|
|
966
|
+
changed: [],
|
|
967
|
+
unchanged: [],
|
|
968
|
+
warnings: [],
|
|
969
|
+
errors: [error],
|
|
970
|
+
exitCode: 1,
|
|
971
|
+
failureKind: "invalid_target",
|
|
972
|
+
});
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
const normalized = packageRequest.spec.trim().toLowerCase();
|
|
262
976
|
const recipe = resolveRecipe(normalized);
|
|
977
|
+
const mode = options.mode ?? "auto";
|
|
978
|
+
|
|
979
|
+
if (packageModeRequested) {
|
|
980
|
+
return forgeAddPackage(packageRequest.spec, effectiveOptions, packageRequest);
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
if (mode === "auto" && (!isReferenceAlias(normalized) || recipe === null)) {
|
|
984
|
+
return forgeAddPackage(packageRequest.spec, effectiveOptions, packageRequest);
|
|
985
|
+
}
|
|
263
986
|
|
|
264
987
|
if (!isReferenceAlias(normalized) || recipe === null) {
|
|
265
988
|
const error = createDiagnostic({
|
|
266
989
|
severity: "error",
|
|
267
990
|
code: "FORGE_UNKNOWN_ALIAS",
|
|
268
|
-
message: `unknown integration alias '${alias}'; supported: stripe, posthog, sentry, zod, ai
|
|
991
|
+
message: `unknown integration alias '${alias}'; supported: stripe, posthog, sentry, zod, convex, workos, ai. For npm packages, use 'forge add package ${alias}' or 'forge add ${alias}'.`,
|
|
992
|
+
suggestedCommands: [`forge add package ${alias} --dry-run --json`, "forge add --help"],
|
|
269
993
|
});
|
|
270
|
-
return {
|
|
994
|
+
return finalizeAddResult({
|
|
271
995
|
alias: normalized,
|
|
996
|
+
mode: "integration",
|
|
272
997
|
changed: [],
|
|
273
998
|
unchanged: [],
|
|
274
999
|
warnings: [],
|
|
275
1000
|
errors: [error],
|
|
276
1001
|
exitCode: 1,
|
|
277
1002
|
failureKind: "unknown_alias",
|
|
278
|
-
};
|
|
1003
|
+
});
|
|
279
1004
|
}
|
|
280
1005
|
|
|
1006
|
+
const effectiveRecipe = applyWorkOSRecipeProfile(recipe, effectiveOptions);
|
|
1007
|
+
|
|
281
1008
|
const pm =
|
|
282
1009
|
options.pmAdapter ??
|
|
283
1010
|
detectAndCreatePackageManagerAdapter(options.workspaceRoot);
|
|
284
1011
|
|
|
285
1012
|
if (options.dryRun) {
|
|
286
|
-
const ctx = discover({ workspaceRoot:
|
|
1013
|
+
const ctx = discover({ workspaceRoot: effectiveOptions.workspaceRoot });
|
|
287
1014
|
let installRoot = options.workspaceRoot;
|
|
288
1015
|
|
|
289
1016
|
try {
|
|
290
1017
|
const dryRun = await pm.dryRunAddWithPath(
|
|
291
|
-
|
|
1018
|
+
effectiveRecipe.packages.map((pkg) => pkg.packageName).join(" "),
|
|
292
1019
|
{
|
|
293
1020
|
cwd: options.workspaceRoot,
|
|
294
1021
|
ignoreScripts: !options.allowScripts,
|
|
@@ -299,10 +1026,10 @@ export async function forgeAdd(
|
|
|
299
1026
|
const fallback = dryRunRecipeFallbackMessage(normalized);
|
|
300
1027
|
const { emitPlan, warnings, errors } = await buildAddPlan(
|
|
301
1028
|
normalized,
|
|
302
|
-
|
|
1029
|
+
effectiveRecipe,
|
|
303
1030
|
ctx,
|
|
304
1031
|
installRoot,
|
|
305
|
-
|
|
1032
|
+
effectiveOptions,
|
|
306
1033
|
);
|
|
307
1034
|
warnings.push(
|
|
308
1035
|
createDiagnostic({
|
|
@@ -312,50 +1039,83 @@ export async function forgeAdd(
|
|
|
312
1039
|
}),
|
|
313
1040
|
);
|
|
314
1041
|
|
|
315
|
-
return {
|
|
1042
|
+
return finalizeAddResult({
|
|
316
1043
|
alias: normalized,
|
|
1044
|
+
mode: "integration",
|
|
1045
|
+
...recipeResultMetadata(effectiveRecipe),
|
|
317
1046
|
changed: [...emitPlan.files.map((file) => file.path), "forge.lock"],
|
|
318
1047
|
unchanged: [],
|
|
319
1048
|
warnings,
|
|
320
1049
|
errors,
|
|
321
1050
|
exitCode: errors.length > 0 ? 1 : 0,
|
|
322
1051
|
failureKind: failureKind(errors),
|
|
323
|
-
};
|
|
1052
|
+
});
|
|
324
1053
|
}
|
|
325
1054
|
|
|
326
1055
|
const { emitPlan, warnings, errors } = await buildAddPlan(
|
|
327
1056
|
normalized,
|
|
328
|
-
|
|
1057
|
+
effectiveRecipe,
|
|
329
1058
|
ctx,
|
|
330
1059
|
installRoot,
|
|
331
|
-
|
|
1060
|
+
effectiveOptions,
|
|
332
1061
|
);
|
|
333
1062
|
|
|
334
|
-
return {
|
|
1063
|
+
return finalizeAddResult({
|
|
335
1064
|
alias: normalized,
|
|
1065
|
+
mode: "integration",
|
|
1066
|
+
...recipeResultMetadata(effectiveRecipe),
|
|
336
1067
|
changed: [...emitPlan.files.map((file) => file.path), "forge.lock"],
|
|
337
1068
|
unchanged: [],
|
|
338
1069
|
warnings,
|
|
339
1070
|
errors,
|
|
340
1071
|
exitCode: errors.length > 0 ? 1 : 0,
|
|
341
1072
|
failureKind: failureKind(errors),
|
|
342
|
-
};
|
|
1073
|
+
});
|
|
343
1074
|
}
|
|
344
1075
|
|
|
345
1076
|
const snapshot = snapshotVersionControlled(options.workspaceRoot);
|
|
346
1077
|
|
|
347
1078
|
try {
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
1079
|
+
const frontendWorkspace = normalized === "workos" ? workosFrontendWorkspace(options.workspaceRoot) : undefined;
|
|
1080
|
+
const packageManagerBefore = snapshotPackageManagerFiles(
|
|
1081
|
+
options.workspaceRoot,
|
|
1082
|
+
pm,
|
|
1083
|
+
frontendWorkspace ? [packageJsonRelativeFor(frontendWorkspace)] : [],
|
|
1084
|
+
);
|
|
1085
|
+
const preinstalledWarnings: Diagnostic[] = [];
|
|
1086
|
+
for (const pkg of effectiveRecipe.packages) {
|
|
1087
|
+
const rootPackageJson = join(options.workspaceRoot, "package.json");
|
|
1088
|
+
await addPackageOrContinueIfInstalled({
|
|
1089
|
+
pm,
|
|
1090
|
+
packageName: pkg.packageName,
|
|
1091
|
+
workspaceRoot: options.workspaceRoot,
|
|
1092
|
+
installRoot: options.workspaceRoot,
|
|
1093
|
+
packageJsonPath: rootPackageJson,
|
|
351
1094
|
ignoreScripts: !options.allowScripts,
|
|
1095
|
+
warnings: preinstalledWarnings,
|
|
1096
|
+
doctorCommand: "forge check --json",
|
|
1097
|
+
allowInstalledFallback: normalized === "workos",
|
|
1098
|
+
});
|
|
1099
|
+
}
|
|
1100
|
+
if (frontendWorkspace) {
|
|
1101
|
+
const frontendPackageJson = join(options.workspaceRoot, frontendWorkspace, "package.json");
|
|
1102
|
+
await addPackageOrContinueIfInstalled({
|
|
1103
|
+
pm,
|
|
1104
|
+
packageName: "@workos-inc/authkit-react",
|
|
1105
|
+
workspaceRoot: options.workspaceRoot,
|
|
1106
|
+
installRoot: join(options.workspaceRoot, frontendWorkspace),
|
|
1107
|
+
packageJsonPath: frontendPackageJson,
|
|
1108
|
+
ignoreScripts: !options.allowScripts,
|
|
1109
|
+
warnings: preinstalledWarnings,
|
|
1110
|
+
doctorCommand: "forge workos doctor --json",
|
|
1111
|
+
allowInstalledFallback: true,
|
|
352
1112
|
});
|
|
353
1113
|
}
|
|
354
1114
|
|
|
355
1115
|
const ctx = discover({ workspaceRoot: options.workspaceRoot });
|
|
356
1116
|
const { emitPlan, warnings, errors: analyzeErrors } = await buildAddPlan(
|
|
357
1117
|
normalized,
|
|
358
|
-
|
|
1118
|
+
effectiveRecipe,
|
|
359
1119
|
ctx,
|
|
360
1120
|
options.workspaceRoot,
|
|
361
1121
|
options,
|
|
@@ -363,15 +1123,17 @@ export async function forgeAdd(
|
|
|
363
1123
|
|
|
364
1124
|
if (analyzeErrors.length > 0) {
|
|
365
1125
|
restoreVersionControlledSnapshot(options.workspaceRoot, snapshot);
|
|
366
|
-
return {
|
|
1126
|
+
return finalizeAddResult({
|
|
367
1127
|
alias: normalized,
|
|
1128
|
+
mode: "integration",
|
|
1129
|
+
...recipeResultMetadata(effectiveRecipe),
|
|
368
1130
|
changed: [],
|
|
369
1131
|
unchanged: [],
|
|
370
1132
|
warnings,
|
|
371
1133
|
errors: analyzeErrors,
|
|
372
1134
|
exitCode: 1,
|
|
373
1135
|
failureKind: failureKind(analyzeErrors),
|
|
374
|
-
};
|
|
1136
|
+
});
|
|
375
1137
|
}
|
|
376
1138
|
|
|
377
1139
|
const emitResult = await emit(emitPlan, {
|
|
@@ -379,20 +1141,30 @@ export async function forgeAdd(
|
|
|
379
1141
|
mode: "write",
|
|
380
1142
|
});
|
|
381
1143
|
|
|
382
|
-
const
|
|
1144
|
+
const workosWeb = normalized === "workos" && frontendWorkspace
|
|
1145
|
+
? (() => {
|
|
1146
|
+
const root = connectWorkOSReactRoot(options.workspaceRoot, frontendWorkspace);
|
|
1147
|
+
const env = syncWorkOSPublicWebEnv(options.workspaceRoot, frontendWorkspace);
|
|
1148
|
+
return { changed: [...root.changed, ...env.changed], warnings: root.warnings };
|
|
1149
|
+
})()
|
|
1150
|
+
: { changed: [] as string[], warnings: [] as Diagnostic[] };
|
|
1151
|
+
|
|
1152
|
+
const warningsCombined = [...preinstalledWarnings, ...warnings, ...emitResult.warnings, ...workosWeb.warnings];
|
|
383
1153
|
const errors = [...analyzeErrors, ...emitResult.errors];
|
|
384
1154
|
|
|
385
1155
|
if (errors.length > 0) {
|
|
386
1156
|
restoreVersionControlledSnapshot(options.workspaceRoot, snapshot);
|
|
387
|
-
return {
|
|
1157
|
+
return finalizeAddResult({
|
|
388
1158
|
alias: normalized,
|
|
1159
|
+
mode: "integration",
|
|
1160
|
+
...recipeResultMetadata(effectiveRecipe),
|
|
389
1161
|
changed: [],
|
|
390
1162
|
unchanged: [],
|
|
391
1163
|
warnings: warningsCombined,
|
|
392
1164
|
errors,
|
|
393
1165
|
exitCode: 1,
|
|
394
1166
|
failureKind: failureKind(errors),
|
|
395
|
-
};
|
|
1167
|
+
});
|
|
396
1168
|
}
|
|
397
1169
|
|
|
398
1170
|
const integrityErrors = verifyLockIntegrity(
|
|
@@ -401,15 +1173,17 @@ export async function forgeAdd(
|
|
|
401
1173
|
);
|
|
402
1174
|
if (integrityErrors.length > 0) {
|
|
403
1175
|
restoreVersionControlledSnapshot(options.workspaceRoot, snapshot);
|
|
404
|
-
return {
|
|
1176
|
+
return finalizeAddResult({
|
|
405
1177
|
alias: normalized,
|
|
1178
|
+
mode: "integration",
|
|
1179
|
+
...recipeResultMetadata(effectiveRecipe),
|
|
406
1180
|
changed: [],
|
|
407
1181
|
unchanged: [],
|
|
408
1182
|
warnings: warningsCombined,
|
|
409
1183
|
errors: integrityErrors,
|
|
410
1184
|
exitCode: 1,
|
|
411
1185
|
failureKind: "lock_integrity",
|
|
412
|
-
};
|
|
1186
|
+
});
|
|
413
1187
|
}
|
|
414
1188
|
|
|
415
1189
|
const manifest = loadManifest(ctx.cacheDir);
|
|
@@ -435,14 +1209,20 @@ export async function forgeAdd(
|
|
|
435
1209
|
),
|
|
436
1210
|
);
|
|
437
1211
|
|
|
438
|
-
return {
|
|
1212
|
+
return finalizeAddResult({
|
|
439
1213
|
alias: normalized,
|
|
440
|
-
|
|
1214
|
+
mode: "integration",
|
|
1215
|
+
...recipeResultMetadata(effectiveRecipe),
|
|
1216
|
+
changed: [
|
|
1217
|
+
...changedPackageManagerFiles(options.workspaceRoot, packageManagerBefore),
|
|
1218
|
+
...emitResult.changed,
|
|
1219
|
+
...workosWeb.changed,
|
|
1220
|
+
],
|
|
441
1221
|
unchanged: emitResult.unchanged,
|
|
442
1222
|
warnings: warningsCombined,
|
|
443
1223
|
errors: [],
|
|
444
1224
|
exitCode: 0,
|
|
445
|
-
};
|
|
1225
|
+
});
|
|
446
1226
|
} catch (error) {
|
|
447
1227
|
restoreVersionControlledSnapshot(options.workspaceRoot, snapshot);
|
|
448
1228
|
|
|
@@ -459,15 +1239,193 @@ export async function forgeAdd(
|
|
|
459
1239
|
message: `forge add failed: ${message}`,
|
|
460
1240
|
});
|
|
461
1241
|
|
|
462
|
-
return {
|
|
1242
|
+
return finalizeAddResult({
|
|
463
1243
|
alias: normalized,
|
|
1244
|
+
mode: "integration",
|
|
1245
|
+
...recipeResultMetadata(effectiveRecipe),
|
|
464
1246
|
changed: [],
|
|
465
1247
|
unchanged: [],
|
|
466
1248
|
warnings: [],
|
|
467
1249
|
errors: [diagnostic],
|
|
468
1250
|
exitCode: 1,
|
|
469
1251
|
failureKind: "install_failed",
|
|
470
|
-
};
|
|
1252
|
+
});
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
async function forgeAddPackage(
|
|
1257
|
+
spec: string,
|
|
1258
|
+
options: ForgeAddOptions,
|
|
1259
|
+
request = normalizePackageRequest(spec, options).request,
|
|
1260
|
+
): Promise<ForgeAddResult> {
|
|
1261
|
+
const normalized = request.spec.trim();
|
|
1262
|
+
const packageName = parsePackageName(normalized);
|
|
1263
|
+
const target = resolveInstallRoot(options);
|
|
1264
|
+
if (target.error) {
|
|
1265
|
+
return finalizeAddResult({
|
|
1266
|
+
alias: normalized,
|
|
1267
|
+
mode: "package",
|
|
1268
|
+
target: target.target,
|
|
1269
|
+
packageTarget: request.packageTarget,
|
|
1270
|
+
packageTargetReason: request.packageTargetReason,
|
|
1271
|
+
changed: [],
|
|
1272
|
+
unchanged: [],
|
|
1273
|
+
warnings: [],
|
|
1274
|
+
errors: [target.error],
|
|
1275
|
+
exitCode: 1,
|
|
1276
|
+
failureKind: "invalid_workspace",
|
|
1277
|
+
});
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
const pm =
|
|
1281
|
+
options.pmAdapter ??
|
|
1282
|
+
detectAndCreatePackageManagerAdapter(options.workspaceRoot);
|
|
1283
|
+
const packageManagerCwd = target.installRoot;
|
|
1284
|
+
const semanticInstallWorkspace = target.target === "root" ? undefined : target.target;
|
|
1285
|
+
const installCommand = buildAddCommand(pm.name, normalized, {
|
|
1286
|
+
ignoreScripts: !options.allowScripts,
|
|
1287
|
+
workspace: undefined,
|
|
1288
|
+
});
|
|
1289
|
+
const avoidedManualCommand = installCommand.join(" ");
|
|
1290
|
+
const installPlan = {
|
|
1291
|
+
packageSpec: normalized,
|
|
1292
|
+
packageName,
|
|
1293
|
+
packageManager: pm.name,
|
|
1294
|
+
installCommand,
|
|
1295
|
+
nativeInstallCommand: installCommand,
|
|
1296
|
+
avoidedManualCommand,
|
|
1297
|
+
installCwd: packageManagerCwd.replace(/\\/g, "/"),
|
|
1298
|
+
packageTarget: request.packageTarget,
|
|
1299
|
+
packageTargetReason: request.packageTargetReason,
|
|
1300
|
+
...(semanticInstallWorkspace ? { installWorkspace: semanticInstallWorkspace } : {}),
|
|
1301
|
+
};
|
|
1302
|
+
|
|
1303
|
+
if (options.dryRun) {
|
|
1304
|
+
try {
|
|
1305
|
+
await pm.dryRunAdd(normalized, {
|
|
1306
|
+
cwd: packageManagerCwd,
|
|
1307
|
+
ignoreScripts: !options.allowScripts,
|
|
1308
|
+
workspace: undefined,
|
|
1309
|
+
});
|
|
1310
|
+
} catch (error) {
|
|
1311
|
+
const message =
|
|
1312
|
+
error instanceof PackageManagerCommandError
|
|
1313
|
+
? error.message
|
|
1314
|
+
: error instanceof Error
|
|
1315
|
+
? error.message
|
|
1316
|
+
: String(error);
|
|
1317
|
+
const diagnostic = createDiagnostic({
|
|
1318
|
+
severity: "error",
|
|
1319
|
+
code: "FORGE_ADD_INSTALL_FAILED",
|
|
1320
|
+
message: `forge add package dry-run failed: ${message}`,
|
|
1321
|
+
});
|
|
1322
|
+
return finalizeAddResult({
|
|
1323
|
+
alias: normalized,
|
|
1324
|
+
mode: "package",
|
|
1325
|
+
target: target.target,
|
|
1326
|
+
...installPlan,
|
|
1327
|
+
changed: [],
|
|
1328
|
+
unchanged: [],
|
|
1329
|
+
warnings: [],
|
|
1330
|
+
errors: [diagnostic],
|
|
1331
|
+
exitCode: 1,
|
|
1332
|
+
failureKind: "install_failed",
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
return finalizeAddResult({
|
|
1337
|
+
alias: normalized,
|
|
1338
|
+
mode: "package",
|
|
1339
|
+
target: target.target,
|
|
1340
|
+
...installPlan,
|
|
1341
|
+
changed: [
|
|
1342
|
+
packageJsonRelativeFor(target.target === "root" ? undefined : target.target),
|
|
1343
|
+
],
|
|
1344
|
+
unchanged: [],
|
|
1345
|
+
warnings: [],
|
|
1346
|
+
errors: [],
|
|
1347
|
+
exitCode: 0,
|
|
1348
|
+
});
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
const snapshot = snapshotVersionControlled(
|
|
1352
|
+
options.workspaceRoot,
|
|
1353
|
+
target.extraSnapshotPaths,
|
|
1354
|
+
);
|
|
1355
|
+
|
|
1356
|
+
try {
|
|
1357
|
+
await pm.add(normalized, {
|
|
1358
|
+
cwd: packageManagerCwd,
|
|
1359
|
+
ignoreScripts: !options.allowScripts,
|
|
1360
|
+
workspace: undefined,
|
|
1361
|
+
});
|
|
1362
|
+
|
|
1363
|
+
const generated = await runGenerate({
|
|
1364
|
+
workspaceRoot: options.workspaceRoot,
|
|
1365
|
+
check: false,
|
|
1366
|
+
dryRun: false,
|
|
1367
|
+
json: options.json,
|
|
1368
|
+
concurrency: 4,
|
|
1369
|
+
});
|
|
1370
|
+
|
|
1371
|
+
if (generated.exitCode !== 0) {
|
|
1372
|
+
restoreVersionControlledSnapshot(options.workspaceRoot, snapshot);
|
|
1373
|
+
return finalizeAddResult({
|
|
1374
|
+
alias: normalized,
|
|
1375
|
+
mode: "package",
|
|
1376
|
+
target: target.target,
|
|
1377
|
+
...installPlan,
|
|
1378
|
+
changed: [],
|
|
1379
|
+
unchanged: [],
|
|
1380
|
+
warnings: generated.warnings,
|
|
1381
|
+
errors: generated.errors,
|
|
1382
|
+
exitCode: 1,
|
|
1383
|
+
failureKind: generated.failureKind,
|
|
1384
|
+
});
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
return finalizeAddResult({
|
|
1388
|
+
alias: normalized,
|
|
1389
|
+
mode: "package",
|
|
1390
|
+
target: target.target,
|
|
1391
|
+
...installPlan,
|
|
1392
|
+
changed: [
|
|
1393
|
+
packageJsonRelativeFor(target.target === "root" ? undefined : target.target),
|
|
1394
|
+
...generated.changed,
|
|
1395
|
+
],
|
|
1396
|
+
unchanged: generated.unchanged,
|
|
1397
|
+
warnings: generated.warnings,
|
|
1398
|
+
errors: generated.errors,
|
|
1399
|
+
exitCode: 0,
|
|
1400
|
+
});
|
|
1401
|
+
} catch (error) {
|
|
1402
|
+
restoreVersionControlledSnapshot(options.workspaceRoot, snapshot);
|
|
1403
|
+
|
|
1404
|
+
const message =
|
|
1405
|
+
error instanceof PackageManagerCommandError
|
|
1406
|
+
? error.message
|
|
1407
|
+
: error instanceof Error
|
|
1408
|
+
? error.message
|
|
1409
|
+
: String(error);
|
|
1410
|
+
|
|
1411
|
+
const diagnostic = createDiagnostic({
|
|
1412
|
+
severity: "error",
|
|
1413
|
+
code: "FORGE_ADD_INSTALL_FAILED",
|
|
1414
|
+
message: `forge add package failed: ${message}`,
|
|
1415
|
+
});
|
|
1416
|
+
|
|
1417
|
+
return finalizeAddResult({
|
|
1418
|
+
alias: normalized,
|
|
1419
|
+
mode: "package",
|
|
1420
|
+
target: target.target,
|
|
1421
|
+
...installPlan,
|
|
1422
|
+
changed: [],
|
|
1423
|
+
unchanged: [],
|
|
1424
|
+
warnings: [],
|
|
1425
|
+
errors: [diagnostic],
|
|
1426
|
+
exitCode: 1,
|
|
1427
|
+
failureKind: "install_failed",
|
|
1428
|
+
});
|
|
471
1429
|
}
|
|
472
1430
|
}
|
|
473
1431
|
|