@diffci.com/diffci 0.1.1 → 0.1.3

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.
@@ -3,6 +3,7 @@ import { createTestFileMatcher, DEFAULT_TEST_FILE_MATCHER, testFileMatcherForPro
3
3
  import { isBuiltin } from "node:module";
4
4
  import { dirname, extname, join, normalize, relative, resolve, sep } from "node:path";
5
5
  import ts from "typescript";
6
+ import { adapterFiles, REPOSITORY_ADAPTERS } from "./adapters/index.js";
6
7
  import { analyzeRepository } from "./analyzer.js";
7
8
  const SOURCE_EXTENSIONS = new Set([
8
9
  ".ts",
@@ -13,6 +14,7 @@ const SOURCE_EXTENSIONS = new Set([
13
14
  ".cjs",
14
15
  ".mts",
15
16
  ".cts",
17
+ ".vue",
16
18
  ]);
17
19
  const ASSET_EXTENSIONS = new Set([
18
20
  ".css",
@@ -323,7 +325,7 @@ export function discoverNestedTsconfigPaths(repoPath) {
323
325
  // merged compiler options reproducible across filesystems (readdir order is OS-dependent).
324
326
  return found.sort();
325
327
  }
326
- function createProgram(repoPath, fallbackSourceRoots = []) {
328
+ function createProgram(repoPath, fallbackSourceRoots = [], additionalSources = []) {
327
329
  // Phase 01 F5 (2026-08-26). This was `ts.findConfigFile(repoPath, ...)`, which starts at repoPath
328
330
  // and walks UP - so a repository cloned beneath any directory containing a tsconfig.json was
329
331
  // silently analysed against that ANCESTOR's project instead of its own. Flagged as a known latent
@@ -440,6 +442,10 @@ function createProgram(repoPath, fallbackSourceRoots = []) {
440
442
  options = { ...options, allowJs: true };
441
443
  }
442
444
  }
445
+ if (additionalSources.length) {
446
+ fileNames = [...new Set([...fileNames, ...additionalSources])];
447
+ options = { module: ts.ModuleKind.ESNext, moduleResolution: ts.ModuleResolutionKind.Bundler, target: ts.ScriptTarget.ES2022, ...options, allowJs: true };
448
+ }
443
449
  const program = ts.createProgram({
444
450
  rootNames: fileNames,
445
451
  options,
@@ -523,12 +529,38 @@ export async function buildDependencyGraph(options = {}) {
523
529
  const start = process.hrtime.bigint();
524
530
  const repoPath = options.repoPath ? resolve(options.repoPath) : process.cwd();
525
531
  const profile = analyzeRepository(options);
532
+ const files = adapterFiles(repoPath, options.excludeDirs);
533
+ const context = { repoPath, files, profile };
534
+ const contributions = REPOSITORY_ADAPTERS.filter((adapter) => adapter.detect(context)).map((adapter) => adapter.analyze(context));
535
+ const adapterBlockers = contributions.flatMap((item) => item.blockers);
536
+ if (contributions.some((item) => item.id === "go") && files.some((file) => /\.(?:[cm]?[jt]sx?|vue)$/.test(file))) {
537
+ adapterBlockers.push("Mixed Go/JavaScript repositories require explicit cross-language dependencies; full validation required");
538
+ }
539
+ if (contributions.length && files.some((file) => /\.(?:py|rs|java|kt|cs|svelte|astro)$/.test(file))) {
540
+ adapterBlockers.push("Unmodeled languages alongside an adapter require full validation");
541
+ }
542
+ profile.adapters = contributions.map(({ id, version, blockers }) => ({ id, version, blockers }));
543
+ profile.goTestPackages = Object.assign({}, ...contributions.map((item) => item.testPackages));
544
+ profile.goTestEnvironment = contributions.find((item) => item.id === "go")?.executionEnv;
545
+ const adapterTests = contributions.flatMap((item) => item.testFiles);
546
+ profile.testFilePaths = [...new Set([...profile.testFilePaths, ...adapterTests])].sort();
547
+ if (profile.testUniverse) {
548
+ profile.testUniverse.discoveredTestFiles = profile.testFilePaths.length;
549
+ profile.testUniverse.blindSpot = (profile.testUniverse.declaredFrameworks.length > 0 || contributions.some((item) => item.id === "go")) && profile.testFilePaths.length === 0;
550
+ }
526
551
  const entryPointPaths = new Set(profile.entryPoints.map((e) => e.path));
527
- let { program, options: compilerOptions, resolvedViaProjectReferences } = createProgram(repoPath, profile.sourceRoots);
552
+ const vueSources = contributions.some((item) => item.id === "vue")
553
+ ? files.filter((file) => /\.[cm]?[jt]sx?$/.test(file)).map((file) => join(repoPath, file)) : [];
554
+ let { program, options: compilerOptions, resolvedViaProjectReferences } = createProgram(repoPath, profile.sourceRoots, vueSources);
528
555
  let moduleResolutionCache = ts.createModuleResolutionCache(repoPath, (x) => x, compilerOptions);
529
556
  const sourceFiles = program
530
557
  .getSourceFiles()
531
558
  .filter((sf) => sf.fileName && !sf.fileName.endsWith(".d.ts"));
559
+ for (const item of contributions) {
560
+ for (const virtual of item.virtualSources) {
561
+ sourceFiles.push(ts.createSourceFile(join(repoPath, virtual.path), virtual.source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX));
562
+ }
563
+ }
532
564
  const internalSourcePaths = new Set();
533
565
  for (const sf of sourceFiles) {
534
566
  const rel = toRelativeInternal(repoPath, sf.fileName);
@@ -536,11 +568,14 @@ export async function buildDependencyGraph(options = {}) {
536
568
  internalSourcePaths.add(rel);
537
569
  }
538
570
  }
539
- const edges = [];
571
+ const edges = contributions.flatMap((item) => item.edges);
540
572
  const unresolved = [];
541
573
  const references = [];
542
- const assetPaths = new Set();
543
- const edgeKeys = new Set();
574
+ const assetPaths = new Set(contributions.flatMap((item) => item.assetPaths));
575
+ for (const item of contributions)
576
+ for (const path of item.sourcePaths)
577
+ internalSourcePaths.add(path);
578
+ const edgeKeys = new Set(edges.map((edge) => `${edge.from}|${edge.to}|${edge.kind}`));
544
579
  function addEdge(from, to, kind) {
545
580
  const key = `${from}|${to}|${kind}`;
546
581
  if (edgeKeys.has(key))
@@ -590,6 +625,20 @@ export async function buildDependencyGraph(options = {}) {
590
625
  }
591
626
  const specifierCategory = classifySpecifier(ref.specifier);
592
627
  const resolvableSpecifier = specifierCategory === "relative" || specifierCategory === "absolute" || specifierCategory === "alias" ? stripImportQuery(ref.specifier) : ref.specifier;
628
+ // TypeScript may resolve a Vue import to a declaration shim. Preserve the actual SFC edge.
629
+ if (resolvableSpecifier.endsWith(".vue")) {
630
+ const compilerAliases = Object.entries(compilerOptions.paths ?? {}).map(([pattern, substitutions]) => ({ pattern, substitutions }));
631
+ const candidate = findAssetCandidate(sf.fileName, resolvableSpecifier, compilerAliases.length ? compilerAliases : profile.pathAliases, compilerOptions.baseUrl ?? repoPath);
632
+ const target = candidate && toRelativeInternal(repoPath, candidate);
633
+ if (target && internalSourcePaths.has(target)) {
634
+ addEdge(importerRel, target, ref.kind);
635
+ recordReference("internal-source", importerRel, ref);
636
+ continue;
637
+ }
638
+ recordUnresolved(importerRel, ref, "Vue component not found in analyzed source inventory");
639
+ recordReference("unresolved", importerRel, ref);
640
+ continue;
641
+ }
593
642
  const resolution = ts.resolveModuleName(resolvableSpecifier, sf.fileName, compilerOptions, ts.sys, moduleResolutionCache);
594
643
  if (!resolution.resolvedModule || !resolution.resolvedModule.resolvedFileName) {
595
644
  const category = classifySpecifier(ref.specifier);
@@ -637,6 +686,10 @@ export async function buildDependencyGraph(options = {}) {
637
686
  }
638
687
  }
639
688
  }
689
+ if (unresolved.some((ref) => ref.importer.endsWith(".vue") || stripImportQuery(ref.specifier).endsWith(".vue"))) {
690
+ adapterBlockers.push("Unresolved Vue dependencies require full validation");
691
+ }
692
+ profile.adapterBlockers = [...adapterBlockers];
640
693
  // Nested-package test visibility (2026-08-24, biomejs/biome finding): `internalSourcePaths` above is
641
694
  // strictly the TS PROGRAM's own file list (createProgram()'s `include`/nested-tsconfig-merged
642
695
  // fileNames) - so a package whose own tsconfig deliberately excludes its test directory (a real,
@@ -679,7 +732,7 @@ export async function buildDependencyGraph(options = {}) {
679
732
  profile.stats.testFiles = graph.nodes.filter((n) => n.isTest).length;
680
733
  const integrity = validateDependencyGraph(graph);
681
734
  const dynamicUnresolvedCount = unresolved.filter((u) => u.dynamic).length;
682
- const confidence = computeConfidence(unresolved.length, dynamicUnresolvedCount, integrity.criticalCount, profile.stats.sourceFiles, resolvedViaProjectReferences);
735
+ const confidence = adapterBlockers.length ? "UNSAFE" : computeConfidence(unresolved.length, dynamicUnresolvedCount, integrity.criticalCount, profile.stats.sourceFiles, resolvedViaProjectReferences);
683
736
  const internalAssetEdges = edges.filter((e) => e.kind === "asset").length;
684
737
  const externalReferences = references.filter((r) => r.resolution === "external-package").length;
685
738
  const platformBuiltinReferences = references.filter((r) => r.resolution === "platform-builtin").length;
@@ -700,6 +753,7 @@ export async function buildDependencyGraph(options = {}) {
700
753
  };
701
754
  return {
702
755
  graph,
756
+ adapterBlockers,
703
757
  profile,
704
758
  unresolved,
705
759
  references,
@@ -713,6 +767,18 @@ export async function buildDependencyGraph(options = {}) {
713
767
  resolvedViaProjectReferences,
714
768
  };
715
769
  }
770
+ /** Product eligibility includes native adapters; legacy TS corpus classification stays separate. */
771
+ export function classifyRepositoryProject(repoPath) {
772
+ const typescript = classifyTypeScriptProject(repoPath);
773
+ if (typescript.capable)
774
+ return typescript;
775
+ const files = adapterFiles(repoPath);
776
+ if (files.includes("go.mod"))
777
+ return { capable: true, reason: "Go module (package-level analysis)" };
778
+ if (files.some((file) => file.endsWith(".vue")))
779
+ return { capable: true, reason: "Vue single-file components" };
780
+ return { capable: false, reason: "No TypeScript project, Vue components, or root Go module found" };
781
+ }
716
782
  /**
717
783
  * Can DiffCI build a dependency graph for this repository? (Phase 01 F3, 2026-08-26.)
718
784
  *
@@ -899,6 +965,8 @@ function computeConfidence(unresolvedCount, dynamicUnresolvedCount, integrityCri
899
965
  * narrowing only applies when unresolved/dynamic-unresolved imports are the actual reason, never when
900
966
  * sourceFileCount or integrity triggered it. */
901
967
  export function refineConfidenceForDelta(result, changedFiles) {
968
+ if (result.adapterBlockers?.length)
969
+ return "UNSAFE";
902
970
  // Anything that was never UNSAFE in the first place passes through untouched - there is nothing to
903
971
  // narrow, and re-deriving sourceFileCount/integrity from raw fields here (rather than trusting the
904
972
  // already-computed confidence) would be both redundant and a real correctness risk: a caller's
@@ -3,7 +3,7 @@ import { refineConfidenceForDelta } from "./graph.js";
3
3
  import { repositoryLayout, UNKNOWN_REPOSITORY_LAYOUT } from "./layout.js";
4
4
  import { DEFAULT_TEST_FILE_MATCHER, matchesGlob as matchesTestGlob, testFileMatcherForProfile } from "./test-discovery.js";
5
5
  import { resolveTestFixtureOwners } from "./test-fixture-ownership.js";
6
- const SOURCE_EXTENSIONS = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"]);
6
+ const SOURCE_EXTENSIONS = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts", ".vue", ".go"]);
7
7
  const ASSET_EXTENSIONS = new Set([".css", ".scss", ".sass", ".less", ".json", ".jsonc", ".svg", ".png", ".jpg", ".jpeg", ".gif", ".webp", ".ico", ".bmp", ".woff", ".woff2", ".ttf", ".otf", ".eot", ".wasm", ".md", ".txt"]);
8
8
  const NEXT_ENTRY_NAMES = new Set(["page", "layout", "route", "api", "loading", "error", "template", "not-found", "middleware", "generatemetadata", "generatestaticparams"]);
9
9
  function isSourceFilePath(filePath) { return SOURCE_EXTENSIONS.has(extname(filePath).toLowerCase()); }
@@ -18,6 +18,10 @@ function isDocumentationFile(filePath, layout) { return layout.isDocumentationPa
18
18
  function isConfigFile(filePath) {
19
19
  const CONFIG_FILE_NAMES = new Set(["package.json", "package-lock.json", "yarn.lock", "pnpm-lock.yaml", "bun.lockb", "bun.lock", "tsconfig.json", "tsconfig.base.json", "tsconfig.build.json", "jsconfig.json"]);
20
20
  const base = posix.basename(filePath);
21
+ if (["go.mod", "go.sum", "go.work", "go.work.sum"].includes(base))
22
+ return true;
23
+ if (/^(?:vite|vue|nuxt)\.config\./.test(base))
24
+ return true;
21
25
  if (CONFIG_FILE_NAMES.has(base))
22
26
  return true;
23
27
  if (base.startsWith("next.config"))
@@ -265,7 +269,12 @@ export class ImpactAnalyzer {
265
269
  const changedImpacts = delta.files.map((file) => ({ file, category: classifyChangedFile(file, this.isTestFile, this.layout, options.repositoryFiles), reasons: changedFileReasons(file) }));
266
270
  const evidence = [];
267
271
  const riskSignals = [];
268
- const fallbackReasons = [];
272
+ const fallbackReasons = [...(graphResult.adapterBlockers ?? [])];
273
+ for (const file of delta.files) {
274
+ if (allChangePaths(file).some((path) => /(?:^|\/)(?:go\.(?:mod|sum|work)|go\.work\.sum|(?:vite|vue|nuxt)\.config\.[^/]+)$/.test(path))) {
275
+ fallbackReasons.push(`Language/framework configuration changed: ${file.path}`);
276
+ }
277
+ }
269
278
  this.applyGlobalRiskRules(delta, riskSignals, fallbackReasons);
270
279
  // Stage 1B fix (2026-08-21, docs/research/2026-08-21-stage1b-*.md): refine the graph's raw,
271
280
  // delta-independent confidence to THIS delta's changed files - see refineConfidenceForDelta()'s doc
@@ -370,6 +370,12 @@ export function createTestFileMatcher(patterns, options = {}) {
370
370
  /** The one place that turns a profile into a matcher, so analyzer discovery, graph node flags and
371
371
  * impact classification cannot disagree about what a test is. */
372
372
  export function testFileMatcherForProfile(profile) {
373
+ if (profile.goTestPackages && Object.keys(profile.goTestPackages).length) {
374
+ const jsMatcher = testFileMatcherForProfile({ ...profile, goTestPackages: undefined });
375
+ const matcher = ((path) => Object.hasOwn(profile.goTestPackages, path) || jsMatcher(path));
376
+ Object.defineProperty(matcher, "patterns", { value: jsMatcher.patterns });
377
+ return matcher;
378
+ }
373
379
  if (!profile.testPatterns)
374
380
  return DEFAULT_TEST_FILE_MATCHER;
375
381
  return createTestFileMatcher(profile.testPatterns, {
@@ -3,6 +3,10 @@
3
3
  DiffCI has three install surfaces with the same initial contract: observe CI, write a report, and do
4
4
  not change what the host repository runs.
5
5
 
6
+ The product model is open core. The npm CLI and basic GitHub Action are the open-source adoption path;
7
+ DiffCI Cloud adds hosted history, organization dashboards, policies, managed operations, and support.
8
+ See [`open-core-packaging.md`](open-core-packaging.md).
9
+
6
10
  ## GitHub App
7
11
 
8
12
  The DiffCI Shadow GitHub App is the lowest-friction research and design-partner path. It receives
@@ -28,7 +32,7 @@ jobs:
28
32
  - uses: DiffCI/DiffCI.com@v1
29
33
  ```
30
34
 
31
- For the strongest supply-chain posture, pin the Action to a full commit SHA. `npx @diffci.com/diffci verify-workflow`
35
+ For the strongest supply-chain posture, pin the Action to a full commit SHA. `npx @diffci.com/diffci@latest verify-workflow`
32
36
  checks that the job is dedicated, read-only, not required by other jobs, and unable to alter the rest
33
37
  of CI.
34
38
 
@@ -37,8 +41,8 @@ of CI.
37
41
  The CLI is the standalone npm package surface. The package name is `@diffci.com/diffci`:
38
42
 
39
43
  ```bash
40
- npx @diffci.com/diffci observe
41
- npx @diffci.com/diffci verify-workflow
44
+ npx @diffci.com/diffci@latest observe
45
+ npx @diffci.com/diffci@latest verify-workflow
42
46
  ```
43
47
 
44
48
  `observe` writes a JSON report outside the checkout by default. It never runs, skips, cancels, or
@@ -79,3 +83,10 @@ brew install diffci
79
83
 
80
84
  Those should ship only after the npm CLI and Action have signed releases, provenance, pinned build
81
85
  workflows, and repeatable package verification.
86
+
87
+ ## Supported OSS Channel
88
+
89
+ Tidelift belongs to the open-source package channel. It can provide maintenance, security, license, and
90
+ supply-chain assurance for the npm package without requiring a hosted DiffCI account. It should support
91
+ the OSS core rather than define a separate feature tier. The readiness checklist lives in
92
+ [`tidelift-package-support.md`](tidelift-package-support.md).
@@ -0,0 +1,70 @@
1
+ # Language and framework support
2
+
3
+ DiffCI now has an extensible repository-adapter boundary and initial Vue and Go support.
4
+ These additions propose selections in the existing observer; they do not enable production CI skipping.
5
+
6
+ | Surface | Implemented scope | Boundaries |
7
+ | --- | --- | --- |
8
+ | JavaScript / TypeScript | Existing dependency analysis and ten existing test-runner command mappings | Runner recognition is not a guarantee of complete framework semantics |
9
+ | Vue | SFC parsing with `@vue/compiler-sfc`; script imports, nested components, compiled template asset imports; propagation into importing JS/TS tests | Runtime component/directive resolution, preprocessors, external/custom SFC blocks, style URLs/imports, Nuxt conventions and glob imports require full validation |
10
+ | Go | One root module; native `go list` metadata; package-level transitive test selection, external test packages, embedded files; `go test -json` commands and result parsing | Workspaces/nested modules, inactive Go files, cgo/native objects, runtime plugins, generation/linkname, external local replacements and incomplete metadata require full validation |
11
+ | Mixed Go and JS/TS | Detected | Full validation until cross-language relationships are declared and modeled |
12
+ | Python, Svelte, Astro, Java/Kotlin, C#, Rust | No new semantic support in this release | Require additional adapters and qualification |
13
+
14
+ ## Using the observer
15
+
16
+ Use the existing `observe` command and commit range options. The observer now admits a root
17
+ `go.mod` or Vue SFCs as well as a TypeScript project. Vue projects without a tsconfig have their
18
+ JS/TS files parsed alongside their components. Existing TS-only corpus eligibility remains separate:
19
+ this release does not silently enroll Go repositories in historical JS/TS research cohorts.
20
+
21
+ For Go, install a compatible Go toolchain on the **same host and build environment** used for analysis
22
+ and testing, and prepare the repository's dependencies first using its normal setup procedure.
23
+ DiffCI invokes `go list -mod=readonly -deps -test -json ./...` with `GOTOOLCHAIN=local`, `GOPROXY=off`,
24
+ `GOSUMDB=off`, and `GOWORK=off`. Missing toolchains or dependencies produce refusal/full fallback.
25
+ Go may populate its own build cache but must not modify the checkout. It does not run `go generate`.
26
+ Custom `GOFLAGS` currently require full validation. Discovered GOOS, GOARCH and CGO_ENABLED settings
27
+ are carried into the structured test command.
28
+
29
+ A selection such as `lib/value_test.go` becomes:
30
+
31
+ ```sh
32
+ go test -mod=readonly -json -count=1 ./lib
33
+ ```
34
+
35
+ It runs the entire package. Consumers must honor the emitted `CommandSpec.env`, preserve the build
36
+ context, and check fallback/command-synthesis status before execution. Commands are not portable
37
+ between different GOOS/GOARCH/GOFLAGS contexts. The controlled runner command policies accept `go`;
38
+ hosted images still need a Go installation before Go workloads can run. No deployment is performed
39
+ by these code changes.
40
+
41
+ Go result parsing counts failing **packages**, records failing test names, and rejects incomplete
42
+ JSON streams. It does not invent test-file counts from package counts, so file-based economics
43
+ qualification may still report an unsupported denominator for Go.
44
+
45
+ ## Extension points
46
+
47
+ - `src/repo/adapters/types.ts`: adapter context and graph contribution contract.
48
+ - `src/repo/adapters/index.ts`: framework/language adapter registry and bounded file inventory.
49
+ - `src/repo/adapters/vue.ts`: Vue compiler integration.
50
+ - `src/repo/adapters/go.ts`: native Go package metadata and conservative dependency model.
51
+ - `src/repo/adapters/go-test.ts`: structured Go outcome parsing.
52
+ - `src/planner/test-command.ts`: runner command routing, including verified Go package targets.
53
+
54
+ Adapters contribute source and asset nodes, dependency edges, virtual JS/TS source, runnable test
55
+ identities and explicit blockers. Blockers persist into the profile and graph result and cannot be
56
+ removed by delta-specific reachability refinement. Go graphs bypass the disk cache until every cache
57
+ caller provides a complete toolchain/build-context identity. The cache schema was bumped to prevent
58
+ reuse of graphs created before adapter support.
59
+
60
+ ## Validation and qualification
61
+
62
+ `tests/repo/language-adapters.test.ts` covers transitive Vue selection, unsupported-feature fallbacks,
63
+ Go package imports and embeds, metadata failures, command routing, and incomplete output.
64
+ When Go is on PATH, its native integration test runs the observer against a real Git fixture,
65
+ compares successful full/subset test runs, and verifies the subset catches an introduced fault.
66
+ Without Go, that native test is explicitly skipped.
67
+
68
+ These are implementation checks, not prospective customer safety or savings evidence. Each new
69
+ ecosystem still needs real repository shadow observations and economic qualification before broader
70
+ support or savings claims are made.
package/package.json CHANGED
@@ -1,7 +1,12 @@
1
1
  {
2
2
  "name": "@diffci.com/diffci",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "DiffCI - deterministic change-aware CI planning",
5
+ "license": "AGPL-3.0-only",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/DiffCI/DiffCI.com.git"
9
+ },
5
10
  "private": false,
6
11
  "type": "module",
7
12
  "engines": {
@@ -18,7 +23,10 @@
18
23
  "dist-client/src/repo",
19
24
  "README.md",
20
25
  "docs/distribution.md",
21
- "docs/language-support.md"
26
+ "docs/language-support.md",
27
+ "SECURITY.md",
28
+ "SUPPORT.md",
29
+ "COMMERCIAL.md"
22
30
  ],
23
31
  "exports": {
24
32
  "./*": {
@@ -90,10 +98,12 @@
90
98
  "qualify:universe": "tsx scripts/qualify-universe.ts",
91
99
  "corpus:register": "tsx scripts/register-corpus-entry.ts",
92
100
  "ci:benchmark": "tsx scripts/ci-inference-benchmark.ts",
93
- "ci:reproduce": "tsx scripts/ci-reproduction.ts"
101
+ "ci:reproduce": "tsx scripts/ci-reproduction.ts",
102
+ "check:oss-boundary": "node scripts/check-oss-boundary.mjs"
94
103
  },
95
104
  "dependencies": {
96
105
  "@types/node": "^22.15.12",
106
+ "@vue/compiler-sfc": "3.5.42",
97
107
  "typescript": "^5.8.3",
98
108
  "yaml": "^2.9.0"
99
109
  },
@@ -114,9 +124,5 @@
114
124
  "**/validate-*.test.*",
115
125
  "scripts/**/*.test.mjs"
116
126
  ]
117
- },
118
- "repository": {
119
- "type": "git",
120
- "url": "https://github.com/DiffCI/DiffCI.com"
121
127
  }
122
128
  }