@launchsecure/launch-kit 0.0.40 → 0.0.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chart-client/assets/index-Dd6IotOZ.css +1 -0
- package/dist/chart-client/index.html +2 -2
- package/dist/client/assets/index-DE0uje6k.css +32 -0
- package/dist/client/index.html +2 -2
- package/dist/council-client/assets/index-CGYusOCK.css +1 -0
- package/dist/council-client/assets/{index-B1v46vTE.js → index-DkTFX53U.js} +1 -1
- package/dist/council-client/index.html +2 -2
- package/dist/deck-client/assets/_baseUniq-mvYvzeEJ.js +1 -0
- package/dist/deck-client/assets/arc-CX4ylnp2.js +1 -0
- package/dist/deck-client/assets/architectureDiagram-Q4EWVU46-BkR-5IRK.js +36 -0
- package/dist/deck-client/assets/{blockDiagram-DXYQGD6D-CUdblaWk.js → blockDiagram-DXYQGD6D-DVNQht7c.js} +2 -2
- package/dist/deck-client/assets/{c4Diagram-AHTNJAMY-MfAO5lak.js → c4Diagram-AHTNJAMY-Cbq1rlG8.js} +2 -2
- package/dist/deck-client/assets/channel-B9GC-CLn.js +1 -0
- package/dist/deck-client/assets/chunk-4BX2VUAB-D58Co4lU.js +1 -0
- package/dist/deck-client/assets/{chunk-4TB4RGXK-BUJtZ7jO.js → chunk-4TB4RGXK-BYvhTm3d.js} +1 -1
- package/dist/deck-client/assets/chunk-55IACEB6-oWukUhYg.js +1 -0
- package/dist/deck-client/assets/chunk-EDXVE4YY-Cm58kVnZ.js +1 -0
- package/dist/deck-client/assets/{chunk-FMBD7UC4-PnZ9v6ey.js → chunk-FMBD7UC4-Dg-i7kzi.js} +1 -1
- package/dist/deck-client/assets/{chunk-OYMX7WX6-DXrWNOsV.js → chunk-OYMX7WX6-C72wigPl.js} +1 -1
- package/dist/deck-client/assets/chunk-QZHKN3VN-CLgeuAKw.js +1 -0
- package/dist/deck-client/assets/chunk-YZCP3GAM-HDDlJ5oI.js +1 -0
- package/dist/deck-client/assets/classDiagram-6PBFFD2Q-CFBvYQ9j.js +1 -0
- package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-CFBvYQ9j.js +1 -0
- package/dist/deck-client/assets/clone-n-WQlAGe.js +1 -0
- package/dist/deck-client/assets/cose-bilkent-S5V4N54A-CUXQKg2M.js +1 -0
- package/dist/deck-client/assets/dagre-KV5264BT-C5M-fVDc.js +4 -0
- package/dist/deck-client/assets/diagram-5BDNPKRD-CcVsQ0S8.js +10 -0
- package/dist/deck-client/assets/diagram-G4DWMVQ6-DJswXyep.js +24 -0
- package/dist/deck-client/assets/diagram-MMDJMWI5-CGT76fm1.js +43 -0
- package/dist/deck-client/assets/diagram-TYMM5635-BBsYUNN6.js +24 -0
- package/dist/deck-client/assets/{erDiagram-SMLLAGMA-56pn_93p.js → erDiagram-SMLLAGMA-DKWYEHQS.js} +2 -2
- package/dist/deck-client/assets/{flowDiagram-DWJPFMVM-BtV3M5xJ.js → flowDiagram-DWJPFMVM-DLuDYIKT.js} +2 -2
- package/dist/deck-client/assets/ganttDiagram-T4ZO3ILL-B19b6Qtj.js +292 -0
- package/dist/deck-client/assets/gitGraphDiagram-UUTBAWPF-BYLAfYVS.js +106 -0
- package/dist/deck-client/assets/graph-CfzQUfPh.js +1 -0
- package/dist/deck-client/assets/index-DlwdTgE_.js +892 -0
- package/dist/deck-client/assets/index-evAPhGvM.css +1 -0
- package/dist/deck-client/assets/infoDiagram-42DDH7IO-Dp3mUA9c.js +2 -0
- package/dist/deck-client/assets/{ishikawaDiagram-UXIWVN3A-DXYkdO3T.js → ishikawaDiagram-UXIWVN3A-BhrNX_jI.js} +5 -5
- package/dist/deck-client/assets/{journeyDiagram-VCZTEJTY-C2zBr-J5.js → journeyDiagram-VCZTEJTY-B5lJI492.js} +2 -2
- package/dist/deck-client/assets/{kanban-definition-6JOO6SKY-CdoYLS4Z.js → kanban-definition-6JOO6SKY-D9-lmhQf.js} +2 -2
- package/dist/deck-client/assets/layout-CfIe_Su8.js +1 -0
- package/dist/deck-client/assets/linear-09ZFRoh_.js +1 -0
- package/dist/deck-client/assets/mermaid.core-BaQyIOvj.js +309 -0
- package/dist/deck-client/assets/min-CYwCzYaL.js +1 -0
- package/dist/deck-client/assets/{mindmap-definition-QFDTVHPH-oAybLedr.js → mindmap-definition-QFDTVHPH-CouFxf6C.js} +2 -2
- package/dist/deck-client/assets/pieDiagram-DEJITSTG-DMB1ufC0.js +30 -0
- package/dist/deck-client/assets/{quadrantDiagram-34T5L4WZ-dtluDZXs.js → quadrantDiagram-34T5L4WZ-CBiOKudN.js} +2 -2
- package/dist/deck-client/assets/{requirementDiagram-MS252O5E-Cq8l7bOl.js → requirementDiagram-MS252O5E-BMc3GJkx.js} +2 -2
- package/dist/deck-client/assets/sankeyDiagram-XADWPNL6-CxACUncm.js +10 -0
- package/dist/deck-client/assets/{sequenceDiagram-FGHM5R23-CYkd7oQK.js → sequenceDiagram-FGHM5R23-Ch-P3Mzc.js} +2 -2
- package/dist/deck-client/assets/stateDiagram-FHFEXIEX-Cy8n7Yzk.js +1 -0
- package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-C14VKCzi.js +1 -0
- package/dist/deck-client/assets/{timeline-definition-GMOUNBTQ-DZIxSyd1.js → timeline-definition-GMOUNBTQ-C2V4sSkm.js} +2 -2
- package/dist/deck-client/assets/{vennDiagram-DHZGUBPP-Ct4JVRDM.js → vennDiagram-DHZGUBPP-YOqt4VbE.js} +2 -2
- package/dist/deck-client/assets/{wardley-RL74JXVD-V29ycxOW.js → wardley-RL74JXVD-Bxo5x40D.js} +3 -3
- package/dist/deck-client/assets/{wardleyDiagram-NUSXRM2D-D-Ua6Cmi.js → wardleyDiagram-NUSXRM2D-DW9SOqbx.js} +2 -2
- package/dist/deck-client/assets/{xychartDiagram-5P7HB3ND-BPCOuRVl.js → xychartDiagram-5P7HB3ND-D-rZvZOL.js} +2 -2
- package/dist/deck-client/index.html +2 -2
- package/dist/server/cli.js +488 -215
- package/dist/server/council-entry.js +7 -1
- package/dist/server/council-serve.js +7 -1
- package/dist/server/deck-mcp-entry.js +287 -49
- package/dist/server/deck-serve.js +258 -48
- package/dist/server/graph-mcp-entry.js +331 -37
- package/dist/server/init-entry.js +17 -7
- package/dist/server/rover-entry.js +1 -1
- package/package.json +1 -1
- package/scaffolds/ls-marketplace/plugins/kit/skills/comms/SKILL.md +34 -1
- package/scaffolds/ls-marketplace/plugins/kit/skills/gen-test/SKILL.md +126 -0
- package/dist/chart-client/assets/index-CWJFFDPu.css +0 -1
- package/dist/client/assets/index-CTzFcfGV.css +0 -32
- package/dist/council-client/assets/index-ArgRc5mN.css +0 -1
- package/dist/deck-client/assets/_baseUniq-BZP7n41F.js +0 -1
- package/dist/deck-client/assets/arc-31biU3Az.js +0 -1
- package/dist/deck-client/assets/architectureDiagram-Q4EWVU46-DHg6Ss--.js +0 -36
- package/dist/deck-client/assets/channel-BBkRLdnC.js +0 -1
- package/dist/deck-client/assets/chunk-4BX2VUAB-DQ1MrGgN.js +0 -1
- package/dist/deck-client/assets/chunk-55IACEB6-BdSnXB6g.js +0 -1
- package/dist/deck-client/assets/chunk-EDXVE4YY-94yZIUI8.js +0 -1
- package/dist/deck-client/assets/chunk-QZHKN3VN-CsIGIDKX.js +0 -1
- package/dist/deck-client/assets/chunk-YZCP3GAM-DVkBO9tn.js +0 -1
- package/dist/deck-client/assets/classDiagram-6PBFFD2Q-DFCaeF-7.js +0 -1
- package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-DFCaeF-7.js +0 -1
- package/dist/deck-client/assets/clone-GCEVRScB.js +0 -1
- package/dist/deck-client/assets/cose-bilkent-S5V4N54A-m126Oh3b.js +0 -1
- package/dist/deck-client/assets/dagre-KV5264BT-C2aig8U5.js +0 -4
- package/dist/deck-client/assets/diagram-5BDNPKRD-CKpoRfGn.js +0 -10
- package/dist/deck-client/assets/diagram-G4DWMVQ6-Cjh115Ep.js +0 -24
- package/dist/deck-client/assets/diagram-MMDJMWI5-DKlBv_2L.js +0 -43
- package/dist/deck-client/assets/diagram-TYMM5635-CdBh4cEn.js +0 -24
- package/dist/deck-client/assets/ganttDiagram-T4ZO3ILL-DTIsC6Zg.js +0 -292
- package/dist/deck-client/assets/gitGraphDiagram-UUTBAWPF-CJYeyCLe.js +0 -106
- package/dist/deck-client/assets/graph-BDvMu1Ss.js +0 -1
- package/dist/deck-client/assets/index-D4eSxcBn.css +0 -1
- package/dist/deck-client/assets/index-QnGVE9PZ.js +0 -1196
- package/dist/deck-client/assets/infoDiagram-42DDH7IO-BWyKJnpW.js +0 -2
- package/dist/deck-client/assets/layout-vOnxnCQU.js +0 -1
- package/dist/deck-client/assets/linear-B0J0WCGz.js +0 -1
- package/dist/deck-client/assets/min-B0AXlT9L.js +0 -1
- package/dist/deck-client/assets/pieDiagram-DEJITSTG-BjHyHxGk.js +0 -30
- package/dist/deck-client/assets/sankeyDiagram-XADWPNL6-C1Vih91z.js +0 -10
- package/dist/deck-client/assets/stateDiagram-FHFEXIEX-CtyG8wBK.js +0 -1
- package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-BLyKWfcN.js +0 -1
- /package/dist/chart-client/assets/{index-Dzlj-oCj.js → index-CrYM1-ac.js} +0 -0
- /package/dist/client/assets/{index-tTg_ezUF.js → index-BoIjawzY.js} +0 -0
package/dist/server/cli.js
CHANGED
|
@@ -23468,8 +23468,8 @@ function getQuery(name) {
|
|
|
23468
23468
|
ensureInit();
|
|
23469
23469
|
const cached = queryCache.get(name);
|
|
23470
23470
|
if (cached) return cached;
|
|
23471
|
-
const scmPath = (0,
|
|
23472
|
-
const scm = (0,
|
|
23471
|
+
const scmPath = (0, import_node_path22.join)(queriesDir, `${name}.scm`);
|
|
23472
|
+
const scm = (0, import_node_fs17.readFileSync)(scmPath, "utf-8");
|
|
23473
23473
|
const query = tsxLanguage.query(scm);
|
|
23474
23474
|
queryCache.set(name, query);
|
|
23475
23475
|
return query;
|
|
@@ -23489,13 +23489,13 @@ function parseSource(absPath) {
|
|
|
23489
23489
|
ensureInit();
|
|
23490
23490
|
let content;
|
|
23491
23491
|
try {
|
|
23492
|
-
const stat = (0,
|
|
23492
|
+
const stat = (0, import_node_fs17.statSync)(absPath);
|
|
23493
23493
|
if (stat.size > MAX_PARSEABLE_BYTES) {
|
|
23494
23494
|
process.stderr.write(`[lc-extractor] skipping ${absPath}: ${stat.size} bytes exceeds max ${MAX_PARSEABLE_BYTES}
|
|
23495
23495
|
`);
|
|
23496
23496
|
return null;
|
|
23497
23497
|
}
|
|
23498
|
-
content = (0,
|
|
23498
|
+
content = (0, import_node_fs17.readFileSync)(absPath, "utf-8");
|
|
23499
23499
|
} catch (e) {
|
|
23500
23500
|
process.stderr.write(`[lc-extractor] read failed for ${absPath}: ${e instanceof Error ? e.message : String(e)}
|
|
23501
23501
|
`);
|
|
@@ -24529,18 +24529,18 @@ function collectUiLabels(root) {
|
|
|
24529
24529
|
visit(root);
|
|
24530
24530
|
return out;
|
|
24531
24531
|
}
|
|
24532
|
-
var
|
|
24532
|
+
var import_node_fs17, import_node_path22, tsxLanguage, parserInstance, TreeSitterCtor, initPromise, initialized, queriesDir, queryCache, MAX_PARSEABLE_BYTES, MAX_CONSECUTIVE_PARSE_FAILURES, consecutiveParseFailures, ParseCascadeError, PRISMA_MUTATION_METHODS_BUILTIN, SUPABASE_MUTATION_METHODS_BUILTIN, DB_IDENTIFIERS_FALLBACK, extraDbIdentifiers, extraMutationMethods, INLINE_AUTH_IMPORTS, EXEMPT_NAME_PATTERNS, PROTECT_NAME_PATTERNS, TRUST_AS_PROTECT_KEYS, TIMER_FNS, DOM_METHOD_NAMES, CLASSLIST_METHODS, STORAGE_OBJECTS, HISTORY_METHODS, LOCATION_METHODS, ASSIGN_DOM_PROPS, UI_LABEL_KEYS, UI_LABELS_MAX, NOTE_REGEX, NOTES_MAX;
|
|
24533
24533
|
var init_ts_extractor = __esm({
|
|
24534
24534
|
"src/server/graph/core/ts-extractor.ts"() {
|
|
24535
24535
|
"use strict";
|
|
24536
|
-
|
|
24537
|
-
|
|
24536
|
+
import_node_fs17 = require("node:fs");
|
|
24537
|
+
import_node_path22 = require("node:path");
|
|
24538
24538
|
init_parse_failure_cache();
|
|
24539
24539
|
initialized = false;
|
|
24540
24540
|
queriesDir = (() => {
|
|
24541
|
-
const srcPath = (0,
|
|
24541
|
+
const srcPath = (0, import_node_path22.join)((0, import_node_path22.dirname)(__filename), "..", "queries");
|
|
24542
24542
|
if (require("fs").existsSync(srcPath)) return srcPath;
|
|
24543
|
-
return (0,
|
|
24543
|
+
return (0, import_node_path22.join)((0, import_node_path22.dirname)(__filename), "graph", "queries");
|
|
24544
24544
|
})();
|
|
24545
24545
|
queryCache = /* @__PURE__ */ new Map();
|
|
24546
24546
|
MAX_PARSEABLE_BYTES = 2 * 1024 * 1024;
|
|
@@ -24680,7 +24680,7 @@ __export(watcher_exports, {
|
|
|
24680
24680
|
function isIgnoredPath(rel) {
|
|
24681
24681
|
if (rel.startsWith(GRAPHS_RELATIVE)) return true;
|
|
24682
24682
|
if (rel.endsWith(".lock") || rel.endsWith(".log")) return true;
|
|
24683
|
-
for (const part of rel.split(
|
|
24683
|
+
for (const part of rel.split(import_node_path37.sep)) {
|
|
24684
24684
|
if (IGNORE_SEGMENTS.has(part)) return true;
|
|
24685
24685
|
}
|
|
24686
24686
|
return false;
|
|
@@ -24722,7 +24722,7 @@ function startGraphWatcher(rootDir, opts = {}) {
|
|
|
24722
24722
|
regenerating = false;
|
|
24723
24723
|
}
|
|
24724
24724
|
}
|
|
24725
|
-
const watcher = (0,
|
|
24725
|
+
const watcher = (0, import_node_fs29.watch)(rootDir, { recursive: true }, (event, filename) => {
|
|
24726
24726
|
if (!filename) return;
|
|
24727
24727
|
const rel = filename.toString();
|
|
24728
24728
|
if (process.env.LAUNCH_CHART_WATCH_TRACE === "1") {
|
|
@@ -24755,12 +24755,12 @@ function startGraphWatcher(rootDir, opts = {}) {
|
|
|
24755
24755
|
freshness: () => getFreshnessTracker(rootDir).get()
|
|
24756
24756
|
};
|
|
24757
24757
|
}
|
|
24758
|
-
var
|
|
24758
|
+
var import_node_fs29, import_node_path37, IGNORE_SEGMENTS, TRIGGER_EXTENSIONS, GRAPHS_RELATIVE;
|
|
24759
24759
|
var init_watcher = __esm({
|
|
24760
24760
|
"src/server/graph/core/watcher.ts"() {
|
|
24761
24761
|
"use strict";
|
|
24762
|
-
|
|
24763
|
-
|
|
24762
|
+
import_node_fs29 = require("node:fs");
|
|
24763
|
+
import_node_path37 = require("node:path");
|
|
24764
24764
|
init_launch_kit_paths();
|
|
24765
24765
|
init_graph();
|
|
24766
24766
|
init_freshness();
|
|
@@ -24789,7 +24789,7 @@ var init_watcher = __esm({
|
|
|
24789
24789
|
".prisma",
|
|
24790
24790
|
".sql"
|
|
24791
24791
|
]);
|
|
24792
|
-
GRAPHS_RELATIVE = (0,
|
|
24792
|
+
GRAPHS_RELATIVE = (0, import_node_path37.join)(LAUNCHSECURE_DIR, "graphs");
|
|
24793
24793
|
}
|
|
24794
24794
|
});
|
|
24795
24795
|
|
|
@@ -29771,8 +29771,8 @@ function streamTranscript(opts) {
|
|
|
29771
29771
|
}
|
|
29772
29772
|
|
|
29773
29773
|
// src/server/graph-mcp.ts
|
|
29774
|
-
var
|
|
29775
|
-
var
|
|
29774
|
+
var import_node_fs30 = require("node:fs");
|
|
29775
|
+
var import_node_path38 = require("node:path");
|
|
29776
29776
|
var import_node_child_process3 = require("node:child_process");
|
|
29777
29777
|
var import_node_os6 = require("node:os");
|
|
29778
29778
|
init_launch_kit_paths();
|
|
@@ -29811,31 +29811,209 @@ export const ${exportName} = {
|
|
|
29811
29811
|
return { exportName, code };
|
|
29812
29812
|
}
|
|
29813
29813
|
|
|
29814
|
+
// src/server/graph/core/context/snippet-registry.ts
|
|
29815
|
+
var import_node_fs13 = require("node:fs");
|
|
29816
|
+
var import_node_path17 = require("node:path");
|
|
29817
|
+
var DEFAULT_SNIPPETS_DIR = "tests/snippets";
|
|
29818
|
+
function parseStringArray(src, key) {
|
|
29819
|
+
const m = src.match(new RegExp(`${key}\\s*:\\s*\\[([^\\]]*)\\]`));
|
|
29820
|
+
if (!m) return [];
|
|
29821
|
+
return [...m[1].matchAll(/['"]([^'"]+)['"]/g)].map((x) => x[1]);
|
|
29822
|
+
}
|
|
29823
|
+
function parseSnippetFile(content, file) {
|
|
29824
|
+
const idM = content.match(/\bid\s*:\s*['"]([^'"]+)['"]/);
|
|
29825
|
+
if (!idM) return null;
|
|
29826
|
+
const exportM = content.match(/export\s+const\s+(\w+)/);
|
|
29827
|
+
return {
|
|
29828
|
+
id: idM[1],
|
|
29829
|
+
exportName: exportM ? exportM[1] : "default",
|
|
29830
|
+
file,
|
|
29831
|
+
requires: parseStringArray(content, "requires"),
|
|
29832
|
+
produces: parseStringArray(content, "produces"),
|
|
29833
|
+
params: parseStringArray(content, "params")
|
|
29834
|
+
};
|
|
29835
|
+
}
|
|
29836
|
+
function loadSnippetIndex(rootDir, snippetsDir = DEFAULT_SNIPPETS_DIR) {
|
|
29837
|
+
const dir = (0, import_node_path17.join)(rootDir, snippetsDir);
|
|
29838
|
+
const index = /* @__PURE__ */ new Map();
|
|
29839
|
+
if (!(0, import_node_fs13.existsSync)(dir)) return index;
|
|
29840
|
+
for (const f of (0, import_node_fs13.readdirSync)(dir)) {
|
|
29841
|
+
if (!f.endsWith(".ts") && !f.endsWith(".tsx")) continue;
|
|
29842
|
+
const full = (0, import_node_path17.join)(dir, f);
|
|
29843
|
+
try {
|
|
29844
|
+
if (!(0, import_node_fs13.statSync)(full).isFile()) continue;
|
|
29845
|
+
const entry = parseSnippetFile((0, import_node_fs13.readFileSync)(full, "utf-8"), (0, import_node_path17.join)(snippetsDir, f));
|
|
29846
|
+
if (entry) index.set(entry.id, entry);
|
|
29847
|
+
} catch {
|
|
29848
|
+
}
|
|
29849
|
+
}
|
|
29850
|
+
return index;
|
|
29851
|
+
}
|
|
29852
|
+
|
|
29853
|
+
// src/server/graph/core/context/test-plan.ts
|
|
29854
|
+
var stripState = (s) => s.replace(/^state:/, "");
|
|
29855
|
+
function buildTestPlan(graph, targetId, snippets) {
|
|
29856
|
+
const nodesById = /* @__PURE__ */ new Map();
|
|
29857
|
+
for (const n of graph.nodes) nodesById.set(n.id, n);
|
|
29858
|
+
const requiresOf = /* @__PURE__ */ new Map();
|
|
29859
|
+
const producesOf = /* @__PURE__ */ new Map();
|
|
29860
|
+
const producersOf = /* @__PURE__ */ new Map();
|
|
29861
|
+
for (const e of graph.edges) {
|
|
29862
|
+
if (e.type === "requires") {
|
|
29863
|
+
(requiresOf.get(e.source) ?? requiresOf.set(e.source, /* @__PURE__ */ new Set()).get(e.source)).add(e.target);
|
|
29864
|
+
} else if (e.type === "produces") {
|
|
29865
|
+
(producesOf.get(e.source) ?? producesOf.set(e.source, /* @__PURE__ */ new Set()).get(e.source)).add(e.target);
|
|
29866
|
+
(producersOf.get(e.target) ?? producersOf.set(e.target, /* @__PURE__ */ new Set()).get(e.target)).add(e.source);
|
|
29867
|
+
}
|
|
29868
|
+
}
|
|
29869
|
+
const pickProducer = (producers) => {
|
|
29870
|
+
const withSnippet = producers.filter((p) => snippets.has(p)).sort();
|
|
29871
|
+
return withSnippet.length ? withSnippet[0] : [...producers].sort()[0];
|
|
29872
|
+
};
|
|
29873
|
+
const order = [];
|
|
29874
|
+
const done = /* @__PURE__ */ new Set();
|
|
29875
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
29876
|
+
const gaps = [];
|
|
29877
|
+
const allRequired = /* @__PURE__ */ new Set();
|
|
29878
|
+
const visit = (actionId2) => {
|
|
29879
|
+
if (done.has(actionId2)) return;
|
|
29880
|
+
if (visiting.has(actionId2)) {
|
|
29881
|
+
gaps.push({ type: "cycle", action: actionId2, detail: `dependency cycle through ${actionId2}` });
|
|
29882
|
+
return;
|
|
29883
|
+
}
|
|
29884
|
+
visiting.add(actionId2);
|
|
29885
|
+
for (const state of requiresOf.get(actionId2) ?? []) {
|
|
29886
|
+
allRequired.add(state);
|
|
29887
|
+
const producers = [...producersOf.get(state) ?? []];
|
|
29888
|
+
if (producers.length === 0) {
|
|
29889
|
+
gaps.push({
|
|
29890
|
+
type: "no_producer",
|
|
29891
|
+
state: stripState(state),
|
|
29892
|
+
action: actionId2,
|
|
29893
|
+
detail: `${actionId2} requires "${stripState(state)}" but no action produces it`
|
|
29894
|
+
});
|
|
29895
|
+
continue;
|
|
29896
|
+
}
|
|
29897
|
+
visit(pickProducer(producers));
|
|
29898
|
+
}
|
|
29899
|
+
visiting.delete(actionId2);
|
|
29900
|
+
done.add(actionId2);
|
|
29901
|
+
order.push(actionId2);
|
|
29902
|
+
};
|
|
29903
|
+
visit(targetId);
|
|
29904
|
+
const steps = order.map((actionId2) => {
|
|
29905
|
+
const node = nodesById.get(actionId2);
|
|
29906
|
+
const entry = snippets.get(actionId2) ?? null;
|
|
29907
|
+
if (!entry) {
|
|
29908
|
+
gaps.push({
|
|
29909
|
+
type: "no_snippet",
|
|
29910
|
+
action: actionId2,
|
|
29911
|
+
detail: `no snippet bound to ${actionId2} \u2014 scaffold one with scaffold_snippet`
|
|
29912
|
+
});
|
|
29913
|
+
}
|
|
29914
|
+
const satisfies = [...producesOf.get(actionId2) ?? []].filter((s) => allRequired.has(s)).map(stripState).sort();
|
|
29915
|
+
return {
|
|
29916
|
+
action: actionId2,
|
|
29917
|
+
name: String(node?.name ?? actionId2),
|
|
29918
|
+
satisfies,
|
|
29919
|
+
snippet: entry ? { id: entry.id, exportName: entry.exportName, file: entry.file, params: entry.params } : null
|
|
29920
|
+
};
|
|
29921
|
+
});
|
|
29922
|
+
return { target: targetId, steps, gaps, runnable: gaps.length === 0 };
|
|
29923
|
+
}
|
|
29924
|
+
|
|
29925
|
+
// src/server/graph/core/context/spec-gen.ts
|
|
29926
|
+
var import_node_path18 = require("node:path");
|
|
29927
|
+
function toEnvRef(name) {
|
|
29928
|
+
return `process.env.${name.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toUpperCase()}`;
|
|
29929
|
+
}
|
|
29930
|
+
function classify(name) {
|
|
29931
|
+
const n = name.toLowerCase();
|
|
29932
|
+
if (/pass|secret|token|credential|apikey|api_key|_key$|^key$/.test(n)) return { kind: "secret" };
|
|
29933
|
+
if (/email|slug|(^|_)id$|uuid|userid|orgid|projectid/.test(n)) return { kind: "real" };
|
|
29934
|
+
if (/desc|summary|body|message|content|note/.test(n)) return { kind: "faker", faker: "faker.lorem.sentence()" };
|
|
29935
|
+
if (/colou?r/.test(n)) return { kind: "faker", faker: "faker.color.rgb({ format: 'hex' })" };
|
|
29936
|
+
if (/icon/.test(n)) return { kind: "faker", faker: "faker.helpers.arrayElement(['rocket','bug','star','flag','zap','heart'])" };
|
|
29937
|
+
if (/name|title|label/.test(n)) return { kind: "faker", faker: "faker.word.noun()" };
|
|
29938
|
+
if (/url|link|href/.test(n)) return { kind: "faker", faker: "faker.internet.url()" };
|
|
29939
|
+
if (/count|qty|quantity|amount|number|price/.test(n)) return { kind: "faker", faker: "String(faker.number.int({ min: 1, max: 100 }))" };
|
|
29940
|
+
return { kind: "faker", faker: "faker.lorem.word()" };
|
|
29941
|
+
}
|
|
29942
|
+
function relImport(specDir, file) {
|
|
29943
|
+
let r = (0, import_node_path18.relative)(specDir, file).replace(/\.tsx?$/, "");
|
|
29944
|
+
if (!r.startsWith(".")) r = `./${r}`;
|
|
29945
|
+
return r;
|
|
29946
|
+
}
|
|
29947
|
+
function generateSpec(plan, opts = {}) {
|
|
29948
|
+
const specDir = opts.specDir ?? "tests/generated";
|
|
29949
|
+
const fixtures = opts.fixtures ?? {};
|
|
29950
|
+
const missing = /* @__PURE__ */ new Set();
|
|
29951
|
+
let usesFaker = false;
|
|
29952
|
+
const bound = plan.steps.filter((s) => s.snippet);
|
|
29953
|
+
const unbound = plan.steps.filter((s) => !s.snippet);
|
|
29954
|
+
const importLines = /* @__PURE__ */ new Set();
|
|
29955
|
+
for (const s of bound) {
|
|
29956
|
+
importLines.add(`import { ${s.snippet.exportName} } from '${relImport(specDir, s.snippet.file)}';`);
|
|
29957
|
+
}
|
|
29958
|
+
const callLines = bound.map((s) => {
|
|
29959
|
+
const params = s.snippet.params.map((p) => {
|
|
29960
|
+
if (Object.prototype.hasOwnProperty.call(fixtures, p)) {
|
|
29961
|
+
return ` ${p}: ${JSON.stringify(fixtures[p])},`;
|
|
29962
|
+
}
|
|
29963
|
+
const c = classify(p);
|
|
29964
|
+
if (c.kind === "secret") return ` ${p}: ${toEnvRef(p)},`;
|
|
29965
|
+
if (c.kind === "faker") {
|
|
29966
|
+
usesFaker = true;
|
|
29967
|
+
return ` ${p}: ${c.faker},`;
|
|
29968
|
+
}
|
|
29969
|
+
missing.add(p);
|
|
29970
|
+
return ` ${p}: undefined, // TODO: real value (seeded ${p})`;
|
|
29971
|
+
});
|
|
29972
|
+
const block = params.length ? `{
|
|
29973
|
+
${params.join("\n")}
|
|
29974
|
+
}` : "{}";
|
|
29975
|
+
return ` await ${s.snippet.exportName}.run(page, ${block});`;
|
|
29976
|
+
});
|
|
29977
|
+
const warnings = unbound.map(
|
|
29978
|
+
(s) => ` // \u26A0 GAP: no snippet for ${s.action} \u2014 scaffold_snippet then re-plan.`
|
|
29979
|
+
);
|
|
29980
|
+
const header = [`import { test } from '@playwright/test';`];
|
|
29981
|
+
if (usesFaker) header.push(`import { faker } from '@faker-js/faker';`);
|
|
29982
|
+
const code = `${header.join("\n")}
|
|
29983
|
+
${[...importLines].join("\n")}
|
|
29984
|
+
|
|
29985
|
+
test(${JSON.stringify(opts.title ?? `plan: ${plan.target}`)}, async ({ page }) => {
|
|
29986
|
+
${[...warnings, ...callLines].join("\n")}
|
|
29987
|
+
});
|
|
29988
|
+
`;
|
|
29989
|
+
return { code, missingFixtures: [...missing], complete: plan.runnable && missing.size === 0 };
|
|
29990
|
+
}
|
|
29991
|
+
|
|
29814
29992
|
// src/server/lockfile.ts
|
|
29815
29993
|
var import_node_child_process2 = require("node:child_process");
|
|
29816
|
-
var
|
|
29994
|
+
var import_node_fs14 = require("node:fs");
|
|
29817
29995
|
var import_node_os4 = require("node:os");
|
|
29818
|
-
var
|
|
29996
|
+
var import_node_path19 = require("node:path");
|
|
29819
29997
|
init_launch_kit_paths();
|
|
29820
29998
|
function lockDir(projectRoot) {
|
|
29821
29999
|
if (projectRoot) {
|
|
29822
|
-
return (0,
|
|
30000
|
+
return (0, import_node_path19.join)(projectRoot, LAUNCHSECURE_DIR);
|
|
29823
30001
|
}
|
|
29824
|
-
return (0,
|
|
30002
|
+
return (0, import_node_path19.join)((0, import_node_os4.homedir)(), LAUNCHSECURE_DIR);
|
|
29825
30003
|
}
|
|
29826
30004
|
function lockPath(projectRoot) {
|
|
29827
|
-
return (0,
|
|
30005
|
+
return (0, import_node_path19.join)(lockDir(projectRoot), "launch-chart.lock");
|
|
29828
30006
|
}
|
|
29829
30007
|
var _activeProjectRoot;
|
|
29830
30008
|
function readLock(projectRoot) {
|
|
29831
30009
|
const root = projectRoot ?? _activeProjectRoot;
|
|
29832
30010
|
const p = lockPath(root);
|
|
29833
|
-
if (!(0,
|
|
30011
|
+
if (!(0, import_node_fs14.existsSync)(p)) {
|
|
29834
30012
|
if (root) {
|
|
29835
30013
|
const globalP = lockPath();
|
|
29836
|
-
if ((0,
|
|
30014
|
+
if ((0, import_node_fs14.existsSync)(globalP)) {
|
|
29837
30015
|
try {
|
|
29838
|
-
const data = JSON.parse((0,
|
|
30016
|
+
const data = JSON.parse((0, import_node_fs14.readFileSync)(globalP, "utf-8"));
|
|
29839
30017
|
if (typeof data.pid === "number" && typeof data.port === "number" && data.cwd === root) {
|
|
29840
30018
|
return data;
|
|
29841
30019
|
}
|
|
@@ -29846,7 +30024,7 @@ function readLock(projectRoot) {
|
|
|
29846
30024
|
return null;
|
|
29847
30025
|
}
|
|
29848
30026
|
try {
|
|
29849
|
-
const data = JSON.parse((0,
|
|
30027
|
+
const data = JSON.parse((0, import_node_fs14.readFileSync)(p, "utf-8"));
|
|
29850
30028
|
if (typeof data.pid !== "number" || typeof data.port !== "number") return null;
|
|
29851
30029
|
return data;
|
|
29852
30030
|
} catch {
|
|
@@ -29883,7 +30061,7 @@ function getLiveLock(projectRoot) {
|
|
|
29883
30061
|
const live = listenerPid !== null ? listenerPid === lock.pid : isPidAlive(lock.pid);
|
|
29884
30062
|
if (!live) {
|
|
29885
30063
|
try {
|
|
29886
|
-
(0,
|
|
30064
|
+
(0, import_node_fs14.unlinkSync)(lockPath(root));
|
|
29887
30065
|
} catch {
|
|
29888
30066
|
}
|
|
29889
30067
|
return null;
|
|
@@ -29893,7 +30071,7 @@ function getLiveLock(projectRoot) {
|
|
|
29893
30071
|
function clearLock(projectRoot) {
|
|
29894
30072
|
const root = projectRoot ?? _activeProjectRoot;
|
|
29895
30073
|
try {
|
|
29896
|
-
(0,
|
|
30074
|
+
(0, import_node_fs14.unlinkSync)(lockPath(root));
|
|
29897
30075
|
} catch {
|
|
29898
30076
|
}
|
|
29899
30077
|
}
|
|
@@ -29902,20 +30080,20 @@ function clearLock(projectRoot) {
|
|
|
29902
30080
|
init_config();
|
|
29903
30081
|
|
|
29904
30082
|
// src/server/graph/core/parser-registry.ts
|
|
29905
|
-
var
|
|
30083
|
+
var import_node_path30 = require("node:path");
|
|
29906
30084
|
|
|
29907
30085
|
// src/server/graph/parsers/ts/typescript-project.ts
|
|
29908
|
-
var
|
|
29909
|
-
var
|
|
30086
|
+
var import_node_fs18 = require("node:fs");
|
|
30087
|
+
var import_node_path23 = require("node:path");
|
|
29910
30088
|
init_config();
|
|
29911
30089
|
|
|
29912
30090
|
// src/server/graph/core/resolve-paths.ts
|
|
29913
|
-
var
|
|
29914
|
-
var
|
|
30091
|
+
var import_node_fs16 = require("node:fs");
|
|
30092
|
+
var import_node_path21 = require("node:path");
|
|
29915
30093
|
|
|
29916
30094
|
// src/server/graph/core/walk.ts
|
|
29917
|
-
var
|
|
29918
|
-
var
|
|
30095
|
+
var import_node_fs15 = require("node:fs");
|
|
30096
|
+
var import_node_path20 = require("node:path");
|
|
29919
30097
|
var DEFAULT_IGNORE_DIRS = /* @__PURE__ */ new Set([
|
|
29920
30098
|
"node_modules",
|
|
29921
30099
|
"dist",
|
|
@@ -29925,12 +30103,12 @@ var DEFAULT_IGNORE_DIRS = /* @__PURE__ */ new Set([
|
|
|
29925
30103
|
]);
|
|
29926
30104
|
function walk(dir, exts) {
|
|
29927
30105
|
const results = [];
|
|
29928
|
-
if (!(0,
|
|
29929
|
-
for (const entry of (0,
|
|
29930
|
-
const full = (0,
|
|
30106
|
+
if (!(0, import_node_fs15.existsSync)(dir)) return results;
|
|
30107
|
+
for (const entry of (0, import_node_fs15.readdirSync)(dir, { withFileTypes: true })) {
|
|
30108
|
+
const full = (0, import_node_path20.join)(dir, entry.name);
|
|
29931
30109
|
if (entry.isDirectory()) {
|
|
29932
30110
|
results.push(...walk(full, exts));
|
|
29933
|
-
} else if (exts.includes((0,
|
|
30111
|
+
} else if (exts.includes((0, import_node_path20.extname)(entry.name))) {
|
|
29934
30112
|
results.push(full);
|
|
29935
30113
|
}
|
|
29936
30114
|
}
|
|
@@ -29938,15 +30116,15 @@ function walk(dir, exts) {
|
|
|
29938
30116
|
}
|
|
29939
30117
|
function walkWithIgnore(dir, exts, opts = {}) {
|
|
29940
30118
|
const results = [];
|
|
29941
|
-
if (!(0,
|
|
30119
|
+
if (!(0, import_node_fs15.existsSync)(dir)) return results;
|
|
29942
30120
|
const skip = opts.extraIgnore ? /* @__PURE__ */ new Set([...DEFAULT_IGNORE_DIRS, ...opts.extraIgnore]) : DEFAULT_IGNORE_DIRS;
|
|
29943
|
-
for (const entry of (0,
|
|
30121
|
+
for (const entry of (0, import_node_fs15.readdirSync)(dir, { withFileTypes: true })) {
|
|
29944
30122
|
if (entry.isDirectory()) {
|
|
29945
30123
|
if (entry.name.startsWith(".")) continue;
|
|
29946
30124
|
if (skip.has(entry.name)) continue;
|
|
29947
|
-
results.push(...walkWithIgnore((0,
|
|
29948
|
-
} else if (exts.includes((0,
|
|
29949
|
-
results.push((0,
|
|
30125
|
+
results.push(...walkWithIgnore((0, import_node_path20.join)(dir, entry.name), exts, opts));
|
|
30126
|
+
} else if (exts.includes((0, import_node_path20.extname)(entry.name))) {
|
|
30127
|
+
results.push((0, import_node_path20.join)(dir, entry.name));
|
|
29950
30128
|
}
|
|
29951
30129
|
}
|
|
29952
30130
|
return results;
|
|
@@ -29954,9 +30132,9 @@ function walkWithIgnore(dir, exts, opts = {}) {
|
|
|
29954
30132
|
|
|
29955
30133
|
// src/server/graph/core/resolve-paths.ts
|
|
29956
30134
|
function hasSqlFiles(dir) {
|
|
29957
|
-
if (!(0,
|
|
30135
|
+
if (!(0, import_node_fs16.existsSync)(dir)) return false;
|
|
29958
30136
|
try {
|
|
29959
|
-
return (0,
|
|
30137
|
+
return (0, import_node_fs16.readdirSync)(dir, { withFileTypes: true }).some(
|
|
29960
30138
|
(e) => e.isFile() && e.name.endsWith(".sql")
|
|
29961
30139
|
);
|
|
29962
30140
|
} catch {
|
|
@@ -29964,27 +30142,27 @@ function hasSqlFiles(dir) {
|
|
|
29964
30142
|
}
|
|
29965
30143
|
}
|
|
29966
30144
|
function hasNestedMigrationSql(dir) {
|
|
29967
|
-
if (!(0,
|
|
30145
|
+
if (!(0, import_node_fs16.existsSync)(dir)) return false;
|
|
29968
30146
|
try {
|
|
29969
|
-
return (0,
|
|
29970
|
-
(e) => e.isDirectory() && (0,
|
|
30147
|
+
return (0, import_node_fs16.readdirSync)(dir, { withFileTypes: true }).some(
|
|
30148
|
+
(e) => e.isDirectory() && (0, import_node_fs16.existsSync)((0, import_node_path21.join)(dir, e.name, "migration.sql"))
|
|
29971
30149
|
);
|
|
29972
30150
|
} catch {
|
|
29973
30151
|
return false;
|
|
29974
30152
|
}
|
|
29975
30153
|
}
|
|
29976
30154
|
function resolveDbFromDir(dir) {
|
|
29977
|
-
if (!(0,
|
|
29978
|
-
const schemaPath = (0,
|
|
29979
|
-
if ((0,
|
|
29980
|
-
const migrationsDir2 = (0,
|
|
30155
|
+
if (!(0, import_node_fs16.existsSync)(dir)) return { kind: "none", schemaPath: null, migrationsDir: null };
|
|
30156
|
+
const schemaPath = (0, import_node_path21.join)(dir, "schema.prisma");
|
|
30157
|
+
if ((0, import_node_fs16.existsSync)(schemaPath)) {
|
|
30158
|
+
const migrationsDir2 = (0, import_node_path21.join)(dir, "migrations");
|
|
29981
30159
|
return {
|
|
29982
30160
|
kind: "prisma",
|
|
29983
30161
|
schemaPath,
|
|
29984
|
-
migrationsDir: (0,
|
|
30162
|
+
migrationsDir: (0, import_node_fs16.existsSync)(migrationsDir2) ? migrationsDir2 : null
|
|
29985
30163
|
};
|
|
29986
30164
|
}
|
|
29987
|
-
const migrationsDir = (0,
|
|
30165
|
+
const migrationsDir = (0, import_node_path21.join)(dir, "migrations");
|
|
29988
30166
|
if (hasSqlFiles(migrationsDir) || hasNestedMigrationSql(migrationsDir)) {
|
|
29989
30167
|
return { kind: "sql-migrations", migrationsDir, schemaPath: null };
|
|
29990
30168
|
}
|
|
@@ -29995,19 +30173,19 @@ function resolveDbFromDir(dir) {
|
|
|
29995
30173
|
}
|
|
29996
30174
|
function detectDbConfig(rootDir, config) {
|
|
29997
30175
|
if (config.paths?.dbDir) {
|
|
29998
|
-
return resolveDbFromDir((0,
|
|
30176
|
+
return resolveDbFromDir((0, import_node_path21.join)(rootDir, config.paths.dbDir));
|
|
29999
30177
|
}
|
|
30000
|
-
const candidates = ["prisma", "supabase", "drizzle", (0,
|
|
30178
|
+
const candidates = ["prisma", "supabase", "drizzle", (0, import_node_path21.join)("db", "migrations"), "migrations"];
|
|
30001
30179
|
for (const c of candidates) {
|
|
30002
|
-
const dir = (0,
|
|
30180
|
+
const dir = (0, import_node_path21.join)(rootDir, c);
|
|
30003
30181
|
const resolved = resolveDbFromDir(dir);
|
|
30004
30182
|
if (resolved.kind !== "none") return resolved;
|
|
30005
30183
|
}
|
|
30006
30184
|
return { kind: "none", schemaPath: null, migrationsDir: null };
|
|
30007
30185
|
}
|
|
30008
30186
|
function detectDbDir(rootDir, config, dbConfig) {
|
|
30009
|
-
if (config.paths?.dbDir) return (0,
|
|
30010
|
-
if (dbConfig.kind === "prisma") return (0,
|
|
30187
|
+
if (config.paths?.dbDir) return (0, import_node_path21.join)(rootDir, config.paths.dbDir);
|
|
30188
|
+
if (dbConfig.kind === "prisma") return (0, import_node_path21.dirname)(dbConfig.schemaPath);
|
|
30011
30189
|
if (dbConfig.kind === "sql-migrations") return dbConfig.migrationsDir;
|
|
30012
30190
|
return null;
|
|
30013
30191
|
}
|
|
@@ -30038,16 +30216,16 @@ var NON_SOURCE_DIRS = /* @__PURE__ */ new Set([
|
|
|
30038
30216
|
"libs"
|
|
30039
30217
|
]);
|
|
30040
30218
|
function dirHasTSFiles(dir) {
|
|
30041
|
-
if (!(0,
|
|
30219
|
+
if (!(0, import_node_fs16.existsSync)(dir)) return false;
|
|
30042
30220
|
try {
|
|
30043
30221
|
const stack = [dir];
|
|
30044
30222
|
while (stack.length > 0) {
|
|
30045
30223
|
const cur = stack.pop();
|
|
30046
|
-
const entries = (0,
|
|
30224
|
+
const entries = (0, import_node_fs16.readdirSync)(cur, { withFileTypes: true });
|
|
30047
30225
|
for (const e of entries) {
|
|
30048
30226
|
if (e.isFile() && (e.name.endsWith(".ts") || e.name.endsWith(".tsx"))) return true;
|
|
30049
30227
|
if (e.isDirectory() && !e.name.startsWith(".") && !DEFAULT_IGNORE_DIRS.has(e.name)) {
|
|
30050
|
-
stack.push((0,
|
|
30228
|
+
stack.push((0, import_node_path21.join)(cur, e.name));
|
|
30051
30229
|
}
|
|
30052
30230
|
}
|
|
30053
30231
|
}
|
|
@@ -30056,15 +30234,15 @@ function dirHasTSFiles(dir) {
|
|
|
30056
30234
|
return false;
|
|
30057
30235
|
}
|
|
30058
30236
|
function collectCodeBearingChildren(dir, extraSkip) {
|
|
30059
|
-
if (!(0,
|
|
30237
|
+
if (!(0, import_node_fs16.existsSync)(dir)) return [];
|
|
30060
30238
|
const out = [];
|
|
30061
30239
|
try {
|
|
30062
|
-
for (const entry of (0,
|
|
30240
|
+
for (const entry of (0, import_node_fs16.readdirSync)(dir, { withFileTypes: true })) {
|
|
30063
30241
|
if (!entry.isDirectory()) continue;
|
|
30064
30242
|
if (entry.name.startsWith(".")) continue;
|
|
30065
30243
|
if (NON_SOURCE_DIRS.has(entry.name)) continue;
|
|
30066
30244
|
if (extraSkip?.has(entry.name)) continue;
|
|
30067
|
-
const full = (0,
|
|
30245
|
+
const full = (0, import_node_path21.join)(dir, entry.name);
|
|
30068
30246
|
if (dirHasTSFiles(full)) out.push(full);
|
|
30069
30247
|
}
|
|
30070
30248
|
} catch {
|
|
@@ -30076,7 +30254,7 @@ function detectSrcRoots(rootDir, srcDir, appDir, config) {
|
|
|
30076
30254
|
const roots2 = /* @__PURE__ */ new Set();
|
|
30077
30255
|
roots2.add(appDir);
|
|
30078
30256
|
for (const r of config.paths.srcRoots) {
|
|
30079
|
-
const abs = (0,
|
|
30257
|
+
const abs = (0, import_node_path21.isAbsolute)(r) ? r : (0, import_node_path21.resolve)(rootDir, r);
|
|
30080
30258
|
roots2.add(abs);
|
|
30081
30259
|
}
|
|
30082
30260
|
return [...roots2];
|
|
@@ -30085,7 +30263,7 @@ function detectSrcRoots(rootDir, srcDir, appDir, config) {
|
|
|
30085
30263
|
roots.add(appDir);
|
|
30086
30264
|
for (const c of collectCodeBearingChildren(srcDir)) roots.add(c);
|
|
30087
30265
|
if (srcDir !== rootDir) {
|
|
30088
|
-
const skipSrcWrapper = /* @__PURE__ */ new Set([(0,
|
|
30266
|
+
const skipSrcWrapper = /* @__PURE__ */ new Set([(0, import_node_path21.basename)(srcDir)]);
|
|
30089
30267
|
for (const c of collectCodeBearingChildren(rootDir, skipSrcWrapper)) roots.add(c);
|
|
30090
30268
|
}
|
|
30091
30269
|
return [...roots];
|
|
@@ -30097,10 +30275,10 @@ function detectConventionFiles(rootDir, srcDir) {
|
|
|
30097
30275
|
const dirs = srcDir === rootDir ? [rootDir] : [srcDir, rootDir];
|
|
30098
30276
|
for (const dir of dirs) {
|
|
30099
30277
|
for (const name of CONVENTION_NAMES) {
|
|
30100
|
-
const full = (0,
|
|
30101
|
-
if (!seen.has(full) && (0,
|
|
30278
|
+
const full = (0, import_node_path21.join)(dir, name);
|
|
30279
|
+
if (!seen.has(full) && (0, import_node_fs16.existsSync)(full)) {
|
|
30102
30280
|
try {
|
|
30103
|
-
if ((0,
|
|
30281
|
+
if ((0, import_node_fs16.statSync)(full).isFile()) {
|
|
30104
30282
|
seen.add(full);
|
|
30105
30283
|
out.push(full);
|
|
30106
30284
|
}
|
|
@@ -30115,22 +30293,22 @@ function resolveProjectPaths(rootDir, config) {
|
|
|
30115
30293
|
let srcDir;
|
|
30116
30294
|
let appDir;
|
|
30117
30295
|
if (config.paths?.appDir) {
|
|
30118
|
-
appDir = (0,
|
|
30119
|
-
srcDir = config.paths.srcDir ? (0,
|
|
30296
|
+
appDir = (0, import_node_path21.join)(rootDir, config.paths.appDir);
|
|
30297
|
+
srcDir = config.paths.srcDir ? (0, import_node_path21.join)(rootDir, config.paths.srcDir) : (0, import_node_path21.dirname)(appDir);
|
|
30120
30298
|
} else {
|
|
30121
|
-
const srcApp = (0,
|
|
30122
|
-
const rootApp = (0,
|
|
30123
|
-
if ((0,
|
|
30124
|
-
srcDir = (0,
|
|
30299
|
+
const srcApp = (0, import_node_path21.join)(rootDir, "src", "app");
|
|
30300
|
+
const rootApp = (0, import_node_path21.join)(rootDir, "app");
|
|
30301
|
+
if ((0, import_node_fs16.existsSync)(srcApp)) {
|
|
30302
|
+
srcDir = (0, import_node_path21.join)(rootDir, "src");
|
|
30125
30303
|
appDir = srcApp;
|
|
30126
|
-
} else if ((0,
|
|
30304
|
+
} else if ((0, import_node_fs16.existsSync)(rootApp)) {
|
|
30127
30305
|
srcDir = rootDir;
|
|
30128
30306
|
appDir = rootApp;
|
|
30129
30307
|
} else {
|
|
30130
30308
|
return null;
|
|
30131
30309
|
}
|
|
30132
30310
|
}
|
|
30133
|
-
const apiDir = (0,
|
|
30311
|
+
const apiDir = (0, import_node_path21.join)(appDir, "api");
|
|
30134
30312
|
const dbConfig = detectDbConfig(rootDir, config);
|
|
30135
30313
|
const dbDir = detectDbDir(rootDir, config, dbConfig);
|
|
30136
30314
|
const srcRoots = detectSrcRoots(rootDir, srcDir, appDir, config);
|
|
@@ -30157,25 +30335,25 @@ var CLASSIFICATION_TO_LAYER = {
|
|
|
30157
30335
|
external: "ui"
|
|
30158
30336
|
};
|
|
30159
30337
|
function toNodeId(srcDir, rootDir, absPath) {
|
|
30160
|
-
const relFromSrc = (0,
|
|
30338
|
+
const relFromSrc = (0, import_node_path23.relative)(srcDir, absPath).replace(/\\/g, "/");
|
|
30161
30339
|
if (relFromSrc.startsWith("..")) {
|
|
30162
|
-
return (0,
|
|
30340
|
+
return (0, import_node_path23.relative)(rootDir, absPath).replace(/\\/g, "/");
|
|
30163
30341
|
}
|
|
30164
30342
|
return relFromSrc;
|
|
30165
30343
|
}
|
|
30166
30344
|
function resolveImport(srcDir, specifier) {
|
|
30167
30345
|
if (!specifier.startsWith("@/")) return null;
|
|
30168
30346
|
const rel = specifier.slice(2);
|
|
30169
|
-
const base = (0,
|
|
30170
|
-
for (const c of [base, base + ".ts", base + ".tsx", (0,
|
|
30171
|
-
if ((0,
|
|
30347
|
+
const base = (0, import_node_path23.join)(srcDir, rel);
|
|
30348
|
+
for (const c of [base, base + ".ts", base + ".tsx", (0, import_node_path23.join)(base, "index.ts"), (0, import_node_path23.join)(base, "index.tsx")]) {
|
|
30349
|
+
if ((0, import_node_fs18.existsSync)(c) && (0, import_node_fs18.statSync)(c).isFile()) return c;
|
|
30172
30350
|
}
|
|
30173
30351
|
return null;
|
|
30174
30352
|
}
|
|
30175
30353
|
function resolveRelativeImport(fromFile, specifier) {
|
|
30176
|
-
const base = (0,
|
|
30177
|
-
for (const c of [base, base + ".ts", base + ".tsx", (0,
|
|
30178
|
-
if ((0,
|
|
30354
|
+
const base = (0, import_node_path23.join)((0, import_node_path23.dirname)(fromFile), specifier);
|
|
30355
|
+
for (const c of [base, base + ".ts", base + ".tsx", (0, import_node_path23.join)(base, "index.ts"), (0, import_node_path23.join)(base, "index.tsx")]) {
|
|
30356
|
+
if ((0, import_node_fs18.existsSync)(c) && (0, import_node_fs18.statSync)(c).isFile()) return c;
|
|
30179
30357
|
}
|
|
30180
30358
|
return null;
|
|
30181
30359
|
}
|
|
@@ -30196,7 +30374,7 @@ function resolveBarrelMap(barrelAbsPath, parsedByPath, memo, visiting) {
|
|
|
30196
30374
|
const resolved = resolveRelativeImport(barrelAbsPath, re.from);
|
|
30197
30375
|
if (!resolved) continue;
|
|
30198
30376
|
if (re.isWildcard) {
|
|
30199
|
-
const targetBn = (0,
|
|
30377
|
+
const targetBn = (0, import_node_path23.basename)(resolved);
|
|
30200
30378
|
const targetIsBarrel = targetBn === "index.ts" || targetBn === "index.tsx";
|
|
30201
30379
|
if (targetIsBarrel) {
|
|
30202
30380
|
const nested = resolveBarrelMap(resolved, parsedByPath, memo, visiting);
|
|
@@ -30223,12 +30401,12 @@ function buildAllBarrelMaps(srcDir, parsedByPath) {
|
|
|
30223
30401
|
const barrels = /* @__PURE__ */ new Map();
|
|
30224
30402
|
const memo = /* @__PURE__ */ new Map();
|
|
30225
30403
|
for (const [absPath, parsed] of parsedByPath) {
|
|
30226
|
-
const bn = (0,
|
|
30404
|
+
const bn = (0, import_node_path23.basename)(absPath);
|
|
30227
30405
|
if (bn !== "index.ts" && bn !== "index.tsx") continue;
|
|
30228
30406
|
if (parsed.reExports.length === 0) continue;
|
|
30229
30407
|
const map = resolveBarrelMap(absPath, parsedByPath, memo, /* @__PURE__ */ new Set());
|
|
30230
30408
|
if (map.size > 0) {
|
|
30231
|
-
const barrelId = (0,
|
|
30409
|
+
const barrelId = (0, import_node_path23.relative)(srcDir, (0, import_node_path23.dirname)(absPath)).replace(/\\/g, "/");
|
|
30232
30410
|
barrels.set(barrelId, map);
|
|
30233
30411
|
}
|
|
30234
30412
|
}
|
|
@@ -30253,10 +30431,10 @@ function extractRoute(id) {
|
|
|
30253
30431
|
return route || "/";
|
|
30254
30432
|
}
|
|
30255
30433
|
function nameFromFilename(absPath) {
|
|
30256
|
-
return (0,
|
|
30434
|
+
return (0, import_node_path23.basename)(absPath, (0, import_node_path23.extname)(absPath)).replace(/[-_](\w)/g, (_, c) => c.toUpperCase()).replace(/^(\w)/, (_, c) => c.toUpperCase());
|
|
30257
30435
|
}
|
|
30258
30436
|
function filePathToAppRoute(appDir, absPath) {
|
|
30259
|
-
let route = ("/" + (0,
|
|
30437
|
+
let route = ("/" + (0, import_node_path23.relative)(appDir, absPath).replace(/\\/g, "/")).replace(/\/route\.tsx?$/, "");
|
|
30260
30438
|
route = route.replace(/\/\([^)]+\)/g, "");
|
|
30261
30439
|
route = route.replace(/\[\[\.\.\.([^\]]+)\]\]/g, "*$1?");
|
|
30262
30440
|
route = route.replace(/\[\.\.\.([^\]]+)\]/g, "*$1");
|
|
@@ -30504,7 +30682,7 @@ function generate(rootDir) {
|
|
|
30504
30682
|
const apiNodes = [];
|
|
30505
30683
|
const nodeIdSet = /* @__PURE__ */ new Set();
|
|
30506
30684
|
const routeToNodeId = /* @__PURE__ */ new Map();
|
|
30507
|
-
const fileSet = allDiscovered.filter((f) => !(0,
|
|
30685
|
+
const fileSet = allDiscovered.filter((f) => !(0, import_node_path23.basename)(f).startsWith("index."));
|
|
30508
30686
|
for (const absPath of fileSet) {
|
|
30509
30687
|
const id = toNodeId(srcDir, rootDir, absPath);
|
|
30510
30688
|
const type = classifyType(absPath, id);
|
|
@@ -30664,7 +30842,7 @@ function generate(rootDir) {
|
|
|
30664
30842
|
} catch {
|
|
30665
30843
|
continue;
|
|
30666
30844
|
}
|
|
30667
|
-
const externalId = (0,
|
|
30845
|
+
const externalId = (0, import_node_path23.relative)(rootDir, absPath).replace(/\\/g, "/");
|
|
30668
30846
|
const edgesFromThis = [];
|
|
30669
30847
|
const seen = /* @__PURE__ */ new Set();
|
|
30670
30848
|
for (const imp of parsed.imports) {
|
|
@@ -31014,7 +31192,7 @@ var typescriptProjectParser = {
|
|
|
31014
31192
|
};
|
|
31015
31193
|
|
|
31016
31194
|
// src/server/graph/parsers/db/prisma-schema.ts
|
|
31017
|
-
var
|
|
31195
|
+
var import_node_fs19 = require("node:fs");
|
|
31018
31196
|
init_config();
|
|
31019
31197
|
function parseModels(content) {
|
|
31020
31198
|
const nodes = [];
|
|
@@ -31107,7 +31285,7 @@ function parseEnums(content) {
|
|
|
31107
31285
|
}
|
|
31108
31286
|
function detect2(rootDir) {
|
|
31109
31287
|
const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
|
|
31110
|
-
return paths?.dbConfig.kind === "prisma" && (0,
|
|
31288
|
+
return paths?.dbConfig.kind === "prisma" && (0, import_node_fs19.existsSync)(paths.dbConfig.schemaPath);
|
|
31111
31289
|
}
|
|
31112
31290
|
function generate2(rootDir) {
|
|
31113
31291
|
const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
|
|
@@ -31124,7 +31302,7 @@ function generate2(rootDir) {
|
|
|
31124
31302
|
};
|
|
31125
31303
|
}
|
|
31126
31304
|
const schemaPath = paths.dbConfig.schemaPath;
|
|
31127
|
-
const content = (0,
|
|
31305
|
+
const content = (0, import_node_fs19.readFileSync)(schemaPath, "utf-8");
|
|
31128
31306
|
const { nodes: modelNodes, relations } = parseModels(content);
|
|
31129
31307
|
const enumNodes = parseEnums(content);
|
|
31130
31308
|
const allNodes = [...modelNodes, ...enumNodes];
|
|
@@ -31181,8 +31359,8 @@ var prismaSchemaParser = {
|
|
|
31181
31359
|
};
|
|
31182
31360
|
|
|
31183
31361
|
// src/server/graph/parsers/db/sql-migrations.ts
|
|
31184
|
-
var
|
|
31185
|
-
var
|
|
31362
|
+
var import_node_fs20 = require("node:fs");
|
|
31363
|
+
var import_node_path24 = require("node:path");
|
|
31186
31364
|
var import_pgsql_parser = require("pgsql-parser");
|
|
31187
31365
|
init_config();
|
|
31188
31366
|
var PG_TO_PRISMA = {
|
|
@@ -31216,15 +31394,15 @@ function pgTypeToPrisma(pgType) {
|
|
|
31216
31394
|
return PG_TO_PRISMA[upper] ?? upper;
|
|
31217
31395
|
}
|
|
31218
31396
|
function discoverMigrationFiles(migrationsDir) {
|
|
31219
|
-
if (!(0,
|
|
31397
|
+
if (!(0, import_node_fs20.existsSync)(migrationsDir)) return [];
|
|
31220
31398
|
const out = [];
|
|
31221
|
-
const entries = (0,
|
|
31399
|
+
const entries = (0, import_node_fs20.readdirSync)(migrationsDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
31222
31400
|
for (const entry of entries) {
|
|
31223
31401
|
if (entry.isDirectory()) {
|
|
31224
|
-
const sqlPath = (0,
|
|
31225
|
-
if ((0,
|
|
31402
|
+
const sqlPath = (0, import_node_path24.join)(migrationsDir, entry.name, "migration.sql");
|
|
31403
|
+
if ((0, import_node_fs20.existsSync)(sqlPath)) out.push(sqlPath);
|
|
31226
31404
|
} else if (entry.isFile() && entry.name.endsWith(".sql")) {
|
|
31227
|
-
out.push((0,
|
|
31405
|
+
out.push((0, import_node_path24.join)(migrationsDir, entry.name));
|
|
31228
31406
|
}
|
|
31229
31407
|
}
|
|
31230
31408
|
return out;
|
|
@@ -31269,7 +31447,7 @@ function parseMigrations(migrationsDir, dialect = postgresDialect) {
|
|
|
31269
31447
|
};
|
|
31270
31448
|
if (!migrationsDir) return state;
|
|
31271
31449
|
for (const sqlPath of discoverMigrationFiles(migrationsDir)) {
|
|
31272
|
-
const sql = (0,
|
|
31450
|
+
const sql = (0, import_node_fs20.readFileSync)(sqlPath, "utf-8");
|
|
31273
31451
|
let ast;
|
|
31274
31452
|
try {
|
|
31275
31453
|
ast = dialect.parse(sql);
|
|
@@ -31838,8 +32016,8 @@ function indexIsPrismaUncoverable(idx) {
|
|
|
31838
32016
|
return idx.hasPredicate || idx.hasExpressions || idx.method !== "btree";
|
|
31839
32017
|
}
|
|
31840
32018
|
function loadPrismaState(schemaPath) {
|
|
31841
|
-
if (!schemaPath || !(0,
|
|
31842
|
-
const content = (0,
|
|
32019
|
+
if (!schemaPath || !(0, import_node_fs20.existsSync)(schemaPath)) return null;
|
|
32020
|
+
const content = (0, import_node_fs20.readFileSync)(schemaPath, "utf-8");
|
|
31843
32021
|
const tables = /* @__PURE__ */ new Map();
|
|
31844
32022
|
const enums = /* @__PURE__ */ new Map();
|
|
31845
32023
|
const relations = [];
|
|
@@ -32246,7 +32424,7 @@ function generate3(rootDir) {
|
|
|
32246
32424
|
const migrationFiles = migrationsDir ? discoverMigrationFiles(migrationsDir) : [];
|
|
32247
32425
|
let migrationNodeCount = 0;
|
|
32248
32426
|
for (const sqlPath of migrationFiles) {
|
|
32249
|
-
const sql = (0,
|
|
32427
|
+
const sql = (0, import_node_fs20.readFileSync)(sqlPath, "utf-8");
|
|
32250
32428
|
const name = deriveMigrationName(sqlPath);
|
|
32251
32429
|
let ast;
|
|
32252
32430
|
try {
|
|
@@ -32564,14 +32742,14 @@ var fetchResolverParser = {
|
|
|
32564
32742
|
};
|
|
32565
32743
|
|
|
32566
32744
|
// src/server/graph/parsers/crosslayer/api-annotations.ts
|
|
32567
|
-
var
|
|
32568
|
-
var
|
|
32745
|
+
var import_node_fs21 = require("node:fs");
|
|
32746
|
+
var import_node_path25 = require("node:path");
|
|
32569
32747
|
init_config();
|
|
32570
32748
|
var API_ANNOTATION_RE = /@api\s+(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)\s+(\/\S+)/g;
|
|
32571
32749
|
function toNodeId2(srcDir, rootDir, absPath) {
|
|
32572
|
-
const relFromSrc = (0,
|
|
32750
|
+
const relFromSrc = (0, import_node_path25.relative)(srcDir, absPath).replace(/\\/g, "/");
|
|
32573
32751
|
if (relFromSrc.startsWith("..")) {
|
|
32574
|
-
return (0,
|
|
32752
|
+
return (0, import_node_path25.relative)(rootDir, absPath).replace(/\\/g, "/");
|
|
32575
32753
|
}
|
|
32576
32754
|
return relFromSrc;
|
|
32577
32755
|
}
|
|
@@ -32616,7 +32794,7 @@ var apiAnnotationsParser = {
|
|
|
32616
32794
|
const flaggedEdges = [];
|
|
32617
32795
|
const seenEdge = /* @__PURE__ */ new Set();
|
|
32618
32796
|
for (const absPath of files) {
|
|
32619
|
-
const content = (0,
|
|
32797
|
+
const content = (0, import_node_fs21.readFileSync)(absPath, "utf-8");
|
|
32620
32798
|
const sourceId = toNodeId2(srcDir, rootDir, absPath);
|
|
32621
32799
|
if (!uiNodeIds.has(sourceId)) continue;
|
|
32622
32800
|
let match;
|
|
@@ -32660,14 +32838,14 @@ var apiAnnotationsParser = {
|
|
|
32660
32838
|
};
|
|
32661
32839
|
|
|
32662
32840
|
// src/server/graph/parsers/crosslayer/url-literal-scanner.ts
|
|
32663
|
-
var
|
|
32664
|
-
var
|
|
32841
|
+
var import_node_fs22 = require("node:fs");
|
|
32842
|
+
var import_node_path26 = require("node:path");
|
|
32665
32843
|
init_config();
|
|
32666
32844
|
var URL_LITERAL_RE = /['"`](\/[a-zA-Z][^'"`\s]*?)['"`]/g;
|
|
32667
32845
|
function toNodeId3(srcDir, rootDir, absPath) {
|
|
32668
|
-
const relFromSrc = (0,
|
|
32846
|
+
const relFromSrc = (0, import_node_path26.relative)(srcDir, absPath).replace(/\\/g, "/");
|
|
32669
32847
|
if (relFromSrc.startsWith("..")) {
|
|
32670
|
-
return (0,
|
|
32848
|
+
return (0, import_node_path26.relative)(rootDir, absPath).replace(/\\/g, "/");
|
|
32671
32849
|
}
|
|
32672
32850
|
return relFromSrc;
|
|
32673
32851
|
}
|
|
@@ -32711,7 +32889,7 @@ var urlLiteralScannerParser = {
|
|
|
32711
32889
|
for (const absPath of files) {
|
|
32712
32890
|
const sourceId = toNodeId3(srcDir, rootDir, absPath);
|
|
32713
32891
|
if (!uiNodeIds.has(sourceId)) continue;
|
|
32714
|
-
const content = (0,
|
|
32892
|
+
const content = (0, import_node_fs22.readFileSync)(absPath, "utf-8");
|
|
32715
32893
|
let match;
|
|
32716
32894
|
URL_LITERAL_RE.lastIndex = 0;
|
|
32717
32895
|
while ((match = URL_LITERAL_RE.exec(content)) !== null) {
|
|
@@ -32742,8 +32920,8 @@ var urlLiteralScannerParser = {
|
|
|
32742
32920
|
};
|
|
32743
32921
|
|
|
32744
32922
|
// src/server/graph/parsers/static/static-values.ts
|
|
32745
|
-
var
|
|
32746
|
-
var
|
|
32923
|
+
var import_node_fs23 = require("node:fs");
|
|
32924
|
+
var import_node_path27 = require("node:path");
|
|
32747
32925
|
init_config();
|
|
32748
32926
|
var parseCode = null;
|
|
32749
32927
|
function tryLoadTreeSitter() {
|
|
@@ -32780,21 +32958,21 @@ function extractEnumValues(rootDir) {
|
|
|
32780
32958
|
const schemaPaths = [];
|
|
32781
32959
|
if (paths?.dbConfig.kind === "prisma" && paths.dbConfig.schemaPath) {
|
|
32782
32960
|
schemaPaths.push(paths.dbConfig.schemaPath);
|
|
32783
|
-
schemaPaths.push((0,
|
|
32961
|
+
schemaPaths.push((0, import_node_path27.join)((0, import_node_path27.dirname)(paths.dbConfig.schemaPath), "schema"));
|
|
32784
32962
|
} else {
|
|
32785
|
-
schemaPaths.push((0,
|
|
32786
|
-
schemaPaths.push((0,
|
|
32963
|
+
schemaPaths.push((0, import_node_path27.join)(rootDir, "prisma", "schema.prisma"));
|
|
32964
|
+
schemaPaths.push((0, import_node_path27.join)(rootDir, "prisma", "schema"));
|
|
32787
32965
|
}
|
|
32788
32966
|
let content = "";
|
|
32789
32967
|
for (const p of schemaPaths) {
|
|
32790
|
-
if ((0,
|
|
32968
|
+
if ((0, import_node_fs23.existsSync)(p)) {
|
|
32791
32969
|
try {
|
|
32792
|
-
const stat = (0,
|
|
32970
|
+
const stat = (0, import_node_fs23.statSync)(p);
|
|
32793
32971
|
if (stat.isFile()) {
|
|
32794
|
-
content = (0,
|
|
32972
|
+
content = (0, import_node_fs23.readFileSync)(p, "utf-8");
|
|
32795
32973
|
} else if (stat.isDirectory()) {
|
|
32796
|
-
const files = (0,
|
|
32797
|
-
content = files.map((f) => (0,
|
|
32974
|
+
const files = (0, import_node_fs23.readdirSync)(p).filter((f) => f.endsWith(".prisma"));
|
|
32975
|
+
content = files.map((f) => (0, import_node_fs23.readFileSync)((0, import_node_path27.join)(p, f), "utf-8")).join("\n");
|
|
32798
32976
|
}
|
|
32799
32977
|
} catch {
|
|
32800
32978
|
continue;
|
|
@@ -32952,27 +33130,27 @@ function extractSeedData(rootDir) {
|
|
|
32952
33130
|
const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
|
|
32953
33131
|
const candidates = [];
|
|
32954
33132
|
if (paths?.dbDir) {
|
|
32955
|
-
candidates.push((0,
|
|
32956
|
-
candidates.push((0,
|
|
33133
|
+
candidates.push((0, import_node_path27.join)(paths.dbDir, "seed.ts"));
|
|
33134
|
+
candidates.push((0, import_node_path27.join)(paths.dbDir, "seed.js"));
|
|
32957
33135
|
} else {
|
|
32958
|
-
candidates.push((0,
|
|
32959
|
-
candidates.push((0,
|
|
33136
|
+
candidates.push((0, import_node_path27.join)(rootDir, "prisma", "seed.ts"));
|
|
33137
|
+
candidates.push((0, import_node_path27.join)(rootDir, "prisma", "seed.js"));
|
|
32960
33138
|
}
|
|
32961
|
-
const baseRoots = paths?.srcRoots ?? [(0,
|
|
33139
|
+
const baseRoots = paths?.srcRoots ?? [(0, import_node_path27.join)(rootDir, "src")];
|
|
32962
33140
|
for (const root of baseRoots) {
|
|
32963
|
-
candidates.push((0,
|
|
33141
|
+
candidates.push((0, import_node_path27.join)(root, "server", "lib", "system-tags.ts"));
|
|
32964
33142
|
}
|
|
32965
33143
|
const seedFiles = candidates.filter((p) => {
|
|
32966
33144
|
try {
|
|
32967
|
-
return (0,
|
|
33145
|
+
return (0, import_node_fs23.existsSync)(p) && (0, import_node_fs23.statSync)(p).isFile();
|
|
32968
33146
|
} catch {
|
|
32969
33147
|
return false;
|
|
32970
33148
|
}
|
|
32971
33149
|
});
|
|
32972
33150
|
const useTreeSitter = tryLoadTreeSitter();
|
|
32973
33151
|
for (const filePath of seedFiles) {
|
|
32974
|
-
const content = (0,
|
|
32975
|
-
const relPath = (0,
|
|
33152
|
+
const content = (0, import_node_fs23.readFileSync)(filePath, "utf-8");
|
|
33153
|
+
const relPath = (0, import_node_path27.relative)(rootDir, filePath);
|
|
32976
33154
|
const seeded = detectSeededArrays(content, relPath);
|
|
32977
33155
|
let astRoot = null;
|
|
32978
33156
|
if (useTreeSitter && parseCode) {
|
|
@@ -33066,11 +33244,11 @@ function extractSeedData(rootDir) {
|
|
|
33066
33244
|
return { nodes, edges };
|
|
33067
33245
|
}
|
|
33068
33246
|
function walkDir(dir, exts) {
|
|
33069
|
-
if (!(0,
|
|
33247
|
+
if (!(0, import_node_fs23.existsSync)(dir)) return [];
|
|
33070
33248
|
const results = [];
|
|
33071
|
-
for (const entry of (0,
|
|
33249
|
+
for (const entry of (0, import_node_fs23.readdirSync)(dir, { withFileTypes: true })) {
|
|
33072
33250
|
if (entry.name === "node_modules" || entry.name === ".next" || entry.name === "dist") continue;
|
|
33073
|
-
const full = (0,
|
|
33251
|
+
const full = (0, import_node_path27.join)(dir, entry.name);
|
|
33074
33252
|
if (entry.isDirectory()) results.push(...walkDir(full, exts));
|
|
33075
33253
|
else if (exts.some((ext) => entry.name.endsWith(ext))) results.push(full);
|
|
33076
33254
|
}
|
|
@@ -33079,7 +33257,7 @@ function walkDir(dir, exts) {
|
|
|
33079
33257
|
function extractConstants(rootDir) {
|
|
33080
33258
|
const nodes = [];
|
|
33081
33259
|
const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
|
|
33082
|
-
const roots = paths?.srcRoots ?? [(0,
|
|
33260
|
+
const roots = paths?.srcRoots ?? [(0, import_node_path27.join)(rootDir, "src")];
|
|
33083
33261
|
const seenFile = /* @__PURE__ */ new Set();
|
|
33084
33262
|
const allFiles = [];
|
|
33085
33263
|
for (const root of roots) {
|
|
@@ -33092,8 +33270,8 @@ function extractConstants(rootDir) {
|
|
|
33092
33270
|
}
|
|
33093
33271
|
if (allFiles.length === 0) return { nodes };
|
|
33094
33272
|
for (const filePath of allFiles) {
|
|
33095
|
-
const content = (0,
|
|
33096
|
-
const relPath = (0,
|
|
33273
|
+
const content = (0, import_node_fs23.readFileSync)(filePath, "utf-8");
|
|
33274
|
+
const relPath = (0, import_node_path27.relative)(rootDir, filePath);
|
|
33097
33275
|
const constArrayRe = /export\s+const\s+([A-Z][A-Z_0-9]+)\s*(?::[^=]+)?\s*=\s*\[/g;
|
|
33098
33276
|
let cm;
|
|
33099
33277
|
while ((cm = constArrayRe.exec(content)) !== null) {
|
|
@@ -33127,13 +33305,13 @@ function extractConstants(rootDir) {
|
|
|
33127
33305
|
}
|
|
33128
33306
|
function detect4(rootDir) {
|
|
33129
33307
|
const paths = resolveProjectPaths(rootDir, loadConfig(rootDir));
|
|
33130
|
-
if (paths?.dbConfig.kind === "prisma" && paths.dbConfig.schemaPath && (0,
|
|
33308
|
+
if (paths?.dbConfig.kind === "prisma" && paths.dbConfig.schemaPath && (0, import_node_fs23.existsSync)(paths.dbConfig.schemaPath)) {
|
|
33131
33309
|
return true;
|
|
33132
33310
|
}
|
|
33133
33311
|
if (paths?.dbDir) {
|
|
33134
|
-
if ((0,
|
|
33312
|
+
if ((0, import_node_fs23.existsSync)((0, import_node_path27.join)(paths.dbDir, "seed.ts")) || (0, import_node_fs23.existsSync)((0, import_node_path27.join)(paths.dbDir, "seed.js"))) return true;
|
|
33135
33313
|
}
|
|
33136
|
-
return (0,
|
|
33314
|
+
return (0, import_node_fs23.existsSync)((0, import_node_path27.join)(rootDir, "prisma", "schema.prisma")) || (0, import_node_fs23.existsSync)((0, import_node_path27.join)(rootDir, "prisma", "seed.ts"));
|
|
33137
33315
|
}
|
|
33138
33316
|
function generate4(rootDir) {
|
|
33139
33317
|
const enumResult = extractEnumValues(rootDir);
|
|
@@ -33208,8 +33386,8 @@ var staticValuesParser = {
|
|
|
33208
33386
|
};
|
|
33209
33387
|
|
|
33210
33388
|
// src/server/graph/parsers/crosslayer/static-ref-scanner.ts
|
|
33211
|
-
var
|
|
33212
|
-
var
|
|
33389
|
+
var import_node_fs24 = require("node:fs");
|
|
33390
|
+
var import_node_path28 = require("node:path");
|
|
33213
33391
|
init_config();
|
|
33214
33392
|
var MIN_VALUE_LENGTH = 4;
|
|
33215
33393
|
var SKIP_VALUES = /* @__PURE__ */ new Set([
|
|
@@ -33384,11 +33562,11 @@ var staticRefScannerParser = {
|
|
|
33384
33562
|
const seen = /* @__PURE__ */ new Set();
|
|
33385
33563
|
let filesScanned = 0;
|
|
33386
33564
|
for (const absPath of files) {
|
|
33387
|
-
const relFromSrc = (0,
|
|
33388
|
-
const sourceId = relFromSrc.startsWith("..") ? (0,
|
|
33565
|
+
const relFromSrc = (0, import_node_path28.relative)(srcDir, absPath).replace(/\\/g, "/");
|
|
33566
|
+
const sourceId = relFromSrc.startsWith("..") ? (0, import_node_path28.relative)(rootDir, absPath).replace(/\\/g, "/") : relFromSrc;
|
|
33389
33567
|
const sourceLayer = uiNodeIds.has(sourceId) ? "ui" : apiNodeIds.has(sourceId) ? "api" : null;
|
|
33390
33568
|
if (!sourceLayer) continue;
|
|
33391
|
-
const content = (0,
|
|
33569
|
+
const content = (0, import_node_fs24.readFileSync)(absPath, "utf-8");
|
|
33392
33570
|
filesScanned++;
|
|
33393
33571
|
let fileRefs;
|
|
33394
33572
|
if (parseCode2) {
|
|
@@ -33430,13 +33608,13 @@ var staticRefScannerParser = {
|
|
|
33430
33608
|
};
|
|
33431
33609
|
|
|
33432
33610
|
// src/server/graph/parsers/crosslayer/middleware-gates.ts
|
|
33433
|
-
var
|
|
33611
|
+
var import_node_path29 = require("node:path");
|
|
33434
33612
|
init_ts_extractor();
|
|
33435
33613
|
init_config();
|
|
33436
33614
|
function toNodeId4(srcDir, rootDir, absPath) {
|
|
33437
|
-
const relFromSrc = (0,
|
|
33615
|
+
const relFromSrc = (0, import_node_path29.relative)(srcDir, absPath).replace(/\\/g, "/");
|
|
33438
33616
|
if (relFromSrc.startsWith("..")) {
|
|
33439
|
-
return (0,
|
|
33617
|
+
return (0, import_node_path29.relative)(rootDir, absPath).replace(/\\/g, "/");
|
|
33440
33618
|
}
|
|
33441
33619
|
return relFromSrc;
|
|
33442
33620
|
}
|
|
@@ -33738,7 +33916,7 @@ function registerBuiltins3(registry, disabled) {
|
|
|
33738
33916
|
function loadCustomParsers(registry, config, rootDir, disabled) {
|
|
33739
33917
|
for (const entry of config.parsers?.custom ?? []) {
|
|
33740
33918
|
try {
|
|
33741
|
-
const absPath = (0,
|
|
33919
|
+
const absPath = (0, import_node_path30.resolve)(rootDir, entry.path);
|
|
33742
33920
|
const mod = require(absPath);
|
|
33743
33921
|
const parser = "default" in mod ? mod.default : mod;
|
|
33744
33922
|
if (disabled.has(parser.id)) continue;
|
|
@@ -33767,8 +33945,8 @@ function createRegistry(config, rootDir) {
|
|
|
33767
33945
|
}
|
|
33768
33946
|
|
|
33769
33947
|
// src/server/graph/core/language-detection.ts
|
|
33770
|
-
var
|
|
33771
|
-
var
|
|
33948
|
+
var import_node_fs25 = require("node:fs");
|
|
33949
|
+
var import_node_path31 = require("node:path");
|
|
33772
33950
|
init_launch_kit_paths();
|
|
33773
33951
|
var EXTENSION_TO_LANGUAGE = {
|
|
33774
33952
|
// Web / Frontend
|
|
@@ -33881,10 +34059,10 @@ var AUXILIARY_LANGUAGES = /* @__PURE__ */ new Set([
|
|
|
33881
34059
|
]);
|
|
33882
34060
|
function walkForExtensions(dir, extCounts, depth = 0) {
|
|
33883
34061
|
if (depth > 10) return;
|
|
33884
|
-
if (!(0,
|
|
34062
|
+
if (!(0, import_node_fs25.existsSync)(dir)) return;
|
|
33885
34063
|
let entries;
|
|
33886
34064
|
try {
|
|
33887
|
-
entries = (0,
|
|
34065
|
+
entries = (0, import_node_fs25.readdirSync)(dir, { withFileTypes: true });
|
|
33888
34066
|
} catch {
|
|
33889
34067
|
return;
|
|
33890
34068
|
}
|
|
@@ -33892,9 +34070,9 @@ function walkForExtensions(dir, extCounts, depth = 0) {
|
|
|
33892
34070
|
if (entry.name.startsWith(".") && entry.isDirectory()) continue;
|
|
33893
34071
|
if (entry.isDirectory()) {
|
|
33894
34072
|
if (IGNORE_DIRS.has(entry.name)) continue;
|
|
33895
|
-
walkForExtensions((0,
|
|
34073
|
+
walkForExtensions((0, import_node_path31.join)(dir, entry.name), extCounts, depth + 1);
|
|
33896
34074
|
} else {
|
|
33897
|
-
const ext = (0,
|
|
34075
|
+
const ext = (0, import_node_path31.extname)(entry.name).toLowerCase();
|
|
33898
34076
|
if (ext && EXTENSION_TO_LANGUAGE[ext]) {
|
|
33899
34077
|
extCounts.set(ext, (extCounts.get(ext) ?? 0) + 1);
|
|
33900
34078
|
}
|
|
@@ -33935,13 +34113,13 @@ function detectLanguages(rootDir, supportedLanguages) {
|
|
|
33935
34113
|
}
|
|
33936
34114
|
|
|
33937
34115
|
// src/server/graph/core/audit-core.ts
|
|
33938
|
-
var
|
|
33939
|
-
var
|
|
34116
|
+
var import_node_fs27 = require("node:fs");
|
|
34117
|
+
var import_node_path33 = require("node:path");
|
|
33940
34118
|
init_launch_kit_paths();
|
|
33941
34119
|
|
|
33942
34120
|
// src/server/graph/core/audit-security.ts
|
|
33943
|
-
var
|
|
33944
|
-
var
|
|
34121
|
+
var import_node_fs26 = require("node:fs");
|
|
34122
|
+
var import_node_path32 = require("node:path");
|
|
33945
34123
|
init_ts_extractor();
|
|
33946
34124
|
init_config();
|
|
33947
34125
|
function collectSourceFiles(rootDir) {
|
|
@@ -33966,9 +34144,9 @@ function collectSourceFiles(rootDir) {
|
|
|
33966
34144
|
return out;
|
|
33967
34145
|
}
|
|
33968
34146
|
function toNodeId5(rootDir, srcDir, absPath) {
|
|
33969
|
-
const relFromSrc = (0,
|
|
34147
|
+
const relFromSrc = (0, import_node_path32.relative)(srcDir, absPath).replace(/\\/g, "/");
|
|
33970
34148
|
if (relFromSrc.startsWith("..")) {
|
|
33971
|
-
return (0,
|
|
34149
|
+
return (0, import_node_path32.relative)(rootDir, absPath).replace(/\\/g, "/");
|
|
33972
34150
|
}
|
|
33973
34151
|
return relFromSrc;
|
|
33974
34152
|
}
|
|
@@ -34078,18 +34256,18 @@ function collectDeclaredEnvKeys(rootDir) {
|
|
|
34078
34256
|
const files = [];
|
|
34079
34257
|
let entries = [];
|
|
34080
34258
|
try {
|
|
34081
|
-
entries = (0,
|
|
34259
|
+
entries = (0, import_node_fs26.readdirSync)(rootDir);
|
|
34082
34260
|
} catch {
|
|
34083
34261
|
return { keys, files };
|
|
34084
34262
|
}
|
|
34085
34263
|
for (const name of entries) {
|
|
34086
34264
|
if (!name.startsWith(".env")) continue;
|
|
34087
|
-
const abs = (0,
|
|
34088
|
-
if (!(0,
|
|
34265
|
+
const abs = (0, import_node_path32.join)(rootDir, name);
|
|
34266
|
+
if (!(0, import_node_fs26.existsSync)(abs)) continue;
|
|
34089
34267
|
files.push(name);
|
|
34090
34268
|
let content = "";
|
|
34091
34269
|
try {
|
|
34092
|
-
content = (0,
|
|
34270
|
+
content = (0, import_node_fs26.readFileSync)(abs, "utf-8");
|
|
34093
34271
|
} catch {
|
|
34094
34272
|
continue;
|
|
34095
34273
|
}
|
|
@@ -34276,10 +34454,10 @@ function checkHardcodedUrlFallback(rootDir, core) {
|
|
|
34276
34454
|
|
|
34277
34455
|
// src/server/graph/core/audit-core.ts
|
|
34278
34456
|
function readGraphFile(rootDir, layer) {
|
|
34279
|
-
const filePath = (0,
|
|
34280
|
-
if (!(0,
|
|
34457
|
+
const filePath = (0, import_node_path33.join)(rootDir, LAUNCHSECURE_DIR, "graphs", `${layer}.json`);
|
|
34458
|
+
if (!(0, import_node_fs27.existsSync)(filePath)) return null;
|
|
34281
34459
|
try {
|
|
34282
|
-
return JSON.parse((0,
|
|
34460
|
+
return JSON.parse((0, import_node_fs27.readFileSync)(filePath, "utf-8"));
|
|
34283
34461
|
} catch {
|
|
34284
34462
|
return null;
|
|
34285
34463
|
}
|
|
@@ -34321,15 +34499,15 @@ function checkUnprotectedRoutes(rootDir) {
|
|
|
34321
34499
|
const findings = [];
|
|
34322
34500
|
const api = readGraphFile(rootDir, "api");
|
|
34323
34501
|
if (!api) return buildSkipped("api", "unprotected_routes", "no api graph");
|
|
34324
|
-
const routePermsPath = (0,
|
|
34325
|
-
if (!(0,
|
|
34502
|
+
const routePermsPath = (0, import_node_path33.join)(rootDir, "src", "config", "route-permissions.ts");
|
|
34503
|
+
if (!(0, import_node_fs27.existsSync)(routePermsPath)) {
|
|
34326
34504
|
return buildSkipped(
|
|
34327
34505
|
"api",
|
|
34328
34506
|
"unprotected_routes",
|
|
34329
34507
|
`no src/config/route-permissions.ts \u2014 this check needs a centralized ROUTE_PERMISSIONS inventory to compare endpoints against`
|
|
34330
34508
|
);
|
|
34331
34509
|
}
|
|
34332
|
-
const routePermsContent = (0,
|
|
34510
|
+
const routePermsContent = (0, import_node_fs27.readFileSync)(routePermsPath, "utf-8");
|
|
34333
34511
|
const registeredRoutes = /* @__PURE__ */ new Set();
|
|
34334
34512
|
const routeEntryRe = /path:\s*'([^']+)'/g;
|
|
34335
34513
|
let rm;
|
|
@@ -34414,15 +34592,15 @@ function checkUnenforcedPermissions(rootDir) {
|
|
|
34414
34592
|
`no seed_permission nodes \u2014 this project either has no seed permissions or hasn't tagged them in seed.ts`
|
|
34415
34593
|
);
|
|
34416
34594
|
}
|
|
34417
|
-
const routePermsPath = (0,
|
|
34418
|
-
if (!(0,
|
|
34595
|
+
const routePermsPath = (0, import_node_path33.join)(rootDir, "src", "config", "route-permissions.ts");
|
|
34596
|
+
if (!(0, import_node_fs27.existsSync)(routePermsPath)) {
|
|
34419
34597
|
return buildSkipped(
|
|
34420
34598
|
"static",
|
|
34421
34599
|
"unenforced_permissions",
|
|
34422
34600
|
`no src/config/route-permissions.ts to compare seed permissions against`
|
|
34423
34601
|
);
|
|
34424
34602
|
}
|
|
34425
|
-
const routePermsContent = (0,
|
|
34603
|
+
const routePermsContent = (0, import_node_fs27.readFileSync)(routePermsPath, "utf-8");
|
|
34426
34604
|
for (const perm of permissions) {
|
|
34427
34605
|
const regex = new RegExp(`permission:\\s*['"]${perm.key}['"]`);
|
|
34428
34606
|
if (!regex.test(routePermsContent)) {
|
|
@@ -34458,9 +34636,9 @@ function checkHardcodedValues(rootDir) {
|
|
|
34458
34636
|
const seen = /* @__PURE__ */ new Set();
|
|
34459
34637
|
for (const node of api.nodes) {
|
|
34460
34638
|
if (node.type !== "endpoint") continue;
|
|
34461
|
-
const filePath = (0,
|
|
34462
|
-
if (!(0,
|
|
34463
|
-
const content = (0,
|
|
34639
|
+
const filePath = (0, import_node_path33.join)(rootDir, "src", node.id);
|
|
34640
|
+
if (!(0, import_node_fs27.existsSync)(filePath)) continue;
|
|
34641
|
+
const content = (0, import_node_fs27.readFileSync)(filePath, "utf-8");
|
|
34464
34642
|
let m;
|
|
34465
34643
|
allCapsRe.lastIndex = 0;
|
|
34466
34644
|
while ((m = allCapsRe.exec(content)) !== null) {
|
|
@@ -34565,26 +34743,26 @@ function runAudit(rootDir, layer, check) {
|
|
|
34565
34743
|
}
|
|
34566
34744
|
|
|
34567
34745
|
// src/server/graph/core/projects.ts
|
|
34568
|
-
var
|
|
34746
|
+
var import_node_path36 = require("node:path");
|
|
34569
34747
|
|
|
34570
34748
|
// src/server/lib/worktree.ts
|
|
34571
|
-
var
|
|
34749
|
+
var import_node_path35 = require("node:path");
|
|
34572
34750
|
|
|
34573
34751
|
// src/server/orbit/registry.ts
|
|
34574
|
-
var
|
|
34752
|
+
var import_node_fs28 = require("node:fs");
|
|
34575
34753
|
var import_node_os5 = require("node:os");
|
|
34576
|
-
var
|
|
34754
|
+
var import_node_path34 = require("node:path");
|
|
34577
34755
|
init_launch_kit_paths();
|
|
34578
|
-
var REGISTRY_DIR = (0,
|
|
34579
|
-
var REGISTRY_PATH = (0,
|
|
34580
|
-
var LOCK_PATH = (0,
|
|
34756
|
+
var REGISTRY_DIR = (0, import_node_path34.join)((0, import_node_os5.homedir)(), LAUNCHSECURE_DIR, "orbit");
|
|
34757
|
+
var REGISTRY_PATH = (0, import_node_path34.join)(REGISTRY_DIR, "state.json");
|
|
34758
|
+
var LOCK_PATH = (0, import_node_path34.join)(REGISTRY_DIR, "state.json.lock");
|
|
34581
34759
|
function emptyRegistry() {
|
|
34582
34760
|
return { version: 1, worktrees: {} };
|
|
34583
34761
|
}
|
|
34584
34762
|
function readRegistry() {
|
|
34585
|
-
if (!(0,
|
|
34763
|
+
if (!(0, import_node_fs28.existsSync)(REGISTRY_PATH)) return emptyRegistry();
|
|
34586
34764
|
try {
|
|
34587
|
-
const parsed = JSON.parse((0,
|
|
34765
|
+
const parsed = JSON.parse((0, import_node_fs28.readFileSync)(REGISTRY_PATH, "utf-8"));
|
|
34588
34766
|
if (parsed?.version === 1 && parsed.worktrees && typeof parsed.worktrees === "object") {
|
|
34589
34767
|
return parsed;
|
|
34590
34768
|
}
|
|
@@ -34614,7 +34792,7 @@ function resolveWorktreeRoot(slug, monorepoRoot) {
|
|
|
34614
34792
|
function resolveWorktreeOrProjectRoot(args, monorepoRoot) {
|
|
34615
34793
|
const projectRoot = typeof args.project_root === "string" ? args.project_root.trim() : "";
|
|
34616
34794
|
if (projectRoot) {
|
|
34617
|
-
return (0,
|
|
34795
|
+
return (0, import_node_path35.isAbsolute)(projectRoot) ? projectRoot : (0, import_node_path35.resolve)(monorepoRoot, projectRoot);
|
|
34618
34796
|
}
|
|
34619
34797
|
const worktree = typeof args.worktree === "string" ? args.worktree.trim() : "";
|
|
34620
34798
|
if (worktree) {
|
|
@@ -34633,7 +34811,7 @@ function listProjects(monorepoRoot) {
|
|
|
34633
34811
|
return entries.map((p) => ({
|
|
34634
34812
|
name: p.name,
|
|
34635
34813
|
root: p.root,
|
|
34636
|
-
absoluteRoot: (0,
|
|
34814
|
+
absoluteRoot: (0, import_node_path36.resolve)(monorepoRoot, p.root)
|
|
34637
34815
|
}));
|
|
34638
34816
|
}
|
|
34639
34817
|
function resolveProject(name, projects) {
|
|
@@ -35056,6 +35234,39 @@ USE THIS FOR: "are there unsafe migrations on this branch", "audit the migration
|
|
|
35056
35234
|
required: ["target"]
|
|
35057
35235
|
}
|
|
35058
35236
|
},
|
|
35237
|
+
{
|
|
35238
|
+
name: "test_plan",
|
|
35239
|
+
description: 'Assemble the ordered snippet chain needed to exercise a target action. Walks the context graph\'s requires/produces backward from the target (prerequisites first, target last), binds each step to its snippet (from tests/snippets/), and flags gaps \u2014 a required state nothing produces, an action with no snippet, or a cycle.\n\nUSE THIS FOR: "what\'s the test plan for creating a tag", "what setup does action X need". Returns { target, steps[], gaps[], runnable }. Requires the `context` layer (run generate_graph first). When runnable is false, the gaps tell you which snippets to scaffold next.',
|
|
35240
|
+
inputSchema: {
|
|
35241
|
+
type: "object",
|
|
35242
|
+
properties: {
|
|
35243
|
+
target: { type: "string", description: 'Context action node id (e.g. "action:app/api/orgs/[orgSlug]/tags/route.ts") or the bare key.' },
|
|
35244
|
+
snippets_dir: { type: "string", description: `Snippets directory relative to project root. Default "${DEFAULT_SNIPPETS_DIR}".` },
|
|
35245
|
+
project: { type: "string", description: PROJECT_PARAM_DESCRIPTION },
|
|
35246
|
+
worktree: { type: "string", description: WORKTREE_PARAM_DESCRIPTION2 },
|
|
35247
|
+
project_root: { type: "string", description: PROJECT_ROOT_PARAM_DESCRIPTION2 }
|
|
35248
|
+
},
|
|
35249
|
+
required: ["target"]
|
|
35250
|
+
}
|
|
35251
|
+
},
|
|
35252
|
+
{
|
|
35253
|
+
name: "generate_spec",
|
|
35254
|
+
description: 'Generate a runnable Playwright .spec.ts from a target action: builds the test_plan, then emits imports + ordered `await snippet.run(page, {...})` calls. Params are auto-classified \u2014 secrets \u2192 process.env, free-form (name/color/icon/description) \u2192 faker.*, and state-bound (email/slug/id) \u2192 TODO + returned in missingFixtures. Supply those via `fixtures`.\n\nUSE THIS FOR: "generate the test for creating a tag". Returns { code, missingFixtures, complete }. complete:true means every state-bound param had a fixture (secrets via env + faker auto). Requires the `context` layer + snippets.',
|
|
35255
|
+
inputSchema: {
|
|
35256
|
+
type: "object",
|
|
35257
|
+
properties: {
|
|
35258
|
+
target: { type: "string", description: "Context action node id (or bare key)." },
|
|
35259
|
+
fixtures: { type: "object", description: 'param name -> value for state-bound params (e.g. {"email":"...","orgSlug":"..."}). Overrides classification.', additionalProperties: true },
|
|
35260
|
+
title: { type: "string", description: "Test title. Defaults to the target." },
|
|
35261
|
+
spec_dir: { type: "string", description: 'Where the spec will live (for import paths). Default "tests/generated".' },
|
|
35262
|
+
snippets_dir: { type: "string", description: `Snippets directory. Default "${DEFAULT_SNIPPETS_DIR}".` },
|
|
35263
|
+
project: { type: "string", description: PROJECT_PARAM_DESCRIPTION },
|
|
35264
|
+
worktree: { type: "string", description: WORKTREE_PARAM_DESCRIPTION2 },
|
|
35265
|
+
project_root: { type: "string", description: PROJECT_ROOT_PARAM_DESCRIPTION2 }
|
|
35266
|
+
},
|
|
35267
|
+
required: ["target"]
|
|
35268
|
+
}
|
|
35269
|
+
},
|
|
35059
35270
|
{
|
|
35060
35271
|
name: "auth_coverage_report",
|
|
35061
35272
|
description: 'Aggregate every API endpoint by its auth[] wrapper(s) \u2014 surfaces endpoints with empty auth, groups by module, shows which auth strategies dominate. Computed from api.json endpoint auth field (100% populated).\n\nUSE THIS FOR: "are there unauthenticated endpoints", "which auth wrappers are in use", "audit auth strategy consistency across modules". Paginated. Returns { total, by_strategy: {strategy: count}, unauthenticated: [endpoint_ids], by_module: {module: {total, by_strategy}} } plus the paginated endpoint list.',
|
|
@@ -36039,12 +36250,12 @@ function handleReadGraph(args) {
|
|
|
36039
36250
|
return okJson(result);
|
|
36040
36251
|
}
|
|
36041
36252
|
function nodeToFilePath(rootDir, layer, nodeId) {
|
|
36042
|
-
if (layer === "ui" || layer === "api") return (0,
|
|
36043
|
-
if (layer === "db") return (0,
|
|
36044
|
-
const withSrc = (0,
|
|
36045
|
-
if ((0,
|
|
36046
|
-
const direct = (0,
|
|
36047
|
-
if ((0,
|
|
36253
|
+
if (layer === "ui" || layer === "api") return (0, import_node_path38.join)(rootDir, "src", nodeId);
|
|
36254
|
+
if (layer === "db") return (0, import_node_path38.join)(rootDir, "prisma", "schema.prisma");
|
|
36255
|
+
const withSrc = (0, import_node_path38.join)(rootDir, "src", nodeId);
|
|
36256
|
+
if ((0, import_node_fs30.existsSync)(withSrc)) return withSrc;
|
|
36257
|
+
const direct = (0, import_node_path38.join)(rootDir, nodeId);
|
|
36258
|
+
if ((0, import_node_fs30.existsSync)(direct)) return direct;
|
|
36048
36259
|
return null;
|
|
36049
36260
|
}
|
|
36050
36261
|
function handleInspectNode(args) {
|
|
@@ -36312,11 +36523,11 @@ function handleGrepNodes(args) {
|
|
|
36312
36523
|
let filesSearched = 0;
|
|
36313
36524
|
let truncated = false;
|
|
36314
36525
|
for (const [filePath, nodeId] of filePaths) {
|
|
36315
|
-
if (!(0,
|
|
36526
|
+
if (!(0, import_node_fs30.existsSync)(filePath)) continue;
|
|
36316
36527
|
filesSearched++;
|
|
36317
36528
|
let content;
|
|
36318
36529
|
try {
|
|
36319
|
-
content = (0,
|
|
36530
|
+
content = (0, import_node_fs30.readFileSync)(filePath, "utf-8");
|
|
36320
36531
|
} catch {
|
|
36321
36532
|
continue;
|
|
36322
36533
|
}
|
|
@@ -36535,11 +36746,11 @@ function handleStartChartServer(args) {
|
|
|
36535
36746
|
});
|
|
36536
36747
|
}
|
|
36537
36748
|
const entryPath = process.argv[1];
|
|
36538
|
-
const logDir = (0,
|
|
36539
|
-
(0,
|
|
36540
|
-
const logPath = (0,
|
|
36541
|
-
const out = (0,
|
|
36542
|
-
const err2 = (0,
|
|
36749
|
+
const logDir = (0, import_node_path38.join)((0, import_node_os6.homedir)(), LAUNCHSECURE_DIR);
|
|
36750
|
+
(0, import_node_fs30.mkdirSync)(logDir, { recursive: true });
|
|
36751
|
+
const logPath = (0, import_node_path38.join)(logDir, "launch-chart.log");
|
|
36752
|
+
const out = (0, import_node_fs30.openSync)(logPath, "a");
|
|
36753
|
+
const err2 = (0, import_node_fs30.openSync)(logPath, "a");
|
|
36543
36754
|
const portArgs = args.port ? ["--port", String(args.port)] : [];
|
|
36544
36755
|
const child = (0, import_node_child_process3.spawn)(process.execPath, [entryPath, "serve", ...portArgs], {
|
|
36545
36756
|
detached: true,
|
|
@@ -36717,6 +36928,60 @@ function handleDriftReport(args) {
|
|
|
36717
36928
|
items: page
|
|
36718
36929
|
});
|
|
36719
36930
|
}
|
|
36931
|
+
function handleGenerateSpec(args) {
|
|
36932
|
+
const __resolved = resolveOrErr(args);
|
|
36933
|
+
if ("content" in __resolved) return __resolved;
|
|
36934
|
+
const { rootDir } = __resolved;
|
|
36935
|
+
const target = typeof args.target === "string" ? args.target.trim() : "";
|
|
36936
|
+
if (!target) return err("target is required (a context action node id).");
|
|
36937
|
+
const snippetsDir = typeof args.snippets_dir === "string" && args.snippets_dir.trim() ? args.snippets_dir.trim() : DEFAULT_SNIPPETS_DIR;
|
|
36938
|
+
const specDir = typeof args.spec_dir === "string" && args.spec_dir.trim() ? args.spec_dir.trim() : "tests/generated";
|
|
36939
|
+
const fixtures = args.fixtures && typeof args.fixtures === "object" ? args.fixtures : {};
|
|
36940
|
+
const title = typeof args.title === "string" ? args.title : void 0;
|
|
36941
|
+
const g = readGraph(rootDir, "context");
|
|
36942
|
+
if (!g) return err("No `context` layer found. Run generate_graph first to build context.json.");
|
|
36943
|
+
let node = g.nodes.find((n) => n.id === target);
|
|
36944
|
+
if (!node && !target.startsWith("action:") && !target.startsWith("state:")) {
|
|
36945
|
+
node = g.nodes.find((n) => n.id === `action:${target}`) ?? g.nodes.find((n) => n.id === `state:${target}`);
|
|
36946
|
+
}
|
|
36947
|
+
if (!node) return err(`No context node matching "${target}". Use read_graph layer:context to list nodes.`);
|
|
36948
|
+
const snippets = loadSnippetIndex(rootDir, snippetsDir);
|
|
36949
|
+
const plan = buildTestPlan(g, node.id, snippets);
|
|
36950
|
+
const spec = generateSpec(plan, { title: title ?? String(node.name), specDir, fixtures });
|
|
36951
|
+
return okJson({
|
|
36952
|
+
target: node.id,
|
|
36953
|
+
spec_dir: specDir,
|
|
36954
|
+
suggested_path: `${specDir}/${String(node.name).replace(/[^A-Za-z0-9]+/g, "-").replace(/^-|-$/g, "") || "spec"}.spec.ts`,
|
|
36955
|
+
complete: spec.complete,
|
|
36956
|
+
missing_fixtures: spec.missingFixtures,
|
|
36957
|
+
plan_gaps: plan.gaps,
|
|
36958
|
+
code: spec.code,
|
|
36959
|
+
next: spec.complete ? "Write `code` to suggested_path and run `playwright test` (needs @faker-js/faker installed + the secret env vars set)." : "Supply `fixtures` for missing_fixtures (real seeded values), then regenerate."
|
|
36960
|
+
});
|
|
36961
|
+
}
|
|
36962
|
+
function handleTestPlan(args) {
|
|
36963
|
+
const __resolved = resolveOrErr(args);
|
|
36964
|
+
if ("content" in __resolved) return __resolved;
|
|
36965
|
+
const { rootDir } = __resolved;
|
|
36966
|
+
const target = typeof args.target === "string" ? args.target.trim() : "";
|
|
36967
|
+
if (!target) return err("target is required (a context action node id).");
|
|
36968
|
+
const snippetsDir = typeof args.snippets_dir === "string" && args.snippets_dir.trim() ? args.snippets_dir.trim() : DEFAULT_SNIPPETS_DIR;
|
|
36969
|
+
const g = readGraph(rootDir, "context");
|
|
36970
|
+
if (!g) return err("No `context` layer found. Run generate_graph first to build context.json.");
|
|
36971
|
+
let node = g.nodes.find((n) => n.id === target);
|
|
36972
|
+
if (!node && !target.startsWith("action:") && !target.startsWith("state:")) {
|
|
36973
|
+
node = g.nodes.find((n) => n.id === `action:${target}`) ?? g.nodes.find((n) => n.id === `state:${target}`);
|
|
36974
|
+
}
|
|
36975
|
+
if (!node) return err(`No context node matching "${target}". Use read_graph layer:context to list nodes.`);
|
|
36976
|
+
const snippets = loadSnippetIndex(rootDir, snippetsDir);
|
|
36977
|
+
const plan = buildTestPlan(g, node.id, snippets);
|
|
36978
|
+
return okJson({
|
|
36979
|
+
...plan,
|
|
36980
|
+
snippets_dir: snippetsDir,
|
|
36981
|
+
snippets_found: snippets.size,
|
|
36982
|
+
next: plan.runnable ? "Runnable: execute the snippets in `steps` order, threading produced state forward." : "Not yet runnable \u2014 resolve `gaps` (scaffold_snippet for missing bindings; add a producer for unmet states)."
|
|
36983
|
+
});
|
|
36984
|
+
}
|
|
36720
36985
|
function handleScaffoldSnippet(args) {
|
|
36721
36986
|
const __resolved = resolveOrErr(args);
|
|
36722
36987
|
if ("content" in __resolved) return __resolved;
|
|
@@ -36998,20 +37263,20 @@ function handleDetectProjectStack() {
|
|
|
36998
37263
|
if (ref.type === "references_api") stats.references_api++;
|
|
36999
37264
|
}
|
|
37000
37265
|
}
|
|
37001
|
-
const srcDir = (0,
|
|
37002
|
-
if ((0,
|
|
37266
|
+
const srcDir = (0, import_node_path38.join)(rootDir, "src");
|
|
37267
|
+
if ((0, import_node_fs30.existsSync)(srcDir)) {
|
|
37003
37268
|
const scanDir = (dir) => {
|
|
37004
|
-
if (!(0,
|
|
37005
|
-
for (const entry of (0,
|
|
37269
|
+
if (!(0, import_node_fs30.existsSync)(dir)) return;
|
|
37270
|
+
for (const entry of (0, import_node_fs30.readdirSync)(dir, { withFileTypes: true })) {
|
|
37006
37271
|
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
37007
|
-
const full = (0,
|
|
37272
|
+
const full = (0, import_node_path38.join)(dir, entry.name);
|
|
37008
37273
|
if (entry.isDirectory()) {
|
|
37009
37274
|
scanDir(full);
|
|
37010
37275
|
continue;
|
|
37011
37276
|
}
|
|
37012
|
-
if (![".ts", ".tsx"].includes((0,
|
|
37277
|
+
if (![".ts", ".tsx"].includes((0, import_node_path38.extname)(entry.name))) continue;
|
|
37013
37278
|
try {
|
|
37014
|
-
const content = (0,
|
|
37279
|
+
const content = (0, import_node_fs30.readFileSync)(full, "utf-8");
|
|
37015
37280
|
const matches = content.match(/@api\s+(GET|POST|PUT|DELETE|PATCH)\s+\/\S+/g);
|
|
37016
37281
|
if (matches) stats.annotations += matches.length;
|
|
37017
37282
|
} catch {
|
|
@@ -37030,7 +37295,7 @@ function handleDetectProjectStack() {
|
|
|
37030
37295
|
name: p.name,
|
|
37031
37296
|
root: p.root,
|
|
37032
37297
|
absolute_root: p.absoluteRoot,
|
|
37033
|
-
has_graph: (0,
|
|
37298
|
+
has_graph: (0, import_node_fs30.existsSync)((0, import_node_path38.join)(p.absoluteRoot, LAUNCHSECURE_DIR, "graphs"))
|
|
37034
37299
|
}));
|
|
37035
37300
|
return okJson({
|
|
37036
37301
|
languages,
|
|
@@ -37164,6 +37429,14 @@ async function handleMessage(msg) {
|
|
|
37164
37429
|
respond(id ?? null, withFreshnessMeta(handleScaffoldSnippet(args), args));
|
|
37165
37430
|
return;
|
|
37166
37431
|
}
|
|
37432
|
+
if (toolName === "test_plan") {
|
|
37433
|
+
respond(id ?? null, withFreshnessMeta(handleTestPlan(args), args));
|
|
37434
|
+
return;
|
|
37435
|
+
}
|
|
37436
|
+
if (toolName === "generate_spec") {
|
|
37437
|
+
respond(id ?? null, withFreshnessMeta(handleGenerateSpec(args), args));
|
|
37438
|
+
return;
|
|
37439
|
+
}
|
|
37167
37440
|
if (toolName === "trace_path") {
|
|
37168
37441
|
respond(id ?? null, withFreshnessMeta(handleTracePath(args), args));
|
|
37169
37442
|
return;
|