opencode-ship 1.1.2-rc.2 → 1.1.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/CHANGELOG.md +96 -1
- package/README.md +2 -2
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/assets/agents/delivery-reviewer.md +1 -0
- package/assets/agents/delivery-verifier.md +1 -0
- package/assets/agents/ship-controller.md +20 -7
- package/assets/agents/ship-final-spec-reviewer.md +5 -3
- package/assets/agents/ship-final-standards-reviewer.md +5 -3
- package/assets/agents/ship-planner.md +1 -0
- package/assets/agents/ship-task-builder.md +1 -0
- package/assets/agents/ship-task-reviewer.md +1 -0
- package/dist/cli.js +2274 -362
- package/dist/core.js +794 -10
- package/dist/plugin.js +3487 -1795
- package/package.json +9 -4
- package/tests/plugin/expected-tools.mjs +2 -2
- package/tests/plugin/plugin-load.test.mjs +8 -3
- package/assets/_archive/issue-tracker-gitlab.md +0 -46
- package/assets/_archive/issue-tracker-local.md +0 -30
- package/docs/adr/0001-opencode-ship-redesign.md +0 -168
- package/docs/release/1.0.0-execution-plan.md +0 -1063
- package/docs/release/1.1.1-stabilization-plan.md +0 -655
- package/vendor/upstreams/mattpocock/skills/engineering/code-review/SKILL.md +0 -89
- package/vendor/upstreams/mattpocock/skills/engineering/codebase-design/DEEPENING.md +0 -37
- package/vendor/upstreams/mattpocock/skills/engineering/codebase-design/DESIGN-IT-TWICE.md +0 -44
- package/vendor/upstreams/mattpocock/skills/engineering/codebase-design/SKILL.md +0 -114
- package/vendor/upstreams/mattpocock/skills/engineering/domain-modeling/ADR-FORMAT.md +0 -47
- package/vendor/upstreams/mattpocock/skills/engineering/domain-modeling/CONTEXT-FORMAT.md +0 -60
- package/vendor/upstreams/mattpocock/skills/engineering/domain-modeling/SKILL.md +0 -74
- package/vendor/upstreams/mattpocock/skills/engineering/grill-with-docs/SKILL.md +0 -7
- package/vendor/upstreams/mattpocock/skills/engineering/prototype/LOGIC.md +0 -79
- package/vendor/upstreams/mattpocock/skills/engineering/prototype/SKILL.md +0 -26
- package/vendor/upstreams/mattpocock/skills/engineering/prototype/UI.md +0 -112
- package/vendor/upstreams/mattpocock/skills/engineering/research/SKILL.md +0 -12
- package/vendor/upstreams/mattpocock/skills/engineering/setup-matt-pocock-skills/SKILL.md +0 -116
- package/vendor/upstreams/mattpocock/skills/engineering/setup-matt-pocock-skills/domain.md +0 -51
- package/vendor/upstreams/mattpocock/skills/engineering/setup-matt-pocock-skills/issue-tracker-github.md +0 -45
- package/vendor/upstreams/mattpocock/skills/engineering/setup-matt-pocock-skills/issue-tracker-gitlab.md +0 -46
- package/vendor/upstreams/mattpocock/skills/engineering/setup-matt-pocock-skills/issue-tracker-local.md +0 -30
- package/vendor/upstreams/mattpocock/skills/engineering/setup-matt-pocock-skills/triage-labels.md +0 -15
- package/vendor/upstreams/mattpocock/skills/engineering/to-spec/SKILL.md +0 -75
- package/vendor/upstreams/mattpocock/skills/engineering/to-tickets/SKILL.md +0 -105
- package/vendor/upstreams/mattpocock/skills/engineering/triage/AGENT-BRIEF.md +0 -207
- package/vendor/upstreams/mattpocock/skills/engineering/triage/OUT-OF-SCOPE.md +0 -105
- package/vendor/upstreams/mattpocock/skills/engineering/triage/SKILL.md +0 -112
- package/vendor/upstreams/mattpocock/skills/engineering/wayfinder/SKILL.md +0 -128
- package/vendor/upstreams/mattpocock/skills/productivity/grilling/SKILL.md +0 -12
- package/vendor/upstreams/mattpocock/skills/productivity/handoff/SKILL.md +0 -16
- package/vendor/upstreams/obra/skills/brainstorming/SKILL.md +0 -151
- package/vendor/upstreams/obra/skills/brainstorming/spec-document-reviewer-prompt.md +0 -49
- package/vendor/upstreams/obra/skills/brainstorming/visual-companion.md +0 -298
- package/vendor/upstreams/obra/skills/dispatching-parallel-agents/SKILL.md +0 -167
- package/vendor/upstreams/obra/skills/executing-plans/SKILL.md +0 -64
- package/vendor/upstreams/obra/skills/receiving-code-review/SKILL.md +0 -205
- package/vendor/upstreams/obra/skills/requesting-code-review/SKILL.md +0 -95
- package/vendor/upstreams/obra/skills/requesting-code-review/code-reviewer.md +0 -172
- package/vendor/upstreams/obra/skills/subagent-driven-development/SKILL.md +0 -503
- package/vendor/upstreams/obra/skills/subagent-driven-development/implementer-prompt.md +0 -142
- package/vendor/upstreams/obra/skills/subagent-driven-development/re-review-prompt.md +0 -106
- package/vendor/upstreams/obra/skills/subagent-driven-development/task-reviewer-prompt.md +0 -185
- package/vendor/upstreams/obra/skills/systematic-debugging/CREATION-LOG.md +0 -119
- package/vendor/upstreams/obra/skills/systematic-debugging/SKILL.md +0 -283
- package/vendor/upstreams/obra/skills/systematic-debugging/condition-based-waiting-example.ts +0 -158
- package/vendor/upstreams/obra/skills/systematic-debugging/condition-based-waiting.md +0 -115
- package/vendor/upstreams/obra/skills/systematic-debugging/defense-in-depth.md +0 -122
- package/vendor/upstreams/obra/skills/systematic-debugging/find-polluter.sh +0 -72
- package/vendor/upstreams/obra/skills/systematic-debugging/root-cause-tracing.md +0 -169
- package/vendor/upstreams/obra/skills/systematic-debugging/test-academic.md +0 -14
- package/vendor/upstreams/obra/skills/systematic-debugging/test-pressure-1.md +0 -58
- package/vendor/upstreams/obra/skills/systematic-debugging/test-pressure-2.md +0 -68
- package/vendor/upstreams/obra/skills/systematic-debugging/test-pressure-3.md +0 -69
- package/vendor/upstreams/obra/skills/test-driven-development/SKILL.md +0 -320
- package/vendor/upstreams/obra/skills/test-driven-development/writing-good-tests.md +0 -198
- package/vendor/upstreams/obra/skills/verification-before-completion/SKILL.md +0 -120
- package/vendor/upstreams/obra/skills/writing-plans/SKILL.md +0 -168
- package/vendor/upstreams/obra/skills/writing-plans/plan-document-reviewer-prompt.md +0 -49
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// opencode-ship CLI v1.1.2
|
|
2
|
+
// opencode-ship CLI v1.1.2
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
5
|
var __esm = (fn, res) => function __init() {
|
|
@@ -110,7 +110,7 @@ import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
|
110
110
|
var PACKAGE_VERSION, TEMPLATE_SET;
|
|
111
111
|
var init_version = __esm({
|
|
112
112
|
"src/version.js"() {
|
|
113
|
-
PACKAGE_VERSION = "1.1.2
|
|
113
|
+
PACKAGE_VERSION = "1.1.2";
|
|
114
114
|
TEMPLATE_SET = `v${PACKAGE_VERSION}`;
|
|
115
115
|
}
|
|
116
116
|
});
|
|
@@ -359,6 +359,9 @@ var init_catalog = __esm({
|
|
|
359
359
|
function unescape(token) {
|
|
360
360
|
return token.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
361
361
|
}
|
|
362
|
+
function escape(token) {
|
|
363
|
+
return token.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
364
|
+
}
|
|
362
365
|
function* parsePointer(pointer) {
|
|
363
366
|
if (typeof pointer !== "string" || pointer === "") return;
|
|
364
367
|
if (pointer[0] !== "/") {
|
|
@@ -421,6 +424,9 @@ function stableStringify(value) {
|
|
|
421
424
|
}
|
|
422
425
|
return JSON.stringify(value);
|
|
423
426
|
}
|
|
427
|
+
function pointerPath(segments) {
|
|
428
|
+
return "/" + segments.map((s) => escape(String(s))).join("/");
|
|
429
|
+
}
|
|
424
430
|
var init_json_pointer = __esm({
|
|
425
431
|
"src/installer/json-pointer.js"() {
|
|
426
432
|
}
|
|
@@ -858,6 +864,126 @@ var init_config = __esm({
|
|
|
858
864
|
}
|
|
859
865
|
});
|
|
860
866
|
|
|
867
|
+
// src/installer/lock.js
|
|
868
|
+
import { readFile as readFile2, writeFile as writeFile2, rename as rename2, mkdir as mkdir2 } from "node:fs/promises";
|
|
869
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
870
|
+
import { dirname as dirname4, resolve as resolve5, posix } from "node:path";
|
|
871
|
+
function lockPath(repoRoot) {
|
|
872
|
+
return resolve5(repoRoot, ".opencode", "ship.lock.json");
|
|
873
|
+
}
|
|
874
|
+
function computeIntegrity(lock) {
|
|
875
|
+
const { integrity: _ignored, ...without } = lock ?? {};
|
|
876
|
+
void _ignored;
|
|
877
|
+
return {
|
|
878
|
+
lockSha256: bytesHashString(stableStringify(without))
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
function normalizeLegacyLock(lock) {
|
|
882
|
+
if (!lock || typeof lock !== "object") return lock;
|
|
883
|
+
const { cleanupPending: _drop, ...rest } = lock;
|
|
884
|
+
void _drop;
|
|
885
|
+
return rest;
|
|
886
|
+
}
|
|
887
|
+
function validateLock(rawLock) {
|
|
888
|
+
if (rawLock === null || rawLock === void 0) {
|
|
889
|
+
return { ok: true, kind: "missing", issues: [] };
|
|
890
|
+
}
|
|
891
|
+
if (typeof rawLock !== "object" || Array.isArray(rawLock)) {
|
|
892
|
+
return { ok: false, kind: "shape", issues: ["lock root must be an object"] };
|
|
893
|
+
}
|
|
894
|
+
const issues = [];
|
|
895
|
+
let kind = "ok";
|
|
896
|
+
if (rawLock.contractVersion !== CURRENT_LOCK_SCHEMA && rawLock.contractVersion !== 3 && rawLock.contractVersion !== 2 && rawLock.contractVersion !== 1) {
|
|
897
|
+
issues.push(`unsupported contractVersion: ${JSON.stringify(rawLock.contractVersion)} (expected ${CURRENT_LOCK_SCHEMA}, 3, 2, or 1)`);
|
|
898
|
+
kind = "schema";
|
|
899
|
+
}
|
|
900
|
+
const manager = rawLock.manager;
|
|
901
|
+
if (manager === void 0) {
|
|
902
|
+
issues.push("manager section missing");
|
|
903
|
+
kind = kind === "ok" ? "shape" : kind;
|
|
904
|
+
} else if (typeof manager !== "object" || manager === null) {
|
|
905
|
+
issues.push("manager section must be an object");
|
|
906
|
+
kind = kind === "ok" ? "shape" : kind;
|
|
907
|
+
} else if (manager.schemaVersion !== CURRENT_LOCK_SCHEMA && manager.schemaVersion !== 3 && manager.schemaVersion !== 2 && manager.schemaVersion !== 1) {
|
|
908
|
+
issues.push(`unsupported manager.schemaVersion: ${JSON.stringify(manager.schemaVersion)} (expected ${CURRENT_LOCK_SCHEMA}, 3, 2, or 1)`);
|
|
909
|
+
kind = "schema";
|
|
910
|
+
} else if (manager.name !== "opencode-ship") {
|
|
911
|
+
issues.push(`unknown manager.name: ${JSON.stringify(manager.name)}`);
|
|
912
|
+
kind = "shape";
|
|
913
|
+
} else if (rawLock.contractVersion >= 2 && manager.schemaVersion >= 2 && manager.profile !== void 0 && manager.profile !== "core" && manager.profile !== "engineering") {
|
|
914
|
+
issues.push(`invalid manager.profile: ${JSON.stringify(manager.profile)} (expected one of: engineering, core [legacy])`);
|
|
915
|
+
kind = "shape";
|
|
916
|
+
}
|
|
917
|
+
if (!rawLock.files || !Array.isArray(rawLock.files)) {
|
|
918
|
+
issues.push("files must be an array");
|
|
919
|
+
kind = kind === "ok" ? "shape" : kind;
|
|
920
|
+
} else {
|
|
921
|
+
for (const entry of rawLock.files) {
|
|
922
|
+
if (!entry || typeof entry !== "object" || !isSafeManagedPath(entry.path)) {
|
|
923
|
+
issues.push(`unsafe managed file path: ${JSON.stringify(entry?.path)}`);
|
|
924
|
+
kind = kind === "ok" ? "shape" : kind;
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
if (!rawLock.integrity || typeof rawLock.integrity !== "object") {
|
|
929
|
+
issues.push("integrity section missing");
|
|
930
|
+
kind = kind === "ok" ? "shape" : kind;
|
|
931
|
+
} else {
|
|
932
|
+
const expected = computeIntegrity(rawLock).lockSha256;
|
|
933
|
+
if (expected !== rawLock.integrity.lockSha256) {
|
|
934
|
+
issues.push(`integrity mismatch: stored ${rawLock.integrity.lockSha256} != computed ${expected}`);
|
|
935
|
+
kind = "integrity";
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
return { ok: issues.length === 0, kind, issues };
|
|
939
|
+
}
|
|
940
|
+
function isSafeManagedPath(value) {
|
|
941
|
+
if (typeof value !== "string" || value.length === 0 || value.includes("\\")) return false;
|
|
942
|
+
if (posix.isAbsolute(value) || posix.normalize(value) !== value) return false;
|
|
943
|
+
return value.split("/").every((part) => part !== "" && part !== "." && part !== "..");
|
|
944
|
+
}
|
|
945
|
+
async function readValidatedLock(repoRoot) {
|
|
946
|
+
const path = lockPath(repoRoot);
|
|
947
|
+
if (!existsSync5(path)) {
|
|
948
|
+
return { kind: "missing", lock: null, issues: [] };
|
|
949
|
+
}
|
|
950
|
+
let raw;
|
|
951
|
+
try {
|
|
952
|
+
const text = await readFile2(path, "utf8");
|
|
953
|
+
raw = JSON.parse(text);
|
|
954
|
+
} catch (e) {
|
|
955
|
+
return {
|
|
956
|
+
kind: "integrity",
|
|
957
|
+
lock: null,
|
|
958
|
+
issues: [`unable to parse lock JSON: ${e?.message ?? String(e)}`]
|
|
959
|
+
};
|
|
960
|
+
}
|
|
961
|
+
const validation = validateLock(raw);
|
|
962
|
+
if (validation.ok) {
|
|
963
|
+
return {
|
|
964
|
+
kind: validation.kind,
|
|
965
|
+
lock: normalizeLegacyLock(raw),
|
|
966
|
+
issues: []
|
|
967
|
+
};
|
|
968
|
+
}
|
|
969
|
+
return { kind: validation.kind, lock: null, issues: validation.issues };
|
|
970
|
+
}
|
|
971
|
+
function isSetupComplete(lock) {
|
|
972
|
+
if (!lock || typeof lock !== "object") return false;
|
|
973
|
+
const manager = lock.manager;
|
|
974
|
+
if (!manager || typeof manager !== "object") return false;
|
|
975
|
+
return manager.setupComplete === true;
|
|
976
|
+
}
|
|
977
|
+
var CURRENT_LOCK_SCHEMA;
|
|
978
|
+
var init_lock = __esm({
|
|
979
|
+
"src/installer/lock.js"() {
|
|
980
|
+
init_hash();
|
|
981
|
+
init_json_pointer();
|
|
982
|
+
init_profile();
|
|
983
|
+
CURRENT_LOCK_SCHEMA = 4;
|
|
984
|
+
}
|
|
985
|
+
});
|
|
986
|
+
|
|
861
987
|
// src/installer/plan-mode-permissions.js
|
|
862
988
|
function planModePermissions() {
|
|
863
989
|
return {
|
|
@@ -865,7 +991,8 @@ function planModePermissions() {
|
|
|
865
991
|
bash: DENY_DEFAULT,
|
|
866
992
|
edit: {
|
|
867
993
|
"*": DENY_DEFAULT,
|
|
868
|
-
[PLANS_GLOB]: ALLOW_PLANS
|
|
994
|
+
[PLANS_GLOB]: ALLOW_PLANS,
|
|
995
|
+
[SUPERPOWERS_GLOB]: ALLOW_PLANS
|
|
869
996
|
},
|
|
870
997
|
webfetch: DENY_DEFAULT,
|
|
871
998
|
task: DENY_DEFAULT,
|
|
@@ -881,13 +1008,64 @@ function planModePermissions() {
|
|
|
881
1008
|
}
|
|
882
1009
|
};
|
|
883
1010
|
}
|
|
884
|
-
|
|
1011
|
+
function promotePlanEditIfString(doc) {
|
|
1012
|
+
const edit = readPath(doc, ["agent", "plan", "permission", "edit"]);
|
|
1013
|
+
if (edit === void 0) {
|
|
1014
|
+
return { doc, record: null };
|
|
1015
|
+
}
|
|
1016
|
+
if (typeof edit === "string") {
|
|
1017
|
+
const next = setPath(doc, ["agent", "plan", "permission", "edit"], { "*": edit });
|
|
1018
|
+
const record = {
|
|
1019
|
+
pointer: PLAN_EDIT_PARENT_POINTER,
|
|
1020
|
+
previous: { existed: true, value: edit },
|
|
1021
|
+
promotion: true
|
|
1022
|
+
};
|
|
1023
|
+
return { doc: next, record };
|
|
1024
|
+
}
|
|
1025
|
+
if (edit && typeof edit === "object" && !Array.isArray(edit)) {
|
|
1026
|
+
if (Object.prototype.hasOwnProperty.call(edit, SUPERPOWERS_GLOB) && edit[SUPERPOWERS_GLOB] === "deny") {
|
|
1027
|
+
return { doc, record: { conflict: true, pointer: PLAN_EDIT_GLOB_POINTER } };
|
|
1028
|
+
}
|
|
1029
|
+
return { doc, record: null };
|
|
1030
|
+
}
|
|
1031
|
+
return { doc, record: null };
|
|
1032
|
+
}
|
|
1033
|
+
function readPath(doc, tokens) {
|
|
1034
|
+
let cursor = doc;
|
|
1035
|
+
for (const token of tokens) {
|
|
1036
|
+
if (cursor === null || cursor === void 0) return void 0;
|
|
1037
|
+
cursor = cursor[token];
|
|
1038
|
+
}
|
|
1039
|
+
return cursor;
|
|
1040
|
+
}
|
|
1041
|
+
function setPath(doc, tokens, value) {
|
|
1042
|
+
if (!doc || typeof doc !== "object" || Array.isArray(doc)) return doc;
|
|
1043
|
+
const root = Array.isArray(doc) ? [...doc] : { ...doc };
|
|
1044
|
+
let cursor = root;
|
|
1045
|
+
for (let i = 0; i < tokens.length - 1; i += 1) {
|
|
1046
|
+
const key = tokens[i];
|
|
1047
|
+
const next = cursor[key];
|
|
1048
|
+
const copy = next && typeof next === "object" && !Array.isArray(next) ? { ...next } : {};
|
|
1049
|
+
cursor[key] = copy;
|
|
1050
|
+
cursor = copy;
|
|
1051
|
+
}
|
|
1052
|
+
cursor[tokens[tokens.length - 1]] = value;
|
|
1053
|
+
return root;
|
|
1054
|
+
}
|
|
1055
|
+
var PLAN_PATH_PREFIX, SUPERPOWERS_PATH_PREFIX, DENY_DEFAULT, ALLOW_PLANS, PLANS_GLOB, SUPERPOWERS_GLOB, PLAN_EDIT_GLOB, PLAN_EDIT_PLANS_GLOB, PLAN_EDIT_GLOB_POINTER, PLAN_EDIT_PLANS_GLOB_POINTER, PLAN_EDIT_PARENT_POINTER;
|
|
885
1056
|
var init_plan_mode_permissions = __esm({
|
|
886
1057
|
"src/installer/plan-mode-permissions.js"() {
|
|
887
1058
|
PLAN_PATH_PREFIX = ".git/opencode-ship/plans";
|
|
1059
|
+
SUPERPOWERS_PATH_PREFIX = "docs/superpowers";
|
|
888
1060
|
DENY_DEFAULT = "deny";
|
|
889
1061
|
ALLOW_PLANS = "allow";
|
|
890
1062
|
PLANS_GLOB = `${PLAN_PATH_PREFIX}/**`;
|
|
1063
|
+
SUPERPOWERS_GLOB = `${SUPERPOWERS_PATH_PREFIX}/**`;
|
|
1064
|
+
PLAN_EDIT_GLOB = SUPERPOWERS_GLOB;
|
|
1065
|
+
PLAN_EDIT_PLANS_GLOB = PLANS_GLOB;
|
|
1066
|
+
PLAN_EDIT_GLOB_POINTER = "/agent/plan/permission/edit/docs~1superpowers~1**";
|
|
1067
|
+
PLAN_EDIT_PLANS_GLOB_POINTER = "/agent/plan/permission/edit/.git~1opencode-ship~1plans~1**";
|
|
1068
|
+
PLAN_EDIT_PARENT_POINTER = "/agent/plan/permission/edit";
|
|
891
1069
|
}
|
|
892
1070
|
});
|
|
893
1071
|
|
|
@@ -907,21 +1085,21 @@ __export(root_config_exports, {
|
|
|
907
1085
|
readRootConfig: () => readRootConfig,
|
|
908
1086
|
synthesizeDefaultRootConfig: () => synthesizeDefaultRootConfig
|
|
909
1087
|
});
|
|
910
|
-
import { existsSync as
|
|
911
|
-
import { readFile as
|
|
912
|
-
import { resolve as
|
|
1088
|
+
import { existsSync as existsSync6, readFileSync as readFileSync3 } from "node:fs";
|
|
1089
|
+
import { readFile as readFile3 } from "node:fs/promises";
|
|
1090
|
+
import { resolve as resolve6 } from "node:path";
|
|
913
1091
|
function findRootConfig(repoRoot) {
|
|
914
1092
|
for (const rel of ROOT_PATH_CANDIDATES) {
|
|
915
|
-
const abs =
|
|
916
|
-
if (
|
|
1093
|
+
const abs = resolve6(repoRoot, rel);
|
|
1094
|
+
if (existsSync6(abs)) return { path: abs, relative: rel, format: rel.endsWith(".jsonc") ? "jsonc" : "json" };
|
|
917
1095
|
}
|
|
918
1096
|
return { path: null, relative: ROOT_PATH_CANDIDATES[0], format: "json" };
|
|
919
1097
|
}
|
|
920
1098
|
function defaultRootConfigPath(repoRoot) {
|
|
921
|
-
return
|
|
1099
|
+
return resolve6(repoRoot, ROOT_PATH_CANDIDATES[0]);
|
|
922
1100
|
}
|
|
923
1101
|
function readRootConfig(absPath) {
|
|
924
|
-
if (!
|
|
1102
|
+
if (!existsSync6(absPath)) {
|
|
925
1103
|
return { ok: false, error: { kind: "missing", path: absPath } };
|
|
926
1104
|
}
|
|
927
1105
|
const raw = readFileSync3(absPath, "utf8");
|
|
@@ -952,15 +1130,15 @@ function stripJsonc(text) {
|
|
|
952
1130
|
let stripped = "";
|
|
953
1131
|
let i = 0;
|
|
954
1132
|
let inString = false;
|
|
955
|
-
let
|
|
1133
|
+
let escape2 = false;
|
|
956
1134
|
while (i < text.length) {
|
|
957
1135
|
const ch = text[i];
|
|
958
1136
|
if (inString) {
|
|
959
1137
|
stripped += ch;
|
|
960
|
-
if (
|
|
961
|
-
|
|
1138
|
+
if (escape2) {
|
|
1139
|
+
escape2 = false;
|
|
962
1140
|
} else if (ch === "\\") {
|
|
963
|
-
|
|
1141
|
+
escape2 = true;
|
|
964
1142
|
} else if (ch === '"') {
|
|
965
1143
|
inString = false;
|
|
966
1144
|
}
|
|
@@ -1011,6 +1189,7 @@ function applyOwnedPointers(rootDoc, { pointerEntries = POINTER_ENTRIES, allowEq
|
|
|
1011
1189
|
desired: entry.value
|
|
1012
1190
|
});
|
|
1013
1191
|
}
|
|
1192
|
+
result.doc = doc;
|
|
1014
1193
|
return result;
|
|
1015
1194
|
}
|
|
1016
1195
|
function applyPlanModeOwnership(rootDoc, { pointer = PLAN_MODE_POINTER, block = planModePermissions().build } = {}) {
|
|
@@ -1025,20 +1204,11 @@ function synthesizeDefaultRootConfig() {
|
|
|
1025
1204
|
return {
|
|
1026
1205
|
$schema: "https://opencode.ai/config.json",
|
|
1027
1206
|
agent: {
|
|
1028
|
-
|
|
1207
|
+
plan: {
|
|
1029
1208
|
permission: {
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
delivery_verify: "deny",
|
|
1034
|
-
delivery_review: "deny",
|
|
1035
|
-
delivery_pr: "allow",
|
|
1036
|
-
delivery_ready: "allow",
|
|
1037
|
-
delivery_merge: "ask",
|
|
1038
|
-
delivery_cleanup: "allow",
|
|
1039
|
-
task: {
|
|
1040
|
-
"delivery-reviewer": "allow",
|
|
1041
|
-
"delivery-verifier": "allow"
|
|
1209
|
+
edit: {
|
|
1210
|
+
[PLAN_EDIT_GLOB]: "allow",
|
|
1211
|
+
[PLAN_EDIT_PLANS_GLOB]: "allow"
|
|
1042
1212
|
}
|
|
1043
1213
|
}
|
|
1044
1214
|
}
|
|
@@ -1306,114 +1476,6 @@ var init_root_config = __esm({
|
|
|
1306
1476
|
}
|
|
1307
1477
|
});
|
|
1308
1478
|
|
|
1309
|
-
// src/installer/lock.js
|
|
1310
|
-
import { readFile as readFile4, writeFile as writeFile2, rename as rename2, mkdir as mkdir2 } from "node:fs/promises";
|
|
1311
|
-
import { existsSync as existsSync8 } from "node:fs";
|
|
1312
|
-
import { dirname as dirname4, resolve as resolve6 } from "node:path";
|
|
1313
|
-
function lockPath(repoRoot) {
|
|
1314
|
-
return resolve6(repoRoot, ".opencode", "ship.lock.json");
|
|
1315
|
-
}
|
|
1316
|
-
function computeIntegrity(lock) {
|
|
1317
|
-
const { integrity: _ignored, ...without } = lock ?? {};
|
|
1318
|
-
void _ignored;
|
|
1319
|
-
return {
|
|
1320
|
-
lockSha256: bytesHashString(stableStringify(without))
|
|
1321
|
-
};
|
|
1322
|
-
}
|
|
1323
|
-
function normalizeLegacyLock(lock) {
|
|
1324
|
-
if (!lock || typeof lock !== "object") return lock;
|
|
1325
|
-
const { cleanupPending: _drop, ...rest } = lock;
|
|
1326
|
-
void _drop;
|
|
1327
|
-
return rest;
|
|
1328
|
-
}
|
|
1329
|
-
function validateLock(rawLock) {
|
|
1330
|
-
if (rawLock === null || rawLock === void 0) {
|
|
1331
|
-
return { ok: true, kind: "missing", issues: [] };
|
|
1332
|
-
}
|
|
1333
|
-
if (typeof rawLock !== "object" || Array.isArray(rawLock)) {
|
|
1334
|
-
return { ok: false, kind: "shape", issues: ["lock root must be an object"] };
|
|
1335
|
-
}
|
|
1336
|
-
const issues = [];
|
|
1337
|
-
let kind = "ok";
|
|
1338
|
-
if (rawLock.contractVersion !== CURRENT_LOCK_SCHEMA && rawLock.contractVersion !== 3 && rawLock.contractVersion !== 2 && rawLock.contractVersion !== 1) {
|
|
1339
|
-
issues.push(`unsupported contractVersion: ${JSON.stringify(rawLock.contractVersion)} (expected ${CURRENT_LOCK_SCHEMA}, 3, 2, or 1)`);
|
|
1340
|
-
kind = "schema";
|
|
1341
|
-
}
|
|
1342
|
-
const manager = rawLock.manager;
|
|
1343
|
-
if (manager === void 0) {
|
|
1344
|
-
issues.push("manager section missing");
|
|
1345
|
-
kind = kind === "ok" ? "shape" : kind;
|
|
1346
|
-
} else if (typeof manager !== "object" || manager === null) {
|
|
1347
|
-
issues.push("manager section must be an object");
|
|
1348
|
-
kind = kind === "ok" ? "shape" : kind;
|
|
1349
|
-
} else if (manager.schemaVersion !== CURRENT_LOCK_SCHEMA && manager.schemaVersion !== 3 && manager.schemaVersion !== 2 && manager.schemaVersion !== 1) {
|
|
1350
|
-
issues.push(`unsupported manager.schemaVersion: ${JSON.stringify(manager.schemaVersion)} (expected ${CURRENT_LOCK_SCHEMA}, 3, 2, or 1)`);
|
|
1351
|
-
kind = "schema";
|
|
1352
|
-
} else if (manager.name !== "opencode-ship") {
|
|
1353
|
-
issues.push(`unknown manager.name: ${JSON.stringify(manager.name)}`);
|
|
1354
|
-
kind = "shape";
|
|
1355
|
-
} else if (rawLock.contractVersion >= 2 && manager.schemaVersion >= 2 && manager.profile !== void 0 && manager.profile !== "core" && manager.profile !== "engineering") {
|
|
1356
|
-
issues.push(`invalid manager.profile: ${JSON.stringify(manager.profile)} (expected one of: engineering, core [legacy])`);
|
|
1357
|
-
kind = "shape";
|
|
1358
|
-
}
|
|
1359
|
-
if (!rawLock.files || !Array.isArray(rawLock.files)) {
|
|
1360
|
-
issues.push("files must be an array");
|
|
1361
|
-
kind = kind === "ok" ? "shape" : kind;
|
|
1362
|
-
}
|
|
1363
|
-
if (!rawLock.integrity || typeof rawLock.integrity !== "object") {
|
|
1364
|
-
issues.push("integrity section missing");
|
|
1365
|
-
kind = kind === "ok" ? "shape" : kind;
|
|
1366
|
-
} else {
|
|
1367
|
-
const expected = computeIntegrity(rawLock).lockSha256;
|
|
1368
|
-
if (expected !== rawLock.integrity.lockSha256) {
|
|
1369
|
-
issues.push(`integrity mismatch: stored ${rawLock.integrity.lockSha256} != computed ${expected}`);
|
|
1370
|
-
kind = "integrity";
|
|
1371
|
-
}
|
|
1372
|
-
}
|
|
1373
|
-
return { ok: issues.length === 0, kind, issues };
|
|
1374
|
-
}
|
|
1375
|
-
async function readValidatedLock(repoRoot) {
|
|
1376
|
-
const path = lockPath(repoRoot);
|
|
1377
|
-
if (!existsSync8(path)) {
|
|
1378
|
-
return { kind: "missing", lock: null, issues: [] };
|
|
1379
|
-
}
|
|
1380
|
-
let raw;
|
|
1381
|
-
try {
|
|
1382
|
-
const text = await readFile4(path, "utf8");
|
|
1383
|
-
raw = JSON.parse(text);
|
|
1384
|
-
} catch (e) {
|
|
1385
|
-
return {
|
|
1386
|
-
kind: "integrity",
|
|
1387
|
-
lock: null,
|
|
1388
|
-
issues: [`unable to parse lock JSON: ${e?.message ?? String(e)}`]
|
|
1389
|
-
};
|
|
1390
|
-
}
|
|
1391
|
-
const validation = validateLock(raw);
|
|
1392
|
-
if (validation.ok) {
|
|
1393
|
-
return {
|
|
1394
|
-
kind: validation.kind,
|
|
1395
|
-
lock: normalizeLegacyLock(raw),
|
|
1396
|
-
issues: []
|
|
1397
|
-
};
|
|
1398
|
-
}
|
|
1399
|
-
return { kind: validation.kind, lock: null, issues: validation.issues };
|
|
1400
|
-
}
|
|
1401
|
-
function isSetupComplete(lock) {
|
|
1402
|
-
if (!lock || typeof lock !== "object") return false;
|
|
1403
|
-
const manager = lock.manager;
|
|
1404
|
-
if (!manager || typeof manager !== "object") return false;
|
|
1405
|
-
return manager.setupComplete === true;
|
|
1406
|
-
}
|
|
1407
|
-
var CURRENT_LOCK_SCHEMA;
|
|
1408
|
-
var init_lock = __esm({
|
|
1409
|
-
"src/installer/lock.js"() {
|
|
1410
|
-
init_hash();
|
|
1411
|
-
init_json_pointer();
|
|
1412
|
-
init_profile();
|
|
1413
|
-
CURRENT_LOCK_SCHEMA = 4;
|
|
1414
|
-
}
|
|
1415
|
-
});
|
|
1416
|
-
|
|
1417
1479
|
// src/installer/agent-renderer.js
|
|
1418
1480
|
var agent_renderer_exports = {};
|
|
1419
1481
|
__export(agent_renderer_exports, {
|
|
@@ -1482,37 +1544,6 @@ var init_agent_renderer = __esm({
|
|
|
1482
1544
|
}
|
|
1483
1545
|
});
|
|
1484
1546
|
|
|
1485
|
-
// src/installer/setup-pending.js
|
|
1486
|
-
import { existsSync as existsSync14, readFileSync as readFileSync5, unlinkSync, writeFile as writeFile7, mkdir as mkdirAsync } from "node:fs";
|
|
1487
|
-
import { promisify } from "node:util";
|
|
1488
|
-
import { resolve as resolve13, dirname as dirname9 } from "node:path";
|
|
1489
|
-
function setupPendingPath(repoRoot) {
|
|
1490
|
-
return resolve13(repoRoot, REL_PATH);
|
|
1491
|
-
}
|
|
1492
|
-
async function writeSetupPending(repoRoot, payload) {
|
|
1493
|
-
const path = setupPendingPath(repoRoot);
|
|
1494
|
-
await mkdirAsyncAsync(dirname9(path), { recursive: true });
|
|
1495
|
-
await writeFileAsync(path, JSON.stringify(payload, null, 2) + "\n", "utf8");
|
|
1496
|
-
}
|
|
1497
|
-
function clearSetupPending(repoRoot) {
|
|
1498
|
-
const path = setupPendingPath(repoRoot);
|
|
1499
|
-
if (!existsSync14(path)) return false;
|
|
1500
|
-
try {
|
|
1501
|
-
unlinkSync(path);
|
|
1502
|
-
return true;
|
|
1503
|
-
} catch {
|
|
1504
|
-
return false;
|
|
1505
|
-
}
|
|
1506
|
-
}
|
|
1507
|
-
var writeFileAsync, mkdirAsyncAsync, REL_PATH;
|
|
1508
|
-
var init_setup_pending = __esm({
|
|
1509
|
-
"src/installer/setup-pending.js"() {
|
|
1510
|
-
writeFileAsync = promisify(writeFile7);
|
|
1511
|
-
mkdirAsyncAsync = promisify(mkdirAsync);
|
|
1512
|
-
REL_PATH = ".opencode/ship.setup-pending.json";
|
|
1513
|
-
}
|
|
1514
|
-
});
|
|
1515
|
-
|
|
1516
1547
|
// src/installer/setup-state.js
|
|
1517
1548
|
var setup_state_exports = {};
|
|
1518
1549
|
__export(setup_state_exports, {
|
|
@@ -1521,9 +1552,9 @@ __export(setup_state_exports, {
|
|
|
1521
1552
|
modelsComplete: () => modelsComplete,
|
|
1522
1553
|
setupComplete: () => setupComplete
|
|
1523
1554
|
});
|
|
1524
|
-
import { existsSync as
|
|
1555
|
+
import { existsSync as existsSync14 } from "node:fs";
|
|
1525
1556
|
import { readFile as readFile10 } from "node:fs/promises";
|
|
1526
|
-
import { resolve as
|
|
1557
|
+
import { resolve as resolve13 } from "node:path";
|
|
1527
1558
|
function modelsComplete(repoRoot, configValue) {
|
|
1528
1559
|
if (configValue === void 0) return false;
|
|
1529
1560
|
return hasCompletedModels(configValue);
|
|
@@ -1531,12 +1562,12 @@ function modelsComplete(repoRoot, configValue) {
|
|
|
1531
1562
|
async function setupComplete(repoRoot, configValue) {
|
|
1532
1563
|
const missing = [];
|
|
1533
1564
|
for (const rel of REQUIRED_DOCS) {
|
|
1534
|
-
const path =
|
|
1535
|
-
if (!
|
|
1565
|
+
const path = resolve13(repoRoot, rel);
|
|
1566
|
+
if (!existsSync14(path)) missing.push(rel);
|
|
1536
1567
|
}
|
|
1537
|
-
const agentsPath =
|
|
1568
|
+
const agentsPath = resolve13(repoRoot, "AGENTS.md");
|
|
1538
1569
|
let agentsOk = false;
|
|
1539
|
-
if (
|
|
1570
|
+
if (existsSync14(agentsPath)) {
|
|
1540
1571
|
try {
|
|
1541
1572
|
const raw = await readFile10(agentsPath, "utf8");
|
|
1542
1573
|
agentsOk = /##\s+Ship workflow\b/.test(raw);
|
|
@@ -1549,9 +1580,7 @@ async function setupComplete(repoRoot, configValue) {
|
|
|
1549
1580
|
}
|
|
1550
1581
|
const lockResult = await readValidatedLock(repoRoot);
|
|
1551
1582
|
const cfgOk = modelsComplete(repoRoot, configValue);
|
|
1552
|
-
const
|
|
1553
|
-
if (existsSync15(markerPath)) missing.push("setup-pending marker");
|
|
1554
|
-
const lockOk = lockResult.kind === "ok" || lockResult.kind === "missing";
|
|
1583
|
+
const lockOk = lockResult.kind === "ok" && lockResult.lock?.contractVersion === CURRENT_LOCK_SCHEMA && lockResult.lock?.manager?.schemaVersion === CURRENT_LOCK_SCHEMA;
|
|
1555
1584
|
const ok = cfgOk && lockOk && missing.length === 0;
|
|
1556
1585
|
return {
|
|
1557
1586
|
ok,
|
|
@@ -1564,7 +1593,6 @@ var init_setup_state = __esm({
|
|
|
1564
1593
|
"src/installer/setup-state.js"() {
|
|
1565
1594
|
init_config();
|
|
1566
1595
|
init_lock();
|
|
1567
|
-
init_setup_pending();
|
|
1568
1596
|
REQUIRED_DOCS = [
|
|
1569
1597
|
"docs/agents/issue-tracker.md",
|
|
1570
1598
|
"docs/agents/domain.md",
|
|
@@ -1577,161 +1605,1827 @@ var init_setup_state = __esm({
|
|
|
1577
1605
|
markerPath: SETUP_PENDING_REL_PATH
|
|
1578
1606
|
});
|
|
1579
1607
|
}
|
|
1580
|
-
});
|
|
1581
|
-
|
|
1582
|
-
// src/installer/cli-args.js
|
|
1583
|
-
init_profile();
|
|
1584
|
-
var USAGE = `opencode-ship <command> [options]
|
|
1585
|
-
|
|
1586
|
-
Commands:
|
|
1587
|
-
init Install managed files in this project. One-liner: pnpm dlx opencode-ship@latest init
|
|
1588
|
-
diff Show what would change without writing.
|
|
1589
|
-
update Apply pending updates after recovering the journal.
|
|
1590
|
-
doctor Validate environment, lock, and references.
|
|
1591
|
-
setup-complete Sole writer of lock.manager.setupComplete = true. Validates models + docs + AGENTS.md.
|
|
1592
|
-
uninstall Remove managed files that still match the lock.
|
|
1593
|
-
--version Print the version and exit.
|
|
1594
|
-
--help Show this usage and exit.
|
|
1595
|
-
|
|
1596
|
-
Options:
|
|
1597
|
-
--root <path> Project root (defaults to cwd).
|
|
1598
|
-
--profile engineering Override active profile (engineering only).
|
|
1599
|
-
--force-config Rewrite the user config from detection (init only).
|
|
1600
|
-
--force-root-config Create opencode.json when absent (init only).
|
|
1601
|
-
--strict-doctor Fail init when doctor reports unhealthy checks.
|
|
1602
|
-
--replace-managed Replace locally-modified managed files (update only).
|
|
1603
|
-
--purge-config Remove ship.config.json when uninstalling.
|
|
1604
|
-
--planner-model <id> Strong planner model id (init only, optional).
|
|
1605
|
-
--builder-model <id> Cheap builder model id (init only, optional).
|
|
1606
|
-
--final-reviewer-model <id> Final Standards + Spec reviewer model id (init only, optional).
|
|
1607
|
-
--json Emit a JSON envelope instead of human output.
|
|
1608
|
+
});
|
|
1609
|
+
|
|
1610
|
+
// src/installer/cli-args.js
|
|
1611
|
+
init_profile();
|
|
1612
|
+
var USAGE = `opencode-ship <command> [options]
|
|
1613
|
+
|
|
1614
|
+
Commands:
|
|
1615
|
+
init Install managed files in this project. One-liner: pnpm dlx opencode-ship@latest init
|
|
1616
|
+
diff Show what would change without writing.
|
|
1617
|
+
update Apply pending updates after recovering the journal.
|
|
1618
|
+
doctor Validate environment, lock, and references.
|
|
1619
|
+
setup-complete Sole writer of lock.manager.setupComplete = true. Validates models + docs + AGENTS.md.
|
|
1620
|
+
uninstall Remove managed files that still match the lock.
|
|
1621
|
+
--version Print the version and exit.
|
|
1622
|
+
--help Show this usage and exit.
|
|
1623
|
+
|
|
1624
|
+
Options:
|
|
1625
|
+
--root <path> Project root (defaults to cwd).
|
|
1626
|
+
--profile engineering Override active profile (engineering only).
|
|
1627
|
+
--force-config Rewrite the user config from detection (init only).
|
|
1628
|
+
--force-root-config Create opencode.json when absent (init only).
|
|
1629
|
+
--strict-doctor Fail init when doctor reports unhealthy checks.
|
|
1630
|
+
--replace-managed Replace locally-modified managed files (update only).
|
|
1631
|
+
--purge-config Remove ship.config.json when uninstalling.
|
|
1632
|
+
--planner-model <id> Strong planner model id (init only, optional).
|
|
1633
|
+
--builder-model <id> Cheap builder model id (init only, optional).
|
|
1634
|
+
--final-reviewer-model <id> Final Standards + Spec reviewer model id (init only, optional).
|
|
1635
|
+
--json Emit a JSON envelope instead of human output.
|
|
1636
|
+
|
|
1637
|
+
After init succeeds, restart OpenCode and run /setup-ship-workflow.
|
|
1638
|
+
The setup skill calls 'opencode-ship setup-complete' at the end so
|
|
1639
|
+
the lock.manager.setupComplete flag flips to true and the ship
|
|
1640
|
+
controller can dispatch.
|
|
1641
|
+
`;
|
|
1642
|
+
var MODEL_ID_RE = /^[a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-]+$/;
|
|
1643
|
+
function parseFlags(argv) {
|
|
1644
|
+
const options = {
|
|
1645
|
+
rootPath: null,
|
|
1646
|
+
profile: null,
|
|
1647
|
+
json: false,
|
|
1648
|
+
replaceManaged: false,
|
|
1649
|
+
purgeConfig: false,
|
|
1650
|
+
forceConfig: false,
|
|
1651
|
+
forceRootConfig: false,
|
|
1652
|
+
strictDoctor: false,
|
|
1653
|
+
plannerModel: null,
|
|
1654
|
+
builderModel: null,
|
|
1655
|
+
finalReviewerModel: null
|
|
1656
|
+
};
|
|
1657
|
+
for (let i = 0; i < argv.length; i++) {
|
|
1658
|
+
const arg = argv[i];
|
|
1659
|
+
if (arg === "--json") options.json = true;
|
|
1660
|
+
else if (arg === "--replace-managed") options.replaceManaged = true;
|
|
1661
|
+
else if (arg === "--purge-config") options.purgeConfig = true;
|
|
1662
|
+
else if (arg === "--force-config") options.forceConfig = true;
|
|
1663
|
+
else if (arg === "--force-root-config") options.forceRootConfig = true;
|
|
1664
|
+
else if (arg === "--strict-doctor") options.strictDoctor = true;
|
|
1665
|
+
else if (arg === "--root") options.rootPath = argv[++i];
|
|
1666
|
+
else if (arg === "--profile") {
|
|
1667
|
+
const value = argv[++i];
|
|
1668
|
+
if (value === void 0) {
|
|
1669
|
+
return { error: "--profile requires a value" };
|
|
1670
|
+
}
|
|
1671
|
+
if (value === "core") {
|
|
1672
|
+
return {
|
|
1673
|
+
error: "the 'core' profile was removed in opencode-ship 1.1.0; only 'engineering' is supported. Run /setup-ship-workflow to migrate."
|
|
1674
|
+
};
|
|
1675
|
+
}
|
|
1676
|
+
if (!isValidProfile(value)) {
|
|
1677
|
+
return { error: `unknown profile '${value}' (expected one of: ${PROFILES.join(", ")})` };
|
|
1678
|
+
}
|
|
1679
|
+
options.profile = value;
|
|
1680
|
+
} else if (arg === "--planner-model" || arg === "--builder-model" || arg === "--final-reviewer-model") {
|
|
1681
|
+
const value = argv[++i];
|
|
1682
|
+
if (value === void 0) return { error: `${arg} requires a value` };
|
|
1683
|
+
if (!MODEL_ID_RE.test(value)) {
|
|
1684
|
+
return { error: `${arg} must be a "<provider>/<model>" id, got ${JSON.stringify(value)}` };
|
|
1685
|
+
}
|
|
1686
|
+
if (arg === "--planner-model") options.plannerModel = value;
|
|
1687
|
+
else if (arg === "--builder-model") options.builderModel = value;
|
|
1688
|
+
else options.finalReviewerModel = value;
|
|
1689
|
+
} else if (arg === "-h" || arg === "--help") return { help: true };
|
|
1690
|
+
else if (arg === "-v" || arg === "--version") return { version: true };
|
|
1691
|
+
else return { error: `unknown flag ${arg}` };
|
|
1692
|
+
}
|
|
1693
|
+
return options;
|
|
1694
|
+
}
|
|
1695
|
+
function parseCommand(argv) {
|
|
1696
|
+
for (const arg of argv) {
|
|
1697
|
+
if (arg === "--help" || arg === "-h") return { command: "help" };
|
|
1698
|
+
if (arg === "--version" || arg === "-v") return { command: "version" };
|
|
1699
|
+
}
|
|
1700
|
+
const [cmd, ...rest] = argv;
|
|
1701
|
+
if (!cmd) return { command: "help" };
|
|
1702
|
+
const flags = parseFlags(rest);
|
|
1703
|
+
if ("help" in flags) return { command: "help" };
|
|
1704
|
+
if ("version" in flags) return { command: "version" };
|
|
1705
|
+
if ("error" in flags) return { error: flags.error };
|
|
1706
|
+
switch (cmd) {
|
|
1707
|
+
case "init":
|
|
1708
|
+
case "diff":
|
|
1709
|
+
case "update":
|
|
1710
|
+
case "doctor":
|
|
1711
|
+
case "setup-complete":
|
|
1712
|
+
case "uninstall":
|
|
1713
|
+
return { command: cmd, options: flags };
|
|
1714
|
+
default:
|
|
1715
|
+
return { error: `unknown command ${cmd}` };
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
function helpText() {
|
|
1719
|
+
return USAGE;
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
// src/installer/commands/init.js
|
|
1723
|
+
import { promisify as promisify2 } from "node:util";
|
|
1724
|
+
import { writeFile as writeFile8, mkdir as mkdirAsync2 } from "node:fs/promises";
|
|
1725
|
+
import { dirname as dirname10, resolve as resolvePath } from "node:path";
|
|
1726
|
+
|
|
1727
|
+
// src/installer/executor.js
|
|
1728
|
+
init_catalog();
|
|
1729
|
+
init_version();
|
|
1730
|
+
import { existsSync as existsSync13 } from "node:fs";
|
|
1731
|
+
import { mkdir as mkdir6, readFile as readFile9, rename as rename5, unlink as unlink3, writeFile as writeFile6 } from "node:fs/promises";
|
|
1732
|
+
import { dirname as dirname8, resolve as resolve12 } from "node:path";
|
|
1733
|
+
|
|
1734
|
+
// src/installer/planner.js
|
|
1735
|
+
init_catalog();
|
|
1736
|
+
init_hash();
|
|
1737
|
+
init_config();
|
|
1738
|
+
init_lock();
|
|
1739
|
+
init_json_pointer();
|
|
1740
|
+
init_root_config();
|
|
1741
|
+
import { existsSync as existsSync8 } from "node:fs";
|
|
1742
|
+
import { readFile as readFile4, stat } from "node:fs/promises";
|
|
1743
|
+
|
|
1744
|
+
// src/installer/root-reconciliation.js
|
|
1745
|
+
init_root_config();
|
|
1746
|
+
init_json_pointer();
|
|
1747
|
+
init_hash();
|
|
1748
|
+
init_plan_mode_permissions();
|
|
1749
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
1750
|
+
import { join } from "node:path";
|
|
1751
|
+
|
|
1752
|
+
// src/installer/root-permissions.js
|
|
1753
|
+
init_json_pointer();
|
|
1754
|
+
init_plan_mode_permissions();
|
|
1755
|
+
var ASK = "ask";
|
|
1756
|
+
var ALLOW = "allow";
|
|
1757
|
+
var DENY = "deny";
|
|
1758
|
+
var SUBAGENT_DEPTH = 2;
|
|
1759
|
+
var CONTROLLER_TASK_ALLOW = [
|
|
1760
|
+
"ship-planner",
|
|
1761
|
+
"ship-task-builder",
|
|
1762
|
+
"ship-task-reviewer",
|
|
1763
|
+
"ship-final-standards-reviewer",
|
|
1764
|
+
"ship-final-spec-reviewer",
|
|
1765
|
+
"delivery-verifier"
|
|
1766
|
+
];
|
|
1767
|
+
var PUBLIC_TOOL_IDS = [
|
|
1768
|
+
"delivery_cleanup",
|
|
1769
|
+
"delivery_github_read",
|
|
1770
|
+
"delivery_inspect",
|
|
1771
|
+
"delivery_issue",
|
|
1772
|
+
"delivery_issue_close",
|
|
1773
|
+
"delivery_issue_comment",
|
|
1774
|
+
"delivery_issue_labels",
|
|
1775
|
+
"delivery_issue_link",
|
|
1776
|
+
"delivery_merge",
|
|
1777
|
+
"delivery_pr",
|
|
1778
|
+
"delivery_publish",
|
|
1779
|
+
"delivery_ready",
|
|
1780
|
+
"delivery_review",
|
|
1781
|
+
"delivery_sync",
|
|
1782
|
+
"delivery_verify",
|
|
1783
|
+
"delivery_worktree",
|
|
1784
|
+
"ship_final_review",
|
|
1785
|
+
"ship_plan_approve",
|
|
1786
|
+
"ship_plan_start",
|
|
1787
|
+
"ship_plan_submit",
|
|
1788
|
+
"ship_resume",
|
|
1789
|
+
"ship_run_start",
|
|
1790
|
+
"ship_skill_audit",
|
|
1791
|
+
"ship_skill_discover",
|
|
1792
|
+
"ship_skill_install",
|
|
1793
|
+
"ship_skill_uninstall",
|
|
1794
|
+
"ship_status",
|
|
1795
|
+
"ship_task_commit",
|
|
1796
|
+
"ship_task_complete",
|
|
1797
|
+
"ship_task_report",
|
|
1798
|
+
"ship_task_review",
|
|
1799
|
+
"ship_task_start"
|
|
1800
|
+
];
|
|
1801
|
+
var BUILD_TOOL_ALLOW = [
|
|
1802
|
+
"delivery_cleanup",
|
|
1803
|
+
"delivery_inspect",
|
|
1804
|
+
"delivery_issue",
|
|
1805
|
+
"delivery_pr",
|
|
1806
|
+
"delivery_ready",
|
|
1807
|
+
"delivery_worktree",
|
|
1808
|
+
"ship_status",
|
|
1809
|
+
"ship_resume"
|
|
1810
|
+
];
|
|
1811
|
+
var BUILD_TOOL_ASK = [
|
|
1812
|
+
"ship_plan_approve",
|
|
1813
|
+
"delivery_merge",
|
|
1814
|
+
"delivery_issue_close",
|
|
1815
|
+
"ship_skill_install"
|
|
1816
|
+
];
|
|
1817
|
+
var CONTROLLER_TOOL_ALLOW = [
|
|
1818
|
+
"delivery_inspect",
|
|
1819
|
+
"delivery_cleanup",
|
|
1820
|
+
"delivery_github_read",
|
|
1821
|
+
"delivery_issue",
|
|
1822
|
+
"delivery_issue_comment",
|
|
1823
|
+
"delivery_issue_labels",
|
|
1824
|
+
"delivery_issue_link",
|
|
1825
|
+
"delivery_worktree",
|
|
1826
|
+
"delivery_pr",
|
|
1827
|
+
"delivery_ready",
|
|
1828
|
+
"delivery_publish",
|
|
1829
|
+
"delivery_sync",
|
|
1830
|
+
"ship_plan_start",
|
|
1831
|
+
"ship_run_start",
|
|
1832
|
+
"ship_task_start",
|
|
1833
|
+
"ship_task_commit",
|
|
1834
|
+
"ship_task_complete",
|
|
1835
|
+
"ship_resume",
|
|
1836
|
+
"ship_status",
|
|
1837
|
+
"ship_skill_discover",
|
|
1838
|
+
"ship_skill_install",
|
|
1839
|
+
"ship_skill_audit",
|
|
1840
|
+
"ship_skill_uninstall"
|
|
1841
|
+
];
|
|
1842
|
+
var CONTROLLER_TOOL_ASK = [
|
|
1843
|
+
"ship_plan_approve",
|
|
1844
|
+
"delivery_merge",
|
|
1845
|
+
"delivery_issue_close"
|
|
1846
|
+
];
|
|
1847
|
+
var H = "git";
|
|
1848
|
+
var RESET = "--hard";
|
|
1849
|
+
var PUSH = "--force";
|
|
1850
|
+
var PUSH_SHORT = "-f";
|
|
1851
|
+
var STASH = "stash";
|
|
1852
|
+
var WTRF = "--force";
|
|
1853
|
+
var BRDEL = "-D";
|
|
1854
|
+
var FORBIDDEN_BASH_GLOBS = [
|
|
1855
|
+
`${H} ${RESET} *`,
|
|
1856
|
+
`${H} ${PUSH} *`,
|
|
1857
|
+
`${H} ${PUSH_SHORT} *`,
|
|
1858
|
+
`git clean -fd *`,
|
|
1859
|
+
`${H} ${STASH} *`,
|
|
1860
|
+
`${H} worktree remove ${WTRF} *`,
|
|
1861
|
+
`${H} branch ${BRDEL} *`
|
|
1862
|
+
];
|
|
1863
|
+
var FORBIDDEN_BASH_GLOBS_CONTROLLER = [
|
|
1864
|
+
...FORBIDDEN_BASH_GLOBS,
|
|
1865
|
+
"rm -rf *",
|
|
1866
|
+
"rm -rf /*"
|
|
1867
|
+
];
|
|
1868
|
+
function denyMap(globs) {
|
|
1869
|
+
const out = { "*": "allow" };
|
|
1870
|
+
for (const g of globs) out[g] = "deny";
|
|
1871
|
+
return out;
|
|
1872
|
+
}
|
|
1873
|
+
function toolPermissionMap(allow, ask) {
|
|
1874
|
+
const out = { "*": DENY };
|
|
1875
|
+
for (const id of PUBLIC_TOOL_IDS) out[id] = DENY;
|
|
1876
|
+
for (const id of allow) out[id] = ALLOW;
|
|
1877
|
+
for (const id of ask) out[id] = ASK;
|
|
1878
|
+
return out;
|
|
1879
|
+
}
|
|
1880
|
+
function rootPermissionMatrix() {
|
|
1881
|
+
return {
|
|
1882
|
+
subagentDepth: SUBAGENT_DEPTH,
|
|
1883
|
+
build: {
|
|
1884
|
+
permission: {
|
|
1885
|
+
task: {
|
|
1886
|
+
"*": "deny",
|
|
1887
|
+
"ship-controller": "allow",
|
|
1888
|
+
"general": "allow",
|
|
1889
|
+
"plan": "deny",
|
|
1890
|
+
"delivery-reviewer": "allow",
|
|
1891
|
+
"delivery-verifier": "allow"
|
|
1892
|
+
},
|
|
1893
|
+
bash: {
|
|
1894
|
+
...denyMap(FORBIDDEN_BASH_GLOBS),
|
|
1895
|
+
"rm *": "ask"
|
|
1896
|
+
}
|
|
1897
|
+
},
|
|
1898
|
+
tools: {
|
|
1899
|
+
...toolPermissionMap(BUILD_TOOL_ALLOW, BUILD_TOOL_ASK)
|
|
1900
|
+
}
|
|
1901
|
+
},
|
|
1902
|
+
shipController: {
|
|
1903
|
+
permission: {
|
|
1904
|
+
task: {
|
|
1905
|
+
"*": "deny",
|
|
1906
|
+
...Object.fromEntries(CONTROLLER_TASK_ALLOW.map((t) => [t, "allow"]))
|
|
1907
|
+
},
|
|
1908
|
+
bash: denyMap(FORBIDDEN_BASH_GLOBS_CONTROLLER)
|
|
1909
|
+
},
|
|
1910
|
+
tools: {
|
|
1911
|
+
...toolPermissionMap(CONTROLLER_TOOL_ALLOW, CONTROLLER_TOOL_ASK)
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
};
|
|
1915
|
+
}
|
|
1916
|
+
function matrixLeafPointers() {
|
|
1917
|
+
const matrix = rootPermissionMatrix();
|
|
1918
|
+
const out = [];
|
|
1919
|
+
out.push({ pointer: "/subagent_depth", strategy: "value", value: matrix.subagentDepth, scope: "engineering" });
|
|
1920
|
+
const agents = [
|
|
1921
|
+
{ name: "build", block: matrix.build },
|
|
1922
|
+
{ name: "ship-controller", block: matrix.shipController }
|
|
1923
|
+
];
|
|
1924
|
+
for (const agent of agents) {
|
|
1925
|
+
const perm = agent.block.permission;
|
|
1926
|
+
for (const category of Object.keys(perm)) {
|
|
1927
|
+
const map = perm[category];
|
|
1928
|
+
for (const key of Object.keys(map)) {
|
|
1929
|
+
const v = map[key];
|
|
1930
|
+
if (v === void 0 || v === null) continue;
|
|
1931
|
+
out.push({
|
|
1932
|
+
pointer: pointerPath(["agent", agent.name, "permission", category, key]),
|
|
1933
|
+
strategy: "value",
|
|
1934
|
+
value: v,
|
|
1935
|
+
scope: "engineering"
|
|
1936
|
+
});
|
|
1937
|
+
}
|
|
1938
|
+
}
|
|
1939
|
+
const tools = agent.block.tools;
|
|
1940
|
+
if (tools && typeof tools === "object") {
|
|
1941
|
+
for (const key of Object.keys(tools)) {
|
|
1942
|
+
const v = tools[key];
|
|
1943
|
+
if (v === void 0 || v === null) continue;
|
|
1944
|
+
out.push({
|
|
1945
|
+
pointer: pointerPath(["agent", agent.name, "permission", key]),
|
|
1946
|
+
strategy: "value",
|
|
1947
|
+
value: v,
|
|
1948
|
+
scope: "engineering"
|
|
1949
|
+
});
|
|
1950
|
+
}
|
|
1951
|
+
}
|
|
1952
|
+
}
|
|
1953
|
+
out.push({ pointer: PLAN_EDIT_GLOB_POINTER, strategy: "value", value: "allow", scope: "engineering" });
|
|
1954
|
+
out.push({ pointer: PLAN_EDIT_PLANS_GLOB_POINTER, strategy: "value", value: "allow", scope: "engineering" });
|
|
1955
|
+
return out;
|
|
1956
|
+
}
|
|
1957
|
+
|
|
1958
|
+
// node_modules/jsonc-parser/lib/esm/impl/scanner.js
|
|
1959
|
+
function createScanner(text, ignoreTrivia = false) {
|
|
1960
|
+
const len = text.length;
|
|
1961
|
+
let pos = 0, value = "", tokenOffset = 0, token = 16, lineNumber = 0, lineStartOffset = 0, tokenLineStartOffset = 0, prevTokenLineStartOffset = 0, scanError = 0;
|
|
1962
|
+
function scanHexDigits(count, exact) {
|
|
1963
|
+
let digits = 0;
|
|
1964
|
+
let value2 = 0;
|
|
1965
|
+
while (digits < count || !exact) {
|
|
1966
|
+
let ch = text.charCodeAt(pos);
|
|
1967
|
+
if (ch >= 48 && ch <= 57) {
|
|
1968
|
+
value2 = value2 * 16 + ch - 48;
|
|
1969
|
+
} else if (ch >= 65 && ch <= 70) {
|
|
1970
|
+
value2 = value2 * 16 + ch - 65 + 10;
|
|
1971
|
+
} else if (ch >= 97 && ch <= 102) {
|
|
1972
|
+
value2 = value2 * 16 + ch - 97 + 10;
|
|
1973
|
+
} else {
|
|
1974
|
+
break;
|
|
1975
|
+
}
|
|
1976
|
+
pos++;
|
|
1977
|
+
digits++;
|
|
1978
|
+
}
|
|
1979
|
+
if (digits < count) {
|
|
1980
|
+
value2 = -1;
|
|
1981
|
+
}
|
|
1982
|
+
return value2;
|
|
1983
|
+
}
|
|
1984
|
+
function setPosition(newPosition) {
|
|
1985
|
+
pos = newPosition;
|
|
1986
|
+
value = "";
|
|
1987
|
+
tokenOffset = 0;
|
|
1988
|
+
token = 16;
|
|
1989
|
+
scanError = 0;
|
|
1990
|
+
}
|
|
1991
|
+
function scanNumber() {
|
|
1992
|
+
let start = pos;
|
|
1993
|
+
if (text.charCodeAt(pos) === 48) {
|
|
1994
|
+
pos++;
|
|
1995
|
+
} else {
|
|
1996
|
+
pos++;
|
|
1997
|
+
while (pos < text.length && isDigit(text.charCodeAt(pos))) {
|
|
1998
|
+
pos++;
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
if (pos < text.length && text.charCodeAt(pos) === 46) {
|
|
2002
|
+
pos++;
|
|
2003
|
+
if (pos < text.length && isDigit(text.charCodeAt(pos))) {
|
|
2004
|
+
pos++;
|
|
2005
|
+
while (pos < text.length && isDigit(text.charCodeAt(pos))) {
|
|
2006
|
+
pos++;
|
|
2007
|
+
}
|
|
2008
|
+
} else {
|
|
2009
|
+
scanError = 3;
|
|
2010
|
+
return text.substring(start, pos);
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
let end = pos;
|
|
2014
|
+
if (pos < text.length && (text.charCodeAt(pos) === 69 || text.charCodeAt(pos) === 101)) {
|
|
2015
|
+
pos++;
|
|
2016
|
+
if (pos < text.length && text.charCodeAt(pos) === 43 || text.charCodeAt(pos) === 45) {
|
|
2017
|
+
pos++;
|
|
2018
|
+
}
|
|
2019
|
+
if (pos < text.length && isDigit(text.charCodeAt(pos))) {
|
|
2020
|
+
pos++;
|
|
2021
|
+
while (pos < text.length && isDigit(text.charCodeAt(pos))) {
|
|
2022
|
+
pos++;
|
|
2023
|
+
}
|
|
2024
|
+
end = pos;
|
|
2025
|
+
} else {
|
|
2026
|
+
scanError = 3;
|
|
2027
|
+
}
|
|
2028
|
+
}
|
|
2029
|
+
return text.substring(start, end);
|
|
2030
|
+
}
|
|
2031
|
+
function scanString() {
|
|
2032
|
+
let result = "", start = pos;
|
|
2033
|
+
while (true) {
|
|
2034
|
+
if (pos >= len) {
|
|
2035
|
+
result += text.substring(start, pos);
|
|
2036
|
+
scanError = 2;
|
|
2037
|
+
break;
|
|
2038
|
+
}
|
|
2039
|
+
const ch = text.charCodeAt(pos);
|
|
2040
|
+
if (ch === 34) {
|
|
2041
|
+
result += text.substring(start, pos);
|
|
2042
|
+
pos++;
|
|
2043
|
+
break;
|
|
2044
|
+
}
|
|
2045
|
+
if (ch === 92) {
|
|
2046
|
+
result += text.substring(start, pos);
|
|
2047
|
+
pos++;
|
|
2048
|
+
if (pos >= len) {
|
|
2049
|
+
scanError = 2;
|
|
2050
|
+
break;
|
|
2051
|
+
}
|
|
2052
|
+
const ch2 = text.charCodeAt(pos++);
|
|
2053
|
+
switch (ch2) {
|
|
2054
|
+
case 34:
|
|
2055
|
+
result += '"';
|
|
2056
|
+
break;
|
|
2057
|
+
case 92:
|
|
2058
|
+
result += "\\";
|
|
2059
|
+
break;
|
|
2060
|
+
case 47:
|
|
2061
|
+
result += "/";
|
|
2062
|
+
break;
|
|
2063
|
+
case 98:
|
|
2064
|
+
result += "\b";
|
|
2065
|
+
break;
|
|
2066
|
+
case 102:
|
|
2067
|
+
result += "\f";
|
|
2068
|
+
break;
|
|
2069
|
+
case 110:
|
|
2070
|
+
result += "\n";
|
|
2071
|
+
break;
|
|
2072
|
+
case 114:
|
|
2073
|
+
result += "\r";
|
|
2074
|
+
break;
|
|
2075
|
+
case 116:
|
|
2076
|
+
result += " ";
|
|
2077
|
+
break;
|
|
2078
|
+
case 117:
|
|
2079
|
+
const ch3 = scanHexDigits(4, true);
|
|
2080
|
+
if (ch3 >= 0) {
|
|
2081
|
+
result += String.fromCharCode(ch3);
|
|
2082
|
+
} else {
|
|
2083
|
+
scanError = 4;
|
|
2084
|
+
}
|
|
2085
|
+
break;
|
|
2086
|
+
default:
|
|
2087
|
+
scanError = 5;
|
|
2088
|
+
}
|
|
2089
|
+
start = pos;
|
|
2090
|
+
continue;
|
|
2091
|
+
}
|
|
2092
|
+
if (ch >= 0 && ch <= 31) {
|
|
2093
|
+
if (isLineBreak(ch)) {
|
|
2094
|
+
result += text.substring(start, pos);
|
|
2095
|
+
scanError = 2;
|
|
2096
|
+
break;
|
|
2097
|
+
} else {
|
|
2098
|
+
scanError = 6;
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
pos++;
|
|
2102
|
+
}
|
|
2103
|
+
return result;
|
|
2104
|
+
}
|
|
2105
|
+
function scanNext() {
|
|
2106
|
+
value = "";
|
|
2107
|
+
scanError = 0;
|
|
2108
|
+
tokenOffset = pos;
|
|
2109
|
+
lineStartOffset = lineNumber;
|
|
2110
|
+
prevTokenLineStartOffset = tokenLineStartOffset;
|
|
2111
|
+
if (pos >= len) {
|
|
2112
|
+
tokenOffset = len;
|
|
2113
|
+
return token = 17;
|
|
2114
|
+
}
|
|
2115
|
+
let code = text.charCodeAt(pos);
|
|
2116
|
+
if (isWhiteSpace(code)) {
|
|
2117
|
+
do {
|
|
2118
|
+
pos++;
|
|
2119
|
+
value += String.fromCharCode(code);
|
|
2120
|
+
code = text.charCodeAt(pos);
|
|
2121
|
+
} while (isWhiteSpace(code));
|
|
2122
|
+
return token = 15;
|
|
2123
|
+
}
|
|
2124
|
+
if (isLineBreak(code)) {
|
|
2125
|
+
pos++;
|
|
2126
|
+
value += String.fromCharCode(code);
|
|
2127
|
+
if (code === 13 && text.charCodeAt(pos) === 10) {
|
|
2128
|
+
pos++;
|
|
2129
|
+
value += "\n";
|
|
2130
|
+
}
|
|
2131
|
+
lineNumber++;
|
|
2132
|
+
tokenLineStartOffset = pos;
|
|
2133
|
+
return token = 14;
|
|
2134
|
+
}
|
|
2135
|
+
switch (code) {
|
|
2136
|
+
// tokens: []{}:,
|
|
2137
|
+
case 123:
|
|
2138
|
+
pos++;
|
|
2139
|
+
return token = 1;
|
|
2140
|
+
case 125:
|
|
2141
|
+
pos++;
|
|
2142
|
+
return token = 2;
|
|
2143
|
+
case 91:
|
|
2144
|
+
pos++;
|
|
2145
|
+
return token = 3;
|
|
2146
|
+
case 93:
|
|
2147
|
+
pos++;
|
|
2148
|
+
return token = 4;
|
|
2149
|
+
case 58:
|
|
2150
|
+
pos++;
|
|
2151
|
+
return token = 6;
|
|
2152
|
+
case 44:
|
|
2153
|
+
pos++;
|
|
2154
|
+
return token = 5;
|
|
2155
|
+
// strings
|
|
2156
|
+
case 34:
|
|
2157
|
+
pos++;
|
|
2158
|
+
value = scanString();
|
|
2159
|
+
return token = 10;
|
|
2160
|
+
// comments
|
|
2161
|
+
case 47:
|
|
2162
|
+
const start = pos - 1;
|
|
2163
|
+
if (text.charCodeAt(pos + 1) === 47) {
|
|
2164
|
+
pos += 2;
|
|
2165
|
+
while (pos < len) {
|
|
2166
|
+
if (isLineBreak(text.charCodeAt(pos))) {
|
|
2167
|
+
break;
|
|
2168
|
+
}
|
|
2169
|
+
pos++;
|
|
2170
|
+
}
|
|
2171
|
+
value = text.substring(start, pos);
|
|
2172
|
+
return token = 12;
|
|
2173
|
+
}
|
|
2174
|
+
if (text.charCodeAt(pos + 1) === 42) {
|
|
2175
|
+
pos += 2;
|
|
2176
|
+
const safeLength = len - 1;
|
|
2177
|
+
let commentClosed = false;
|
|
2178
|
+
while (pos < safeLength) {
|
|
2179
|
+
const ch = text.charCodeAt(pos);
|
|
2180
|
+
if (ch === 42 && text.charCodeAt(pos + 1) === 47) {
|
|
2181
|
+
pos += 2;
|
|
2182
|
+
commentClosed = true;
|
|
2183
|
+
break;
|
|
2184
|
+
}
|
|
2185
|
+
pos++;
|
|
2186
|
+
if (isLineBreak(ch)) {
|
|
2187
|
+
if (ch === 13 && text.charCodeAt(pos) === 10) {
|
|
2188
|
+
pos++;
|
|
2189
|
+
}
|
|
2190
|
+
lineNumber++;
|
|
2191
|
+
tokenLineStartOffset = pos;
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
if (!commentClosed) {
|
|
2195
|
+
pos++;
|
|
2196
|
+
scanError = 1;
|
|
2197
|
+
}
|
|
2198
|
+
value = text.substring(start, pos);
|
|
2199
|
+
return token = 13;
|
|
2200
|
+
}
|
|
2201
|
+
value += String.fromCharCode(code);
|
|
2202
|
+
pos++;
|
|
2203
|
+
return token = 16;
|
|
2204
|
+
// numbers
|
|
2205
|
+
case 45:
|
|
2206
|
+
value += String.fromCharCode(code);
|
|
2207
|
+
pos++;
|
|
2208
|
+
if (pos === len || !isDigit(text.charCodeAt(pos))) {
|
|
2209
|
+
return token = 16;
|
|
2210
|
+
}
|
|
2211
|
+
// found a minus, followed by a number so
|
|
2212
|
+
// we fall through to proceed with scanning
|
|
2213
|
+
// numbers
|
|
2214
|
+
case 48:
|
|
2215
|
+
case 49:
|
|
2216
|
+
case 50:
|
|
2217
|
+
case 51:
|
|
2218
|
+
case 52:
|
|
2219
|
+
case 53:
|
|
2220
|
+
case 54:
|
|
2221
|
+
case 55:
|
|
2222
|
+
case 56:
|
|
2223
|
+
case 57:
|
|
2224
|
+
value += scanNumber();
|
|
2225
|
+
return token = 11;
|
|
2226
|
+
// literals and unknown symbols
|
|
2227
|
+
default:
|
|
2228
|
+
while (pos < len && isUnknownContentCharacter(code)) {
|
|
2229
|
+
pos++;
|
|
2230
|
+
code = text.charCodeAt(pos);
|
|
2231
|
+
}
|
|
2232
|
+
if (tokenOffset !== pos) {
|
|
2233
|
+
value = text.substring(tokenOffset, pos);
|
|
2234
|
+
switch (value) {
|
|
2235
|
+
case "true":
|
|
2236
|
+
return token = 8;
|
|
2237
|
+
case "false":
|
|
2238
|
+
return token = 9;
|
|
2239
|
+
case "null":
|
|
2240
|
+
return token = 7;
|
|
2241
|
+
}
|
|
2242
|
+
return token = 16;
|
|
2243
|
+
}
|
|
2244
|
+
value += String.fromCharCode(code);
|
|
2245
|
+
pos++;
|
|
2246
|
+
return token = 16;
|
|
2247
|
+
}
|
|
2248
|
+
}
|
|
2249
|
+
function isUnknownContentCharacter(code) {
|
|
2250
|
+
if (isWhiteSpace(code) || isLineBreak(code)) {
|
|
2251
|
+
return false;
|
|
2252
|
+
}
|
|
2253
|
+
switch (code) {
|
|
2254
|
+
case 125:
|
|
2255
|
+
case 93:
|
|
2256
|
+
case 123:
|
|
2257
|
+
case 91:
|
|
2258
|
+
case 34:
|
|
2259
|
+
case 58:
|
|
2260
|
+
case 44:
|
|
2261
|
+
case 47:
|
|
2262
|
+
return false;
|
|
2263
|
+
}
|
|
2264
|
+
return true;
|
|
2265
|
+
}
|
|
2266
|
+
function scanNextNonTrivia() {
|
|
2267
|
+
let result;
|
|
2268
|
+
do {
|
|
2269
|
+
result = scanNext();
|
|
2270
|
+
} while (result >= 12 && result <= 15);
|
|
2271
|
+
return result;
|
|
2272
|
+
}
|
|
2273
|
+
return {
|
|
2274
|
+
setPosition,
|
|
2275
|
+
getPosition: () => pos,
|
|
2276
|
+
scan: ignoreTrivia ? scanNextNonTrivia : scanNext,
|
|
2277
|
+
getToken: () => token,
|
|
2278
|
+
getTokenValue: () => value,
|
|
2279
|
+
getTokenOffset: () => tokenOffset,
|
|
2280
|
+
getTokenLength: () => pos - tokenOffset,
|
|
2281
|
+
getTokenStartLine: () => lineStartOffset,
|
|
2282
|
+
getTokenStartCharacter: () => tokenOffset - prevTokenLineStartOffset,
|
|
2283
|
+
getTokenError: () => scanError
|
|
2284
|
+
};
|
|
2285
|
+
}
|
|
2286
|
+
function isWhiteSpace(ch) {
|
|
2287
|
+
return ch === 32 || ch === 9;
|
|
2288
|
+
}
|
|
2289
|
+
function isLineBreak(ch) {
|
|
2290
|
+
return ch === 10 || ch === 13;
|
|
2291
|
+
}
|
|
2292
|
+
function isDigit(ch) {
|
|
2293
|
+
return ch >= 48 && ch <= 57;
|
|
2294
|
+
}
|
|
2295
|
+
var CharacterCodes;
|
|
2296
|
+
(function(CharacterCodes2) {
|
|
2297
|
+
CharacterCodes2[CharacterCodes2["lineFeed"] = 10] = "lineFeed";
|
|
2298
|
+
CharacterCodes2[CharacterCodes2["carriageReturn"] = 13] = "carriageReturn";
|
|
2299
|
+
CharacterCodes2[CharacterCodes2["space"] = 32] = "space";
|
|
2300
|
+
CharacterCodes2[CharacterCodes2["_0"] = 48] = "_0";
|
|
2301
|
+
CharacterCodes2[CharacterCodes2["_1"] = 49] = "_1";
|
|
2302
|
+
CharacterCodes2[CharacterCodes2["_2"] = 50] = "_2";
|
|
2303
|
+
CharacterCodes2[CharacterCodes2["_3"] = 51] = "_3";
|
|
2304
|
+
CharacterCodes2[CharacterCodes2["_4"] = 52] = "_4";
|
|
2305
|
+
CharacterCodes2[CharacterCodes2["_5"] = 53] = "_5";
|
|
2306
|
+
CharacterCodes2[CharacterCodes2["_6"] = 54] = "_6";
|
|
2307
|
+
CharacterCodes2[CharacterCodes2["_7"] = 55] = "_7";
|
|
2308
|
+
CharacterCodes2[CharacterCodes2["_8"] = 56] = "_8";
|
|
2309
|
+
CharacterCodes2[CharacterCodes2["_9"] = 57] = "_9";
|
|
2310
|
+
CharacterCodes2[CharacterCodes2["a"] = 97] = "a";
|
|
2311
|
+
CharacterCodes2[CharacterCodes2["b"] = 98] = "b";
|
|
2312
|
+
CharacterCodes2[CharacterCodes2["c"] = 99] = "c";
|
|
2313
|
+
CharacterCodes2[CharacterCodes2["d"] = 100] = "d";
|
|
2314
|
+
CharacterCodes2[CharacterCodes2["e"] = 101] = "e";
|
|
2315
|
+
CharacterCodes2[CharacterCodes2["f"] = 102] = "f";
|
|
2316
|
+
CharacterCodes2[CharacterCodes2["g"] = 103] = "g";
|
|
2317
|
+
CharacterCodes2[CharacterCodes2["h"] = 104] = "h";
|
|
2318
|
+
CharacterCodes2[CharacterCodes2["i"] = 105] = "i";
|
|
2319
|
+
CharacterCodes2[CharacterCodes2["j"] = 106] = "j";
|
|
2320
|
+
CharacterCodes2[CharacterCodes2["k"] = 107] = "k";
|
|
2321
|
+
CharacterCodes2[CharacterCodes2["l"] = 108] = "l";
|
|
2322
|
+
CharacterCodes2[CharacterCodes2["m"] = 109] = "m";
|
|
2323
|
+
CharacterCodes2[CharacterCodes2["n"] = 110] = "n";
|
|
2324
|
+
CharacterCodes2[CharacterCodes2["o"] = 111] = "o";
|
|
2325
|
+
CharacterCodes2[CharacterCodes2["p"] = 112] = "p";
|
|
2326
|
+
CharacterCodes2[CharacterCodes2["q"] = 113] = "q";
|
|
2327
|
+
CharacterCodes2[CharacterCodes2["r"] = 114] = "r";
|
|
2328
|
+
CharacterCodes2[CharacterCodes2["s"] = 115] = "s";
|
|
2329
|
+
CharacterCodes2[CharacterCodes2["t"] = 116] = "t";
|
|
2330
|
+
CharacterCodes2[CharacterCodes2["u"] = 117] = "u";
|
|
2331
|
+
CharacterCodes2[CharacterCodes2["v"] = 118] = "v";
|
|
2332
|
+
CharacterCodes2[CharacterCodes2["w"] = 119] = "w";
|
|
2333
|
+
CharacterCodes2[CharacterCodes2["x"] = 120] = "x";
|
|
2334
|
+
CharacterCodes2[CharacterCodes2["y"] = 121] = "y";
|
|
2335
|
+
CharacterCodes2[CharacterCodes2["z"] = 122] = "z";
|
|
2336
|
+
CharacterCodes2[CharacterCodes2["A"] = 65] = "A";
|
|
2337
|
+
CharacterCodes2[CharacterCodes2["B"] = 66] = "B";
|
|
2338
|
+
CharacterCodes2[CharacterCodes2["C"] = 67] = "C";
|
|
2339
|
+
CharacterCodes2[CharacterCodes2["D"] = 68] = "D";
|
|
2340
|
+
CharacterCodes2[CharacterCodes2["E"] = 69] = "E";
|
|
2341
|
+
CharacterCodes2[CharacterCodes2["F"] = 70] = "F";
|
|
2342
|
+
CharacterCodes2[CharacterCodes2["G"] = 71] = "G";
|
|
2343
|
+
CharacterCodes2[CharacterCodes2["H"] = 72] = "H";
|
|
2344
|
+
CharacterCodes2[CharacterCodes2["I"] = 73] = "I";
|
|
2345
|
+
CharacterCodes2[CharacterCodes2["J"] = 74] = "J";
|
|
2346
|
+
CharacterCodes2[CharacterCodes2["K"] = 75] = "K";
|
|
2347
|
+
CharacterCodes2[CharacterCodes2["L"] = 76] = "L";
|
|
2348
|
+
CharacterCodes2[CharacterCodes2["M"] = 77] = "M";
|
|
2349
|
+
CharacterCodes2[CharacterCodes2["N"] = 78] = "N";
|
|
2350
|
+
CharacterCodes2[CharacterCodes2["O"] = 79] = "O";
|
|
2351
|
+
CharacterCodes2[CharacterCodes2["P"] = 80] = "P";
|
|
2352
|
+
CharacterCodes2[CharacterCodes2["Q"] = 81] = "Q";
|
|
2353
|
+
CharacterCodes2[CharacterCodes2["R"] = 82] = "R";
|
|
2354
|
+
CharacterCodes2[CharacterCodes2["S"] = 83] = "S";
|
|
2355
|
+
CharacterCodes2[CharacterCodes2["T"] = 84] = "T";
|
|
2356
|
+
CharacterCodes2[CharacterCodes2["U"] = 85] = "U";
|
|
2357
|
+
CharacterCodes2[CharacterCodes2["V"] = 86] = "V";
|
|
2358
|
+
CharacterCodes2[CharacterCodes2["W"] = 87] = "W";
|
|
2359
|
+
CharacterCodes2[CharacterCodes2["X"] = 88] = "X";
|
|
2360
|
+
CharacterCodes2[CharacterCodes2["Y"] = 89] = "Y";
|
|
2361
|
+
CharacterCodes2[CharacterCodes2["Z"] = 90] = "Z";
|
|
2362
|
+
CharacterCodes2[CharacterCodes2["asterisk"] = 42] = "asterisk";
|
|
2363
|
+
CharacterCodes2[CharacterCodes2["backslash"] = 92] = "backslash";
|
|
2364
|
+
CharacterCodes2[CharacterCodes2["closeBrace"] = 125] = "closeBrace";
|
|
2365
|
+
CharacterCodes2[CharacterCodes2["closeBracket"] = 93] = "closeBracket";
|
|
2366
|
+
CharacterCodes2[CharacterCodes2["colon"] = 58] = "colon";
|
|
2367
|
+
CharacterCodes2[CharacterCodes2["comma"] = 44] = "comma";
|
|
2368
|
+
CharacterCodes2[CharacterCodes2["dot"] = 46] = "dot";
|
|
2369
|
+
CharacterCodes2[CharacterCodes2["doubleQuote"] = 34] = "doubleQuote";
|
|
2370
|
+
CharacterCodes2[CharacterCodes2["minus"] = 45] = "minus";
|
|
2371
|
+
CharacterCodes2[CharacterCodes2["openBrace"] = 123] = "openBrace";
|
|
2372
|
+
CharacterCodes2[CharacterCodes2["openBracket"] = 91] = "openBracket";
|
|
2373
|
+
CharacterCodes2[CharacterCodes2["plus"] = 43] = "plus";
|
|
2374
|
+
CharacterCodes2[CharacterCodes2["slash"] = 47] = "slash";
|
|
2375
|
+
CharacterCodes2[CharacterCodes2["formFeed"] = 12] = "formFeed";
|
|
2376
|
+
CharacterCodes2[CharacterCodes2["tab"] = 9] = "tab";
|
|
2377
|
+
})(CharacterCodes || (CharacterCodes = {}));
|
|
2378
|
+
|
|
2379
|
+
// node_modules/jsonc-parser/lib/esm/impl/string-intern.js
|
|
2380
|
+
var cachedSpaces = new Array(20).fill(0).map((_, index) => {
|
|
2381
|
+
return " ".repeat(index);
|
|
2382
|
+
});
|
|
2383
|
+
var maxCachedValues = 200;
|
|
2384
|
+
var cachedBreakLinesWithSpaces = {
|
|
2385
|
+
" ": {
|
|
2386
|
+
"\n": new Array(maxCachedValues).fill(0).map((_, index) => {
|
|
2387
|
+
return "\n" + " ".repeat(index);
|
|
2388
|
+
}),
|
|
2389
|
+
"\r": new Array(maxCachedValues).fill(0).map((_, index) => {
|
|
2390
|
+
return "\r" + " ".repeat(index);
|
|
2391
|
+
}),
|
|
2392
|
+
"\r\n": new Array(maxCachedValues).fill(0).map((_, index) => {
|
|
2393
|
+
return "\r\n" + " ".repeat(index);
|
|
2394
|
+
})
|
|
2395
|
+
},
|
|
2396
|
+
" ": {
|
|
2397
|
+
"\n": new Array(maxCachedValues).fill(0).map((_, index) => {
|
|
2398
|
+
return "\n" + " ".repeat(index);
|
|
2399
|
+
}),
|
|
2400
|
+
"\r": new Array(maxCachedValues).fill(0).map((_, index) => {
|
|
2401
|
+
return "\r" + " ".repeat(index);
|
|
2402
|
+
}),
|
|
2403
|
+
"\r\n": new Array(maxCachedValues).fill(0).map((_, index) => {
|
|
2404
|
+
return "\r\n" + " ".repeat(index);
|
|
2405
|
+
})
|
|
2406
|
+
}
|
|
2407
|
+
};
|
|
2408
|
+
var supportedEols = ["\n", "\r", "\r\n"];
|
|
2409
|
+
|
|
2410
|
+
// node_modules/jsonc-parser/lib/esm/impl/format.js
|
|
2411
|
+
function format(documentText, range, options) {
|
|
2412
|
+
let initialIndentLevel;
|
|
2413
|
+
let formatText;
|
|
2414
|
+
let formatTextStart;
|
|
2415
|
+
let rangeStart;
|
|
2416
|
+
let rangeEnd;
|
|
2417
|
+
if (range) {
|
|
2418
|
+
rangeStart = range.offset;
|
|
2419
|
+
rangeEnd = rangeStart + range.length;
|
|
2420
|
+
formatTextStart = rangeStart;
|
|
2421
|
+
while (formatTextStart > 0 && !isEOL(documentText, formatTextStart - 1)) {
|
|
2422
|
+
formatTextStart--;
|
|
2423
|
+
}
|
|
2424
|
+
let endOffset = rangeEnd;
|
|
2425
|
+
while (endOffset < documentText.length && !isEOL(documentText, endOffset)) {
|
|
2426
|
+
endOffset++;
|
|
2427
|
+
}
|
|
2428
|
+
formatText = documentText.substring(formatTextStart, endOffset);
|
|
2429
|
+
initialIndentLevel = computeIndentLevel(formatText, options);
|
|
2430
|
+
} else {
|
|
2431
|
+
formatText = documentText;
|
|
2432
|
+
initialIndentLevel = 0;
|
|
2433
|
+
formatTextStart = 0;
|
|
2434
|
+
rangeStart = 0;
|
|
2435
|
+
rangeEnd = documentText.length;
|
|
2436
|
+
}
|
|
2437
|
+
const eol = getEOL(options, documentText);
|
|
2438
|
+
const eolFastPathSupported = supportedEols.includes(eol);
|
|
2439
|
+
let numberLineBreaks = 0;
|
|
2440
|
+
let indentLevel = 0;
|
|
2441
|
+
let indentValue;
|
|
2442
|
+
if (options.insertSpaces) {
|
|
2443
|
+
indentValue = cachedSpaces[options.tabSize || 4] ?? repeat(cachedSpaces[1], options.tabSize || 4);
|
|
2444
|
+
} else {
|
|
2445
|
+
indentValue = " ";
|
|
2446
|
+
}
|
|
2447
|
+
const indentType = indentValue === " " ? " " : " ";
|
|
2448
|
+
let scanner = createScanner(formatText, false);
|
|
2449
|
+
let hasError = false;
|
|
2450
|
+
function newLinesAndIndent() {
|
|
2451
|
+
if (numberLineBreaks > 1) {
|
|
2452
|
+
return repeat(eol, numberLineBreaks) + repeat(indentValue, initialIndentLevel + indentLevel);
|
|
2453
|
+
}
|
|
2454
|
+
const amountOfSpaces = indentValue.length * (initialIndentLevel + indentLevel);
|
|
2455
|
+
if (!eolFastPathSupported || amountOfSpaces > cachedBreakLinesWithSpaces[indentType][eol].length) {
|
|
2456
|
+
return eol + repeat(indentValue, initialIndentLevel + indentLevel);
|
|
2457
|
+
}
|
|
2458
|
+
if (amountOfSpaces <= 0) {
|
|
2459
|
+
return eol;
|
|
2460
|
+
}
|
|
2461
|
+
return cachedBreakLinesWithSpaces[indentType][eol][amountOfSpaces];
|
|
2462
|
+
}
|
|
2463
|
+
function scanNext() {
|
|
2464
|
+
let token = scanner.scan();
|
|
2465
|
+
numberLineBreaks = 0;
|
|
2466
|
+
while (token === 15 || token === 14) {
|
|
2467
|
+
if (token === 14 && options.keepLines) {
|
|
2468
|
+
numberLineBreaks += 1;
|
|
2469
|
+
} else if (token === 14) {
|
|
2470
|
+
numberLineBreaks = 1;
|
|
2471
|
+
}
|
|
2472
|
+
token = scanner.scan();
|
|
2473
|
+
}
|
|
2474
|
+
hasError = token === 16 || scanner.getTokenError() !== 0;
|
|
2475
|
+
return token;
|
|
2476
|
+
}
|
|
2477
|
+
const editOperations = [];
|
|
2478
|
+
function addEdit(text, startOffset, endOffset) {
|
|
2479
|
+
if (!hasError && (!range || startOffset < rangeEnd && endOffset > rangeStart) && documentText.substring(startOffset, endOffset) !== text) {
|
|
2480
|
+
editOperations.push({ offset: startOffset, length: endOffset - startOffset, content: text });
|
|
2481
|
+
}
|
|
2482
|
+
}
|
|
2483
|
+
let firstToken = scanNext();
|
|
2484
|
+
if (options.keepLines && numberLineBreaks > 0) {
|
|
2485
|
+
addEdit(repeat(eol, numberLineBreaks), 0, 0);
|
|
2486
|
+
}
|
|
2487
|
+
if (firstToken !== 17) {
|
|
2488
|
+
let firstTokenStart = scanner.getTokenOffset() + formatTextStart;
|
|
2489
|
+
let initialIndent = indentValue.length * initialIndentLevel < 20 && options.insertSpaces ? cachedSpaces[indentValue.length * initialIndentLevel] : repeat(indentValue, initialIndentLevel);
|
|
2490
|
+
addEdit(initialIndent, formatTextStart, firstTokenStart);
|
|
2491
|
+
}
|
|
2492
|
+
while (firstToken !== 17) {
|
|
2493
|
+
let firstTokenEnd = scanner.getTokenOffset() + scanner.getTokenLength() + formatTextStart;
|
|
2494
|
+
let secondToken = scanNext();
|
|
2495
|
+
let replaceContent = "";
|
|
2496
|
+
let needsLineBreak = false;
|
|
2497
|
+
while (numberLineBreaks === 0 && (secondToken === 12 || secondToken === 13)) {
|
|
2498
|
+
let commentTokenStart = scanner.getTokenOffset() + formatTextStart;
|
|
2499
|
+
addEdit(cachedSpaces[1], firstTokenEnd, commentTokenStart);
|
|
2500
|
+
firstTokenEnd = scanner.getTokenOffset() + scanner.getTokenLength() + formatTextStart;
|
|
2501
|
+
needsLineBreak = secondToken === 12;
|
|
2502
|
+
replaceContent = needsLineBreak ? newLinesAndIndent() : "";
|
|
2503
|
+
secondToken = scanNext();
|
|
2504
|
+
}
|
|
2505
|
+
if (secondToken === 2) {
|
|
2506
|
+
if (firstToken !== 1) {
|
|
2507
|
+
indentLevel--;
|
|
2508
|
+
}
|
|
2509
|
+
;
|
|
2510
|
+
if (options.keepLines && numberLineBreaks > 0 || !options.keepLines && firstToken !== 1) {
|
|
2511
|
+
replaceContent = newLinesAndIndent();
|
|
2512
|
+
} else if (options.keepLines) {
|
|
2513
|
+
replaceContent = cachedSpaces[1];
|
|
2514
|
+
}
|
|
2515
|
+
} else if (secondToken === 4) {
|
|
2516
|
+
if (firstToken !== 3) {
|
|
2517
|
+
indentLevel--;
|
|
2518
|
+
}
|
|
2519
|
+
;
|
|
2520
|
+
if (options.keepLines && numberLineBreaks > 0 || !options.keepLines && firstToken !== 3) {
|
|
2521
|
+
replaceContent = newLinesAndIndent();
|
|
2522
|
+
} else if (options.keepLines) {
|
|
2523
|
+
replaceContent = cachedSpaces[1];
|
|
2524
|
+
}
|
|
2525
|
+
} else {
|
|
2526
|
+
switch (firstToken) {
|
|
2527
|
+
case 3:
|
|
2528
|
+
case 1:
|
|
2529
|
+
indentLevel++;
|
|
2530
|
+
if (options.keepLines && numberLineBreaks > 0 || !options.keepLines) {
|
|
2531
|
+
replaceContent = newLinesAndIndent();
|
|
2532
|
+
} else {
|
|
2533
|
+
replaceContent = cachedSpaces[1];
|
|
2534
|
+
}
|
|
2535
|
+
break;
|
|
2536
|
+
case 5:
|
|
2537
|
+
if (options.keepLines && numberLineBreaks > 0 || !options.keepLines) {
|
|
2538
|
+
replaceContent = newLinesAndIndent();
|
|
2539
|
+
} else {
|
|
2540
|
+
replaceContent = cachedSpaces[1];
|
|
2541
|
+
}
|
|
2542
|
+
break;
|
|
2543
|
+
case 12:
|
|
2544
|
+
replaceContent = newLinesAndIndent();
|
|
2545
|
+
break;
|
|
2546
|
+
case 13:
|
|
2547
|
+
if (numberLineBreaks > 0) {
|
|
2548
|
+
replaceContent = newLinesAndIndent();
|
|
2549
|
+
} else if (!needsLineBreak) {
|
|
2550
|
+
replaceContent = cachedSpaces[1];
|
|
2551
|
+
}
|
|
2552
|
+
break;
|
|
2553
|
+
case 6:
|
|
2554
|
+
if (options.keepLines && numberLineBreaks > 0) {
|
|
2555
|
+
replaceContent = newLinesAndIndent();
|
|
2556
|
+
} else if (!needsLineBreak) {
|
|
2557
|
+
replaceContent = cachedSpaces[1];
|
|
2558
|
+
}
|
|
2559
|
+
break;
|
|
2560
|
+
case 10:
|
|
2561
|
+
if (options.keepLines && numberLineBreaks > 0) {
|
|
2562
|
+
replaceContent = newLinesAndIndent();
|
|
2563
|
+
} else if (secondToken === 6 && !needsLineBreak) {
|
|
2564
|
+
replaceContent = "";
|
|
2565
|
+
}
|
|
2566
|
+
break;
|
|
2567
|
+
case 7:
|
|
2568
|
+
case 8:
|
|
2569
|
+
case 9:
|
|
2570
|
+
case 11:
|
|
2571
|
+
case 2:
|
|
2572
|
+
case 4:
|
|
2573
|
+
if (options.keepLines && numberLineBreaks > 0) {
|
|
2574
|
+
replaceContent = newLinesAndIndent();
|
|
2575
|
+
} else {
|
|
2576
|
+
if ((secondToken === 12 || secondToken === 13) && !needsLineBreak) {
|
|
2577
|
+
replaceContent = cachedSpaces[1];
|
|
2578
|
+
} else if (secondToken !== 5 && secondToken !== 17) {
|
|
2579
|
+
hasError = true;
|
|
2580
|
+
}
|
|
2581
|
+
}
|
|
2582
|
+
break;
|
|
2583
|
+
case 16:
|
|
2584
|
+
hasError = true;
|
|
2585
|
+
break;
|
|
2586
|
+
}
|
|
2587
|
+
if (numberLineBreaks > 0 && (secondToken === 12 || secondToken === 13)) {
|
|
2588
|
+
replaceContent = newLinesAndIndent();
|
|
2589
|
+
}
|
|
2590
|
+
}
|
|
2591
|
+
if (secondToken === 17) {
|
|
2592
|
+
if (options.keepLines && numberLineBreaks > 0) {
|
|
2593
|
+
replaceContent = newLinesAndIndent();
|
|
2594
|
+
} else {
|
|
2595
|
+
replaceContent = options.insertFinalNewline ? eol : "";
|
|
2596
|
+
}
|
|
2597
|
+
}
|
|
2598
|
+
const secondTokenStart = scanner.getTokenOffset() + formatTextStart;
|
|
2599
|
+
addEdit(replaceContent, firstTokenEnd, secondTokenStart);
|
|
2600
|
+
firstToken = secondToken;
|
|
2601
|
+
}
|
|
2602
|
+
return editOperations;
|
|
2603
|
+
}
|
|
2604
|
+
function repeat(s, count) {
|
|
2605
|
+
let result = "";
|
|
2606
|
+
for (let i = 0; i < count; i++) {
|
|
2607
|
+
result += s;
|
|
2608
|
+
}
|
|
2609
|
+
return result;
|
|
2610
|
+
}
|
|
2611
|
+
function computeIndentLevel(content, options) {
|
|
2612
|
+
let i = 0;
|
|
2613
|
+
let nChars = 0;
|
|
2614
|
+
const tabSize = options.tabSize || 4;
|
|
2615
|
+
while (i < content.length) {
|
|
2616
|
+
let ch = content.charAt(i);
|
|
2617
|
+
if (ch === cachedSpaces[1]) {
|
|
2618
|
+
nChars++;
|
|
2619
|
+
} else if (ch === " ") {
|
|
2620
|
+
nChars += tabSize;
|
|
2621
|
+
} else {
|
|
2622
|
+
break;
|
|
2623
|
+
}
|
|
2624
|
+
i++;
|
|
2625
|
+
}
|
|
2626
|
+
return Math.floor(nChars / tabSize);
|
|
2627
|
+
}
|
|
2628
|
+
function getEOL(options, text) {
|
|
2629
|
+
for (let i = 0; i < text.length; i++) {
|
|
2630
|
+
const ch = text.charAt(i);
|
|
2631
|
+
if (ch === "\r") {
|
|
2632
|
+
if (i + 1 < text.length && text.charAt(i + 1) === "\n") {
|
|
2633
|
+
return "\r\n";
|
|
2634
|
+
}
|
|
2635
|
+
return "\r";
|
|
2636
|
+
} else if (ch === "\n") {
|
|
2637
|
+
return "\n";
|
|
2638
|
+
}
|
|
2639
|
+
}
|
|
2640
|
+
return options && options.eol || "\n";
|
|
2641
|
+
}
|
|
2642
|
+
function isEOL(text, offset) {
|
|
2643
|
+
return "\r\n".indexOf(text.charAt(offset)) !== -1;
|
|
2644
|
+
}
|
|
2645
|
+
|
|
2646
|
+
// node_modules/jsonc-parser/lib/esm/impl/parser.js
|
|
2647
|
+
var ParseOptions;
|
|
2648
|
+
(function(ParseOptions2) {
|
|
2649
|
+
ParseOptions2.DEFAULT = {
|
|
2650
|
+
allowTrailingComma: false
|
|
2651
|
+
};
|
|
2652
|
+
})(ParseOptions || (ParseOptions = {}));
|
|
2653
|
+
function parse(text, errors = [], options = ParseOptions.DEFAULT) {
|
|
2654
|
+
let currentProperty = null;
|
|
2655
|
+
let currentParent = [];
|
|
2656
|
+
const previousParents = [];
|
|
2657
|
+
function onValue(value) {
|
|
2658
|
+
if (Array.isArray(currentParent)) {
|
|
2659
|
+
currentParent.push(value);
|
|
2660
|
+
} else if (currentProperty !== null) {
|
|
2661
|
+
currentParent[currentProperty] = value;
|
|
2662
|
+
}
|
|
2663
|
+
}
|
|
2664
|
+
const visitor = {
|
|
2665
|
+
onObjectBegin: () => {
|
|
2666
|
+
const object = {};
|
|
2667
|
+
onValue(object);
|
|
2668
|
+
previousParents.push(currentParent);
|
|
2669
|
+
currentParent = object;
|
|
2670
|
+
currentProperty = null;
|
|
2671
|
+
},
|
|
2672
|
+
onObjectProperty: (name) => {
|
|
2673
|
+
currentProperty = name;
|
|
2674
|
+
},
|
|
2675
|
+
onObjectEnd: () => {
|
|
2676
|
+
currentParent = previousParents.pop();
|
|
2677
|
+
},
|
|
2678
|
+
onArrayBegin: () => {
|
|
2679
|
+
const array = [];
|
|
2680
|
+
onValue(array);
|
|
2681
|
+
previousParents.push(currentParent);
|
|
2682
|
+
currentParent = array;
|
|
2683
|
+
currentProperty = null;
|
|
2684
|
+
},
|
|
2685
|
+
onArrayEnd: () => {
|
|
2686
|
+
currentParent = previousParents.pop();
|
|
2687
|
+
},
|
|
2688
|
+
onLiteralValue: onValue,
|
|
2689
|
+
onError: (error, offset, length) => {
|
|
2690
|
+
errors.push({ error, offset, length });
|
|
2691
|
+
}
|
|
2692
|
+
};
|
|
2693
|
+
visit(text, visitor, options);
|
|
2694
|
+
return currentParent[0];
|
|
2695
|
+
}
|
|
2696
|
+
function parseTree(text, errors = [], options = ParseOptions.DEFAULT) {
|
|
2697
|
+
let currentParent = { type: "array", offset: -1, length: -1, children: [], parent: void 0 };
|
|
2698
|
+
function ensurePropertyComplete(endOffset) {
|
|
2699
|
+
if (currentParent.type === "property") {
|
|
2700
|
+
currentParent.length = endOffset - currentParent.offset;
|
|
2701
|
+
currentParent = currentParent.parent;
|
|
2702
|
+
}
|
|
2703
|
+
}
|
|
2704
|
+
function onValue(valueNode) {
|
|
2705
|
+
currentParent.children.push(valueNode);
|
|
2706
|
+
return valueNode;
|
|
2707
|
+
}
|
|
2708
|
+
const visitor = {
|
|
2709
|
+
onObjectBegin: (offset) => {
|
|
2710
|
+
currentParent = onValue({ type: "object", offset, length: -1, parent: currentParent, children: [] });
|
|
2711
|
+
},
|
|
2712
|
+
onObjectProperty: (name, offset, length) => {
|
|
2713
|
+
currentParent = onValue({ type: "property", offset, length: -1, parent: currentParent, children: [] });
|
|
2714
|
+
currentParent.children.push({ type: "string", value: name, offset, length, parent: currentParent });
|
|
2715
|
+
},
|
|
2716
|
+
onObjectEnd: (offset, length) => {
|
|
2717
|
+
ensurePropertyComplete(offset + length);
|
|
2718
|
+
currentParent.length = offset + length - currentParent.offset;
|
|
2719
|
+
currentParent = currentParent.parent;
|
|
2720
|
+
ensurePropertyComplete(offset + length);
|
|
2721
|
+
},
|
|
2722
|
+
onArrayBegin: (offset, length) => {
|
|
2723
|
+
currentParent = onValue({ type: "array", offset, length: -1, parent: currentParent, children: [] });
|
|
2724
|
+
},
|
|
2725
|
+
onArrayEnd: (offset, length) => {
|
|
2726
|
+
currentParent.length = offset + length - currentParent.offset;
|
|
2727
|
+
currentParent = currentParent.parent;
|
|
2728
|
+
ensurePropertyComplete(offset + length);
|
|
2729
|
+
},
|
|
2730
|
+
onLiteralValue: (value, offset, length) => {
|
|
2731
|
+
onValue({ type: getNodeType(value), offset, length, parent: currentParent, value });
|
|
2732
|
+
ensurePropertyComplete(offset + length);
|
|
2733
|
+
},
|
|
2734
|
+
onSeparator: (sep2, offset, length) => {
|
|
2735
|
+
if (currentParent.type === "property") {
|
|
2736
|
+
if (sep2 === ":") {
|
|
2737
|
+
currentParent.colonOffset = offset;
|
|
2738
|
+
} else if (sep2 === ",") {
|
|
2739
|
+
ensurePropertyComplete(offset);
|
|
2740
|
+
}
|
|
2741
|
+
}
|
|
2742
|
+
},
|
|
2743
|
+
onError: (error, offset, length) => {
|
|
2744
|
+
errors.push({ error, offset, length });
|
|
2745
|
+
}
|
|
2746
|
+
};
|
|
2747
|
+
visit(text, visitor, options);
|
|
2748
|
+
const result = currentParent.children[0];
|
|
2749
|
+
if (result) {
|
|
2750
|
+
delete result.parent;
|
|
2751
|
+
}
|
|
2752
|
+
return result;
|
|
2753
|
+
}
|
|
2754
|
+
function findNodeAtLocation(root, path) {
|
|
2755
|
+
if (!root) {
|
|
2756
|
+
return void 0;
|
|
2757
|
+
}
|
|
2758
|
+
let node = root;
|
|
2759
|
+
for (let segment of path) {
|
|
2760
|
+
if (typeof segment === "string") {
|
|
2761
|
+
if (node.type !== "object" || !Array.isArray(node.children)) {
|
|
2762
|
+
return void 0;
|
|
2763
|
+
}
|
|
2764
|
+
let found = false;
|
|
2765
|
+
for (const propertyNode of node.children) {
|
|
2766
|
+
if (Array.isArray(propertyNode.children) && propertyNode.children[0].value === segment && propertyNode.children.length === 2) {
|
|
2767
|
+
node = propertyNode.children[1];
|
|
2768
|
+
found = true;
|
|
2769
|
+
break;
|
|
2770
|
+
}
|
|
2771
|
+
}
|
|
2772
|
+
if (!found) {
|
|
2773
|
+
return void 0;
|
|
2774
|
+
}
|
|
2775
|
+
} else {
|
|
2776
|
+
const index = segment;
|
|
2777
|
+
if (node.type !== "array" || index < 0 || !Array.isArray(node.children) || index >= node.children.length) {
|
|
2778
|
+
return void 0;
|
|
2779
|
+
}
|
|
2780
|
+
node = node.children[index];
|
|
2781
|
+
}
|
|
2782
|
+
}
|
|
2783
|
+
return node;
|
|
2784
|
+
}
|
|
2785
|
+
function visit(text, visitor, options = ParseOptions.DEFAULT) {
|
|
2786
|
+
const _scanner = createScanner(text, false);
|
|
2787
|
+
const _jsonPath = [];
|
|
2788
|
+
let suppressedCallbacks = 0;
|
|
2789
|
+
function toNoArgVisit(visitFunction) {
|
|
2790
|
+
return visitFunction ? () => suppressedCallbacks === 0 && visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter()) : () => true;
|
|
2791
|
+
}
|
|
2792
|
+
function toOneArgVisit(visitFunction) {
|
|
2793
|
+
return visitFunction ? (arg) => suppressedCallbacks === 0 && visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter()) : () => true;
|
|
2794
|
+
}
|
|
2795
|
+
function toOneArgVisitWithPath(visitFunction) {
|
|
2796
|
+
return visitFunction ? (arg) => suppressedCallbacks === 0 && visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter(), () => _jsonPath.slice()) : () => true;
|
|
2797
|
+
}
|
|
2798
|
+
function toBeginVisit(visitFunction) {
|
|
2799
|
+
return visitFunction ? () => {
|
|
2800
|
+
if (suppressedCallbacks > 0) {
|
|
2801
|
+
suppressedCallbacks++;
|
|
2802
|
+
} else {
|
|
2803
|
+
let cbReturn = visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter(), () => _jsonPath.slice());
|
|
2804
|
+
if (cbReturn === false) {
|
|
2805
|
+
suppressedCallbacks = 1;
|
|
2806
|
+
}
|
|
2807
|
+
}
|
|
2808
|
+
} : () => true;
|
|
2809
|
+
}
|
|
2810
|
+
function toEndVisit(visitFunction) {
|
|
2811
|
+
return visitFunction ? () => {
|
|
2812
|
+
if (suppressedCallbacks > 0) {
|
|
2813
|
+
suppressedCallbacks--;
|
|
2814
|
+
}
|
|
2815
|
+
if (suppressedCallbacks === 0) {
|
|
2816
|
+
visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter());
|
|
2817
|
+
}
|
|
2818
|
+
} : () => true;
|
|
2819
|
+
}
|
|
2820
|
+
const onObjectBegin = toBeginVisit(visitor.onObjectBegin), onObjectProperty = toOneArgVisitWithPath(visitor.onObjectProperty), onObjectEnd = toEndVisit(visitor.onObjectEnd), onArrayBegin = toBeginVisit(visitor.onArrayBegin), onArrayEnd = toEndVisit(visitor.onArrayEnd), onLiteralValue = toOneArgVisitWithPath(visitor.onLiteralValue), onSeparator = toOneArgVisit(visitor.onSeparator), onComment = toNoArgVisit(visitor.onComment), onError = toOneArgVisit(visitor.onError);
|
|
2821
|
+
const disallowComments = options && options.disallowComments;
|
|
2822
|
+
const allowTrailingComma = options && options.allowTrailingComma;
|
|
2823
|
+
function scanNext() {
|
|
2824
|
+
while (true) {
|
|
2825
|
+
const token = _scanner.scan();
|
|
2826
|
+
switch (_scanner.getTokenError()) {
|
|
2827
|
+
case 4:
|
|
2828
|
+
handleError(
|
|
2829
|
+
14
|
|
2830
|
+
/* ParseErrorCode.InvalidUnicode */
|
|
2831
|
+
);
|
|
2832
|
+
break;
|
|
2833
|
+
case 5:
|
|
2834
|
+
handleError(
|
|
2835
|
+
15
|
|
2836
|
+
/* ParseErrorCode.InvalidEscapeCharacter */
|
|
2837
|
+
);
|
|
2838
|
+
break;
|
|
2839
|
+
case 3:
|
|
2840
|
+
handleError(
|
|
2841
|
+
13
|
|
2842
|
+
/* ParseErrorCode.UnexpectedEndOfNumber */
|
|
2843
|
+
);
|
|
2844
|
+
break;
|
|
2845
|
+
case 1:
|
|
2846
|
+
if (!disallowComments) {
|
|
2847
|
+
handleError(
|
|
2848
|
+
11
|
|
2849
|
+
/* ParseErrorCode.UnexpectedEndOfComment */
|
|
2850
|
+
);
|
|
2851
|
+
}
|
|
2852
|
+
break;
|
|
2853
|
+
case 2:
|
|
2854
|
+
handleError(
|
|
2855
|
+
12
|
|
2856
|
+
/* ParseErrorCode.UnexpectedEndOfString */
|
|
2857
|
+
);
|
|
2858
|
+
break;
|
|
2859
|
+
case 6:
|
|
2860
|
+
handleError(
|
|
2861
|
+
16
|
|
2862
|
+
/* ParseErrorCode.InvalidCharacter */
|
|
2863
|
+
);
|
|
2864
|
+
break;
|
|
2865
|
+
}
|
|
2866
|
+
switch (token) {
|
|
2867
|
+
case 12:
|
|
2868
|
+
case 13:
|
|
2869
|
+
if (disallowComments) {
|
|
2870
|
+
handleError(
|
|
2871
|
+
10
|
|
2872
|
+
/* ParseErrorCode.InvalidCommentToken */
|
|
2873
|
+
);
|
|
2874
|
+
} else {
|
|
2875
|
+
onComment();
|
|
2876
|
+
}
|
|
2877
|
+
break;
|
|
2878
|
+
case 16:
|
|
2879
|
+
handleError(
|
|
2880
|
+
1
|
|
2881
|
+
/* ParseErrorCode.InvalidSymbol */
|
|
2882
|
+
);
|
|
2883
|
+
break;
|
|
2884
|
+
case 15:
|
|
2885
|
+
case 14:
|
|
2886
|
+
break;
|
|
2887
|
+
default:
|
|
2888
|
+
return token;
|
|
2889
|
+
}
|
|
2890
|
+
}
|
|
2891
|
+
}
|
|
2892
|
+
function handleError(error, skipUntilAfter = [], skipUntil = []) {
|
|
2893
|
+
onError(error);
|
|
2894
|
+
if (skipUntilAfter.length + skipUntil.length > 0) {
|
|
2895
|
+
let token = _scanner.getToken();
|
|
2896
|
+
while (token !== 17) {
|
|
2897
|
+
if (skipUntilAfter.indexOf(token) !== -1) {
|
|
2898
|
+
scanNext();
|
|
2899
|
+
break;
|
|
2900
|
+
} else if (skipUntil.indexOf(token) !== -1) {
|
|
2901
|
+
break;
|
|
2902
|
+
}
|
|
2903
|
+
token = scanNext();
|
|
2904
|
+
}
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2907
|
+
function parseString(isValue) {
|
|
2908
|
+
const value = _scanner.getTokenValue();
|
|
2909
|
+
if (isValue) {
|
|
2910
|
+
onLiteralValue(value);
|
|
2911
|
+
} else {
|
|
2912
|
+
onObjectProperty(value);
|
|
2913
|
+
_jsonPath.push(value);
|
|
2914
|
+
}
|
|
2915
|
+
scanNext();
|
|
2916
|
+
return true;
|
|
2917
|
+
}
|
|
2918
|
+
function parseLiteral() {
|
|
2919
|
+
switch (_scanner.getToken()) {
|
|
2920
|
+
case 11:
|
|
2921
|
+
const tokenValue = _scanner.getTokenValue();
|
|
2922
|
+
let value = Number(tokenValue);
|
|
2923
|
+
if (isNaN(value)) {
|
|
2924
|
+
handleError(
|
|
2925
|
+
2
|
|
2926
|
+
/* ParseErrorCode.InvalidNumberFormat */
|
|
2927
|
+
);
|
|
2928
|
+
value = 0;
|
|
2929
|
+
}
|
|
2930
|
+
onLiteralValue(value);
|
|
2931
|
+
break;
|
|
2932
|
+
case 7:
|
|
2933
|
+
onLiteralValue(null);
|
|
2934
|
+
break;
|
|
2935
|
+
case 8:
|
|
2936
|
+
onLiteralValue(true);
|
|
2937
|
+
break;
|
|
2938
|
+
case 9:
|
|
2939
|
+
onLiteralValue(false);
|
|
2940
|
+
break;
|
|
2941
|
+
default:
|
|
2942
|
+
return false;
|
|
2943
|
+
}
|
|
2944
|
+
scanNext();
|
|
2945
|
+
return true;
|
|
2946
|
+
}
|
|
2947
|
+
function parseProperty() {
|
|
2948
|
+
if (_scanner.getToken() !== 10) {
|
|
2949
|
+
handleError(3, [], [
|
|
2950
|
+
2,
|
|
2951
|
+
5
|
|
2952
|
+
/* SyntaxKind.CommaToken */
|
|
2953
|
+
]);
|
|
2954
|
+
return false;
|
|
2955
|
+
}
|
|
2956
|
+
parseString(false);
|
|
2957
|
+
if (_scanner.getToken() === 6) {
|
|
2958
|
+
onSeparator(":");
|
|
2959
|
+
scanNext();
|
|
2960
|
+
if (!parseValue()) {
|
|
2961
|
+
handleError(4, [], [
|
|
2962
|
+
2,
|
|
2963
|
+
5
|
|
2964
|
+
/* SyntaxKind.CommaToken */
|
|
2965
|
+
]);
|
|
2966
|
+
}
|
|
2967
|
+
} else {
|
|
2968
|
+
handleError(5, [], [
|
|
2969
|
+
2,
|
|
2970
|
+
5
|
|
2971
|
+
/* SyntaxKind.CommaToken */
|
|
2972
|
+
]);
|
|
2973
|
+
}
|
|
2974
|
+
_jsonPath.pop();
|
|
2975
|
+
return true;
|
|
2976
|
+
}
|
|
2977
|
+
function parseObject() {
|
|
2978
|
+
onObjectBegin();
|
|
2979
|
+
scanNext();
|
|
2980
|
+
let needsComma = false;
|
|
2981
|
+
while (_scanner.getToken() !== 2 && _scanner.getToken() !== 17) {
|
|
2982
|
+
if (_scanner.getToken() === 5) {
|
|
2983
|
+
if (!needsComma) {
|
|
2984
|
+
handleError(4, [], []);
|
|
2985
|
+
}
|
|
2986
|
+
onSeparator(",");
|
|
2987
|
+
scanNext();
|
|
2988
|
+
if (_scanner.getToken() === 2 && allowTrailingComma) {
|
|
2989
|
+
break;
|
|
2990
|
+
}
|
|
2991
|
+
} else if (needsComma) {
|
|
2992
|
+
handleError(6, [], []);
|
|
2993
|
+
}
|
|
2994
|
+
if (!parseProperty()) {
|
|
2995
|
+
handleError(4, [], [
|
|
2996
|
+
2,
|
|
2997
|
+
5
|
|
2998
|
+
/* SyntaxKind.CommaToken */
|
|
2999
|
+
]);
|
|
3000
|
+
}
|
|
3001
|
+
needsComma = true;
|
|
3002
|
+
}
|
|
3003
|
+
onObjectEnd();
|
|
3004
|
+
if (_scanner.getToken() !== 2) {
|
|
3005
|
+
handleError(7, [
|
|
3006
|
+
2
|
|
3007
|
+
/* SyntaxKind.CloseBraceToken */
|
|
3008
|
+
], []);
|
|
3009
|
+
} else {
|
|
3010
|
+
scanNext();
|
|
3011
|
+
}
|
|
3012
|
+
return true;
|
|
3013
|
+
}
|
|
3014
|
+
function parseArray() {
|
|
3015
|
+
onArrayBegin();
|
|
3016
|
+
scanNext();
|
|
3017
|
+
let isFirstElement = true;
|
|
3018
|
+
let needsComma = false;
|
|
3019
|
+
while (_scanner.getToken() !== 4 && _scanner.getToken() !== 17) {
|
|
3020
|
+
if (_scanner.getToken() === 5) {
|
|
3021
|
+
if (!needsComma) {
|
|
3022
|
+
handleError(4, [], []);
|
|
3023
|
+
}
|
|
3024
|
+
onSeparator(",");
|
|
3025
|
+
scanNext();
|
|
3026
|
+
if (_scanner.getToken() === 4 && allowTrailingComma) {
|
|
3027
|
+
break;
|
|
3028
|
+
}
|
|
3029
|
+
} else if (needsComma) {
|
|
3030
|
+
handleError(6, [], []);
|
|
3031
|
+
}
|
|
3032
|
+
if (isFirstElement) {
|
|
3033
|
+
_jsonPath.push(0);
|
|
3034
|
+
isFirstElement = false;
|
|
3035
|
+
} else {
|
|
3036
|
+
_jsonPath[_jsonPath.length - 1]++;
|
|
3037
|
+
}
|
|
3038
|
+
if (!parseValue()) {
|
|
3039
|
+
handleError(4, [], [
|
|
3040
|
+
4,
|
|
3041
|
+
5
|
|
3042
|
+
/* SyntaxKind.CommaToken */
|
|
3043
|
+
]);
|
|
3044
|
+
}
|
|
3045
|
+
needsComma = true;
|
|
3046
|
+
}
|
|
3047
|
+
onArrayEnd();
|
|
3048
|
+
if (!isFirstElement) {
|
|
3049
|
+
_jsonPath.pop();
|
|
3050
|
+
}
|
|
3051
|
+
if (_scanner.getToken() !== 4) {
|
|
3052
|
+
handleError(8, [
|
|
3053
|
+
4
|
|
3054
|
+
/* SyntaxKind.CloseBracketToken */
|
|
3055
|
+
], []);
|
|
3056
|
+
} else {
|
|
3057
|
+
scanNext();
|
|
3058
|
+
}
|
|
3059
|
+
return true;
|
|
3060
|
+
}
|
|
3061
|
+
function parseValue() {
|
|
3062
|
+
switch (_scanner.getToken()) {
|
|
3063
|
+
case 3:
|
|
3064
|
+
return parseArray();
|
|
3065
|
+
case 1:
|
|
3066
|
+
return parseObject();
|
|
3067
|
+
case 10:
|
|
3068
|
+
return parseString(true);
|
|
3069
|
+
default:
|
|
3070
|
+
return parseLiteral();
|
|
3071
|
+
}
|
|
3072
|
+
}
|
|
3073
|
+
scanNext();
|
|
3074
|
+
if (_scanner.getToken() === 17) {
|
|
3075
|
+
if (options.allowEmptyContent) {
|
|
3076
|
+
return true;
|
|
3077
|
+
}
|
|
3078
|
+
handleError(4, [], []);
|
|
3079
|
+
return false;
|
|
3080
|
+
}
|
|
3081
|
+
if (!parseValue()) {
|
|
3082
|
+
handleError(4, [], []);
|
|
3083
|
+
return false;
|
|
3084
|
+
}
|
|
3085
|
+
if (_scanner.getToken() !== 17) {
|
|
3086
|
+
handleError(9, [], []);
|
|
3087
|
+
}
|
|
3088
|
+
return true;
|
|
3089
|
+
}
|
|
3090
|
+
function getNodeType(value) {
|
|
3091
|
+
switch (typeof value) {
|
|
3092
|
+
case "boolean":
|
|
3093
|
+
return "boolean";
|
|
3094
|
+
case "number":
|
|
3095
|
+
return "number";
|
|
3096
|
+
case "string":
|
|
3097
|
+
return "string";
|
|
3098
|
+
case "object": {
|
|
3099
|
+
if (!value) {
|
|
3100
|
+
return "null";
|
|
3101
|
+
} else if (Array.isArray(value)) {
|
|
3102
|
+
return "array";
|
|
3103
|
+
}
|
|
3104
|
+
return "object";
|
|
3105
|
+
}
|
|
3106
|
+
default:
|
|
3107
|
+
return "null";
|
|
3108
|
+
}
|
|
3109
|
+
}
|
|
1608
3110
|
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
}
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
else if (arg === "--root") options.rootPath = argv[++i];
|
|
1638
|
-
else if (arg === "--profile") {
|
|
1639
|
-
const value = argv[++i];
|
|
3111
|
+
// node_modules/jsonc-parser/lib/esm/impl/edit.js
|
|
3112
|
+
function setProperty(text, originalPath, value, options) {
|
|
3113
|
+
const path = originalPath.slice();
|
|
3114
|
+
const errors = [];
|
|
3115
|
+
const root = parseTree(text, errors);
|
|
3116
|
+
let parent = void 0;
|
|
3117
|
+
let lastSegment = void 0;
|
|
3118
|
+
while (path.length > 0) {
|
|
3119
|
+
lastSegment = path.pop();
|
|
3120
|
+
parent = findNodeAtLocation(root, path);
|
|
3121
|
+
if (parent === void 0 && value !== void 0) {
|
|
3122
|
+
if (typeof lastSegment === "string") {
|
|
3123
|
+
value = { [lastSegment]: value };
|
|
3124
|
+
} else {
|
|
3125
|
+
value = [value];
|
|
3126
|
+
}
|
|
3127
|
+
} else {
|
|
3128
|
+
break;
|
|
3129
|
+
}
|
|
3130
|
+
}
|
|
3131
|
+
if (!parent) {
|
|
3132
|
+
if (value === void 0) {
|
|
3133
|
+
throw new Error("Can not delete in empty document");
|
|
3134
|
+
}
|
|
3135
|
+
return withFormatting(text, { offset: root ? root.offset : 0, length: root ? root.length : 0, content: JSON.stringify(value) }, options);
|
|
3136
|
+
} else if (parent.type === "object" && typeof lastSegment === "string" && Array.isArray(parent.children)) {
|
|
3137
|
+
const existing = findNodeAtLocation(parent, [lastSegment]);
|
|
3138
|
+
if (existing !== void 0) {
|
|
1640
3139
|
if (value === void 0) {
|
|
1641
|
-
|
|
3140
|
+
if (!existing.parent) {
|
|
3141
|
+
throw new Error("Malformed AST");
|
|
3142
|
+
}
|
|
3143
|
+
const propertyIndex = parent.children.indexOf(existing.parent);
|
|
3144
|
+
let removeBegin;
|
|
3145
|
+
let removeEnd = existing.parent.offset + existing.parent.length;
|
|
3146
|
+
if (propertyIndex > 0) {
|
|
3147
|
+
let previous = parent.children[propertyIndex - 1];
|
|
3148
|
+
removeBegin = previous.offset + previous.length;
|
|
3149
|
+
} else {
|
|
3150
|
+
removeBegin = parent.offset + 1;
|
|
3151
|
+
if (parent.children.length > 1) {
|
|
3152
|
+
let next = parent.children[1];
|
|
3153
|
+
removeEnd = next.offset;
|
|
3154
|
+
}
|
|
3155
|
+
}
|
|
3156
|
+
return withFormatting(text, { offset: removeBegin, length: removeEnd - removeBegin, content: "" }, options);
|
|
3157
|
+
} else {
|
|
3158
|
+
return withFormatting(text, { offset: existing.offset, length: existing.length, content: JSON.stringify(value) }, options);
|
|
1642
3159
|
}
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
};
|
|
3160
|
+
} else {
|
|
3161
|
+
if (value === void 0) {
|
|
3162
|
+
return [];
|
|
1647
3163
|
}
|
|
1648
|
-
|
|
1649
|
-
|
|
3164
|
+
const newProperty = `${JSON.stringify(lastSegment)}: ${JSON.stringify(value)}`;
|
|
3165
|
+
const index = options.getInsertionIndex ? options.getInsertionIndex(parent.children.map((p) => p.children[0].value)) : parent.children.length;
|
|
3166
|
+
let edit;
|
|
3167
|
+
if (index > 0) {
|
|
3168
|
+
let previous = parent.children[index - 1];
|
|
3169
|
+
edit = { offset: previous.offset + previous.length, length: 0, content: "," + newProperty };
|
|
3170
|
+
} else if (parent.children.length === 0) {
|
|
3171
|
+
edit = { offset: parent.offset + 1, length: 0, content: newProperty };
|
|
3172
|
+
} else {
|
|
3173
|
+
edit = { offset: parent.offset + 1, length: 0, content: newProperty + "," };
|
|
1650
3174
|
}
|
|
1651
|
-
|
|
1652
|
-
}
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
3175
|
+
return withFormatting(text, edit, options);
|
|
3176
|
+
}
|
|
3177
|
+
} else if (parent.type === "array" && typeof lastSegment === "number" && Array.isArray(parent.children)) {
|
|
3178
|
+
const insertIndex = lastSegment;
|
|
3179
|
+
if (insertIndex === -1) {
|
|
3180
|
+
const newProperty = `${JSON.stringify(value)}`;
|
|
3181
|
+
let edit;
|
|
3182
|
+
if (parent.children.length === 0) {
|
|
3183
|
+
edit = { offset: parent.offset + 1, length: 0, content: newProperty };
|
|
3184
|
+
} else {
|
|
3185
|
+
const previous = parent.children[parent.children.length - 1];
|
|
3186
|
+
edit = { offset: previous.offset + previous.length, length: 0, content: "," + newProperty };
|
|
1657
3187
|
}
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
3188
|
+
return withFormatting(text, edit, options);
|
|
3189
|
+
} else if (value === void 0 && parent.children.length >= 0) {
|
|
3190
|
+
const removalIndex = lastSegment;
|
|
3191
|
+
const toRemove = parent.children[removalIndex];
|
|
3192
|
+
let edit;
|
|
3193
|
+
if (parent.children.length === 1) {
|
|
3194
|
+
edit = { offset: parent.offset + 1, length: parent.length - 2, content: "" };
|
|
3195
|
+
} else if (parent.children.length - 1 === removalIndex) {
|
|
3196
|
+
let previous = parent.children[removalIndex - 1];
|
|
3197
|
+
let offset = previous.offset + previous.length;
|
|
3198
|
+
let parentEndOffset = parent.offset + parent.length;
|
|
3199
|
+
edit = { offset, length: parentEndOffset - 2 - offset, content: "" };
|
|
3200
|
+
} else {
|
|
3201
|
+
edit = { offset: toRemove.offset, length: parent.children[removalIndex + 1].offset - toRemove.offset, content: "" };
|
|
3202
|
+
}
|
|
3203
|
+
return withFormatting(text, edit, options);
|
|
3204
|
+
} else if (value !== void 0) {
|
|
3205
|
+
let edit;
|
|
3206
|
+
const newProperty = `${JSON.stringify(value)}`;
|
|
3207
|
+
if (!options.isArrayInsertion && parent.children.length > lastSegment) {
|
|
3208
|
+
const toModify = parent.children[lastSegment];
|
|
3209
|
+
edit = { offset: toModify.offset, length: toModify.length, content: newProperty };
|
|
3210
|
+
} else if (parent.children.length === 0 || lastSegment === 0) {
|
|
3211
|
+
edit = { offset: parent.offset + 1, length: 0, content: parent.children.length === 0 ? newProperty : newProperty + "," };
|
|
3212
|
+
} else {
|
|
3213
|
+
const index = lastSegment > parent.children.length ? parent.children.length : lastSegment;
|
|
3214
|
+
const previous = parent.children[index - 1];
|
|
3215
|
+
edit = { offset: previous.offset + previous.length, length: 0, content: "," + newProperty };
|
|
3216
|
+
}
|
|
3217
|
+
return withFormatting(text, edit, options);
|
|
3218
|
+
} else {
|
|
3219
|
+
throw new Error(`Can not ${value === void 0 ? "remove" : options.isArrayInsertion ? "insert" : "modify"} Array index ${insertIndex} as length is not sufficient`);
|
|
3220
|
+
}
|
|
3221
|
+
} else {
|
|
3222
|
+
throw new Error(`Can not add ${typeof lastSegment !== "number" ? "index" : "property"} to parent of type ${parent.type}`);
|
|
1664
3223
|
}
|
|
1665
|
-
return options;
|
|
1666
3224
|
}
|
|
1667
|
-
function
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
if (arg === "--version" || arg === "-v") return { command: "version" };
|
|
3225
|
+
function withFormatting(text, edit, options) {
|
|
3226
|
+
if (!options.formattingOptions) {
|
|
3227
|
+
return [edit];
|
|
1671
3228
|
}
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
if (
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
case "doctor":
|
|
1683
|
-
case "setup-complete":
|
|
1684
|
-
case "uninstall":
|
|
1685
|
-
return { command: cmd, options: flags };
|
|
1686
|
-
default:
|
|
1687
|
-
return { error: `unknown command ${cmd}` };
|
|
3229
|
+
let newText = applyEdit(text, edit);
|
|
3230
|
+
let begin = edit.offset;
|
|
3231
|
+
let end = edit.offset + edit.content.length;
|
|
3232
|
+
if (edit.length === 0 || edit.content.length === 0) {
|
|
3233
|
+
while (begin > 0 && !isEOL(newText, begin - 1)) {
|
|
3234
|
+
begin--;
|
|
3235
|
+
}
|
|
3236
|
+
while (end < newText.length && !isEOL(newText, end)) {
|
|
3237
|
+
end++;
|
|
3238
|
+
}
|
|
1688
3239
|
}
|
|
3240
|
+
const edits = format(newText, { offset: begin, length: end - begin }, { ...options.formattingOptions, keepLines: false });
|
|
3241
|
+
for (let i = edits.length - 1; i >= 0; i--) {
|
|
3242
|
+
const edit2 = edits[i];
|
|
3243
|
+
newText = applyEdit(newText, edit2);
|
|
3244
|
+
begin = Math.min(begin, edit2.offset);
|
|
3245
|
+
end = Math.max(end, edit2.offset + edit2.length);
|
|
3246
|
+
end += edit2.content.length - edit2.length;
|
|
3247
|
+
}
|
|
3248
|
+
const editLength = text.length - (newText.length - end) - begin;
|
|
3249
|
+
return [{ offset: begin, length: editLength, content: newText.substring(begin, end) }];
|
|
1689
3250
|
}
|
|
1690
|
-
function
|
|
1691
|
-
return
|
|
3251
|
+
function applyEdit(text, edit) {
|
|
3252
|
+
return text.substring(0, edit.offset) + edit.content + text.substring(edit.offset + edit.length);
|
|
1692
3253
|
}
|
|
1693
3254
|
|
|
1694
|
-
//
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
3255
|
+
// node_modules/jsonc-parser/lib/esm/main.js
|
|
3256
|
+
var ScanError;
|
|
3257
|
+
(function(ScanError2) {
|
|
3258
|
+
ScanError2[ScanError2["None"] = 0] = "None";
|
|
3259
|
+
ScanError2[ScanError2["UnexpectedEndOfComment"] = 1] = "UnexpectedEndOfComment";
|
|
3260
|
+
ScanError2[ScanError2["UnexpectedEndOfString"] = 2] = "UnexpectedEndOfString";
|
|
3261
|
+
ScanError2[ScanError2["UnexpectedEndOfNumber"] = 3] = "UnexpectedEndOfNumber";
|
|
3262
|
+
ScanError2[ScanError2["InvalidUnicode"] = 4] = "InvalidUnicode";
|
|
3263
|
+
ScanError2[ScanError2["InvalidEscapeCharacter"] = 5] = "InvalidEscapeCharacter";
|
|
3264
|
+
ScanError2[ScanError2["InvalidCharacter"] = 6] = "InvalidCharacter";
|
|
3265
|
+
})(ScanError || (ScanError = {}));
|
|
3266
|
+
var SyntaxKind;
|
|
3267
|
+
(function(SyntaxKind2) {
|
|
3268
|
+
SyntaxKind2[SyntaxKind2["OpenBraceToken"] = 1] = "OpenBraceToken";
|
|
3269
|
+
SyntaxKind2[SyntaxKind2["CloseBraceToken"] = 2] = "CloseBraceToken";
|
|
3270
|
+
SyntaxKind2[SyntaxKind2["OpenBracketToken"] = 3] = "OpenBracketToken";
|
|
3271
|
+
SyntaxKind2[SyntaxKind2["CloseBracketToken"] = 4] = "CloseBracketToken";
|
|
3272
|
+
SyntaxKind2[SyntaxKind2["CommaToken"] = 5] = "CommaToken";
|
|
3273
|
+
SyntaxKind2[SyntaxKind2["ColonToken"] = 6] = "ColonToken";
|
|
3274
|
+
SyntaxKind2[SyntaxKind2["NullKeyword"] = 7] = "NullKeyword";
|
|
3275
|
+
SyntaxKind2[SyntaxKind2["TrueKeyword"] = 8] = "TrueKeyword";
|
|
3276
|
+
SyntaxKind2[SyntaxKind2["FalseKeyword"] = 9] = "FalseKeyword";
|
|
3277
|
+
SyntaxKind2[SyntaxKind2["StringLiteral"] = 10] = "StringLiteral";
|
|
3278
|
+
SyntaxKind2[SyntaxKind2["NumericLiteral"] = 11] = "NumericLiteral";
|
|
3279
|
+
SyntaxKind2[SyntaxKind2["LineCommentTrivia"] = 12] = "LineCommentTrivia";
|
|
3280
|
+
SyntaxKind2[SyntaxKind2["BlockCommentTrivia"] = 13] = "BlockCommentTrivia";
|
|
3281
|
+
SyntaxKind2[SyntaxKind2["LineBreakTrivia"] = 14] = "LineBreakTrivia";
|
|
3282
|
+
SyntaxKind2[SyntaxKind2["Trivia"] = 15] = "Trivia";
|
|
3283
|
+
SyntaxKind2[SyntaxKind2["Unknown"] = 16] = "Unknown";
|
|
3284
|
+
SyntaxKind2[SyntaxKind2["EOF"] = 17] = "EOF";
|
|
3285
|
+
})(SyntaxKind || (SyntaxKind = {}));
|
|
3286
|
+
var parse2 = parse;
|
|
3287
|
+
var ParseErrorCode;
|
|
3288
|
+
(function(ParseErrorCode2) {
|
|
3289
|
+
ParseErrorCode2[ParseErrorCode2["InvalidSymbol"] = 1] = "InvalidSymbol";
|
|
3290
|
+
ParseErrorCode2[ParseErrorCode2["InvalidNumberFormat"] = 2] = "InvalidNumberFormat";
|
|
3291
|
+
ParseErrorCode2[ParseErrorCode2["PropertyNameExpected"] = 3] = "PropertyNameExpected";
|
|
3292
|
+
ParseErrorCode2[ParseErrorCode2["ValueExpected"] = 4] = "ValueExpected";
|
|
3293
|
+
ParseErrorCode2[ParseErrorCode2["ColonExpected"] = 5] = "ColonExpected";
|
|
3294
|
+
ParseErrorCode2[ParseErrorCode2["CommaExpected"] = 6] = "CommaExpected";
|
|
3295
|
+
ParseErrorCode2[ParseErrorCode2["CloseBraceExpected"] = 7] = "CloseBraceExpected";
|
|
3296
|
+
ParseErrorCode2[ParseErrorCode2["CloseBracketExpected"] = 8] = "CloseBracketExpected";
|
|
3297
|
+
ParseErrorCode2[ParseErrorCode2["EndOfFileExpected"] = 9] = "EndOfFileExpected";
|
|
3298
|
+
ParseErrorCode2[ParseErrorCode2["InvalidCommentToken"] = 10] = "InvalidCommentToken";
|
|
3299
|
+
ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfComment"] = 11] = "UnexpectedEndOfComment";
|
|
3300
|
+
ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfString"] = 12] = "UnexpectedEndOfString";
|
|
3301
|
+
ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfNumber"] = 13] = "UnexpectedEndOfNumber";
|
|
3302
|
+
ParseErrorCode2[ParseErrorCode2["InvalidUnicode"] = 14] = "InvalidUnicode";
|
|
3303
|
+
ParseErrorCode2[ParseErrorCode2["InvalidEscapeCharacter"] = 15] = "InvalidEscapeCharacter";
|
|
3304
|
+
ParseErrorCode2[ParseErrorCode2["InvalidCharacter"] = 16] = "InvalidCharacter";
|
|
3305
|
+
})(ParseErrorCode || (ParseErrorCode = {}));
|
|
3306
|
+
function modify(text, path, value, options) {
|
|
3307
|
+
return setProperty(text, path, value, options);
|
|
3308
|
+
}
|
|
3309
|
+
function applyEdits(text, edits) {
|
|
3310
|
+
let sortedEdits = edits.slice(0).sort((a, b) => {
|
|
3311
|
+
const diff = a.offset - b.offset;
|
|
3312
|
+
if (diff === 0) {
|
|
3313
|
+
return a.length - b.length;
|
|
3314
|
+
}
|
|
3315
|
+
return diff;
|
|
3316
|
+
});
|
|
3317
|
+
let lastModifiedOffset = text.length;
|
|
3318
|
+
for (let i = sortedEdits.length - 1; i >= 0; i--) {
|
|
3319
|
+
let e = sortedEdits[i];
|
|
3320
|
+
if (e.offset + e.length <= lastModifiedOffset) {
|
|
3321
|
+
text = applyEdit(text, e);
|
|
3322
|
+
} else {
|
|
3323
|
+
throw new Error("Overlapping edit");
|
|
3324
|
+
}
|
|
3325
|
+
lastModifiedOffset = e.offset;
|
|
3326
|
+
}
|
|
3327
|
+
return text;
|
|
3328
|
+
}
|
|
1705
3329
|
|
|
1706
|
-
// src/installer/
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
3330
|
+
// src/installer/jsonc-edit.js
|
|
3331
|
+
var JsoncEditError = class extends Error {
|
|
3332
|
+
constructor(message, path) {
|
|
3333
|
+
super(`${message} (path=${path ?? "<root>"})`);
|
|
3334
|
+
this.name = "JsoncEditError";
|
|
3335
|
+
this.path = path ?? null;
|
|
3336
|
+
}
|
|
3337
|
+
};
|
|
3338
|
+
function pointerToPath(pointer) {
|
|
3339
|
+
if (typeof pointer !== "string" || pointer.length === 0) return [];
|
|
3340
|
+
return pointer.split("/").slice(1).map(decodePointerToken);
|
|
3341
|
+
}
|
|
3342
|
+
function decodePointerToken(token) {
|
|
3343
|
+
return token.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
3344
|
+
}
|
|
3345
|
+
function applyJsoncEdits(source, edits) {
|
|
3346
|
+
if (typeof source !== "string") {
|
|
3347
|
+
throw new JsoncEditError("source must be a string", null);
|
|
3348
|
+
}
|
|
3349
|
+
if (!Array.isArray(edits)) {
|
|
3350
|
+
throw new JsoncEditError("edits must be an array", null);
|
|
3351
|
+
}
|
|
3352
|
+
if (edits.length === 0) {
|
|
3353
|
+
return Buffer.from(source, "utf8");
|
|
3354
|
+
}
|
|
3355
|
+
const sorted = [...edits].sort((a, b) => {
|
|
3356
|
+
const da = a.pointer.split("/").length;
|
|
3357
|
+
const db = b.pointer.split("/").length;
|
|
3358
|
+
return da - db;
|
|
3359
|
+
});
|
|
3360
|
+
let working = source;
|
|
3361
|
+
for (const edit of sorted) {
|
|
3362
|
+
if (!edit || typeof edit.pointer !== "string" || !edit.pointer.startsWith("/")) {
|
|
3363
|
+
throw new JsoncEditError(`invalid pointer ${JSON.stringify(edit?.pointer)}`, edit?.pointer ?? null);
|
|
3364
|
+
}
|
|
3365
|
+
if (edit.op !== "set" && edit.op !== "delete") {
|
|
3366
|
+
throw new JsoncEditError(`invalid op ${edit.op}`, edit.pointer);
|
|
3367
|
+
}
|
|
3368
|
+
const path = pointerToPath(edit.pointer);
|
|
3369
|
+
const value = edit.op === "delete" ? void 0 : edit.value;
|
|
3370
|
+
let editOps;
|
|
3371
|
+
try {
|
|
3372
|
+
editOps = modify(working, path, value, {});
|
|
3373
|
+
} catch (err) {
|
|
3374
|
+
throw new JsoncEditError(`modify failed at ${edit.pointer}: ${err?.message ?? err}`, edit.pointer);
|
|
3375
|
+
}
|
|
3376
|
+
working = applyEdits(working, editOps);
|
|
3377
|
+
}
|
|
3378
|
+
const errors = [];
|
|
3379
|
+
parse2(working, errors, { allowTrailingComma: true });
|
|
3380
|
+
if (errors.length > 0) {
|
|
3381
|
+
throw new JsoncEditError(`result is not valid JSON: ${errors[0]?.error ?? errors[0]}`, null);
|
|
3382
|
+
}
|
|
3383
|
+
return Buffer.from(working, "utf8");
|
|
3384
|
+
}
|
|
3385
|
+
function diffPointers(before, after, pointers) {
|
|
3386
|
+
const edits = [];
|
|
3387
|
+
for (const pointer of pointers) {
|
|
3388
|
+
const prev = readPointer(before, pointer);
|
|
3389
|
+
const next = readPointer(after, pointer);
|
|
3390
|
+
if (next === void 0) {
|
|
3391
|
+
edits.push({ pointer, op: (
|
|
3392
|
+
/** @type {"delete"} */
|
|
3393
|
+
"delete"
|
|
3394
|
+
) });
|
|
3395
|
+
} else if (prev === void 0 || !stableJsonEqual(prev, next)) {
|
|
3396
|
+
edits.push({ pointer, value: next, op: (
|
|
3397
|
+
/** @type {"set"} */
|
|
3398
|
+
"set"
|
|
3399
|
+
) });
|
|
3400
|
+
}
|
|
3401
|
+
}
|
|
3402
|
+
return edits;
|
|
3403
|
+
}
|
|
3404
|
+
function readPointer(doc, pointer) {
|
|
3405
|
+
if (!doc || typeof doc !== "object") return void 0;
|
|
3406
|
+
const tokens = pointer.split("/").slice(1).map(decodePointerToken);
|
|
3407
|
+
let cursor = doc;
|
|
3408
|
+
for (const tok of tokens) {
|
|
3409
|
+
if (cursor === null || cursor === void 0) return void 0;
|
|
3410
|
+
cursor = cursor[tok];
|
|
3411
|
+
}
|
|
3412
|
+
return cursor === void 0 ? void 0 : cursor;
|
|
3413
|
+
}
|
|
3414
|
+
function stableJsonEqual(a, b) {
|
|
3415
|
+
return canonicalize(a) === canonicalize(b);
|
|
3416
|
+
}
|
|
3417
|
+
function canonicalize(value) {
|
|
3418
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
3419
|
+
if (Array.isArray(value)) return `[${value.map(canonicalize).join(",")}]`;
|
|
3420
|
+
const out = {};
|
|
3421
|
+
const keys = Object.keys(value).sort();
|
|
3422
|
+
for (const k of keys) out[k] = canonicalize(value[k]);
|
|
3423
|
+
return `{${keys.map((k) => `${JSON.stringify(k)}:${out[k]}`).join(",")}}`;
|
|
3424
|
+
}
|
|
1714
3425
|
|
|
1715
3426
|
// src/installer/root-reconciliation.js
|
|
1716
|
-
init_root_config();
|
|
1717
|
-
init_json_pointer();
|
|
1718
|
-
init_hash();
|
|
1719
|
-
init_plan_mode_permissions();
|
|
1720
|
-
import { existsSync as existsSync6 } from "node:fs";
|
|
1721
|
-
import { join } from "node:path";
|
|
1722
3427
|
function desiredPointersForProfile(profile) {
|
|
1723
|
-
return
|
|
1724
|
-
pointer: entry.pointer,
|
|
1725
|
-
strategy: (
|
|
1726
|
-
/** @type {"value" | "object-entry" | "array-member"} */
|
|
1727
|
-
entry.strategy
|
|
1728
|
-
),
|
|
1729
|
-
scope: (
|
|
1730
|
-
/** @type {Profile} */
|
|
1731
|
-
"engineering"
|
|
1732
|
-
),
|
|
1733
|
-
value: entry.value
|
|
1734
|
-
}));
|
|
3428
|
+
return matrixLeafPointers();
|
|
1735
3429
|
}
|
|
1736
3430
|
async function planRootReconciliation(input) {
|
|
1737
3431
|
const profile = input.profile;
|
|
@@ -1754,7 +3448,7 @@ async function planRootReconciliation(input) {
|
|
|
1754
3448
|
previousDocument: input.previousDocument
|
|
1755
3449
|
});
|
|
1756
3450
|
}
|
|
1757
|
-
const fileMissing = !
|
|
3451
|
+
const fileMissing = !existsSync7(target);
|
|
1758
3452
|
if (fileMissing && !input.forceRepair) {
|
|
1759
3453
|
if (mode === "profile-transition") {
|
|
1760
3454
|
return {
|
|
@@ -1780,6 +3474,9 @@ async function planRootReconciliation(input) {
|
|
|
1780
3474
|
let doc;
|
|
1781
3475
|
if (fileMissing && input.forceRepair) {
|
|
1782
3476
|
doc = synthesizeDefaultRootConfig();
|
|
3477
|
+
for (const descriptor of descriptors) {
|
|
3478
|
+
doc = setPointer(doc, descriptor.pointer, descriptor.value);
|
|
3479
|
+
}
|
|
1783
3480
|
const bytes = Buffer.from(formatRootConfig(doc), "utf8");
|
|
1784
3481
|
return {
|
|
1785
3482
|
kind: "create",
|
|
@@ -1842,7 +3539,22 @@ function reconcileRecordsAfterTransition(descriptors, previousRecords) {
|
|
|
1842
3539
|
return out;
|
|
1843
3540
|
}
|
|
1844
3541
|
function planInstallRoot({ doc, target, relPath, descriptors, previousRecords }) {
|
|
1845
|
-
const
|
|
3542
|
+
const promotion = promotePlanEditIfString(doc.value);
|
|
3543
|
+
if (promotion.record && promotion.record.conflict) {
|
|
3544
|
+
return {
|
|
3545
|
+
kind: "conflict",
|
|
3546
|
+
op: "root-config",
|
|
3547
|
+
target,
|
|
3548
|
+
relPath,
|
|
3549
|
+
reason: `consumer-owned Plan edit glob is set to deny: ${promotion.record.pointer}`,
|
|
3550
|
+
edits: [{ kind: "conflict", pointer: promotion.record.pointer, reason: "consumer-denied" }],
|
|
3551
|
+
pointerRecords: previousRecords,
|
|
3552
|
+
format: doc.format,
|
|
3553
|
+
document: doc.value
|
|
3554
|
+
};
|
|
3555
|
+
}
|
|
3556
|
+
const sourceDoc = promotion.doc;
|
|
3557
|
+
const result = applyOwnedPointers(sourceDoc, {
|
|
1846
3558
|
pointerEntries: descriptors.map((d) => ({ pointer: d.pointer, strategy: d.strategy, value: d.value })),
|
|
1847
3559
|
allowEqualValues: true
|
|
1848
3560
|
});
|
|
@@ -1852,21 +3564,65 @@ function planInstallRoot({ doc, target, relPath, descriptors, previousRecords })
|
|
|
1852
3564
|
if (s.reason === "already equal") continue;
|
|
1853
3565
|
edits.push({ kind: "conflict", pointer: s.pointer, reason: s.reason, existing: s.existing, desired: s.desired });
|
|
1854
3566
|
}
|
|
3567
|
+
const reorderPointers = equalExceptionsBeforeNewWildcard(sourceDoc, descriptors);
|
|
1855
3568
|
let docForWrite = result.doc;
|
|
3569
|
+
for (const descriptor of reorderPointers) {
|
|
3570
|
+
docForWrite = setPointer(removePointer(docForWrite, descriptor.pointer), descriptor.pointer, descriptor.value);
|
|
3571
|
+
}
|
|
1856
3572
|
let bytes;
|
|
1857
3573
|
try {
|
|
1858
|
-
const
|
|
1859
|
-
if (
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
docForWrite
|
|
3574
|
+
const isJsonc = doc.format === "jsonc";
|
|
3575
|
+
if (isJsonc) {
|
|
3576
|
+
const pointerEdits = diffPointers(
|
|
3577
|
+
doc.value,
|
|
3578
|
+
docForWrite,
|
|
3579
|
+
result.applied.map((a) => a.pointer)
|
|
3580
|
+
);
|
|
3581
|
+
for (const descriptor of reorderPointers) {
|
|
3582
|
+
pointerEdits.push({ pointer: descriptor.pointer, op: "delete" });
|
|
3583
|
+
pointerEdits.push({ pointer: descriptor.pointer, value: descriptor.value, op: "set" });
|
|
3584
|
+
}
|
|
3585
|
+
if (promotion.record) {
|
|
3586
|
+
pointerEdits.push({ pointer: promotion.record.pointer, op: (
|
|
3587
|
+
/** @type {"delete"} */
|
|
3588
|
+
"delete"
|
|
3589
|
+
) });
|
|
3590
|
+
pointerEdits.push({ pointer: promotion.record.pointer, value: promotion.record.previous.value, op: (
|
|
3591
|
+
/** @type {"set"} */
|
|
3592
|
+
"set"
|
|
3593
|
+
) });
|
|
3594
|
+
}
|
|
3595
|
+
bytes = applyJsoncEdits(doc.raw ?? "", pointerEdits);
|
|
3596
|
+
} else {
|
|
3597
|
+
const { value: sourceValue } = parseRootConfigPreservingOrder(doc.raw ?? "");
|
|
3598
|
+
if (sourceValue && typeof sourceValue === "object") {
|
|
3599
|
+
docForWrite = sourceValue;
|
|
3600
|
+
if (promotion.record) {
|
|
3601
|
+
docForWrite = setPointer(docForWrite, promotion.record.pointer, { "*": promotion.record.previous.value });
|
|
3602
|
+
}
|
|
3603
|
+
for (const a of result.applied) {
|
|
3604
|
+
docForWrite = setPointer(docForWrite, a.pointer, a.value);
|
|
3605
|
+
}
|
|
3606
|
+
for (const descriptor of reorderPointers) {
|
|
3607
|
+
docForWrite = setPointer(removePointer(docForWrite, descriptor.pointer), descriptor.pointer, descriptor.value);
|
|
3608
|
+
}
|
|
1863
3609
|
}
|
|
3610
|
+
bytes = Buffer.from(formatRootConfigPreserving(docForWrite), "utf8");
|
|
1864
3611
|
}
|
|
1865
|
-
bytes = Buffer.from(formatRootConfigPreserving(docForWrite), "utf8");
|
|
1866
3612
|
} catch {
|
|
1867
3613
|
bytes = Buffer.from(formatRootConfig(result.doc), "utf8");
|
|
1868
3614
|
}
|
|
1869
3615
|
const records = mergePointerRecords(descriptors, previousRecords, result, doc.before);
|
|
3616
|
+
if (promotion.record) {
|
|
3617
|
+
records.push({
|
|
3618
|
+
pointer: promotion.record.pointer,
|
|
3619
|
+
strategy: "value",
|
|
3620
|
+
scope: "engineering",
|
|
3621
|
+
installedSha256: null,
|
|
3622
|
+
previous: promotion.record.previous,
|
|
3623
|
+
promotion: true
|
|
3624
|
+
});
|
|
3625
|
+
}
|
|
1870
3626
|
return {
|
|
1871
3627
|
kind: edits.some((e) => e.kind === "conflict") ? "conflict" : edits.length ? "update" : "noop",
|
|
1872
3628
|
op: "root-config",
|
|
@@ -1882,8 +3638,36 @@ function planInstallRoot({ doc, target, relPath, descriptors, previousRecords })
|
|
|
1882
3638
|
reason: edits.length === 0 ? "no installer-owned entries missing" : `apply ${result.applied.length} / skip ${result.skipped.length}`
|
|
1883
3639
|
};
|
|
1884
3640
|
}
|
|
3641
|
+
function equalExceptionsBeforeNewWildcard(doc, descriptors) {
|
|
3642
|
+
const wildcardParents = /* @__PURE__ */ new Set();
|
|
3643
|
+
for (const descriptor of descriptors) {
|
|
3644
|
+
if (!descriptor.pointer.endsWith("/*") || getPointer(doc, descriptor.pointer) !== void 0) continue;
|
|
3645
|
+
wildcardParents.add(descriptor.pointer.slice(0, descriptor.pointer.lastIndexOf("/")));
|
|
3646
|
+
}
|
|
3647
|
+
return descriptors.filter((descriptor) => {
|
|
3648
|
+
if (descriptor.pointer.endsWith("/*")) return false;
|
|
3649
|
+
const parent = descriptor.pointer.slice(0, descriptor.pointer.lastIndexOf("/"));
|
|
3650
|
+
if (!wildcardParents.has(parent)) return false;
|
|
3651
|
+
const existing = getPointer(doc, descriptor.pointer);
|
|
3652
|
+
return existing !== void 0 && stableStringify(existing) === stableStringify(descriptor.value);
|
|
3653
|
+
});
|
|
3654
|
+
}
|
|
1885
3655
|
function planProfileTransitionRoot({ doc, target, relPath, descriptors, previousRecords }) {
|
|
1886
3656
|
const desired = descriptors;
|
|
3657
|
+
const promotion = promotePlanEditIfString(doc.value);
|
|
3658
|
+
if (promotion.record && promotion.record.conflict) {
|
|
3659
|
+
return {
|
|
3660
|
+
kind: "conflict",
|
|
3661
|
+
op: "root-config",
|
|
3662
|
+
target,
|
|
3663
|
+
relPath,
|
|
3664
|
+
reason: `consumer-owned Plan edit glob is set to deny: ${promotion.record.pointer}`,
|
|
3665
|
+
edits: [{ kind: "conflict", pointer: promotion.record.pointer, reason: "consumer-denied" }],
|
|
3666
|
+
pointerRecords: previousRecords,
|
|
3667
|
+
format: doc.format,
|
|
3668
|
+
document: doc.value
|
|
3669
|
+
};
|
|
3670
|
+
}
|
|
1887
3671
|
const drift = [];
|
|
1888
3672
|
for (const rec of previousRecords) {
|
|
1889
3673
|
const stillDesired = desired.some((d) => d.pointer === rec.pointer && d.scope === rec.scope);
|
|
@@ -1909,7 +3693,7 @@ function planProfileTransitionRoot({ doc, target, relPath, descriptors, previous
|
|
|
1909
3693
|
pointerRecords: previousRecords
|
|
1910
3694
|
};
|
|
1911
3695
|
}
|
|
1912
|
-
let next = JSON.parse(JSON.stringify(doc
|
|
3696
|
+
let next = JSON.parse(JSON.stringify(promotion.doc));
|
|
1913
3697
|
const edits = [];
|
|
1914
3698
|
const mergedRecords = previousRecords.map((r) => ({ ...r }));
|
|
1915
3699
|
const recordIndex = new Map(mergedRecords.map((r, idx) => [r.pointer, idx]));
|
|
@@ -1983,22 +3767,68 @@ function planProfileTransitionRoot({ doc, target, relPath, descriptors, previous
|
|
|
1983
3767
|
let docForWrite = next;
|
|
1984
3768
|
let bytes;
|
|
1985
3769
|
try {
|
|
1986
|
-
const
|
|
1987
|
-
if (
|
|
1988
|
-
|
|
3770
|
+
const isJsonc = doc.format === "jsonc";
|
|
3771
|
+
if (isJsonc) {
|
|
3772
|
+
const pointerEdits = [];
|
|
1989
3773
|
for (const e of edits) {
|
|
1990
3774
|
if (e.kind === "create" || e.kind === "restore") {
|
|
1991
|
-
|
|
3775
|
+
pointerEdits.push({ pointer: e.pointer, value: e.value, op: (
|
|
3776
|
+
/** @type {"set"} */
|
|
3777
|
+
"set"
|
|
3778
|
+
) });
|
|
1992
3779
|
} else if (e.kind === "remove") {
|
|
1993
|
-
|
|
3780
|
+
pointerEdits.push({ pointer: e.pointer, op: (
|
|
3781
|
+
/** @type {"delete"} */
|
|
3782
|
+
"delete"
|
|
3783
|
+
) });
|
|
3784
|
+
}
|
|
3785
|
+
}
|
|
3786
|
+
if (promotion.record) {
|
|
3787
|
+
pointerEdits.push({ pointer: promotion.record.pointer, op: (
|
|
3788
|
+
/** @type {"delete"} */
|
|
3789
|
+
"delete"
|
|
3790
|
+
) });
|
|
3791
|
+
pointerEdits.push({ pointer: promotion.record.pointer, value: promotion.record.previous.value, op: (
|
|
3792
|
+
/** @type {"set"} */
|
|
3793
|
+
"set"
|
|
3794
|
+
) });
|
|
3795
|
+
}
|
|
3796
|
+
bytes = applyJsoncEdits(doc.raw ?? "", pointerEdits);
|
|
3797
|
+
const reparsed = parse2(bytes.toString("utf8"), void 0, { allowTrailingComma: true });
|
|
3798
|
+
docForWrite = collapseEmptyAncestors(reparsed) ?? reparsed;
|
|
3799
|
+
} else {
|
|
3800
|
+
const { value: sourceValue } = parseRootConfigPreservingOrder(doc.raw ?? "");
|
|
3801
|
+
if (sourceValue && typeof sourceValue === "object") {
|
|
3802
|
+
docForWrite = sourceValue;
|
|
3803
|
+
if (promotion.record) {
|
|
3804
|
+
docForWrite = setPointer(docForWrite, promotion.record.pointer, { "*": promotion.record.previous.value });
|
|
3805
|
+
}
|
|
3806
|
+
for (const e of edits) {
|
|
3807
|
+
if (e.kind === "create" || e.kind === "restore") {
|
|
3808
|
+
docForWrite = setPointer(docForWrite, e.pointer, e.value);
|
|
3809
|
+
} else if (e.kind === "remove") {
|
|
3810
|
+
docForWrite = removePointer(docForWrite, e.pointer);
|
|
3811
|
+
}
|
|
1994
3812
|
}
|
|
1995
3813
|
}
|
|
3814
|
+
docForWrite = collapseEmptyAncestors(docForWrite) ?? docForWrite;
|
|
3815
|
+
bytes = Buffer.from(formatRootConfigPreserving(docForWrite), "utf8");
|
|
1996
3816
|
}
|
|
1997
|
-
docForWrite = collapseEmptyAncestors(docForWrite) ?? docForWrite;
|
|
1998
|
-
bytes = Buffer.from(formatRootConfigPreserving(docForWrite), "utf8");
|
|
1999
3817
|
} catch {
|
|
2000
3818
|
bytes = Buffer.from(formatRootConfig(collapseEmptyAncestors(next) ?? next), "utf8");
|
|
2001
3819
|
}
|
|
3820
|
+
if (promotion.record) {
|
|
3821
|
+
if (!recordIndex.has(promotion.record.pointer)) {
|
|
3822
|
+
mergedRecords.push({
|
|
3823
|
+
pointer: promotion.record.pointer,
|
|
3824
|
+
strategy: "value",
|
|
3825
|
+
scope: "engineering",
|
|
3826
|
+
installedSha256: null,
|
|
3827
|
+
previous: promotion.record.previous,
|
|
3828
|
+
promotion: true
|
|
3829
|
+
});
|
|
3830
|
+
}
|
|
3831
|
+
}
|
|
2002
3832
|
return {
|
|
2003
3833
|
kind: edits.some((e) => e.kind === "conflict") ? "conflict" : edits.some((e) => e.kind === "create" || e.kind === "remove" || e.kind === "restore") ? "update" : "noop",
|
|
2004
3834
|
op: "root-config",
|
|
@@ -2061,7 +3891,10 @@ function planUninstallRoot({ target, relPath, previousRecords, previousDocument
|
|
|
2061
3891
|
}
|
|
2062
3892
|
let doc = docResult.value;
|
|
2063
3893
|
const edits = [];
|
|
2064
|
-
|
|
3894
|
+
const sortedRecords = [...previousRecords].sort((a, b) => {
|
|
3895
|
+
return b.pointer.split("/").length - a.pointer.split("/").length;
|
|
3896
|
+
});
|
|
3897
|
+
for (const rec of sortedRecords) {
|
|
2065
3898
|
if (rec.previous && rec.previous.existed) {
|
|
2066
3899
|
doc = setPointer(doc, rec.pointer, rec.previous.value);
|
|
2067
3900
|
edits.push({ kind: "restore", pointer: rec.pointer, value: rec.previous.value });
|
|
@@ -2076,19 +3909,56 @@ function planUninstallRoot({ target, relPath, previousRecords, previousDocument
|
|
|
2076
3909
|
let docForWrite = doc;
|
|
2077
3910
|
let bytes;
|
|
2078
3911
|
try {
|
|
2079
|
-
const
|
|
2080
|
-
if (
|
|
2081
|
-
|
|
3912
|
+
const isJsonc = docResult.format === "jsonc";
|
|
3913
|
+
if (isJsonc) {
|
|
3914
|
+
const collapsed = collapseEmptyAncestors(doc) ?? doc;
|
|
3915
|
+
const prunePointers = /* @__PURE__ */ new Set();
|
|
3916
|
+
for (const e of edits) {
|
|
3917
|
+
if (e.kind !== "remove") continue;
|
|
3918
|
+
const tokens = e.pointer.split("/").slice(1);
|
|
3919
|
+
for (let i = tokens.length - 1; i > 0; i--) {
|
|
3920
|
+
const ancestor = `/${tokens.slice(0, i).join("/")}`;
|
|
3921
|
+
if (getPointer(collapsed, ancestor) === void 0) prunePointers.add(ancestor);
|
|
3922
|
+
}
|
|
3923
|
+
}
|
|
3924
|
+
const topPrunes = [...prunePointers].sort((a, b) => a.length - b.length).filter((pointer, index, all) => !all.slice(0, index).some((parent) => pointer.startsWith(`${parent}/`)));
|
|
3925
|
+
const pointerEdits = [];
|
|
2082
3926
|
for (const e of edits) {
|
|
2083
3927
|
if (e.kind === "restore") {
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
3928
|
+
pointerEdits.push({ pointer: e.pointer, value: e.value, op: (
|
|
3929
|
+
/** @type {"set"} */
|
|
3930
|
+
"set"
|
|
3931
|
+
) });
|
|
3932
|
+
} else if (e.kind === "remove" && !topPrunes.some((parent) => e.pointer === parent || e.pointer.startsWith(`${parent}/`))) {
|
|
3933
|
+
pointerEdits.push({ pointer: e.pointer, op: (
|
|
3934
|
+
/** @type {"delete"} */
|
|
3935
|
+
"delete"
|
|
3936
|
+
) });
|
|
3937
|
+
}
|
|
3938
|
+
}
|
|
3939
|
+
for (const pointer of topPrunes) {
|
|
3940
|
+
pointerEdits.push({ pointer, op: (
|
|
3941
|
+
/** @type {"delete"} */
|
|
3942
|
+
"delete"
|
|
3943
|
+
) });
|
|
3944
|
+
}
|
|
3945
|
+
bytes = applyJsoncEdits(docResult.raw ?? "", pointerEdits);
|
|
3946
|
+
docForWrite = parse2(bytes.toString("utf8"), void 0, { allowTrailingComma: true });
|
|
3947
|
+
} else {
|
|
3948
|
+
const { value: sourceValue } = parseRootConfigPreservingOrder(docResult.raw ?? "");
|
|
3949
|
+
if (sourceValue && typeof sourceValue === "object") {
|
|
3950
|
+
docForWrite = sourceValue;
|
|
3951
|
+
for (const e of edits) {
|
|
3952
|
+
if (e.kind === "restore") {
|
|
3953
|
+
docForWrite = setPointer(docForWrite, e.pointer, e.value);
|
|
3954
|
+
} else if (e.kind === "remove") {
|
|
3955
|
+
docForWrite = removePointer(docForWrite, e.pointer);
|
|
3956
|
+
}
|
|
2087
3957
|
}
|
|
2088
3958
|
}
|
|
3959
|
+
docForWrite = collapseEmptyAncestors(docForWrite) ?? docForWrite;
|
|
3960
|
+
bytes = Buffer.from(formatRootConfigPreserving(docForWrite), "utf8");
|
|
2089
3961
|
}
|
|
2090
|
-
docForWrite = collapseEmptyAncestors(docForWrite);
|
|
2091
|
-
bytes = Buffer.from(formatRootConfigPreserving(docForWrite), "utf8");
|
|
2092
3962
|
} catch {
|
|
2093
3963
|
bytes = Buffer.from(formatRootConfig(collapseEmptyAncestors(doc)), "utf8");
|
|
2094
3964
|
}
|
|
@@ -2112,7 +3982,9 @@ function collapseEmptyAncestors(doc) {
|
|
|
2112
3982
|
const out = {};
|
|
2113
3983
|
for (const k of Object.keys(doc)) {
|
|
2114
3984
|
if (k === "__sourceOrder__") continue;
|
|
2115
|
-
|
|
3985
|
+
const collapsed = collapseEmptyAncestors(doc[k]);
|
|
3986
|
+
if (collapsed === void 0) continue;
|
|
3987
|
+
out[k] = collapsed;
|
|
2116
3988
|
}
|
|
2117
3989
|
if (Array.isArray(doc.__sourceOrder__)) {
|
|
2118
3990
|
out.__sourceOrder__ = doc.__sourceOrder__.filter((k) => k in out);
|
|
@@ -2165,6 +4037,7 @@ function mergePointerRecords(descriptors, previousRecords, result, beforeSnapsho
|
|
|
2165
4037
|
};
|
|
2166
4038
|
} else {
|
|
2167
4039
|
out.push(next);
|
|
4040
|
+
index.set(a.pointer, out.length - 1);
|
|
2168
4041
|
}
|
|
2169
4042
|
}
|
|
2170
4043
|
for (const s of result.skipped) {
|
|
@@ -2179,20 +4052,21 @@ function mergePointerRecords(descriptors, previousRecords, result, beforeSnapsho
|
|
|
2179
4052
|
installedSha256: bytesHashString(stableStringify(existing ?? null)),
|
|
2180
4053
|
previous
|
|
2181
4054
|
});
|
|
4055
|
+
index.set(s.pointer, out.length - 1);
|
|
2182
4056
|
}
|
|
2183
4057
|
return out;
|
|
2184
4058
|
}
|
|
2185
4059
|
|
|
2186
4060
|
// src/installer/planner.js
|
|
2187
4061
|
async function readBytes(path) {
|
|
2188
|
-
if (!
|
|
2189
|
-
const buf = await
|
|
4062
|
+
if (!existsSync8(path)) return null;
|
|
4063
|
+
const buf = await readFile4(path);
|
|
2190
4064
|
const fileStat = await stat(path);
|
|
2191
4065
|
return { bytes: buf, hash: bytesHashString(buf.toString("utf8")), mode: fileStat.mode & 511 };
|
|
2192
4066
|
}
|
|
2193
4067
|
async function readDesiredBytes(source) {
|
|
2194
|
-
if (!source || !
|
|
2195
|
-
const buf = await
|
|
4068
|
+
if (!source || !existsSync8(source)) return null;
|
|
4069
|
+
const buf = await readFile4(source);
|
|
2196
4070
|
return { bytes: buf, hash: bytesHashString(buf.toString("utf8")) };
|
|
2197
4071
|
}
|
|
2198
4072
|
function lookupLockedFile(lock, targetPath) {
|
|
@@ -2332,6 +4206,16 @@ async function planUninstall({ repoRoot, lock }) {
|
|
|
2332
4206
|
const plan = [];
|
|
2333
4207
|
const activeProfile = lock?.manager?.profile ?? "core";
|
|
2334
4208
|
for (const entry of lock.files ?? []) {
|
|
4209
|
+
if (!isSafeManagedPath(entry?.path)) {
|
|
4210
|
+
plan.push({
|
|
4211
|
+
kind: "conflict",
|
|
4212
|
+
op: "file",
|
|
4213
|
+
target: repoRoot,
|
|
4214
|
+
relPath: entry?.path ?? null,
|
|
4215
|
+
reason: "managed file path is unsafe; refusing filesystem access"
|
|
4216
|
+
});
|
|
4217
|
+
continue;
|
|
4218
|
+
}
|
|
2335
4219
|
const targetPath = `${repoRoot}/${entry.path}`;
|
|
2336
4220
|
const current = await readBytes(targetPath);
|
|
2337
4221
|
if (!current) continue;
|
|
@@ -3326,7 +5210,7 @@ async function assembleLock({ repoRoot, plan, lock, configPlan, rootPlan, profil
|
|
|
3326
5210
|
manager: {
|
|
3327
5211
|
schemaVersion: CURRENT_LOCK_SCHEMA,
|
|
3328
5212
|
name: "opencode-ship",
|
|
3329
|
-
version: "1.1.2
|
|
5213
|
+
version: "1.1.2",
|
|
3330
5214
|
templateSet: TEMPLATE_SET_ID,
|
|
3331
5215
|
profile: resolvedProfile,
|
|
3332
5216
|
appliedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -3345,7 +5229,7 @@ async function assembleLock({ repoRoot, plan, lock, configPlan, rootPlan, profil
|
|
|
3345
5229
|
files
|
|
3346
5230
|
};
|
|
3347
5231
|
}
|
|
3348
|
-
async function commitInstall(preview, { json, command, fullSetupComplete = false }) {
|
|
5232
|
+
async function commitInstall(preview, { json, command, fullSetupComplete = false, transactionEntries = [] }) {
|
|
3349
5233
|
if (!preview.ok) {
|
|
3350
5234
|
return {
|
|
3351
5235
|
ok: false,
|
|
@@ -3405,6 +5289,7 @@ async function commitInstall(preview, { json, command, fullSetupComplete = false
|
|
|
3405
5289
|
relPath: rootPlan.relPath
|
|
3406
5290
|
});
|
|
3407
5291
|
}
|
|
5292
|
+
txPlan.push(...transactionEntries);
|
|
3408
5293
|
const tx = await executePlan({
|
|
3409
5294
|
repoRoot,
|
|
3410
5295
|
plan: txPlan,
|
|
@@ -3474,12 +5359,12 @@ function relativeTemplate(source) {
|
|
|
3474
5359
|
// src/installer/commands/doctor.js
|
|
3475
5360
|
init_lock();
|
|
3476
5361
|
init_config();
|
|
3477
|
-
import { existsSync as
|
|
5362
|
+
import { existsSync as existsSync15, readFileSync as readFileSync5 } from "node:fs";
|
|
3478
5363
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
3479
5364
|
init_hash();
|
|
3480
5365
|
init_catalog();
|
|
3481
5366
|
init_root_config();
|
|
3482
|
-
import { resolve as
|
|
5367
|
+
import { resolve as resolve14 } from "node:path";
|
|
3483
5368
|
|
|
3484
5369
|
// src/installer/report.js
|
|
3485
5370
|
var REPORT_VERSION = 1;
|
|
@@ -3568,9 +5453,9 @@ function checkPackageIntegrity() {
|
|
|
3568
5453
|
function buildSourceHashIndex() {
|
|
3569
5454
|
const idx = /* @__PURE__ */ new Map();
|
|
3570
5455
|
for (const entry of CATALOG) {
|
|
3571
|
-
if (!
|
|
5456
|
+
if (!existsSync15(entry.source)) continue;
|
|
3572
5457
|
try {
|
|
3573
|
-
const buf =
|
|
5458
|
+
const buf = readFileSync5(entry.source, "utf8");
|
|
3574
5459
|
idx.set(entry.source, bytesHashString(buf));
|
|
3575
5460
|
} catch {
|
|
3576
5461
|
}
|
|
@@ -3581,13 +5466,13 @@ async function checkCatalogInstall(repoRoot, sourceHashes, profile, renderedAgen
|
|
|
3581
5466
|
const rows = [];
|
|
3582
5467
|
const scoped = profile ? filterCatalogByProfile(CATALOG, profile) : CATALOG;
|
|
3583
5468
|
for (const entry of scoped) {
|
|
3584
|
-
const target =
|
|
3585
|
-
if (!
|
|
5469
|
+
const target = resolve14(repoRoot, entry.path);
|
|
5470
|
+
if (!existsSync15(target)) {
|
|
3586
5471
|
rows.push(`${entry.id}: missing`);
|
|
3587
5472
|
continue;
|
|
3588
5473
|
}
|
|
3589
5474
|
try {
|
|
3590
|
-
const buf =
|
|
5475
|
+
const buf = readFileSync5(target, "utf8");
|
|
3591
5476
|
const actual = bytesHashString(buf);
|
|
3592
5477
|
const rendered = renderedAgentMap.get(entry.path);
|
|
3593
5478
|
const expected = rendered ? rendered.sha256 : sourceHashes.get(entry.source);
|
|
@@ -3643,12 +5528,12 @@ async function checkManagedHashes(repoRoot, validatedLock) {
|
|
|
3643
5528
|
const drift = [];
|
|
3644
5529
|
const renderedAgents = await loadRenderedAgentOverrides(repoRoot);
|
|
3645
5530
|
for (const entry of validatedLock.lock.files ?? []) {
|
|
3646
|
-
const p =
|
|
3647
|
-
if (!
|
|
5531
|
+
const p = resolve14(repoRoot, entry.path);
|
|
5532
|
+
if (!existsSync15(p)) {
|
|
3648
5533
|
drift.push(`missing:${entry.path}`);
|
|
3649
5534
|
continue;
|
|
3650
5535
|
}
|
|
3651
|
-
const buf =
|
|
5536
|
+
const buf = readFileSync5(p, "utf8");
|
|
3652
5537
|
const actual = bytesHashString(buf);
|
|
3653
5538
|
if (actual !== entry.sha256) drift.push(`drift:${entry.path}`);
|
|
3654
5539
|
}
|
|
@@ -3781,7 +5666,28 @@ async function runDoctor({ rootPath, profile, json, writeOutput = true }) {
|
|
|
3781
5666
|
// src/installer/commands/init.js
|
|
3782
5667
|
init_catalog();
|
|
3783
5668
|
init_config();
|
|
3784
|
-
|
|
5669
|
+
|
|
5670
|
+
// src/installer/setup-pending.js
|
|
5671
|
+
import { existsSync as existsSync16, readFileSync as readFileSync6, unlinkSync, writeFile as writeFile7, mkdir as mkdirAsync } from "node:fs";
|
|
5672
|
+
import { promisify } from "node:util";
|
|
5673
|
+
import { resolve as resolve15, dirname as dirname9 } from "node:path";
|
|
5674
|
+
var writeFileAsync = promisify(writeFile7);
|
|
5675
|
+
var mkdirAsyncAsync = promisify(mkdirAsync);
|
|
5676
|
+
var REL_PATH = ".opencode/ship.setup-pending.json";
|
|
5677
|
+
function setupPendingPath(repoRoot) {
|
|
5678
|
+
return resolve15(repoRoot, REL_PATH);
|
|
5679
|
+
}
|
|
5680
|
+
function isSetupPending(repoRoot) {
|
|
5681
|
+
return existsSync16(setupPendingPath(repoRoot));
|
|
5682
|
+
}
|
|
5683
|
+
async function writeSetupPending(repoRoot, payload) {
|
|
5684
|
+
const path = setupPendingPath(repoRoot);
|
|
5685
|
+
await mkdirAsyncAsync(dirname9(path), { recursive: true });
|
|
5686
|
+
await writeFileAsync(path, JSON.stringify(payload, null, 2) + "\n", "utf8");
|
|
5687
|
+
}
|
|
5688
|
+
var SETUP_PENDING_REL_PATH2 = REL_PATH;
|
|
5689
|
+
|
|
5690
|
+
// src/installer/commands/init.js
|
|
3785
5691
|
var writeFileAsync2 = promisify2(writeFile8);
|
|
3786
5692
|
var mkdirAsyncAsync2 = promisify2(mkdirAsync2);
|
|
3787
5693
|
async function runInit(options) {
|
|
@@ -4046,7 +5952,6 @@ async function runDiff(options) {
|
|
|
4046
5952
|
|
|
4047
5953
|
// src/installer/commands/update.js
|
|
4048
5954
|
init_catalog();
|
|
4049
|
-
init_setup_pending();
|
|
4050
5955
|
async function runUpdate(options) {
|
|
4051
5956
|
try {
|
|
4052
5957
|
validateCatalog();
|
|
@@ -4124,7 +6029,6 @@ function emitFailure2(code, message, json, command) {
|
|
|
4124
6029
|
// src/installer/commands/setup-complete.js
|
|
4125
6030
|
init_config();
|
|
4126
6031
|
init_setup_state();
|
|
4127
|
-
init_setup_pending();
|
|
4128
6032
|
import { existsSync as existsSync17 } from "node:fs";
|
|
4129
6033
|
import { resolve as resolve16 } from "node:path";
|
|
4130
6034
|
async function runSetupComplete(options) {
|
|
@@ -4132,7 +6036,6 @@ async function runSetupComplete(options) {
|
|
|
4132
6036
|
if (!existsSync17(resolve16(repoRoot, ".git"))) {
|
|
4133
6037
|
return emitFailure3(2, "not a git repository", options.json);
|
|
4134
6038
|
}
|
|
4135
|
-
clearSetupPending(repoRoot);
|
|
4136
6039
|
const config = await loadConfig(repoRoot);
|
|
4137
6040
|
const configValue = config?.ok ? config.value : null;
|
|
4138
6041
|
const state = await setupComplete(repoRoot, configValue);
|
|
@@ -4145,6 +6048,7 @@ async function runSetupComplete(options) {
|
|
|
4145
6048
|
if (!state.ok) {
|
|
4146
6049
|
return emitFailure3(6, `setup incomplete: ${diagnostics.join("; ")}`, options.json, { state });
|
|
4147
6050
|
}
|
|
6051
|
+
const markerWasPresent = isSetupPending(repoRoot);
|
|
4148
6052
|
const preview = await previewInstall({
|
|
4149
6053
|
rootPath: repoRoot,
|
|
4150
6054
|
profile: "engineering",
|
|
@@ -4161,7 +6065,14 @@ async function runSetupComplete(options) {
|
|
|
4161
6065
|
const committed = await commitInstall(preview, {
|
|
4162
6066
|
json: options.json,
|
|
4163
6067
|
command: "setup-complete",
|
|
4164
|
-
fullSetupComplete: true
|
|
6068
|
+
fullSetupComplete: true,
|
|
6069
|
+
transactionEntries: markerWasPresent ? [{
|
|
6070
|
+
op: "file",
|
|
6071
|
+
kind: "delete",
|
|
6072
|
+
target: setupPendingPath(repoRoot),
|
|
6073
|
+
relPath: SETUP_PENDING_REL_PATH2,
|
|
6074
|
+
reason: "clear setup-pending marker in the setup-complete transaction"
|
|
6075
|
+
}] : []
|
|
4165
6076
|
});
|
|
4166
6077
|
if (committed.extra?.exitCode !== 0) {
|
|
4167
6078
|
return emitFailure3(committed.extra?.exitCode ?? 1, "commit failed", options.json, { committed });
|
|
@@ -4172,6 +6083,7 @@ async function runSetupComplete(options) {
|
|
|
4172
6083
|
command: "setup-complete",
|
|
4173
6084
|
status: "ok",
|
|
4174
6085
|
setupComplete: true,
|
|
6086
|
+
markerWasPresent,
|
|
4175
6087
|
requirements: SETUP_REQUIREMENTS,
|
|
4176
6088
|
plan: serializePlan(committed.plan ?? []),
|
|
4177
6089
|
summary: committed.summary ?? {},
|