@superblocksteam/vite-plugin-file-sync 2.0.167-next.0 → 2.0.168-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai-service/agent/middleware.d.ts.map +1 -1
- package/dist/ai-service/agent/middleware.js +23 -0
- package/dist/ai-service/agent/middleware.js.map +1 -1
- package/dist/ai-service/agent/tool-message-utils.d.ts +1 -1
- package/dist/ai-service/agent/tool-message-utils.d.ts.map +1 -1
- package/dist/ai-service/agent/tool-message-utils.js.map +1 -1
- package/dist/ai-service/agent/tool-permission-delivery.d.ts +5 -4
- package/dist/ai-service/agent/tool-permission-delivery.d.ts.map +1 -1
- package/dist/ai-service/agent/tool-permission-delivery.js +22 -28
- package/dist/ai-service/agent/tool-permission-delivery.js.map +1 -1
- package/dist/ai-service/agent/tool-permission-outcome-metrics.d.ts +9 -0
- package/dist/ai-service/agent/tool-permission-outcome-metrics.d.ts.map +1 -0
- package/dist/ai-service/agent/tool-permission-outcome-metrics.js +23 -0
- package/dist/ai-service/agent/tool-permission-outcome-metrics.js.map +1 -0
- package/dist/ai-service/agent/tools/build-capture-screenshot.d.ts +44 -0
- package/dist/ai-service/agent/tools/build-capture-screenshot.d.ts.map +1 -1
- package/dist/ai-service/agent/tools/build-capture-screenshot.js +198 -18
- package/dist/ai-service/agent/tools/build-capture-screenshot.js.map +1 -1
- package/dist/ai-service/agent/tools/build-manage-checklist.d.ts +2 -0
- package/dist/ai-service/agent/tools/build-manage-checklist.d.ts.map +1 -1
- package/dist/ai-service/agent/tools/build-manage-checklist.js.map +1 -1
- package/dist/ai-service/agent/tools/build-reload-file.d.ts.map +1 -1
- package/dist/ai-service/agent/tools/build-reload-file.js +32 -19
- package/dist/ai-service/agent/tools/build-reload-file.js.map +1 -1
- package/dist/ai-service/agent/tools/get-security-findings.d.ts +45 -0
- package/dist/ai-service/agent/tools/get-security-findings.d.ts.map +1 -0
- package/dist/ai-service/agent/tools/get-security-findings.js +74 -0
- package/dist/ai-service/agent/tools/get-security-findings.js.map +1 -0
- package/dist/ai-service/agent/tools/integrations/integration-setup.d.ts +2 -2
- package/dist/ai-service/agent/tools/integrations/integration-setup.d.ts.map +1 -1
- package/dist/ai-service/agent/tools/integrations/integration-setup.js +24 -2
- package/dist/ai-service/agent/tools/integrations/integration-setup.js.map +1 -1
- package/dist/ai-service/agent/tools/report-security-findings.d.ts +20 -20
- package/dist/ai-service/agent/tools.d.ts.map +1 -1
- package/dist/ai-service/agent/tools.js +13 -2
- package/dist/ai-service/agent/tools.js.map +1 -1
- package/dist/ai-service/agent/tools2/tools/exit-plan-mode.d.ts.map +1 -1
- package/dist/ai-service/agent/tools2/tools/exit-plan-mode.js +14 -0
- package/dist/ai-service/agent/tools2/tools/exit-plan-mode.js.map +1 -1
- package/dist/ai-service/agent/tools2/tools/git.d.ts +2 -1
- package/dist/ai-service/agent/tools2/tools/git.d.ts.map +1 -1
- package/dist/ai-service/agent/tools2/tools/git.js +1 -1
- package/dist/ai-service/agent/tools2/tools/git.js.map +1 -1
- package/dist/ai-service/agent/utils.d.ts.map +1 -1
- package/dist/ai-service/agent/utils.js +5 -0
- package/dist/ai-service/agent/utils.js.map +1 -1
- package/dist/ai-service/app-interface/app-package-manager.d.ts +43 -0
- package/dist/ai-service/app-interface/app-package-manager.d.ts.map +1 -0
- package/dist/ai-service/app-interface/app-package-manager.js +82 -0
- package/dist/ai-service/app-interface/app-package-manager.js.map +1 -0
- package/dist/ai-service/app-interface/constants.d.ts +2 -2
- package/dist/ai-service/app-interface/constants.d.ts.map +1 -1
- package/dist/ai-service/app-interface/constants.js +5 -0
- package/dist/ai-service/app-interface/constants.js.map +1 -1
- package/dist/ai-service/app-interface/file-system-interface.d.ts.map +1 -1
- package/dist/ai-service/app-interface/file-system-interface.js +0 -3
- package/dist/ai-service/app-interface/file-system-interface.js.map +1 -1
- package/dist/ai-service/app-interface/npm-error-parser.d.ts +1 -1
- package/dist/ai-service/app-interface/npm-error-parser.d.ts.map +1 -1
- package/dist/ai-service/app-interface/npm-error-parser.js +42 -8
- package/dist/ai-service/app-interface/npm-error-parser.js.map +1 -1
- package/dist/ai-service/app-interface/npm-registry.d.ts +30 -0
- package/dist/ai-service/app-interface/npm-registry.d.ts.map +1 -1
- package/dist/ai-service/app-interface/npm-registry.js +108 -1
- package/dist/ai-service/app-interface/npm-registry.js.map +1 -1
- package/dist/ai-service/app-interface/pnpm-lockfile.d.ts +28 -0
- package/dist/ai-service/app-interface/pnpm-lockfile.d.ts.map +1 -0
- package/dist/ai-service/app-interface/pnpm-lockfile.js +89 -0
- package/dist/ai-service/app-interface/pnpm-lockfile.js.map +1 -0
- package/dist/ai-service/app-interface/shell.d.ts +43 -7
- package/dist/ai-service/app-interface/shell.d.ts.map +1 -1
- package/dist/ai-service/app-interface/shell.js +252 -119
- package/dist/ai-service/app-interface/shell.js.map +1 -1
- package/dist/ai-service/app-interface/vulnerability-gate.d.ts +5 -0
- package/dist/ai-service/app-interface/vulnerability-gate.d.ts.map +1 -1
- package/dist/ai-service/app-interface/vulnerability-gate.js +3 -0
- package/dist/ai-service/app-interface/vulnerability-gate.js.map +1 -1
- package/dist/ai-service/app-skills/helpers.d.ts.map +1 -1
- package/dist/ai-service/app-skills/helpers.js +9 -9
- package/dist/ai-service/app-skills/helpers.js.map +1 -1
- package/dist/ai-service/chat/chat-session-store.d.ts +4 -1
- package/dist/ai-service/chat/chat-session-store.d.ts.map +1 -1
- package/dist/ai-service/chat/chat-session-store.js +4 -0
- package/dist/ai-service/chat/chat-session-store.js.map +1 -1
- package/dist/ai-service/checklist/persisted-checklist-store.d.ts +66 -1
- package/dist/ai-service/checklist/persisted-checklist-store.d.ts.map +1 -1
- package/dist/ai-service/checklist/persisted-checklist-store.js +274 -4
- package/dist/ai-service/checklist/persisted-checklist-store.js.map +1 -1
- package/dist/ai-service/checklist/policy-remediation.d.ts +8 -0
- package/dist/ai-service/checklist/policy-remediation.d.ts.map +1 -0
- package/dist/ai-service/checklist/policy-remediation.js +46 -0
- package/dist/ai-service/checklist/policy-remediation.js.map +1 -0
- package/dist/ai-service/checklist/remediation-findings-client.d.ts +31 -0
- package/dist/ai-service/checklist/remediation-findings-client.d.ts.map +1 -0
- package/dist/ai-service/checklist/remediation-findings-client.js +117 -0
- package/dist/ai-service/checklist/remediation-findings-client.js.map +1 -0
- package/dist/ai-service/context-download.d.ts.map +1 -1
- package/dist/ai-service/context-download.js +76 -37
- package/dist/ai-service/context-download.js.map +1 -1
- package/dist/ai-service/dev-database-file-sync.d.ts +2 -1
- package/dist/ai-service/dev-database-file-sync.d.ts.map +1 -1
- package/dist/ai-service/dev-database-file-sync.js.map +1 -1
- package/dist/ai-service/index.d.ts +59 -9
- package/dist/ai-service/index.d.ts.map +1 -1
- package/dist/ai-service/index.js +1191 -479
- package/dist/ai-service/index.js.map +1 -1
- package/dist/ai-service/integrations/store.d.ts.map +1 -1
- package/dist/ai-service/integrations/store.js +11 -2
- package/dist/ai-service/integrations/store.js.map +1 -1
- package/dist/ai-service/llm/context-v2/adapter.d.ts +3 -0
- package/dist/ai-service/llm/context-v2/adapter.d.ts.map +1 -1
- package/dist/ai-service/llm/context-v2/adapter.js +6 -0
- package/dist/ai-service/llm/context-v2/adapter.js.map +1 -1
- package/dist/ai-service/llm/context-v2/context.d.ts +22 -1
- package/dist/ai-service/llm/context-v2/context.d.ts.map +1 -1
- package/dist/ai-service/llm/context-v2/context.js +185 -30
- package/dist/ai-service/llm/context-v2/context.js.map +1 -1
- package/dist/ai-service/llm/context-v2/conversation-context.d.ts +7 -0
- package/dist/ai-service/llm/context-v2/conversation-context.d.ts.map +1 -1
- package/dist/ai-service/llm/context-v2/manager.d.ts +11 -10
- package/dist/ai-service/llm/context-v2/manager.d.ts.map +1 -1
- package/dist/ai-service/llm/context-v2/manager.js +128 -85
- package/dist/ai-service/llm/context-v2/manager.js.map +1 -1
- package/dist/ai-service/llm/context-v2/storage/event-store.d.ts +73 -1
- package/dist/ai-service/llm/context-v2/storage/event-store.d.ts.map +1 -1
- package/dist/ai-service/llm/context-v2/storage/event-types.d.ts +152 -24
- package/dist/ai-service/llm/context-v2/storage/event-types.d.ts.map +1 -1
- package/dist/ai-service/llm/context-v2/storage/event-types.js +141 -0
- package/dist/ai-service/llm/context-v2/storage/event-types.js.map +1 -1
- package/dist/ai-service/llm/context-v2/storage/jsonl-event-store.d.ts +20 -2
- package/dist/ai-service/llm/context-v2/storage/jsonl-event-store.d.ts.map +1 -1
- package/dist/ai-service/llm/context-v2/storage/jsonl-event-store.js +111 -49
- package/dist/ai-service/llm/context-v2/storage/jsonl-event-store.js.map +1 -1
- package/dist/ai-service/llm/context-v2/storage/migration.d.ts.map +1 -1
- package/dist/ai-service/llm/context-v2/storage/migration.js +31 -4
- package/dist/ai-service/llm/context-v2/storage/migration.js.map +1 -1
- package/dist/ai-service/llm/context-v2/token-tracker.d.ts +34 -0
- package/dist/ai-service/llm/context-v2/token-tracker.d.ts.map +1 -1
- package/dist/ai-service/llm/context-v2/token-tracker.js +164 -0
- package/dist/ai-service/llm/context-v2/token-tracker.js.map +1 -1
- package/dist/ai-service/llm/context-v2/types.d.ts +5 -2
- package/dist/ai-service/llm/context-v2/types.d.ts.map +1 -1
- package/dist/ai-service/llm/context-v2/types.js +1 -1
- package/dist/ai-service/llm/context-v2/types.js.map +1 -1
- package/dist/ai-service/llm/stream/config.d.ts +7 -0
- package/dist/ai-service/llm/stream/config.d.ts.map +1 -1
- package/dist/ai-service/llm/stream/config.js +20 -2
- package/dist/ai-service/llm/stream/config.js.map +1 -1
- package/dist/ai-service/llm/stream/orchestrator.d.ts.map +1 -1
- package/dist/ai-service/llm/stream/orchestrator.js +30 -14
- package/dist/ai-service/llm/stream/orchestrator.js.map +1 -1
- package/dist/ai-service/llm/stream/session.d.ts +1 -1
- package/dist/ai-service/llm/stream/session.d.ts.map +1 -1
- package/dist/ai-service/llm/stream/session.js +1 -1
- package/dist/ai-service/llm/stream/session.js.map +1 -1
- package/dist/ai-service/security/secret-scanner-service.d.ts.map +1 -1
- package/dist/ai-service/security/secret-scanner-service.js +12 -2
- package/dist/ai-service/security/secret-scanner-service.js.map +1 -1
- package/dist/ai-service/security/secret-scanner.d.ts +1 -1
- package/dist/ai-service/security/secret-scanner.d.ts.map +1 -1
- package/dist/ai-service/security/secret-scanner.js +4 -1
- package/dist/ai-service/security/secret-scanner.js.map +1 -1
- package/dist/ai-service/security/vulnerability-triage.d.ts +2 -2
- package/dist/ai-service/state-machine/clark-fsm.d.ts +17 -1
- package/dist/ai-service/state-machine/clark-fsm.d.ts.map +1 -1
- package/dist/ai-service/state-machine/clark-fsm.js +85 -8
- package/dist/ai-service/state-machine/clark-fsm.js.map +1 -1
- package/dist/ai-service/state-machine/handlers/agent-planning.d.ts.map +1 -1
- package/dist/ai-service/state-machine/handlers/agent-planning.js +97 -47
- package/dist/ai-service/state-machine/handlers/agent-planning.js.map +1 -1
- package/dist/ai-service/state-machine/handlers/awaiting-user.d.ts.map +1 -1
- package/dist/ai-service/state-machine/handlers/awaiting-user.js +68 -50
- package/dist/ai-service/state-machine/handlers/awaiting-user.js.map +1 -1
- package/dist/ai-service/state-machine/handlers/llm-generating.d.ts.map +1 -1
- package/dist/ai-service/state-machine/handlers/llm-generating.js +91 -73
- package/dist/ai-service/state-machine/handlers/llm-generating.js.map +1 -1
- package/dist/ai-service/state-machine/helpers/prompt-failure.d.ts +1 -1
- package/dist/ai-service/state-machine/helpers/prompt-failure.d.ts.map +1 -1
- package/dist/ai-service/state-machine/helpers/prompt-failure.js +1 -0
- package/dist/ai-service/state-machine/helpers/prompt-failure.js.map +1 -1
- package/dist/ai-service/state-machine/helpers/prompt-request-metrics.d.ts +2 -1
- package/dist/ai-service/state-machine/helpers/prompt-request-metrics.d.ts.map +1 -1
- package/dist/ai-service/state-machine/helpers/prompt-request-metrics.js +1 -0
- package/dist/ai-service/state-machine/helpers/prompt-request-metrics.js.map +1 -1
- package/dist/ai-service/state-machine/helpers/user-response-message.d.ts +4 -0
- package/dist/ai-service/state-machine/helpers/user-response-message.d.ts.map +1 -0
- package/dist/ai-service/state-machine/helpers/user-response-message.js +37 -0
- package/dist/ai-service/state-machine/helpers/user-response-message.js.map +1 -0
- package/dist/ai-service/template-renderer.d.ts.map +1 -1
- package/dist/ai-service/template-renderer.js +22 -9
- package/dist/ai-service/template-renderer.js.map +1 -1
- package/dist/ai-service/types.d.ts +2 -1
- package/dist/ai-service/types.d.ts.map +1 -1
- package/dist/ai-service/types.js.map +1 -1
- package/dist/components-manager.d.ts +9 -2
- package/dist/components-manager.d.ts.map +1 -1
- package/dist/components-manager.js +0 -4
- package/dist/components-manager.js.map +1 -1
- package/dist/file-sync-vite-plugin.d.ts.map +1 -1
- package/dist/file-sync-vite-plugin.js +2 -1
- package/dist/file-sync-vite-plugin.js.map +1 -1
- package/dist/file-system-helpers.d.ts +7 -0
- package/dist/file-system-helpers.d.ts.map +1 -1
- package/dist/file-system-helpers.js +9 -1
- package/dist/file-system-helpers.js.map +1 -1
- package/dist/file-system-manager.d.ts +12 -1
- package/dist/file-system-manager.d.ts.map +1 -1
- package/dist/file-system-manager.js +37 -22
- package/dist/file-system-manager.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/lock-service/index.d.ts +20 -0
- package/dist/lock-service/index.d.ts.map +1 -1
- package/dist/lock-service/index.js +53 -5
- package/dist/lock-service/index.js.map +1 -1
- package/dist/migration/get-fullstack-template-dir.js +2 -2
- package/dist/migration/get-fullstack-template-dir.js.map +1 -1
- package/dist/migration/migration-routes.d.ts.map +1 -1
- package/dist/migration/migration-routes.js +8 -2
- package/dist/migration/migration-routes.js.map +1 -1
- package/dist/plugin-options.d.ts +1 -0
- package/dist/plugin-options.d.ts.map +1 -1
- package/dist/plugin-options.js.map +1 -1
- package/dist/router-parser.d.ts.map +1 -1
- package/dist/router-parser.js +336 -65
- package/dist/router-parser.js.map +1 -1
- package/dist/socket-manager.d.ts +25 -2
- package/dist/socket-manager.d.ts.map +1 -1
- package/dist/socket-manager.js +270 -55
- package/dist/socket-manager.js.map +1 -1
- package/dist/split-edit-after-clark.d.ts +14 -0
- package/dist/split-edit-after-clark.d.ts.map +1 -0
- package/dist/split-edit-after-clark.js +40 -0
- package/dist/split-edit-after-clark.js.map +1 -0
- package/dist/sync-service/index.d.ts +2 -1
- package/dist/sync-service/index.d.ts.map +1 -1
- package/dist/sync-service/index.js +5 -0
- package/dist/sync-service/index.js.map +1 -1
- package/dist/sync-service/list-dir.d.ts.map +1 -1
- package/dist/sync-service/list-dir.js +9 -4
- package/dist/sync-service/list-dir.js.map +1 -1
- package/dist/util/log-sanitizer.d.ts.map +1 -1
- package/dist/util/log-sanitizer.js +4 -0
- package/dist/util/log-sanitizer.js.map +1 -1
- package/dist/vite-module-reload.d.ts +34 -0
- package/dist/vite-module-reload.d.ts.map +1 -0
- package/dist/vite-module-reload.js +121 -0
- package/dist/vite-module-reload.js.map +1 -0
- package/package.json +9 -8
|
@@ -34,7 +34,8 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
|
|
|
34
34
|
};
|
|
35
35
|
import { isUtf8 } from "node:buffer";
|
|
36
36
|
import { exec, execFile } from "node:child_process";
|
|
37
|
-
import { readFile as fsReadFile, mkdir, writeFile, access, rm, stat, readdir, } from "node:fs/promises";
|
|
37
|
+
import { readFile as fsReadFile, mkdir, writeFile, access, rm, stat, readdir, mkdtemp, copyFile, } from "node:fs/promises";
|
|
38
|
+
import * as os from "node:os";
|
|
38
39
|
import * as path from "node:path";
|
|
39
40
|
import { promisify } from "node:util";
|
|
40
41
|
import { metrics } from "@opentelemetry/api";
|
|
@@ -53,12 +54,14 @@ import { ToolExecutionError } from "../agent/tools2/types.js";
|
|
|
53
54
|
import llmobs from "../llmobs/index.js";
|
|
54
55
|
import { fixLucideDynamicTypeImports, isFixableLucidePath, } from "../transform/lucide-dynamic-type-imports/transformer.js";
|
|
55
56
|
import { NpmInstallBlocked, NpmInstallError, scrubSecrets, } from "../types.js";
|
|
57
|
+
import { detectAppPackageManager, isPnpmEnabled, podPnpmEnv, } from "./app-package-manager.js";
|
|
56
58
|
import { execCancellable } from "./cancellable-exec.js";
|
|
57
59
|
import { CLARK_APP_BLACKLIST_PATTERNS, APPLICATION_FILE_PATTERNS, STANDARD_IGNORE_PATTERNS, } from "./constants.js";
|
|
58
60
|
import { DraftManager, validateFileOperation, } from "./filesystem/index.js";
|
|
59
61
|
import { Linter } from "./linter.js";
|
|
60
|
-
import { parseNpmJsonDiagnostic, parseNpmJsonError, parseNpmJsonSuccess, } from "./npm-error-parser.js";
|
|
62
|
+
import { classifyNpmExecStderr, parseNpmJsonDiagnostic, parseNpmJsonError, parseNpmJsonSuccess, } from "./npm-error-parser.js";
|
|
61
63
|
import { prepareForPrivateRegistry, shouldIgnoreInstallScripts, } from "./npm-registry.js";
|
|
64
|
+
import { readPnpmLockfile } from "./pnpm-lockfile.js";
|
|
62
65
|
import { parseTypecheckOutputByPath } from "./typecheck-output-parser.js";
|
|
63
66
|
import { applyPackageSubstitutions, runVulnerabilityGate, } from "./vulnerability-gate.js";
|
|
64
67
|
const execPromise = promisify(exec);
|
|
@@ -71,6 +74,16 @@ const execFilePromise = promisify(execFile);
|
|
|
71
74
|
// covers real-world npm summaries (per-package entries are tiny) while
|
|
72
75
|
// keeping the worst-case buffer + parsed-object peak bounded.
|
|
73
76
|
const NPM_JSON_MAX_BUFFER = 4 * 1024 * 1024;
|
|
77
|
+
/**
|
|
78
|
+
* Flags that keep an install from running the app's own code when the org
|
|
79
|
+
* disallows install scripts. pnpm also runs `.pnpmfile.cjs` / `.pnpmfile.mjs`
|
|
80
|
+
* hooks, which `--ignore-scripts` does not stop.
|
|
81
|
+
*/
|
|
82
|
+
function ignoreScriptsFlags(packageManager) {
|
|
83
|
+
return packageManager === "pnpm" && isPnpmEnabled()
|
|
84
|
+
? ["--ignore-scripts", "--ignore-pnpmfile"]
|
|
85
|
+
: ["--ignore-scripts"];
|
|
86
|
+
}
|
|
74
87
|
/** Lowest version a declared range admits; skips `workspace:`/`file:`/`*`/git. */
|
|
75
88
|
function declaredRangeFloor(range) {
|
|
76
89
|
if (range == null || semver.validRange(range) == null)
|
|
@@ -720,13 +733,14 @@ let AppShell = (() => {
|
|
|
720
733
|
* raw registry hostname or token cannot reach an exported attribute even
|
|
721
734
|
* if an upstream caller forgot to scrub.
|
|
722
735
|
*/
|
|
723
|
-
observeNpmInstall(runner, registryFetchResult, outcome, durationMs) {
|
|
736
|
+
observeNpmInstall(runner, registryFetchResult, outcome, durationMs, packageManager) {
|
|
724
737
|
const tags = recordNpmInstall({
|
|
725
738
|
runner,
|
|
726
739
|
registryHost: registryUrlFromFetchResult(registryFetchResult),
|
|
727
740
|
outcome,
|
|
728
741
|
configured: registryFetchResult?.config.configured ?? false,
|
|
729
742
|
durationMs,
|
|
743
|
+
packageManager,
|
|
730
744
|
});
|
|
731
745
|
// Record whether `--ignore-scripts` was added for this install on the span
|
|
732
746
|
// only, not as a metric label: the question is "did this one install skip
|
|
@@ -872,6 +886,7 @@ let AppShell = (() => {
|
|
|
872
886
|
await this.maybePreparePackageJsonForCloudNpm();
|
|
873
887
|
await this.applyDeclaredDependencyUpgrades(await this.maybeRemediateVulnerabilities({
|
|
874
888
|
abortSignal,
|
|
889
|
+
ignoreScripts: shouldIgnoreInstallScripts(registryFetchResult),
|
|
875
890
|
mode: "all",
|
|
876
891
|
}));
|
|
877
892
|
});
|
|
@@ -884,18 +899,61 @@ let AppShell = (() => {
|
|
|
884
899
|
* uses (`buildInstallEnv` in the SDK). These execs otherwise inherit
|
|
885
900
|
* `process.env` implicitly, so we spread it before adding the override.
|
|
886
901
|
* pnpm has no equivalent logs-dir config and ignores the var (npm-only).
|
|
902
|
+
* In the pod pnpm also gets the same settings as the startup install (see
|
|
903
|
+
* `podPnpmEnv`); npm ignores those vars. Local dev keeps the developer's own
|
|
904
|
+
* store and build approvals.
|
|
887
905
|
*/
|
|
888
906
|
installLogEnv() {
|
|
889
907
|
return {
|
|
890
908
|
...process.env,
|
|
891
909
|
NPM_CONFIG_LOGS_DIR: path.join(this.appRootDirPath, ".superblocks", "logs"),
|
|
910
|
+
...(process.env.SUPERBLOCKS_SERVER_ENV === "local" || !isPnpmEnabled()
|
|
911
|
+
? {}
|
|
912
|
+
: podPnpmEnv(this.appRootDirPath)),
|
|
892
913
|
};
|
|
893
914
|
}
|
|
894
915
|
/**
|
|
895
|
-
*
|
|
896
|
-
*
|
|
897
|
-
*
|
|
898
|
-
*
|
|
916
|
+
* The package manager for agent-driven installs. Local dev (csb mock server)
|
|
917
|
+
* keeps pnpm, to stay out of the surrounding workspace's lockfile and store.
|
|
918
|
+
* Cloud edit asks `detectAppPackageManager`, the same decision the
|
|
919
|
+
* dev server's startup install makes, so the two never mix a pnpm
|
|
920
|
+
* node_modules with an npm install.
|
|
921
|
+
*/
|
|
922
|
+
async appPackageManager() {
|
|
923
|
+
if (process.env.SUPERBLOCKS_SERVER_ENV === "local") {
|
|
924
|
+
return "pnpm";
|
|
925
|
+
}
|
|
926
|
+
return detectAppPackageManager(this.appRootDirPath);
|
|
927
|
+
}
|
|
928
|
+
/**
|
|
929
|
+
* The package manager for `runPackageManagerInstall` and
|
|
930
|
+
* `installSpecificPackages`. While pnpm is off, local dev detects the app's
|
|
931
|
+
* package manager, as these two did before pnpm support. Everything else is
|
|
932
|
+
* `appPackageManager`.
|
|
933
|
+
*/
|
|
934
|
+
async installingPackageManager() {
|
|
935
|
+
if (isPnpmEnabled() || process.env.SUPERBLOCKS_SERVER_ENV !== "local") {
|
|
936
|
+
return this.appPackageManager();
|
|
937
|
+
}
|
|
938
|
+
const detected = await detect({
|
|
939
|
+
strategies: [
|
|
940
|
+
"packageManager-field",
|
|
941
|
+
"lockfile",
|
|
942
|
+
"install-metadata",
|
|
943
|
+
"devEngines-field",
|
|
944
|
+
],
|
|
945
|
+
cwd: this.appRootDirPath,
|
|
946
|
+
});
|
|
947
|
+
if (!detected) {
|
|
948
|
+
throw new Error("Could not detect package manager");
|
|
949
|
+
}
|
|
950
|
+
return detected.agent;
|
|
951
|
+
}
|
|
952
|
+
/**
|
|
953
|
+
* npm rejects pnpm's `workspace:` protocol, so in the pod rewrite platform
|
|
954
|
+
* deps and strip any remaining workspace entries before an install (APPS-3752
|
|
955
|
+
* bootstrap does this on pod start; migration restructure and agent installs
|
|
956
|
+
* need the same guard).
|
|
899
957
|
*/
|
|
900
958
|
async maybePreparePackageJsonForCloudNpm() {
|
|
901
959
|
if (process.env.SUPERBLOCKS_SERVER_ENV === "local") {
|
|
@@ -910,6 +968,7 @@ let AppShell = (() => {
|
|
|
910
968
|
const installStart = Date.now();
|
|
911
969
|
let outcome = "success";
|
|
912
970
|
let capturedFetchResult;
|
|
971
|
+
let capturedPackageManager;
|
|
913
972
|
try {
|
|
914
973
|
// `withAuthFailedRetry` owns the `.npmrc` materialization (via
|
|
915
974
|
// `prepareForPrivateRegistry`) and the one-shot auth_failed retry —
|
|
@@ -925,22 +984,22 @@ let AppShell = (() => {
|
|
|
925
984
|
await this.maybePreparePackageJsonForCloudNpm();
|
|
926
985
|
const appliedSubstitutions = await this.applyDeclaredDependencyUpgrades(await this.maybeRemediateVulnerabilities({
|
|
927
986
|
abortSignal,
|
|
987
|
+
ignoreScripts: shouldIgnoreInstallScripts(registryFetchResult),
|
|
928
988
|
mode: "all",
|
|
929
989
|
}));
|
|
930
990
|
const ignoreScripts = shouldIgnoreInstallScripts(registryFetchResult);
|
|
931
|
-
|
|
991
|
+
capturedPackageManager = await this.appPackageManager();
|
|
992
|
+
const isNpm = capturedPackageManager === "npm";
|
|
932
993
|
// prepare already ran above so Mode 2 cloud dry-run sees semver deps.
|
|
933
|
-
//
|
|
934
|
-
//
|
|
935
|
-
// so the `--json` error contract — and therefore the registry-blocked
|
|
936
|
-
// advice matrix — applies on this post-processing path too. When the
|
|
937
|
-
// org has opted out via `allow_install_scripts=false`, append
|
|
938
|
-
// `--ignore-scripts` (the flag is honored by both npm and pnpm).
|
|
994
|
+
// When the org has opted out via `allow_install_scripts=false`, append
|
|
995
|
+
// `--ignore-scripts` (and `--ignore-pnpmfile` for pnpm, see `ignoreScriptsFlags`).
|
|
939
996
|
const baseCommand = isNpm
|
|
940
997
|
? "npm install --fund=false --audit=false --json"
|
|
941
|
-
:
|
|
998
|
+
: isPnpmEnabled()
|
|
999
|
+
? "pnpm install --no-frozen-lockfile"
|
|
1000
|
+
: "pnpm install";
|
|
942
1001
|
const command = ignoreScripts
|
|
943
|
-
? `${baseCommand}
|
|
1002
|
+
? `${baseCommand} ${ignoreScriptsFlags(capturedPackageManager).join(" ")}`
|
|
944
1003
|
: baseCommand;
|
|
945
1004
|
await new Promise((resolve, reject) => {
|
|
946
1005
|
exec(command, {
|
|
@@ -956,14 +1015,12 @@ let AppShell = (() => {
|
|
|
956
1015
|
// Route the npm path through the same classifier as the agent-tool
|
|
957
1016
|
// install entry points so E404 / E401 / ENOTFOUND surface as a
|
|
958
1017
|
// `NpmInstallBlocked` (with row-aware advice) instead of a raw
|
|
959
|
-
// `NpmInstallError(stderr)`.
|
|
960
|
-
//
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
}
|
|
966
|
-
return reject(new NpmInstallError(stderr));
|
|
1018
|
+
// `NpmInstallError(stderr)`. pnpm has no `--json` envelope, so
|
|
1019
|
+
// its classifier reads pnpm's plain output instead.
|
|
1020
|
+
const failure = { stdout, stderr, message: error.message };
|
|
1021
|
+
return reject(isNpm
|
|
1022
|
+
? this.classifyNpmExecError(failure, undefined, registryFetchResult)
|
|
1023
|
+
: this.classifyPnpmExecError(failure, undefined, registryFetchResult));
|
|
967
1024
|
}
|
|
968
1025
|
return resolve();
|
|
969
1026
|
});
|
|
@@ -979,7 +1036,7 @@ let AppShell = (() => {
|
|
|
979
1036
|
throw err;
|
|
980
1037
|
}
|
|
981
1038
|
finally {
|
|
982
|
-
this.observeNpmInstall("install_all", capturedFetchResult, outcome, Date.now() - installStart);
|
|
1039
|
+
this.observeNpmInstall("install_all", capturedFetchResult, outcome, Date.now() - installStart, capturedPackageManager);
|
|
983
1040
|
}
|
|
984
1041
|
}
|
|
985
1042
|
/**
|
|
@@ -1078,7 +1135,7 @@ let AppShell = (() => {
|
|
|
1078
1135
|
* rewrite). Local stays floors-only — pnpm + lingering `workspace:*` mean
|
|
1079
1136
|
* full-tree coverage is not available there.
|
|
1080
1137
|
*/
|
|
1081
|
-
async resolveInstallTree(mode, packages, abortSignal) {
|
|
1138
|
+
async resolveInstallTree(mode, packages, abortSignal, ignoreScripts) {
|
|
1082
1139
|
if (mode === "all") {
|
|
1083
1140
|
const topLevel = [];
|
|
1084
1141
|
for (const pkg of packages ?? []) {
|
|
@@ -1093,7 +1150,7 @@ let AppShell = (() => {
|
|
|
1093
1150
|
const fromLock = await this.readPackagesFromPackageLock();
|
|
1094
1151
|
let dryTree = [];
|
|
1095
1152
|
try {
|
|
1096
|
-
dryTree = (await this.resolveTreeViaNpmDryRun([], abortSignal)).tree;
|
|
1153
|
+
dryTree = (await this.resolveTreeViaNpmDryRun([], abortSignal, ignoreScripts)).tree;
|
|
1097
1154
|
}
|
|
1098
1155
|
catch (err) {
|
|
1099
1156
|
// Do not continue remediation after cancel.
|
|
@@ -1113,7 +1170,7 @@ let AppShell = (() => {
|
|
|
1113
1170
|
return { resolves: true, topLevel, tree: [...byKey.values()] };
|
|
1114
1171
|
}
|
|
1115
1172
|
const specs = (packages ?? []).map((pkg) => pkg.version ? `${pkg.name}@${pkg.version}` : pkg.name);
|
|
1116
|
-
const resolved = await this.resolveTreeViaNpmDryRun(specs, abortSignal);
|
|
1173
|
+
const resolved = await this.resolveTreeViaNpmDryRun(specs, abortSignal, ignoreScripts);
|
|
1117
1174
|
// Prefer dry-run concrete pins for top-level. Never inject the raw
|
|
1118
1175
|
// requested range/`latest` string into the lookup tree — the index
|
|
1119
1176
|
// keys on concrete versions, and a range would fail coverage checks.
|
|
@@ -1149,9 +1206,13 @@ let AppShell = (() => {
|
|
|
1149
1206
|
tree: [...byKey.values()],
|
|
1150
1207
|
topLevel,
|
|
1151
1208
|
resolves: resolved.resolves,
|
|
1209
|
+
unnamed: resolved.unnamed,
|
|
1152
1210
|
};
|
|
1153
1211
|
}
|
|
1154
|
-
async resolveTreeViaNpmDryRun(specs, abortSignal) {
|
|
1212
|
+
async resolveTreeViaNpmDryRun(specs, abortSignal, ignoreScripts) {
|
|
1213
|
+
if (isPnpmEnabled() && (await this.appPackageManager()) === "pnpm") {
|
|
1214
|
+
return this.resolveTreeViaPnpmLockfile(specs, abortSignal, ignoreScripts);
|
|
1215
|
+
}
|
|
1155
1216
|
const args = [
|
|
1156
1217
|
"install",
|
|
1157
1218
|
"--dry-run",
|
|
@@ -1202,6 +1263,72 @@ let AppShell = (() => {
|
|
|
1202
1263
|
throw error;
|
|
1203
1264
|
}
|
|
1204
1265
|
}
|
|
1266
|
+
/**
|
|
1267
|
+
* pnpm's dry run for the install security check. npm's `--dry-run` crashes
|
|
1268
|
+
* on a node_modules that pnpm laid out, and pnpm has no dry run of its own,
|
|
1269
|
+
* so this resolves in a throwaway copy of the app's manifest and lockfile
|
|
1270
|
+
* with `--lockfile-only` (nothing downloaded or linked) and reads the tree
|
|
1271
|
+
* pnpm wrote. That is exactly what the real install will pick, overrides and
|
|
1272
|
+
* all. Any pnpm failure counts as "does not resolve", as for npm's error
|
|
1273
|
+
* envelope, so the check never vouches for a tree it couldn't see.
|
|
1274
|
+
*/
|
|
1275
|
+
async resolveTreeViaPnpmLockfile(specs, abortSignal, ignoreScripts) {
|
|
1276
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), "sb-pnpm-resolve-"));
|
|
1277
|
+
try {
|
|
1278
|
+
for (const file of [
|
|
1279
|
+
"package.json",
|
|
1280
|
+
"pnpm-lock.yaml",
|
|
1281
|
+
"pnpm-workspace.yaml",
|
|
1282
|
+
".npmrc",
|
|
1283
|
+
// The real install runs the app's pnpmfile hooks, which can add
|
|
1284
|
+
// dependencies, so the check has to run them too. Unless the org
|
|
1285
|
+
// disallows install scripts: then no install runs them.
|
|
1286
|
+
...(ignoreScripts ? [] : [".pnpmfile.cjs", ".pnpmfile.mjs"]),
|
|
1287
|
+
]) {
|
|
1288
|
+
await copyFile(path.join(this.appRootDirPath, file), path.join(dir, file)).catch(() => undefined);
|
|
1289
|
+
}
|
|
1290
|
+
// `--` so a spec that looks like an option (`--registry=…`) is read as
|
|
1291
|
+
// a package name, as in the npm dry run. execFile, so no shell either.
|
|
1292
|
+
// `--ignore-scripts` always: resolving the tree needs no builds.
|
|
1293
|
+
const flags = [
|
|
1294
|
+
"--lockfile-only",
|
|
1295
|
+
...(ignoreScripts ? ignoreScriptsFlags("pnpm") : ["--ignore-scripts"]),
|
|
1296
|
+
];
|
|
1297
|
+
const args = specs.length > 0
|
|
1298
|
+
? ["add", ...flags, "--", ...specs]
|
|
1299
|
+
: // The lockfile has to be allowed to change, as on the real
|
|
1300
|
+
// install. pnpm 12 already allows that with `--lockfile-only`
|
|
1301
|
+
// under `CI=true`; the flag says so outright. `pnpm add` rejects it.
|
|
1302
|
+
["install", ...flags, "--no-frozen-lockfile"];
|
|
1303
|
+
await execFilePromise("pnpm", args, {
|
|
1304
|
+
cwd: dir,
|
|
1305
|
+
env: this.installLogEnv(),
|
|
1306
|
+
signal: abortSignal,
|
|
1307
|
+
maxBuffer: NPM_JSON_MAX_BUFFER,
|
|
1308
|
+
});
|
|
1309
|
+
const locked = readPnpmLockfile(await fsReadFile(path.join(dir, "pnpm-lock.yaml"), "utf8"));
|
|
1310
|
+
if (!locked)
|
|
1311
|
+
return { tree: [], topLevel: [], resolves: false };
|
|
1312
|
+
// A tarball or git package already in the app's lockfile is already
|
|
1313
|
+
// installed; only the ones this install adds are new.
|
|
1314
|
+
const installed = new Set((await this.readPackagesFromPackageLock())?.unnamed);
|
|
1315
|
+
return {
|
|
1316
|
+
...locked,
|
|
1317
|
+
unnamed: locked.unnamed.filter((key) => !installed.has(key)),
|
|
1318
|
+
resolves: true,
|
|
1319
|
+
};
|
|
1320
|
+
}
|
|
1321
|
+
catch (error) {
|
|
1322
|
+
if (abortSignal?.aborted ||
|
|
1323
|
+
(error instanceof Error && error.name === "AbortError")) {
|
|
1324
|
+
throw error;
|
|
1325
|
+
}
|
|
1326
|
+
return { tree: [], topLevel: [], resolves: false };
|
|
1327
|
+
}
|
|
1328
|
+
finally {
|
|
1329
|
+
await rm(dir, { recursive: true, force: true });
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1205
1332
|
treeFromNpmDryRunJson(parsed, specs) {
|
|
1206
1333
|
if (parsed == null || typeof parsed !== "object") {
|
|
1207
1334
|
return { tree: [], topLevel: [], resolves: true };
|
|
@@ -1257,6 +1384,12 @@ let AppShell = (() => {
|
|
|
1257
1384
|
return { tree, topLevel, resolves: true };
|
|
1258
1385
|
}
|
|
1259
1386
|
async readPackagesFromPackageLock() {
|
|
1387
|
+
// A pnpm app's installed tree is in `pnpm-lock.yaml`; a `package-lock.json`
|
|
1388
|
+
// left over from its npm days would describe packages pnpm never installs.
|
|
1389
|
+
if (isPnpmEnabled() && (await this.appPackageManager()) === "pnpm") {
|
|
1390
|
+
const locked = readPnpmLockfile(await fsReadFile(path.join(this.appRootDirPath, "pnpm-lock.yaml"), "utf8").catch(() => ""));
|
|
1391
|
+
return locked ? { ...locked, resolves: true } : null;
|
|
1392
|
+
}
|
|
1260
1393
|
const lockPath = path.join(this.appRootDirPath, "package-lock.json");
|
|
1261
1394
|
let raw;
|
|
1262
1395
|
try {
|
|
@@ -1332,7 +1465,7 @@ let AppShell = (() => {
|
|
|
1332
1465
|
* No-op when `packageLookup` is unwired. Index failures → malware fail-closed.
|
|
1333
1466
|
*/
|
|
1334
1467
|
async maybeRemediateVulnerabilities(args) {
|
|
1335
|
-
const { abortSignal, cveUserOverride, mode } = args;
|
|
1468
|
+
const { abortSignal, cveUserOverride, ignoreScripts, mode } = args;
|
|
1336
1469
|
if (!this.packageLookup) {
|
|
1337
1470
|
return { substitutions: [] };
|
|
1338
1471
|
}
|
|
@@ -1348,8 +1481,8 @@ let AppShell = (() => {
|
|
|
1348
1481
|
getLogger().warn(message, getErrorMeta(error));
|
|
1349
1482
|
},
|
|
1350
1483
|
pickQuarantineHoldback: this.packageLookup.pickQuarantineHoldback,
|
|
1351
|
-
resolveInstallTree: async (resolveArgs) => await this.resolveInstallTree(resolveArgs.mode, resolveArgs.packages, resolveArgs.abortSignal),
|
|
1352
|
-
resolvePackageSpecs: async (resolveArgs) => await this.resolveTreeViaNpmDryRun(resolveArgs.specs, resolveArgs.abortSignal),
|
|
1484
|
+
resolveInstallTree: async (resolveArgs) => await this.resolveInstallTree(resolveArgs.mode, resolveArgs.packages, resolveArgs.abortSignal, ignoreScripts),
|
|
1485
|
+
resolvePackageSpecs: async (resolveArgs) => await this.resolveTreeViaNpmDryRun(resolveArgs.specs, resolveArgs.abortSignal, ignoreScripts),
|
|
1353
1486
|
},
|
|
1354
1487
|
cveUserOverride,
|
|
1355
1488
|
mode,
|
|
@@ -1398,9 +1531,8 @@ let AppShell = (() => {
|
|
|
1398
1531
|
* pre-existing handler (e.g. agent-planning's POST_PROCESSING_ERRORED
|
|
1399
1532
|
* branch) behaves exactly as it did before.
|
|
1400
1533
|
*
|
|
1401
|
-
* Only used on the npm code path; pnpm
|
|
1402
|
-
*
|
|
1403
|
-
* registry-blocked scenarios only matter in cloud-edit (which forces npm).
|
|
1534
|
+
* Only used on the npm code path; pnpm failures go through
|
|
1535
|
+
* `classifyPnpmExecError`.
|
|
1404
1536
|
*
|
|
1405
1537
|
* `registryFetchResult` carries the most recent
|
|
1406
1538
|
* `prepareForPrivateRegistry` result so the structured error can encode
|
|
@@ -1466,6 +1598,29 @@ let AppShell = (() => {
|
|
|
1466
1598
|
}
|
|
1467
1599
|
return new NpmInstallError(diagnostic || error.stderr || error.message || "");
|
|
1468
1600
|
}
|
|
1601
|
+
/**
|
|
1602
|
+
* pnpm's counterpart to `classifyNpmExecError`. pnpm has no `--json` error
|
|
1603
|
+
* output, so this reads its plain-text error. pnpm 12 writes that to stderr,
|
|
1604
|
+
* pnpm 10 and older to stdout, so both are read. A registry failure
|
|
1605
|
+
* (`ERR_PNPM_FETCH_401` and friends) becomes an `NpmInstallBlocked`, which
|
|
1606
|
+
* gives the agent the same advice and auth retry as npm. Anything else keeps
|
|
1607
|
+
* pnpm's own message instead of an empty one.
|
|
1608
|
+
*/
|
|
1609
|
+
classifyPnpmExecError(error, requestedPackages, registryFetchResult) {
|
|
1610
|
+
// While pnpm is off, a pnpm failure keeps its stderr as it did before.
|
|
1611
|
+
if (!isPnpmEnabled()) {
|
|
1612
|
+
return new NpmInstallError(error.stderr || error.message || "");
|
|
1613
|
+
}
|
|
1614
|
+
const output = `${error.stdout ?? ""}\n${error.stderr ?? ""}`.trim();
|
|
1615
|
+
const blocked = classifyNpmExecStderr(output, {
|
|
1616
|
+
requestedPackages,
|
|
1617
|
+
hasAnyRegistryConfigured: AppShell.deriveHasAnyRegistryConfigured(registryFetchResult),
|
|
1618
|
+
});
|
|
1619
|
+
// The message reaches the agent, and pnpm's output can echo a registry
|
|
1620
|
+
// URL with its token in it.
|
|
1621
|
+
return (blocked ??
|
|
1622
|
+
new NpmInstallError(scrubSecrets(output || error.message || "")));
|
|
1623
|
+
}
|
|
1469
1624
|
/**
|
|
1470
1625
|
* Wraps an install attempt so that a `registry_auth_failed` failure
|
|
1471
1626
|
* triggers one cache-invalidation + re-fetch + retry cycle before
|
|
@@ -1502,80 +1657,69 @@ let AppShell = (() => {
|
|
|
1502
1657
|
const installStart = Date.now();
|
|
1503
1658
|
let outcome = "success";
|
|
1504
1659
|
let capturedFetchResult;
|
|
1660
|
+
let capturedPackageManager;
|
|
1505
1661
|
try {
|
|
1506
1662
|
return await this.withAuthFailedRetry(async (registryFetchResult) => {
|
|
1507
1663
|
capturedFetchResult = registryFetchResult;
|
|
1508
1664
|
// APPS-4370: short-circuit before any exec when server is unreachable
|
|
1509
1665
|
// AND this org's marker says it was previously configured.
|
|
1510
1666
|
this.maybeShortCircuitForUnreachable(registryFetchResult, []);
|
|
1511
|
-
//
|
|
1512
|
-
//
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
await this.maybePreparePackageJsonForCloudNpm();
|
|
1521
|
-
}
|
|
1522
|
-
else {
|
|
1523
|
-
// NOTE: this largely duplicates the logic in the CLI
|
|
1524
|
-
const packageManager = await detect({
|
|
1525
|
-
strategies: [
|
|
1526
|
-
"packageManager-field",
|
|
1527
|
-
"lockfile",
|
|
1528
|
-
"install-metadata",
|
|
1529
|
-
"devEngines-field",
|
|
1530
|
-
],
|
|
1531
|
-
cwd: this.appRootDirPath,
|
|
1532
|
-
});
|
|
1533
|
-
if (!packageManager) {
|
|
1534
|
-
throw new Error("Could not detect package manager");
|
|
1535
|
-
}
|
|
1536
|
-
packageManagerAgent = packageManager.agent;
|
|
1537
|
-
}
|
|
1667
|
+
// Cloud edit uses npm unless the app is a pnpm app and pnpm is on for
|
|
1668
|
+
// the org (see `appPackageManager`).
|
|
1669
|
+
const packageManagerAgent = await this.installingPackageManager();
|
|
1670
|
+
// Prepare before Mode 2 so the dry-run malware scan does not choke on
|
|
1671
|
+
// workspace: protocol entries. pnpm in the pod needs it as much as
|
|
1672
|
+
// npm: the app is a single project there, so `workspace:*` has
|
|
1673
|
+
// nothing to resolve to. A no-op in local dev.
|
|
1674
|
+
await this.maybePreparePackageJsonForCloudNpm();
|
|
1675
|
+
capturedPackageManager = packageManagerAgent;
|
|
1538
1676
|
const appliedSubstitutions = await this.applyDeclaredDependencyUpgrades(await this.maybeRemediateVulnerabilities({
|
|
1539
1677
|
abortSignal,
|
|
1678
|
+
ignoreScripts: shouldIgnoreInstallScripts(registryFetchResult),
|
|
1540
1679
|
mode: "all",
|
|
1541
1680
|
}));
|
|
1542
1681
|
const ignoreScripts = shouldIgnoreInstallScripts(registryFetchResult);
|
|
1543
1682
|
const isNpm = packageManagerAgent === "npm";
|
|
1683
|
+
// pnpm: the lockfile has to be allowed to change, as for `npm
|
|
1684
|
+
// install`; pnpm would otherwise refuse under `CI=true`.
|
|
1544
1685
|
const baseInstallArgs = isNpm
|
|
1545
1686
|
? ["--fund=false", "--audit=false", "--json"]
|
|
1546
|
-
:
|
|
1687
|
+
: packageManagerAgent === "pnpm" && isPnpmEnabled()
|
|
1688
|
+
? ["--no-frozen-lockfile"]
|
|
1689
|
+
: [];
|
|
1547
1690
|
const installArgs = ignoreScripts
|
|
1548
|
-
? [...baseInstallArgs,
|
|
1691
|
+
? [...baseInstallArgs, ...ignoreScriptsFlags(packageManagerAgent)]
|
|
1549
1692
|
: baseInstallArgs;
|
|
1550
1693
|
const installCommand = resolveCommand(packageManagerAgent, "install", installArgs);
|
|
1551
1694
|
if (!installCommand) {
|
|
1552
1695
|
throw new Error(`Could not determine install command for ${packageManagerAgent}, skipping package installation`);
|
|
1553
1696
|
}
|
|
1554
1697
|
const { command, args } = installCommand;
|
|
1698
|
+
let stdout;
|
|
1555
1699
|
try {
|
|
1556
|
-
|
|
1700
|
+
({ stdout } = await execPromise(`${command} ${args.join(" ")}`, {
|
|
1557
1701
|
cwd: this.appRootDirPath,
|
|
1558
1702
|
env: this.installLogEnv(),
|
|
1559
1703
|
signal: abortSignal,
|
|
1560
1704
|
// See `NPM_JSON_MAX_BUFFER` — `--json` summary can outgrow the
|
|
1561
1705
|
// default 1 MiB exec buffer on fat dep trees.
|
|
1562
1706
|
maxBuffer: NPM_JSON_MAX_BUFFER,
|
|
1563
|
-
});
|
|
1564
|
-
// Audit only after the install succeeds (same as Mode 1).
|
|
1565
|
-
this.maybeReportSubstitutions(appliedSubstitutions, "install_all");
|
|
1566
|
-
// On the npm path stdout is a JSON blob; translate to a compact
|
|
1567
|
-
// human-readable summary for the agent, falling back to raw stdout
|
|
1568
|
-
// when the JSON shape drifts.
|
|
1569
|
-
if (isNpm) {
|
|
1570
|
-
return parseNpmJsonSuccess(stdout) ?? stdout;
|
|
1571
|
-
}
|
|
1572
|
-
return stdout;
|
|
1707
|
+
}));
|
|
1573
1708
|
}
|
|
1574
1709
|
catch (error) {
|
|
1575
1710
|
if (isNpm)
|
|
1576
1711
|
throw this.classifyNpmExecError(error, undefined, registryFetchResult);
|
|
1577
|
-
throw
|
|
1712
|
+
throw this.classifyPnpmExecError(error, undefined, registryFetchResult);
|
|
1713
|
+
}
|
|
1714
|
+
// Audit only after the install succeeds (same as Mode 1).
|
|
1715
|
+
this.maybeReportSubstitutions(appliedSubstitutions, "install_all");
|
|
1716
|
+
// On the npm path stdout is a JSON blob; translate to a compact
|
|
1717
|
+
// human-readable summary for the agent, falling back to raw stdout
|
|
1718
|
+
// when the JSON shape drifts.
|
|
1719
|
+
if (isNpm) {
|
|
1720
|
+
return parseNpmJsonSuccess(stdout) ?? stdout;
|
|
1578
1721
|
}
|
|
1722
|
+
return stdout;
|
|
1579
1723
|
});
|
|
1580
1724
|
}
|
|
1581
1725
|
catch (err) {
|
|
@@ -1584,7 +1728,7 @@ let AppShell = (() => {
|
|
|
1584
1728
|
throw err;
|
|
1585
1729
|
}
|
|
1586
1730
|
finally {
|
|
1587
|
-
this.observeNpmInstall("install_all", capturedFetchResult, outcome, Date.now() - installStart);
|
|
1731
|
+
this.observeNpmInstall("install_all", capturedFetchResult, outcome, Date.now() - installStart, capturedPackageManager);
|
|
1588
1732
|
}
|
|
1589
1733
|
}
|
|
1590
1734
|
async installSpecificPackages(packages, abortSignal, options) {
|
|
@@ -1608,6 +1752,7 @@ let AppShell = (() => {
|
|
|
1608
1752
|
const installStart = Date.now();
|
|
1609
1753
|
let outcome = "success";
|
|
1610
1754
|
let capturedFetchResult;
|
|
1755
|
+
let capturedPackageManager;
|
|
1611
1756
|
try {
|
|
1612
1757
|
return await this.withAuthFailedRetry(async (registryFetchResult) => {
|
|
1613
1758
|
capturedFetchResult = registryFetchResult;
|
|
@@ -1616,37 +1761,19 @@ let AppShell = (() => {
|
|
|
1616
1761
|
// surfaces them to the agent ("we tried to install lodash and the
|
|
1617
1762
|
// private registry was unreachable").
|
|
1618
1763
|
this.maybeShortCircuitForUnreachable(registryFetchResult, packages.map((pkg) => pkg.version ? `${pkg.name}@${pkg.version}` : pkg.name));
|
|
1619
|
-
//
|
|
1620
|
-
//
|
|
1621
|
-
//
|
|
1622
|
-
//
|
|
1623
|
-
const
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
// Force npm in cloud mode
|
|
1627
|
-
packageManagerAgent = "npm";
|
|
1628
|
-
await this.maybePreparePackageJsonForCloudNpm();
|
|
1629
|
-
}
|
|
1630
|
-
else {
|
|
1631
|
-
const packageManager = await detect({
|
|
1632
|
-
strategies: [
|
|
1633
|
-
"packageManager-field",
|
|
1634
|
-
"lockfile",
|
|
1635
|
-
"install-metadata",
|
|
1636
|
-
"devEngines-field",
|
|
1637
|
-
],
|
|
1638
|
-
cwd: this.appRootDirPath,
|
|
1639
|
-
});
|
|
1640
|
-
if (!packageManager) {
|
|
1641
|
-
throw new Error("Could not detect package manager");
|
|
1642
|
-
}
|
|
1643
|
-
packageManagerAgent = packageManager.agent;
|
|
1644
|
-
}
|
|
1764
|
+
// Cloud edit uses npm unless the app is a pnpm app and pnpm is on for
|
|
1765
|
+
// the org (see `appPackageManager`). Prepare before the Mode 1 dry-run
|
|
1766
|
+
// so leftover workspace: entries cannot break malware coverage, for
|
|
1767
|
+
// pnpm as well as npm (see `runPackageManagerInstall`).
|
|
1768
|
+
const packageManagerAgent = await this.installingPackageManager();
|
|
1769
|
+
await this.maybePreparePackageJsonForCloudNpm();
|
|
1770
|
+
capturedPackageManager = packageManagerAgent;
|
|
1645
1771
|
// Malware hard-block on the dry-run resolved tree (top-level +
|
|
1646
1772
|
// transitive) before the real install runs. Mode 1 also returns
|
|
1647
1773
|
// silent CVE substitutions applied to the install argv below.
|
|
1648
1774
|
const remediation = await this.maybeRemediateVulnerabilities({
|
|
1649
1775
|
abortSignal,
|
|
1776
|
+
ignoreScripts: shouldIgnoreInstallScripts(registryFetchResult),
|
|
1650
1777
|
cveUserOverride: options?.cveUserOverride,
|
|
1651
1778
|
mode: "specific",
|
|
1652
1779
|
packages,
|
|
@@ -1664,7 +1791,9 @@ let AppShell = (() => {
|
|
|
1664
1791
|
const baseArgs = isNpm
|
|
1665
1792
|
? ["--fund=false", "--audit=false", "--json", ...packageSpecs]
|
|
1666
1793
|
: packageSpecs;
|
|
1667
|
-
const addCommand = resolveCommand(packageManagerAgent, "add", ignoreScripts
|
|
1794
|
+
const addCommand = resolveCommand(packageManagerAgent, "add", ignoreScripts
|
|
1795
|
+
? [...ignoreScriptsFlags(packageManagerAgent), ...baseArgs]
|
|
1796
|
+
: baseArgs);
|
|
1668
1797
|
if (!addCommand) {
|
|
1669
1798
|
throw new Error(`Could not determine add command for ${packageManagerAgent}`);
|
|
1670
1799
|
}
|
|
@@ -1683,7 +1812,7 @@ let AppShell = (() => {
|
|
|
1683
1812
|
catch (error) {
|
|
1684
1813
|
if (isNpm)
|
|
1685
1814
|
throw this.classifyNpmExecError(error, regularPackages, registryFetchResult);
|
|
1686
|
-
throw
|
|
1815
|
+
throw this.classifyPnpmExecError(error, regularPackages, registryFetchResult);
|
|
1687
1816
|
}
|
|
1688
1817
|
}
|
|
1689
1818
|
// Install dev dependencies
|
|
@@ -1698,7 +1827,9 @@ let AppShell = (() => {
|
|
|
1698
1827
|
...packageSpecs,
|
|
1699
1828
|
]
|
|
1700
1829
|
: ["-D", ...packageSpecs];
|
|
1701
|
-
const addCommand = resolveCommand(packageManagerAgent, "add", ignoreScripts
|
|
1830
|
+
const addCommand = resolveCommand(packageManagerAgent, "add", ignoreScripts
|
|
1831
|
+
? [...ignoreScriptsFlags(packageManagerAgent), ...baseArgs]
|
|
1832
|
+
: baseArgs);
|
|
1702
1833
|
if (!addCommand) {
|
|
1703
1834
|
throw new Error(`Could not determine add command for ${packageManagerAgent}`);
|
|
1704
1835
|
}
|
|
@@ -1717,7 +1848,7 @@ let AppShell = (() => {
|
|
|
1717
1848
|
catch (error) {
|
|
1718
1849
|
if (isNpm)
|
|
1719
1850
|
throw this.classifyNpmExecError(error, devPackages, registryFetchResult);
|
|
1720
|
-
throw
|
|
1851
|
+
throw this.classifyPnpmExecError(error, devPackages, registryFetchResult);
|
|
1721
1852
|
}
|
|
1722
1853
|
}
|
|
1723
1854
|
// Audit only after every install group succeeds: a selected
|
|
@@ -1744,7 +1875,7 @@ let AppShell = (() => {
|
|
|
1744
1875
|
throw err;
|
|
1745
1876
|
}
|
|
1746
1877
|
finally {
|
|
1747
|
-
this.observeNpmInstall("install_specific", capturedFetchResult, outcome, Date.now() - installStart);
|
|
1878
|
+
this.observeNpmInstall("install_specific", capturedFetchResult, outcome, Date.now() - installStart, capturedPackageManager);
|
|
1748
1879
|
}
|
|
1749
1880
|
}
|
|
1750
1881
|
async uninstallPackages(packages, options) {
|
|
@@ -1765,6 +1896,7 @@ let AppShell = (() => {
|
|
|
1765
1896
|
const installStart = Date.now();
|
|
1766
1897
|
let outcome = "success";
|
|
1767
1898
|
let capturedFetchResult;
|
|
1899
|
+
let capturedPackageManager;
|
|
1768
1900
|
// Uninstalls hit the same registry resolution rules as installs (the
|
|
1769
1901
|
// dependency-tree solver re-reifies the remaining tree and can re-fetch
|
|
1770
1902
|
// metadata), so they run through the SAME safety wrapper as every
|
|
@@ -1799,13 +1931,14 @@ let AppShell = (() => {
|
|
|
1799
1931
|
// surrounding workspace); npm everywhere else so the `--json` error
|
|
1800
1932
|
// contract — and therefore the registry-blocked advice matrix —
|
|
1801
1933
|
// applies. Mirrors `runNpmInstall` / `installSpecificPackages`.
|
|
1802
|
-
|
|
1934
|
+
capturedPackageManager = await this.appPackageManager();
|
|
1935
|
+
const isNpm = capturedPackageManager === "npm";
|
|
1803
1936
|
const packageManager = isNpm ? "npm" : "pnpm";
|
|
1804
1937
|
const uninstallCmd = isNpm ? "uninstall" : "remove";
|
|
1805
|
-
const
|
|
1806
|
-
const baseCommand = `${packageManager} ${uninstallCmd} ${packages.join(" ")}${
|
|
1938
|
+
const flags = isNpm ? " --json" : "";
|
|
1939
|
+
const baseCommand = `${packageManager} ${uninstallCmd} ${packages.join(" ")}${flags}`;
|
|
1807
1940
|
const command = ignoreScripts
|
|
1808
|
-
? `${baseCommand}
|
|
1941
|
+
? `${baseCommand} ${ignoreScriptsFlags(packageManager).join(" ")}`
|
|
1809
1942
|
: baseCommand;
|
|
1810
1943
|
return await new Promise((resolve, reject) => {
|
|
1811
1944
|
exec(command, {
|
|
@@ -1822,12 +1955,12 @@ let AppShell = (() => {
|
|
|
1822
1955
|
// `NpmInstallBlocked` (with row-aware advice + the
|
|
1823
1956
|
// auth-failed retry signal consumed by `withAuthFailedRetry`);
|
|
1824
1957
|
// anything else falls back to the legacy `NpmInstallError`.
|
|
1825
|
-
// pnpm
|
|
1826
|
-
//
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1958
|
+
// pnpm has no `--json` envelope, so its classifier reads
|
|
1959
|
+
// pnpm's plain output instead.
|
|
1960
|
+
const failure = { stdout, stderr, message: error.message };
|
|
1961
|
+
return reject(isNpm
|
|
1962
|
+
? this.classifyNpmExecError(failure, undefined, registryFetchResult)
|
|
1963
|
+
: this.classifyPnpmExecError(failure, undefined, registryFetchResult));
|
|
1831
1964
|
}
|
|
1832
1965
|
// On the npm path stdout is a `--json` blob; collapse it to a
|
|
1833
1966
|
// compact human-readable summary (same as
|
|
@@ -1849,7 +1982,7 @@ let AppShell = (() => {
|
|
|
1849
1982
|
throw err;
|
|
1850
1983
|
}
|
|
1851
1984
|
finally {
|
|
1852
|
-
this.observeNpmInstall("uninstall", capturedFetchResult, outcome, Date.now() - installStart);
|
|
1985
|
+
this.observeNpmInstall("uninstall", capturedFetchResult, outcome, Date.now() - installStart, capturedPackageManager);
|
|
1853
1986
|
}
|
|
1854
1987
|
}
|
|
1855
1988
|
static MAX_GENERATION_RUNS = 10;
|