forgeos 0.1.0-alpha.0 → 0.1.0-alpha.2
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/.npmignore +9 -1
- package/AGENTS.md +6 -1
- package/CHANGELOG.md +30 -0
- package/CONTRIBUTING.md +22 -1
- package/README.md +30 -3
- package/bin/forge.mjs +4 -3
- package/package.json +3 -1
- package/packages/eslint-plugin-forge/index.ts +15 -15
- package/packages/eslint-plugin-forge/package.json +10 -10
- package/packages/eslint-plugin-forge/src/check-source.ts +95 -95
- package/packages/eslint-plugin-forge/src/load-artifacts.ts +24 -24
- package/packages/eslint-plugin-forge/src/rule-no-forge-guard-violation.ts +93 -93
- package/src/forge/_generated/actionSubscriptions.json +2 -2
- package/src/forge/_generated/actionSubscriptions.ts +3 -3
- package/src/forge/_generated/agentAdapterManifest.json +2 -2
- package/src/forge/_generated/agentAdapterManifest.ts +3 -3
- package/src/forge/_generated/agentContract.json +2 -2
- package/src/forge/_generated/agentContract.ts +6786 -2
- package/src/forge/_generated/agentQuickstart.md +1 -1
- package/src/forge/_generated/aiContext.ts +1 -1
- package/src/forge/_generated/aiModels.json +1 -1
- package/src/forge/_generated/aiModels.ts +1 -1
- package/src/forge/_generated/aiProviders.json +1 -1
- package/src/forge/_generated/aiProviders.ts +1 -1
- package/src/forge/_generated/aiRegistry.json +2 -2
- package/src/forge/_generated/aiRegistry.ts +3 -3
- package/src/forge/_generated/api.json +2 -2
- package/src/forge/_generated/api.ts +1 -1
- package/src/forge/_generated/appGraph.json +2 -2
- package/src/forge/_generated/appGraph.ts +1297 -1141
- package/src/forge/_generated/appMap.md +1 -1
- package/src/forge/_generated/artifactManifest.json +2 -2
- package/src/forge/_generated/artifactManifest.ts +2 -2
- package/src/forge/_generated/authClaims.json +1 -1
- package/src/forge/_generated/authClaims.ts +1 -1
- package/src/forge/_generated/authConfig.json +1 -1
- package/src/forge/_generated/authConfig.ts +1 -1
- package/src/forge/_generated/authContext.ts +1 -1
- package/src/forge/_generated/authRegistry.json +1 -1
- package/src/forge/_generated/authRegistry.ts +1 -1
- package/src/forge/_generated/buildInfo.json +2 -2
- package/src/forge/_generated/buildInfo.ts +4 -4
- package/src/forge/_generated/capabilityMap.json +2 -2
- package/src/forge/_generated/capabilityMap.md +1 -1
- package/src/forge/_generated/capabilityMap.ts +2 -2
- package/src/forge/_generated/client.ts +1 -1
- package/src/forge/_generated/clientApi.ts +1 -1
- package/src/forge/_generated/clientManifest.json +2 -2
- package/src/forge/_generated/clientManifest.ts +3 -3
- package/src/forge/_generated/clientTypes.ts +1 -1
- package/src/forge/_generated/configRegistry.json +1 -1
- package/src/forge/_generated/configRegistry.ts +1 -1
- package/src/forge/_generated/dataGraph.json +2 -2
- package/src/forge/_generated/dataGraph.ts +3 -3
- package/src/forge/_generated/db.json +1 -1
- package/src/forge/_generated/db.ts +1 -1
- package/src/forge/_generated/dbSecurityManifest.json +1 -1
- package/src/forge/_generated/dbSecurityManifest.ts +1 -1
- package/src/forge/_generated/dbSessionContext.json +1 -1
- package/src/forge/_generated/dbSessionContext.ts +1 -1
- package/src/forge/_generated/deployManifest.json +2 -2
- package/src/forge/_generated/deployManifest.ts +7 -7
- package/src/forge/_generated/devManifest.json +2 -2
- package/src/forge/_generated/devManifest.ts +3 -3
- package/src/forge/_generated/envSchema.json +1 -1
- package/src/forge/_generated/envSchema.ts +1 -1
- package/src/forge/_generated/frontendGraph.json +1 -1
- package/src/forge/_generated/frontendGraph.ts +1 -1
- package/src/forge/_generated/importGuards.json +2 -2
- package/src/forge/_generated/importGuards.ts +35 -1
- package/src/forge/_generated/index.ts +1 -1
- package/src/forge/_generated/liveProductionManifest.json +1 -1
- package/src/forge/_generated/liveProductionManifest.ts +1 -1
- package/src/forge/_generated/liveProtocol.json +1 -1
- package/src/forge/_generated/liveProtocol.ts +1 -1
- package/src/forge/_generated/liveQueryRegistry.json +2 -2
- package/src/forge/_generated/liveQueryRegistry.ts +3 -3
- package/src/forge/_generated/liveTransportConfig.json +1 -1
- package/src/forge/_generated/liveTransportConfig.ts +1 -1
- package/src/forge/_generated/makeRegistry.json +2 -2
- package/src/forge/_generated/makeRegistry.ts +2 -2
- package/src/forge/_generated/makeTemplates.json +1 -1
- package/src/forge/_generated/makeTemplates.ts +1 -1
- package/src/forge/_generated/mockMap.json +1 -1
- package/src/forge/_generated/mockMap.ts +1 -1
- package/src/forge/_generated/operationPlaybooks.md +7 -5
- package/src/forge/_generated/packageGraph.json +2 -2
- package/src/forge/_generated/packageGraph.ts +90964 -14284
- package/src/forge/_generated/packageUpgradeRegistry.json +2 -2
- package/src/forge/_generated/packageUpgradeRegistry.ts +2 -2
- package/src/forge/_generated/permissionMatrix.json +2 -2
- package/src/forge/_generated/permissionMatrix.ts +3 -3
- package/src/forge/_generated/policyRegistry.json +2 -2
- package/src/forge/_generated/policyRegistry.ts +3 -3
- package/src/forge/_generated/queryRegistry.json +2 -2
- package/src/forge/_generated/queryRegistry.ts +3 -3
- package/src/forge/_generated/react.d.ts +1 -1
- package/src/forge/_generated/react.ts +1 -1
- package/src/forge/_generated/reactManifest.json +2 -2
- package/src/forge/_generated/reactManifest.ts +3 -3
- package/src/forge/_generated/releaseManifest.json +2 -2
- package/src/forge/_generated/releaseManifest.ts +3 -3
- package/src/forge/_generated/rlsPolicies.json +1 -1
- package/src/forge/_generated/rlsPolicies.sql +1 -1
- package/src/forge/_generated/rlsPolicies.ts +1 -1
- package/src/forge/_generated/runtimeGraph.json +2 -2
- package/src/forge/_generated/runtimeGraph.ts +3 -3
- package/src/forge/_generated/runtimeMatrix.json +2 -2
- package/src/forge/_generated/runtimeMatrix.ts +106177 -7917
- package/src/forge/_generated/runtimeRegistry.ts +1 -1
- package/src/forge/_generated/runtimeRules.md +1 -1
- package/src/forge/_generated/secretRegistry.json +1 -1
- package/src/forge/_generated/secretRegistry.ts +1 -1
- package/src/forge/_generated/secretsContext.ts +1 -1
- package/src/forge/_generated/serverApi.ts +1 -1
- package/src/forge/_generated/sourceMapManifest.json +2 -2
- package/src/forge/_generated/sourceMapManifest.ts +2 -2
- package/src/forge/_generated/sqlPlan.json +1 -1
- package/src/forge/_generated/sqlPlan.ts +1 -1
- package/src/forge/_generated/subscriptionManifest.json +2 -2
- package/src/forge/_generated/subscriptionManifest.ts +3 -3
- package/src/forge/_generated/symbolicationManifest.json +2 -2
- package/src/forge/_generated/symbolicationManifest.ts +2 -2
- package/src/forge/_generated/telemetryRegistry.json +2 -2
- package/src/forge/_generated/telemetryRegistry.ts +3 -3
- package/src/forge/_generated/telemetrySinks.json +2 -2
- package/src/forge/_generated/telemetrySinks.ts +2 -2
- package/src/forge/_generated/tenantScope.json +2 -2
- package/src/forge/_generated/tenantScope.ts +3 -3
- package/src/forge/_generated/testGraph.json +2 -2
- package/src/forge/_generated/testGraph.ts +129 -75
- package/src/forge/_generated/testPlanRegistry.json +2 -2
- package/src/forge/_generated/testPlanRegistry.ts +2 -2
- package/src/forge/_generated/uiRoutes.json +1 -1
- package/src/forge/_generated/uiRoutes.ts +1 -1
- package/src/forge/_generated/uiScenarios.json +1 -1
- package/src/forge/_generated/uiScenarios.ts +1 -1
- package/src/forge/_generated/uiTestManifest.json +2 -2
- package/src/forge/_generated/uiTestManifest.ts +2 -2
- package/src/forge/_generated/workflowRegistry.json +2 -2
- package/src/forge/_generated/workflowRegistry.ts +3 -3
- package/src/forge/_generated/workflowSubscriptions.json +2 -2
- package/src/forge/_generated/workflowSubscriptions.ts +3 -3
- package/src/forge/cli/commands.ts +861 -861
- package/src/forge/cli/deps.ts +178 -11
- package/src/forge/cli/dev.ts +32 -5
- package/src/forge/cli/index.ts +7 -7
- package/src/forge/cli/main.ts +54 -54
- package/src/forge/cli/new.ts +29 -1
- package/src/forge/cli/output.ts +97 -97
- package/src/forge/cli/parse.ts +679 -673
- package/src/forge/cli/version.ts +1 -1
- package/src/forge/compiler/agent-contract/build.ts +28 -0
- package/src/forge/compiler/agent-contract/types.ts +16 -0
- package/src/forge/compiler/app-graph/build.ts +112 -112
- package/src/forge/compiler/app-graph/classify.ts +10 -10
- package/src/forge/compiler/app-graph/dup-symbol.ts +29 -29
- package/src/forge/compiler/app-graph/extract.ts +123 -123
- package/src/forge/compiler/app-graph/forge-apis.ts +29 -29
- package/src/forge/compiler/app-graph/index.ts +11 -11
- package/src/forge/compiler/app-graph/module-graph.ts +316 -316
- package/src/forge/compiler/app-graph/parser.ts +119 -119
- package/src/forge/compiler/app-graph/symbols.ts +48 -48
- package/src/forge/compiler/app-graph/tsconfig-hash.ts +62 -62
- package/src/forge/compiler/app-graph/types.ts +43 -43
- package/src/forge/compiler/app-graph/versions.ts +14 -14
- package/src/forge/compiler/cache/index.ts +17 -17
- package/src/forge/compiler/cache/key.ts +46 -46
- package/src/forge/compiler/cache/scheduler.ts +72 -72
- package/src/forge/compiler/cache/store.ts +78 -78
- package/src/forge/compiler/classifier/capabilities.ts +78 -78
- package/src/forge/compiler/classifier/classify.ts +113 -113
- package/src/forge/compiler/classifier/contexts.ts +188 -188
- package/src/forge/compiler/classifier/index.ts +18 -18
- package/src/forge/compiler/classifier/runtime-matrix.ts +45 -45
- package/src/forge/compiler/classifier/secrets.ts +41 -41
- package/src/forge/compiler/classifier/signals.ts +129 -129
- package/src/forge/compiler/diagnostics/codes.ts +125 -120
- package/src/forge/compiler/diagnostics/create.ts +87 -87
- package/src/forge/compiler/diagnostics/index.ts +41 -41
- package/src/forge/compiler/emitter/artifact-kind.ts +14 -14
- package/src/forge/compiler/emitter/barrel.ts +38 -38
- package/src/forge/compiler/emitter/constants.ts +7 -7
- package/src/forge/compiler/emitter/emit.ts +234 -237
- package/src/forge/compiler/emitter/index.ts +24 -24
- package/src/forge/compiler/emitter/lock.ts +61 -61
- package/src/forge/compiler/emitter/render.ts +73 -73
- package/src/forge/compiler/guards/artifacts.ts +96 -96
- package/src/forge/compiler/guards/check-import-guards.ts +106 -106
- package/src/forge/compiler/guards/index.ts +11 -11
- package/src/forge/compiler/guards/propagate-contexts.ts +57 -57
- package/src/forge/compiler/index.ts +17 -17
- package/src/forge/compiler/integration/add.ts +493 -493
- package/src/forge/compiler/integration/index.ts +17 -17
- package/src/forge/compiler/integration/plan.ts +279 -279
- package/src/forge/compiler/integration/render.ts +189 -189
- package/src/forge/compiler/integration/snapshot.ts +52 -52
- package/src/forge/compiler/orchestrator/discover.ts +214 -214
- package/src/forge/compiler/orchestrator/guards.ts +5 -5
- package/src/forge/compiler/orchestrator/index.ts +27 -27
- package/src/forge/compiler/orchestrator/manifest.ts +69 -69
- package/src/forge/compiler/orchestrator/orphans.ts +51 -51
- package/src/forge/compiler/orchestrator/plan.ts +804 -804
- package/src/forge/compiler/orchestrator/run.ts +178 -178
- package/src/forge/compiler/orchestrator/serialize.ts +859 -859
- package/src/forge/compiler/orchestrator/types.ts +23 -23
- package/src/forge/compiler/orchestrator/verify.ts +35 -35
- package/src/forge/compiler/package-graph/capabilities-stub.ts +33 -33
- package/src/forge/compiler/package-graph/checksum.ts +107 -97
- package/src/forge/compiler/package-graph/compiler.ts +444 -363
- package/src/forge/compiler/package-graph/constants.ts +4 -4
- package/src/forge/compiler/package-graph/exports-discovery.ts +91 -84
- package/src/forge/compiler/package-graph/extract-dts.ts +32 -32
- package/src/forge/compiler/package-graph/index.ts +24 -24
- package/src/forge/compiler/package-graph/jsdoc.ts +50 -50
- package/src/forge/compiler/package-graph/oracle.ts +326 -0
- package/src/forge/compiler/package-graph/read-file.ts +21 -21
- package/src/forge/compiler/package-graph/resolve.ts +131 -127
- package/src/forge/compiler/package-manager/adapter.ts +232 -232
- package/src/forge/compiler/package-manager/commands.ts +47 -47
- package/src/forge/compiler/package-manager/detect.ts +65 -65
- package/src/forge/compiler/package-manager/executor.ts +29 -29
- package/src/forge/compiler/package-manager/index.ts +22 -22
- package/src/forge/compiler/package-manager/parse-spec.ts +16 -16
- package/src/forge/compiler/package-manager/version.ts +20 -20
- package/src/forge/compiler/primitives/compare.ts +26 -26
- package/src/forge/compiler/primitives/hash.ts +42 -33
- package/src/forge/compiler/primitives/header.ts +43 -43
- package/src/forge/compiler/primitives/index.ts +45 -45
- package/src/forge/compiler/primitives/paths.ts +24 -24
- package/src/forge/compiler/primitives/serialize.ts +66 -66
- package/src/forge/compiler/primitives/sort.ts +87 -87
- package/src/forge/compiler/recipes/definitions.ts +269 -269
- package/src/forge/compiler/recipes/helpers.ts +37 -37
- package/src/forge/compiler/recipes/index.ts +21 -21
- package/src/forge/compiler/recipes/registry.ts +87 -87
- package/src/forge/compiler/sandbox/artifact-sanitize.ts +26 -26
- package/src/forge/compiler/sandbox/backends/child.ts +123 -123
- package/src/forge/compiler/sandbox/backends/docker.ts +173 -173
- package/src/forge/compiler/sandbox/index.ts +51 -51
- package/src/forge/compiler/sandbox/inspect.ts +143 -143
- package/src/forge/compiler/sandbox/inspector-entry.ts +115 -115
- package/src/forge/compiler/sandbox/limits.ts +31 -31
- package/src/forge/compiler/sandbox/scrub-env.ts +60 -60
- package/src/forge/compiler/sandbox/secret-scan.ts +54 -54
- package/src/forge/compiler/sandbox/serialize.ts +106 -106
- package/src/forge/compiler/sandbox/types.ts +7 -7
- package/src/forge/compiler/types/app-graph.ts +71 -71
- package/src/forge/compiler/types/capability.ts +29 -29
- package/src/forge/compiler/types/classification.ts +9 -9
- package/src/forge/compiler/types/cli.ts +85 -85
- package/src/forge/compiler/types/diagnostic.ts +2 -2
- package/src/forge/compiler/types/emit.ts +25 -25
- package/src/forge/compiler/types/import-guards.ts +19 -19
- package/src/forge/compiler/types/index.ts +98 -98
- package/src/forge/compiler/types/integration.ts +25 -25
- package/src/forge/compiler/types/json.ts +3 -3
- package/src/forge/compiler/types/lock.ts +37 -37
- package/src/forge/compiler/types/package-graph.ts +122 -77
- package/src/forge/compiler/types/runtime-matrix.ts +16 -16
- package/src/forge/compiler/types/runtime.ts +30 -30
- package/src/forge/compiler/types/sandbox.ts +24 -24
- package/src/forge/dev/server.ts +16 -2
- package/src/forge/refactor/index.ts +10 -2
- package/src/forge/refactor/runtime-rename.ts +598 -0
- package/src/forge/runtime/executor.ts +3 -2
- package/src/forge/runtime/live/live-query-runner.ts +2 -1
- package/src/forge/runtime/outbox/process.ts +2 -1
- package/src/forge/runtime/query/run-query.ts +2 -1
- package/src/forge/runtime/runner/run-entry.ts +2 -1
- package/src/forge/runtime/telemetry/sinks/posthog.ts +4 -5
- package/src/forge/runtime/telemetry/sinks/sentry.ts +4 -5
- package/src/forge/runtime/workflows/resolve-step.ts +2 -1
- package/src/forge/version.ts +3 -0
- package/templates/b2b-support-web/src/actions/captureTicketCreated.ts +7 -2
- package/templates/b2b-support-web/src/commands/closeTicket.ts +6 -1
- package/templates/b2b-support-web/src/commands/createTicket.ts +8 -2
- package/templates/b2b-support-web/src/queries/getTicket.ts +8 -1
- package/templates/b2b-support-web/web/components/CreateTicketForm.tsx +1 -2
- package/templates/b2b-support-web/web/components/PolicyDeniedDemo.tsx +1 -2
- package/templates/b2b-support-web/web/components/TicketList.tsx +1 -2
- package/templates/b2b-support-web/web/components/TraceDetails.tsx +1 -1
- package/templates/b2b-support-web/web/lib/forge.ts +1 -0
|
@@ -3,235 +3,235 @@ import { readFileSync, writeFileSync } from "node:fs";
|
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { nodeFileSystem } from "../fs/index.ts";
|
|
5
5
|
import type { PackageManager } from "../types/runtime.ts";
|
|
6
|
-
import type { PmAddOptions, PmAddResult } from "../types/cli.ts";
|
|
7
|
-
import { buildAddCommand } from "./commands.ts";
|
|
8
|
-
import {
|
|
9
|
-
detectPackageManager,
|
|
10
|
-
getLockfileCandidates,
|
|
11
|
-
getLockfileForPm,
|
|
12
|
-
} from "./detect.ts";
|
|
13
|
-
import {
|
|
14
|
-
defaultCommandExecutor,
|
|
15
|
-
PackageManagerCommandError,
|
|
16
|
-
type CommandExecutor,
|
|
17
|
-
} from "./executor.ts";
|
|
18
|
-
import { parsePackageName } from "./parse-spec.ts";
|
|
19
|
-
import { readInstalledVersion } from "./version.ts";
|
|
20
|
-
|
|
21
|
-
export interface PackageManagerAdapter {
|
|
22
|
-
readonly name: PackageManager;
|
|
23
|
-
readonly lockfile: string;
|
|
24
|
-
add(spec: string, opts: PmAddOptions): Promise<PmAddResult>;
|
|
25
|
-
dryRunAdd(spec: string, opts: PmAddOptions): Promise<PmAddResult>;
|
|
26
|
-
/** Install into a temp dir; caller owns cleanup unless using dryRunAdd. */
|
|
27
|
-
dryRunAddWithPath(spec: string, opts: PmAddOptions): Promise<DryRunAddResult>;
|
|
28
|
-
detectResolvedVersion(spec: string, cwd: string): Promise<string>;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface DryRunAddResult extends PmAddResult {
|
|
32
|
-
/** Absolute path to the temp install directory (for downstream analysis). */
|
|
33
|
-
installPath: string;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface CreatePackageManagerAdapterOptions {
|
|
37
|
-
executor?: CommandExecutor;
|
|
38
|
-
/** When true, retain the temp directory after dryRunAdd (for debugging). */
|
|
39
|
-
retainDryRunDir?: boolean;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function hashFile(path: string): string | null {
|
|
43
|
-
if (!nodeFileSystem.exists(path)) {
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
46
|
-
const content = readFileSync(path);
|
|
47
|
-
return createHash("sha256").update(content).digest("hex");
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function hashLockfiles(cwd: string, pm: PackageManager): string | null {
|
|
51
|
-
const hashes: string[] = [];
|
|
52
|
-
for (const file of getLockfileCandidates(pm)) {
|
|
53
|
-
const h = hashFile(join(cwd, file));
|
|
54
|
-
if (h !== null) {
|
|
55
|
-
hashes.push(`${file}:${h}`);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
return hashes.length > 0 ? hashes.join("|") : null;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function lockfileChanged(
|
|
62
|
-
before: string | null,
|
|
63
|
-
after: string | null,
|
|
64
|
-
pm: PackageManager,
|
|
65
|
-
cwd: string,
|
|
66
|
-
): boolean {
|
|
67
|
-
if (before !== after) {
|
|
68
|
-
return true;
|
|
69
|
-
}
|
|
70
|
-
// Lockfile may be created on first install.
|
|
71
|
-
if (before === null) {
|
|
72
|
-
return getLockfileCandidates(pm).some((f) =>
|
|
73
|
-
nodeFileSystem.exists(join(cwd, f)),
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
return false;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async function runInstall(
|
|
80
|
-
pm: PackageManager,
|
|
81
|
-
spec: string,
|
|
82
|
-
opts: PmAddOptions,
|
|
83
|
-
executor: CommandExecutor,
|
|
84
|
-
): Promise<PmAddResult> {
|
|
85
|
-
const ignoreScripts = opts.ignoreScripts ?? true;
|
|
86
|
-
const argv = buildAddCommand(pm, spec, { ignoreScripts });
|
|
87
|
-
const lockBefore = hashLockfiles(opts.cwd, pm);
|
|
88
|
-
|
|
89
|
-
const result = await executor.run(argv, { cwd: opts.cwd });
|
|
90
|
-
if (result.exitCode !== 0) {
|
|
91
|
-
throw new PackageManagerCommandError(
|
|
92
|
-
`Package manager ${pm} failed to add ${spec}: ${result.stderr || result.stdout}`,
|
|
93
|
-
argv,
|
|
94
|
-
result,
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const packageName = parsePackageName(spec);
|
|
99
|
-
const resolvedVersion = readInstalledVersion(packageName, opts.cwd);
|
|
100
|
-
if (!resolvedVersion) {
|
|
101
|
-
throw new Error(
|
|
102
|
-
`Could not detect installed version for ${packageName} in ${opts.cwd}`,
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const lockAfter = hashLockfiles(opts.cwd, pm);
|
|
107
|
-
|
|
108
|
-
return {
|
|
109
|
-
resolvedVersion,
|
|
110
|
-
lockfileChanged: lockfileChanged(lockBefore, lockAfter, pm, opts.cwd),
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
class PackageManagerAdapterImpl implements PackageManagerAdapter {
|
|
115
|
-
readonly name: PackageManager;
|
|
116
|
-
readonly lockfile: string;
|
|
117
|
-
private readonly executor: CommandExecutor;
|
|
118
|
-
private readonly retainDryRunDir: boolean;
|
|
119
|
-
|
|
120
|
-
constructor(
|
|
121
|
-
name: PackageManager,
|
|
122
|
-
options: CreatePackageManagerAdapterOptions = {},
|
|
123
|
-
) {
|
|
124
|
-
this.name = name;
|
|
125
|
-
this.lockfile = getLockfileForPm(name);
|
|
126
|
-
this.executor = options.executor ?? defaultCommandExecutor;
|
|
127
|
-
this.retainDryRunDir = options.retainDryRunDir ?? false;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
async add(spec: string, opts: PmAddOptions): Promise<PmAddResult> {
|
|
131
|
-
return runInstall(this.name, spec, opts, this.executor);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
async dryRunAdd(spec: string, opts: PmAddOptions): Promise<PmAddResult> {
|
|
135
|
-
const result = await this.dryRunAddWithPath(spec, opts);
|
|
136
|
-
if (!this.retainDryRunDir) {
|
|
137
|
-
try {
|
|
138
|
-
nodeFileSystem.remove(result.installPath);
|
|
139
|
-
} catch {
|
|
140
|
-
// best-effort cleanup
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
return {
|
|
144
|
-
resolvedVersion: result.resolvedVersion,
|
|
145
|
-
integrity: result.integrity,
|
|
146
|
-
lockfileChanged: false,
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/** Internal: dry-run install returning the temp directory path. */
|
|
151
|
-
async dryRunAddWithPath(
|
|
152
|
-
spec: string,
|
|
153
|
-
opts: PmAddOptions,
|
|
154
|
-
): Promise<DryRunAddResult> {
|
|
155
|
-
const cacheBase = join(opts.cwd, ".forge", "cache", "dry-run");
|
|
156
|
-
nodeFileSystem.mkdirp(cacheBase);
|
|
157
|
-
const tempDir = nodeFileSystem.makeTempDir(join(cacheBase, "add-"));
|
|
158
|
-
|
|
159
|
-
const minimalPkg = {
|
|
160
|
-
name: "forge-dry-run",
|
|
161
|
-
private: true,
|
|
162
|
-
version: "0.0.0",
|
|
163
|
-
};
|
|
164
|
-
writeFileSync(
|
|
165
|
-
join(tempDir, "package.json"),
|
|
166
|
-
`${JSON.stringify(minimalPkg, null, 2)}\n`,
|
|
167
|
-
"utf8",
|
|
168
|
-
);
|
|
169
|
-
|
|
170
|
-
const installResult = await runInstall(
|
|
171
|
-
this.name,
|
|
172
|
-
spec,
|
|
173
|
-
{
|
|
174
|
-
cwd: tempDir,
|
|
175
|
-
ignoreScripts: opts.ignoreScripts ?? true,
|
|
176
|
-
},
|
|
177
|
-
this.executor,
|
|
178
|
-
);
|
|
179
|
-
|
|
180
|
-
return {
|
|
181
|
-
...installResult,
|
|
182
|
-
lockfileChanged: false,
|
|
183
|
-
installPath: tempDir,
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
async detectResolvedVersion(spec: string, cwd: string): Promise<string> {
|
|
188
|
-
const version = readInstalledVersion(spec, cwd);
|
|
189
|
-
if (!version) {
|
|
190
|
-
throw new Error(
|
|
191
|
-
`Package ${parsePackageName(spec)} is not installed in ${cwd}`,
|
|
192
|
-
);
|
|
193
|
-
}
|
|
194
|
-
return version;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
export function createPackageManagerAdapter(
|
|
199
|
-
pm: PackageManager,
|
|
200
|
-
options?: CreatePackageManagerAdapterOptions,
|
|
201
|
-
): PackageManagerAdapter {
|
|
202
|
-
return new PackageManagerAdapterImpl(pm, options);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
export function detectAndCreatePackageManagerAdapter(
|
|
206
|
-
workspaceRoot: string,
|
|
207
|
-
options?: CreatePackageManagerAdapterOptions,
|
|
208
|
-
): PackageManagerAdapter {
|
|
209
|
-
const pm = detectPackageManager(workspaceRoot);
|
|
210
|
-
return createPackageManagerAdapter(pm, options);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/** Fallback when dry-run install is unavailable: recipe-known plan placeholder. */
|
|
214
|
-
export function dryRunRecipeFallbackMessage(alias: string): string {
|
|
215
|
-
return (
|
|
216
|
-
`Dry-run for "${alias}": .d.ts analysis requires a real install. ` +
|
|
217
|
-
`Use dryRunAdd to install into a temp directory, or run forge add without --dry-run.`
|
|
218
|
-
);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
export {
|
|
222
|
-
detectPackageManager,
|
|
223
|
-
detectPackageManagerFromLockfiles,
|
|
224
|
-
getLockfileForPm,
|
|
225
|
-
getLockfileCandidates,
|
|
226
|
-
parsePackageManagerField,
|
|
227
|
-
LOCKFILE_PM_MAP,
|
|
228
|
-
} from "./detect.ts";
|
|
229
|
-
export { buildAddCommand } from "./commands.ts";
|
|
230
|
-
export { parsePackageName } from "./parse-spec.ts";
|
|
231
|
-
export { readInstalledVersion } from "./version.ts";
|
|
232
|
-
export {
|
|
233
|
-
defaultCommandExecutor,
|
|
234
|
-
PackageManagerCommandError,
|
|
235
|
-
type CommandExecutor,
|
|
236
|
-
type CommandRunResult,
|
|
237
|
-
} from "./executor.ts";
|
|
6
|
+
import type { PmAddOptions, PmAddResult } from "../types/cli.ts";
|
|
7
|
+
import { buildAddCommand } from "./commands.ts";
|
|
8
|
+
import {
|
|
9
|
+
detectPackageManager,
|
|
10
|
+
getLockfileCandidates,
|
|
11
|
+
getLockfileForPm,
|
|
12
|
+
} from "./detect.ts";
|
|
13
|
+
import {
|
|
14
|
+
defaultCommandExecutor,
|
|
15
|
+
PackageManagerCommandError,
|
|
16
|
+
type CommandExecutor,
|
|
17
|
+
} from "./executor.ts";
|
|
18
|
+
import { parsePackageName } from "./parse-spec.ts";
|
|
19
|
+
import { readInstalledVersion } from "./version.ts";
|
|
20
|
+
|
|
21
|
+
export interface PackageManagerAdapter {
|
|
22
|
+
readonly name: PackageManager;
|
|
23
|
+
readonly lockfile: string;
|
|
24
|
+
add(spec: string, opts: PmAddOptions): Promise<PmAddResult>;
|
|
25
|
+
dryRunAdd(spec: string, opts: PmAddOptions): Promise<PmAddResult>;
|
|
26
|
+
/** Install into a temp dir; caller owns cleanup unless using dryRunAdd. */
|
|
27
|
+
dryRunAddWithPath(spec: string, opts: PmAddOptions): Promise<DryRunAddResult>;
|
|
28
|
+
detectResolvedVersion(spec: string, cwd: string): Promise<string>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface DryRunAddResult extends PmAddResult {
|
|
32
|
+
/** Absolute path to the temp install directory (for downstream analysis). */
|
|
33
|
+
installPath: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface CreatePackageManagerAdapterOptions {
|
|
37
|
+
executor?: CommandExecutor;
|
|
38
|
+
/** When true, retain the temp directory after dryRunAdd (for debugging). */
|
|
39
|
+
retainDryRunDir?: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function hashFile(path: string): string | null {
|
|
43
|
+
if (!nodeFileSystem.exists(path)) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
const content = readFileSync(path);
|
|
47
|
+
return createHash("sha256").update(content).digest("hex");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function hashLockfiles(cwd: string, pm: PackageManager): string | null {
|
|
51
|
+
const hashes: string[] = [];
|
|
52
|
+
for (const file of getLockfileCandidates(pm)) {
|
|
53
|
+
const h = hashFile(join(cwd, file));
|
|
54
|
+
if (h !== null) {
|
|
55
|
+
hashes.push(`${file}:${h}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return hashes.length > 0 ? hashes.join("|") : null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function lockfileChanged(
|
|
62
|
+
before: string | null,
|
|
63
|
+
after: string | null,
|
|
64
|
+
pm: PackageManager,
|
|
65
|
+
cwd: string,
|
|
66
|
+
): boolean {
|
|
67
|
+
if (before !== after) {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
// Lockfile may be created on first install.
|
|
71
|
+
if (before === null) {
|
|
72
|
+
return getLockfileCandidates(pm).some((f) =>
|
|
73
|
+
nodeFileSystem.exists(join(cwd, f)),
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function runInstall(
|
|
80
|
+
pm: PackageManager,
|
|
81
|
+
spec: string,
|
|
82
|
+
opts: PmAddOptions,
|
|
83
|
+
executor: CommandExecutor,
|
|
84
|
+
): Promise<PmAddResult> {
|
|
85
|
+
const ignoreScripts = opts.ignoreScripts ?? true;
|
|
86
|
+
const argv = buildAddCommand(pm, spec, { ignoreScripts });
|
|
87
|
+
const lockBefore = hashLockfiles(opts.cwd, pm);
|
|
88
|
+
|
|
89
|
+
const result = await executor.run(argv, { cwd: opts.cwd });
|
|
90
|
+
if (result.exitCode !== 0) {
|
|
91
|
+
throw new PackageManagerCommandError(
|
|
92
|
+
`Package manager ${pm} failed to add ${spec}: ${result.stderr || result.stdout}`,
|
|
93
|
+
argv,
|
|
94
|
+
result,
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const packageName = parsePackageName(spec);
|
|
99
|
+
const resolvedVersion = readInstalledVersion(packageName, opts.cwd);
|
|
100
|
+
if (!resolvedVersion) {
|
|
101
|
+
throw new Error(
|
|
102
|
+
`Could not detect installed version for ${packageName} in ${opts.cwd}`,
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const lockAfter = hashLockfiles(opts.cwd, pm);
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
resolvedVersion,
|
|
110
|
+
lockfileChanged: lockfileChanged(lockBefore, lockAfter, pm, opts.cwd),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
class PackageManagerAdapterImpl implements PackageManagerAdapter {
|
|
115
|
+
readonly name: PackageManager;
|
|
116
|
+
readonly lockfile: string;
|
|
117
|
+
private readonly executor: CommandExecutor;
|
|
118
|
+
private readonly retainDryRunDir: boolean;
|
|
119
|
+
|
|
120
|
+
constructor(
|
|
121
|
+
name: PackageManager,
|
|
122
|
+
options: CreatePackageManagerAdapterOptions = {},
|
|
123
|
+
) {
|
|
124
|
+
this.name = name;
|
|
125
|
+
this.lockfile = getLockfileForPm(name);
|
|
126
|
+
this.executor = options.executor ?? defaultCommandExecutor;
|
|
127
|
+
this.retainDryRunDir = options.retainDryRunDir ?? false;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async add(spec: string, opts: PmAddOptions): Promise<PmAddResult> {
|
|
131
|
+
return runInstall(this.name, spec, opts, this.executor);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async dryRunAdd(spec: string, opts: PmAddOptions): Promise<PmAddResult> {
|
|
135
|
+
const result = await this.dryRunAddWithPath(spec, opts);
|
|
136
|
+
if (!this.retainDryRunDir) {
|
|
137
|
+
try {
|
|
138
|
+
nodeFileSystem.remove(result.installPath);
|
|
139
|
+
} catch {
|
|
140
|
+
// best-effort cleanup
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
resolvedVersion: result.resolvedVersion,
|
|
145
|
+
integrity: result.integrity,
|
|
146
|
+
lockfileChanged: false,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Internal: dry-run install returning the temp directory path. */
|
|
151
|
+
async dryRunAddWithPath(
|
|
152
|
+
spec: string,
|
|
153
|
+
opts: PmAddOptions,
|
|
154
|
+
): Promise<DryRunAddResult> {
|
|
155
|
+
const cacheBase = join(opts.cwd, ".forge", "cache", "dry-run");
|
|
156
|
+
nodeFileSystem.mkdirp(cacheBase);
|
|
157
|
+
const tempDir = nodeFileSystem.makeTempDir(join(cacheBase, "add-"));
|
|
158
|
+
|
|
159
|
+
const minimalPkg = {
|
|
160
|
+
name: "forge-dry-run",
|
|
161
|
+
private: true,
|
|
162
|
+
version: "0.0.0",
|
|
163
|
+
};
|
|
164
|
+
writeFileSync(
|
|
165
|
+
join(tempDir, "package.json"),
|
|
166
|
+
`${JSON.stringify(minimalPkg, null, 2)}\n`,
|
|
167
|
+
"utf8",
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
const installResult = await runInstall(
|
|
171
|
+
this.name,
|
|
172
|
+
spec,
|
|
173
|
+
{
|
|
174
|
+
cwd: tempDir,
|
|
175
|
+
ignoreScripts: opts.ignoreScripts ?? true,
|
|
176
|
+
},
|
|
177
|
+
this.executor,
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
return {
|
|
181
|
+
...installResult,
|
|
182
|
+
lockfileChanged: false,
|
|
183
|
+
installPath: tempDir,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async detectResolvedVersion(spec: string, cwd: string): Promise<string> {
|
|
188
|
+
const version = readInstalledVersion(spec, cwd);
|
|
189
|
+
if (!version) {
|
|
190
|
+
throw new Error(
|
|
191
|
+
`Package ${parsePackageName(spec)} is not installed in ${cwd}`,
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
return version;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export function createPackageManagerAdapter(
|
|
199
|
+
pm: PackageManager,
|
|
200
|
+
options?: CreatePackageManagerAdapterOptions,
|
|
201
|
+
): PackageManagerAdapter {
|
|
202
|
+
return new PackageManagerAdapterImpl(pm, options);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export function detectAndCreatePackageManagerAdapter(
|
|
206
|
+
workspaceRoot: string,
|
|
207
|
+
options?: CreatePackageManagerAdapterOptions,
|
|
208
|
+
): PackageManagerAdapter {
|
|
209
|
+
const pm = detectPackageManager(workspaceRoot);
|
|
210
|
+
return createPackageManagerAdapter(pm, options);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/** Fallback when dry-run install is unavailable: recipe-known plan placeholder. */
|
|
214
|
+
export function dryRunRecipeFallbackMessage(alias: string): string {
|
|
215
|
+
return (
|
|
216
|
+
`Dry-run for "${alias}": .d.ts analysis requires a real install. ` +
|
|
217
|
+
`Use dryRunAdd to install into a temp directory, or run forge add without --dry-run.`
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export {
|
|
222
|
+
detectPackageManager,
|
|
223
|
+
detectPackageManagerFromLockfiles,
|
|
224
|
+
getLockfileForPm,
|
|
225
|
+
getLockfileCandidates,
|
|
226
|
+
parsePackageManagerField,
|
|
227
|
+
LOCKFILE_PM_MAP,
|
|
228
|
+
} from "./detect.ts";
|
|
229
|
+
export { buildAddCommand } from "./commands.ts";
|
|
230
|
+
export { parsePackageName } from "./parse-spec.ts";
|
|
231
|
+
export { readInstalledVersion } from "./version.ts";
|
|
232
|
+
export {
|
|
233
|
+
defaultCommandExecutor,
|
|
234
|
+
PackageManagerCommandError,
|
|
235
|
+
type CommandExecutor,
|
|
236
|
+
type CommandRunResult,
|
|
237
|
+
} from "./executor.ts";
|
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
import type { PackageManager } from "../types/runtime.ts";
|
|
2
|
-
|
|
3
|
-
export interface BuildAddCommandOptions {
|
|
4
|
-
ignoreScripts: boolean;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Build argv for adding a dependency with lifecycle scripts disabled by default.
|
|
9
|
-
*/
|
|
10
|
-
export function buildAddCommand(
|
|
11
|
-
pm: PackageManager,
|
|
12
|
-
spec: string,
|
|
13
|
-
options: BuildAddCommandOptions,
|
|
14
|
-
): string[] {
|
|
15
|
-
const ignoreScripts = options.ignoreScripts;
|
|
16
|
-
|
|
17
|
-
switch (pm) {
|
|
18
|
-
case "bun": {
|
|
19
|
-
const args = ["bun", "add", spec];
|
|
20
|
-
if (ignoreScripts) {
|
|
21
|
-
args.push("--ignore-scripts");
|
|
22
|
-
}
|
|
23
|
-
return args;
|
|
24
|
-
}
|
|
25
|
-
case "npm": {
|
|
26
|
-
const args = ["npm", "install", spec, "--save", "--no-fund", "--no-audit"];
|
|
27
|
-
if (ignoreScripts) {
|
|
28
|
-
args.push("--ignore-scripts");
|
|
29
|
-
}
|
|
30
|
-
return args;
|
|
31
|
-
}
|
|
32
|
-
case "pnpm": {
|
|
33
|
-
const args = ["pnpm", "add", spec];
|
|
34
|
-
if (ignoreScripts) {
|
|
35
|
-
args.push("--ignore-scripts");
|
|
36
|
-
}
|
|
37
|
-
return args;
|
|
38
|
-
}
|
|
39
|
-
case "yarn": {
|
|
40
|
-
const args = ["yarn", "add", spec];
|
|
41
|
-
if (ignoreScripts) {
|
|
42
|
-
args.push("--ignore-scripts");
|
|
43
|
-
}
|
|
44
|
-
return args;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
1
|
+
import type { PackageManager } from "../types/runtime.ts";
|
|
2
|
+
|
|
3
|
+
export interface BuildAddCommandOptions {
|
|
4
|
+
ignoreScripts: boolean;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Build argv for adding a dependency with lifecycle scripts disabled by default.
|
|
9
|
+
*/
|
|
10
|
+
export function buildAddCommand(
|
|
11
|
+
pm: PackageManager,
|
|
12
|
+
spec: string,
|
|
13
|
+
options: BuildAddCommandOptions,
|
|
14
|
+
): string[] {
|
|
15
|
+
const ignoreScripts = options.ignoreScripts;
|
|
16
|
+
|
|
17
|
+
switch (pm) {
|
|
18
|
+
case "bun": {
|
|
19
|
+
const args = ["bun", "add", spec];
|
|
20
|
+
if (ignoreScripts) {
|
|
21
|
+
args.push("--ignore-scripts");
|
|
22
|
+
}
|
|
23
|
+
return args;
|
|
24
|
+
}
|
|
25
|
+
case "npm": {
|
|
26
|
+
const args = ["npm", "install", spec, "--save", "--no-fund", "--no-audit"];
|
|
27
|
+
if (ignoreScripts) {
|
|
28
|
+
args.push("--ignore-scripts");
|
|
29
|
+
}
|
|
30
|
+
return args;
|
|
31
|
+
}
|
|
32
|
+
case "pnpm": {
|
|
33
|
+
const args = ["pnpm", "add", spec];
|
|
34
|
+
if (ignoreScripts) {
|
|
35
|
+
args.push("--ignore-scripts");
|
|
36
|
+
}
|
|
37
|
+
return args;
|
|
38
|
+
}
|
|
39
|
+
case "yarn": {
|
|
40
|
+
const args = ["yarn", "add", spec];
|
|
41
|
+
if (ignoreScripts) {
|
|
42
|
+
args.push("--ignore-scripts");
|
|
43
|
+
}
|
|
44
|
+
return args;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|