From 16539a629b9d42181c53eb87f3439e2d73e88706 Mon Sep 17 00:00:00 2001
From: swapnil <78632212+swapnilpaliwal-sd@users.noreply.github.com>
Date: Wed, 30 Sep 2026 00:29:42 -0700
Subject: [PATCH 1/6] parser: a bare import of a package the repository
declares binds to its source
A monorepo imports a sibling package by its name, and that package's main /
types / exports name build output that is not in the source tree. tsc then
resolved nothing, or a dist file no program walks, so every call, type and
const across the package boundary was matched by name only. The package-entry
rows already map a dist target back to the source it is built from; import
resolution now uses the same mapping (subpaths and patterns included) for any
bare specifier whose package.json lives under the walked tree, in the
TypeScript and JavaScript front ends. A package tsc resolves inside
node_modules is left alone.
impact: asked of an interface method, the implementations the engine
dispatches to are listed under "must change with it". Without an override
table they had no row at all, and one only surfaced through a wrong by-name
edge that the resolved import removed. The hook's SQL summary gets the same
leg and now drops shape-only pairs as the rules do.
Tests: new TypeScript case 85-workspace-package-import (scoped package with
exports, subpath, pattern, unscoped deep import, a field-typed receiver, and a
third-party control); the three JavaScript alias cases fold into
70-bare-specifier-to-project-source with a workspace-package table row; the
dispatch-base CLI case checks the base side.
Co-authored-by: axiomcode-bot[bot] <334110751+axiomcode-bot[bot]@users.noreply.github.com>
---
.../src/bundler-alias}/legacy/app.js | 0
.../src/bundler-alias}/legacy/lib/extra.js | 0
.../src/bundler-alias}/legacy/lib/index.js | 0
.../bundler-alias}/legacy/lib/util/trim.js | 0
.../bundler-alias}/legacy/webpack.config.cjs | 0
.../src/bundler-alias}/mapped/jsconfig.json | 0
.../src/bundler-alias}/mapped/own/date.js | 0
.../src/bundler-alias}/mapped/probe.js | 0
.../src/bundler-alias}/package.json | 0
.../src/bundler-alias}/shared/fmt.js | 0
.../src/bundler-alias}/src/pages/Home.js | 0
.../src/bundler-alias}/src/utils/date.js | 0
.../src/bundler-alias}/vite.config.js | 0
.../src/framework-alias}/kit/jsconfig.json | 0
.../src/framework-alias}/kit/src/lib/api.js | 0
.../framework-alias}/kit/src/routes/page.js | 0
.../framework-alias}/nuxt/server/api/price.js | 0
.../src/framework-alias}/nuxt/tsconfig.json | 0
.../src/framework-alias}/nuxt/utils/price.js | 0
.../framework-alias}/nuxt4/app/pages/index.js | 0
.../framework-alias}/nuxt4/app/utils/date.js | 0
.../src/framework-alias}/nuxt4/tsconfig.json | 0
.../src/framework-alias}/other/jsconfig.json | 0
.../src/framework-alias}/other/probe.js | 0
.../framework-alias}/other/src/lib/helper.js | 0
.../src/framework-alias}/own/jsconfig.json | 0
.../src/framework-alias}/own/probe.js | 0
.../src/framework-alias}/own/shared/util.js | 0
.../src/framework-alias}/own/src/lib/util.js | 0
.../src/framework-alias}/package.json | 0
.../src/jsconfig-paths}/app.js | 0
.../src/jsconfig-paths}/jsconfig.json | 0
.../src/jsconfig-paths}/lib/check.js | 0
.../src/jsconfig-paths}/noalias/jsconfig.json | 0
.../src/jsconfig-paths}/noalias/probe.js | 0
.../src/jsconfig-paths}/package.json | 0
.../remix/app/models/note.server.js | 0
.../src/jsconfig-paths}/remix/app/route.js | 0
.../src/jsconfig-paths}/remix/tsconfig.json | 0
.../workspace-package/apps/app/package.json | 1 +
.../workspace-package/apps/app/src/main.js | 13 ++
.../packages/lib/package.json | 8 ++
.../packages/lib/src/index.js | 9 ++
.../packages/lib/src/sub/index.js | 3 +
.../packages/tools/package.json | 1 +
.../packages/tools/src/deep.js | 3 +
.../70-bare-specifier-to-project-source.diag | 35 ++++++
.../70-bare-specifier-to-project-source.edges | 35 ++++++
...70-bare-specifier-to-project-source.oracle | 9 ++
.../expected/70-jsconfig-path-alias.diag | 3 -
.../expected/70-jsconfig-path-alias.edges | 4 -
.../expected/70-jsconfig-path-alias.oracle | 2 -
.../expected/71-bundler-config-alias.diag | 21 ----
.../expected/71-bundler-config-alias.edges | 18 ---
.../expected/71-bundler-config-alias.oracle | 8 --
.../71-framework-generated-config-alias.diag | 3 -
.../71-framework-generated-config-alias.edges | 7 --
...71-framework-generated-config-alias.oracle | 1 -
.../src/apps/app/package.json | 1 +
.../src/apps/app/src/local.ts | 1 +
.../src/apps/app/src/main.ts | 25 ++++
.../src/apps/app/types/zod.ts | 4 +
.../src/package.json | 1 +
.../src/packages/lib/package.json | 10 ++
.../src/packages/lib/src/feature/flags.ts | 3 +
.../src/packages/lib/src/index.ts | 7 ++
.../src/packages/lib/src/sub/index.ts | 1 +
.../src/packages/tools/package.json | 1 +
.../src/packages/tools/src/deep.ts | 1 +
.../src/packages/tools/src/index.ts | 1 +
.../src/pnpm-workspace.yaml | 3 +
.../85-workspace-package-import.edges | 8 ++
.../85-workspace-package-import.entries | 3 +
.../85-workspace-package-import.fields | 1 +
.../85-workspace-package-import.fields-oracle | 7 ++
.../85-workspace-package-import.oracle | 1 +
.../85-workspace-package-import.type-use | 1 +
.../85-workspace-package-import.types-oracle | 7 ++
.../typescript/ground-truth/tsc-program.mjs | 26 ++++
.../imports/TsImportResolutionKind.ts | 5 +
.../extractors/js-fact-extractor.ts | 6 +
.../extractors/js-module-edge-extractor.ts | 22 +++-
.../extractors/ts-fact-extractor.ts | 22 ++--
.../extractors/ts-import-extractor.ts | 35 +++++-
.../typescript/ts-package-entry-extractor.ts | 64 +++++++++-
.../parsers/typescript/workspace-packages.ts | 111 ++++++++++++++++++
.../javascript/javascript-project-analyzer.ts | 19 +++
.../typescript/typescript-project-analyzer.ts | 43 +++++++
.../skills/axiomcode/scripts/dl/impact.dl | 6 +
.../skills/axiomcode/scripts/graph_sql.py | 18 +++
.../dispatch-base-is-a-contract/case.json | 6 +-
91 files changed, 567 insertions(+), 87 deletions(-)
rename graph/test/javascript/cases/{71-bundler-config-alias/src => 70-bare-specifier-to-project-source/src/bundler-alias}/legacy/app.js (100%)
rename graph/test/javascript/cases/{71-bundler-config-alias/src => 70-bare-specifier-to-project-source/src/bundler-alias}/legacy/lib/extra.js (100%)
rename graph/test/javascript/cases/{71-bundler-config-alias/src => 70-bare-specifier-to-project-source/src/bundler-alias}/legacy/lib/index.js (100%)
rename graph/test/javascript/cases/{71-bundler-config-alias/src => 70-bare-specifier-to-project-source/src/bundler-alias}/legacy/lib/util/trim.js (100%)
rename graph/test/javascript/cases/{71-bundler-config-alias/src => 70-bare-specifier-to-project-source/src/bundler-alias}/legacy/webpack.config.cjs (100%)
rename graph/test/javascript/cases/{71-bundler-config-alias/src => 70-bare-specifier-to-project-source/src/bundler-alias}/mapped/jsconfig.json (100%)
rename graph/test/javascript/cases/{71-bundler-config-alias/src => 70-bare-specifier-to-project-source/src/bundler-alias}/mapped/own/date.js (100%)
rename graph/test/javascript/cases/{71-bundler-config-alias/src => 70-bare-specifier-to-project-source/src/bundler-alias}/mapped/probe.js (100%)
rename graph/test/javascript/cases/{71-bundler-config-alias/src => 70-bare-specifier-to-project-source/src/bundler-alias}/package.json (100%)
rename graph/test/javascript/cases/{71-bundler-config-alias/src => 70-bare-specifier-to-project-source/src/bundler-alias}/shared/fmt.js (100%)
rename graph/test/javascript/cases/{71-bundler-config-alias/src => 70-bare-specifier-to-project-source/src/bundler-alias}/src/pages/Home.js (100%)
rename graph/test/javascript/cases/{71-bundler-config-alias/src => 70-bare-specifier-to-project-source/src/bundler-alias}/src/utils/date.js (100%)
rename graph/test/javascript/cases/{71-bundler-config-alias/src => 70-bare-specifier-to-project-source/src/bundler-alias}/vite.config.js (100%)
rename graph/test/javascript/cases/{71-framework-generated-config-alias/src => 70-bare-specifier-to-project-source/src/framework-alias}/kit/jsconfig.json (100%)
rename graph/test/javascript/cases/{71-framework-generated-config-alias/src => 70-bare-specifier-to-project-source/src/framework-alias}/kit/src/lib/api.js (100%)
rename graph/test/javascript/cases/{71-framework-generated-config-alias/src => 70-bare-specifier-to-project-source/src/framework-alias}/kit/src/routes/page.js (100%)
rename graph/test/javascript/cases/{71-framework-generated-config-alias/src => 70-bare-specifier-to-project-source/src/framework-alias}/nuxt/server/api/price.js (100%)
rename graph/test/javascript/cases/{71-framework-generated-config-alias/src => 70-bare-specifier-to-project-source/src/framework-alias}/nuxt/tsconfig.json (100%)
rename graph/test/javascript/cases/{71-framework-generated-config-alias/src => 70-bare-specifier-to-project-source/src/framework-alias}/nuxt/utils/price.js (100%)
rename graph/test/javascript/cases/{71-framework-generated-config-alias/src => 70-bare-specifier-to-project-source/src/framework-alias}/nuxt4/app/pages/index.js (100%)
rename graph/test/javascript/cases/{71-framework-generated-config-alias/src => 70-bare-specifier-to-project-source/src/framework-alias}/nuxt4/app/utils/date.js (100%)
rename graph/test/javascript/cases/{71-framework-generated-config-alias/src => 70-bare-specifier-to-project-source/src/framework-alias}/nuxt4/tsconfig.json (100%)
rename graph/test/javascript/cases/{71-framework-generated-config-alias/src => 70-bare-specifier-to-project-source/src/framework-alias}/other/jsconfig.json (100%)
rename graph/test/javascript/cases/{71-framework-generated-config-alias/src => 70-bare-specifier-to-project-source/src/framework-alias}/other/probe.js (100%)
rename graph/test/javascript/cases/{71-framework-generated-config-alias/src => 70-bare-specifier-to-project-source/src/framework-alias}/other/src/lib/helper.js (100%)
rename graph/test/javascript/cases/{71-framework-generated-config-alias/src => 70-bare-specifier-to-project-source/src/framework-alias}/own/jsconfig.json (100%)
rename graph/test/javascript/cases/{71-framework-generated-config-alias/src => 70-bare-specifier-to-project-source/src/framework-alias}/own/probe.js (100%)
rename graph/test/javascript/cases/{71-framework-generated-config-alias/src => 70-bare-specifier-to-project-source/src/framework-alias}/own/shared/util.js (100%)
rename graph/test/javascript/cases/{71-framework-generated-config-alias/src => 70-bare-specifier-to-project-source/src/framework-alias}/own/src/lib/util.js (100%)
rename graph/test/javascript/cases/{71-framework-generated-config-alias/src => 70-bare-specifier-to-project-source/src/framework-alias}/package.json (100%)
rename graph/test/javascript/cases/{70-jsconfig-path-alias/src => 70-bare-specifier-to-project-source/src/jsconfig-paths}/app.js (100%)
rename graph/test/javascript/cases/{70-jsconfig-path-alias/src => 70-bare-specifier-to-project-source/src/jsconfig-paths}/jsconfig.json (100%)
rename graph/test/javascript/cases/{70-jsconfig-path-alias/src => 70-bare-specifier-to-project-source/src/jsconfig-paths}/lib/check.js (100%)
rename graph/test/javascript/cases/{70-jsconfig-path-alias/src => 70-bare-specifier-to-project-source/src/jsconfig-paths}/noalias/jsconfig.json (100%)
rename graph/test/javascript/cases/{70-jsconfig-path-alias/src => 70-bare-specifier-to-project-source/src/jsconfig-paths}/noalias/probe.js (100%)
rename graph/test/javascript/cases/{70-jsconfig-path-alias/src => 70-bare-specifier-to-project-source/src/jsconfig-paths}/package.json (100%)
rename graph/test/javascript/cases/{70-jsconfig-path-alias/src => 70-bare-specifier-to-project-source/src/jsconfig-paths}/remix/app/models/note.server.js (100%)
rename graph/test/javascript/cases/{70-jsconfig-path-alias/src => 70-bare-specifier-to-project-source/src/jsconfig-paths}/remix/app/route.js (100%)
rename graph/test/javascript/cases/{70-jsconfig-path-alias/src => 70-bare-specifier-to-project-source/src/jsconfig-paths}/remix/tsconfig.json (100%)
create mode 100644 graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/apps/app/package.json
create mode 100644 graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/apps/app/src/main.js
create mode 100644 graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/packages/lib/package.json
create mode 100644 graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/packages/lib/src/index.js
create mode 100644 graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/packages/lib/src/sub/index.js
create mode 100644 graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/packages/tools/package.json
create mode 100644 graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/packages/tools/src/deep.js
create mode 100644 graph/test/javascript/expected/70-bare-specifier-to-project-source.diag
create mode 100644 graph/test/javascript/expected/70-bare-specifier-to-project-source.edges
create mode 100644 graph/test/javascript/expected/70-bare-specifier-to-project-source.oracle
delete mode 100644 graph/test/javascript/expected/70-jsconfig-path-alias.diag
delete mode 100644 graph/test/javascript/expected/70-jsconfig-path-alias.edges
delete mode 100644 graph/test/javascript/expected/70-jsconfig-path-alias.oracle
delete mode 100644 graph/test/javascript/expected/71-bundler-config-alias.diag
delete mode 100644 graph/test/javascript/expected/71-bundler-config-alias.edges
delete mode 100644 graph/test/javascript/expected/71-bundler-config-alias.oracle
delete mode 100644 graph/test/javascript/expected/71-framework-generated-config-alias.diag
delete mode 100644 graph/test/javascript/expected/71-framework-generated-config-alias.edges
delete mode 100644 graph/test/javascript/expected/71-framework-generated-config-alias.oracle
create mode 100644 graph/test/typescript/cases/85-workspace-package-import/src/apps/app/package.json
create mode 100644 graph/test/typescript/cases/85-workspace-package-import/src/apps/app/src/local.ts
create mode 100644 graph/test/typescript/cases/85-workspace-package-import/src/apps/app/src/main.ts
create mode 100644 graph/test/typescript/cases/85-workspace-package-import/src/apps/app/types/zod.ts
create mode 100644 graph/test/typescript/cases/85-workspace-package-import/src/package.json
create mode 100644 graph/test/typescript/cases/85-workspace-package-import/src/packages/lib/package.json
create mode 100644 graph/test/typescript/cases/85-workspace-package-import/src/packages/lib/src/feature/flags.ts
create mode 100644 graph/test/typescript/cases/85-workspace-package-import/src/packages/lib/src/index.ts
create mode 100644 graph/test/typescript/cases/85-workspace-package-import/src/packages/lib/src/sub/index.ts
create mode 100644 graph/test/typescript/cases/85-workspace-package-import/src/packages/tools/package.json
create mode 100644 graph/test/typescript/cases/85-workspace-package-import/src/packages/tools/src/deep.ts
create mode 100644 graph/test/typescript/cases/85-workspace-package-import/src/packages/tools/src/index.ts
create mode 100644 graph/test/typescript/cases/85-workspace-package-import/src/pnpm-workspace.yaml
create mode 100644 graph/test/typescript/expected/85-workspace-package-import.edges
create mode 100644 graph/test/typescript/expected/85-workspace-package-import.entries
create mode 100644 graph/test/typescript/expected/85-workspace-package-import.fields
create mode 100644 graph/test/typescript/expected/85-workspace-package-import.fields-oracle
create mode 100644 graph/test/typescript/expected/85-workspace-package-import.oracle
create mode 100644 graph/test/typescript/expected/85-workspace-package-import.type-use
create mode 100644 graph/test/typescript/expected/85-workspace-package-import.types-oracle
create mode 100644 parser/src/parsers/typescript/workspace-packages.ts
diff --git a/graph/test/javascript/cases/71-bundler-config-alias/src/legacy/app.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/bundler-alias/legacy/app.js
similarity index 100%
rename from graph/test/javascript/cases/71-bundler-config-alias/src/legacy/app.js
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/bundler-alias/legacy/app.js
diff --git a/graph/test/javascript/cases/71-bundler-config-alias/src/legacy/lib/extra.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/bundler-alias/legacy/lib/extra.js
similarity index 100%
rename from graph/test/javascript/cases/71-bundler-config-alias/src/legacy/lib/extra.js
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/bundler-alias/legacy/lib/extra.js
diff --git a/graph/test/javascript/cases/71-bundler-config-alias/src/legacy/lib/index.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/bundler-alias/legacy/lib/index.js
similarity index 100%
rename from graph/test/javascript/cases/71-bundler-config-alias/src/legacy/lib/index.js
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/bundler-alias/legacy/lib/index.js
diff --git a/graph/test/javascript/cases/71-bundler-config-alias/src/legacy/lib/util/trim.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/bundler-alias/legacy/lib/util/trim.js
similarity index 100%
rename from graph/test/javascript/cases/71-bundler-config-alias/src/legacy/lib/util/trim.js
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/bundler-alias/legacy/lib/util/trim.js
diff --git a/graph/test/javascript/cases/71-bundler-config-alias/src/legacy/webpack.config.cjs b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/bundler-alias/legacy/webpack.config.cjs
similarity index 100%
rename from graph/test/javascript/cases/71-bundler-config-alias/src/legacy/webpack.config.cjs
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/bundler-alias/legacy/webpack.config.cjs
diff --git a/graph/test/javascript/cases/71-bundler-config-alias/src/mapped/jsconfig.json b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/bundler-alias/mapped/jsconfig.json
similarity index 100%
rename from graph/test/javascript/cases/71-bundler-config-alias/src/mapped/jsconfig.json
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/bundler-alias/mapped/jsconfig.json
diff --git a/graph/test/javascript/cases/71-bundler-config-alias/src/mapped/own/date.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/bundler-alias/mapped/own/date.js
similarity index 100%
rename from graph/test/javascript/cases/71-bundler-config-alias/src/mapped/own/date.js
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/bundler-alias/mapped/own/date.js
diff --git a/graph/test/javascript/cases/71-bundler-config-alias/src/mapped/probe.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/bundler-alias/mapped/probe.js
similarity index 100%
rename from graph/test/javascript/cases/71-bundler-config-alias/src/mapped/probe.js
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/bundler-alias/mapped/probe.js
diff --git a/graph/test/javascript/cases/71-bundler-config-alias/src/package.json b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/bundler-alias/package.json
similarity index 100%
rename from graph/test/javascript/cases/71-bundler-config-alias/src/package.json
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/bundler-alias/package.json
diff --git a/graph/test/javascript/cases/71-bundler-config-alias/src/shared/fmt.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/bundler-alias/shared/fmt.js
similarity index 100%
rename from graph/test/javascript/cases/71-bundler-config-alias/src/shared/fmt.js
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/bundler-alias/shared/fmt.js
diff --git a/graph/test/javascript/cases/71-bundler-config-alias/src/src/pages/Home.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/bundler-alias/src/pages/Home.js
similarity index 100%
rename from graph/test/javascript/cases/71-bundler-config-alias/src/src/pages/Home.js
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/bundler-alias/src/pages/Home.js
diff --git a/graph/test/javascript/cases/71-bundler-config-alias/src/src/utils/date.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/bundler-alias/src/utils/date.js
similarity index 100%
rename from graph/test/javascript/cases/71-bundler-config-alias/src/src/utils/date.js
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/bundler-alias/src/utils/date.js
diff --git a/graph/test/javascript/cases/71-bundler-config-alias/src/vite.config.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/bundler-alias/vite.config.js
similarity index 100%
rename from graph/test/javascript/cases/71-bundler-config-alias/src/vite.config.js
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/bundler-alias/vite.config.js
diff --git a/graph/test/javascript/cases/71-framework-generated-config-alias/src/kit/jsconfig.json b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/kit/jsconfig.json
similarity index 100%
rename from graph/test/javascript/cases/71-framework-generated-config-alias/src/kit/jsconfig.json
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/kit/jsconfig.json
diff --git a/graph/test/javascript/cases/71-framework-generated-config-alias/src/kit/src/lib/api.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/kit/src/lib/api.js
similarity index 100%
rename from graph/test/javascript/cases/71-framework-generated-config-alias/src/kit/src/lib/api.js
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/kit/src/lib/api.js
diff --git a/graph/test/javascript/cases/71-framework-generated-config-alias/src/kit/src/routes/page.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/kit/src/routes/page.js
similarity index 100%
rename from graph/test/javascript/cases/71-framework-generated-config-alias/src/kit/src/routes/page.js
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/kit/src/routes/page.js
diff --git a/graph/test/javascript/cases/71-framework-generated-config-alias/src/nuxt/server/api/price.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/nuxt/server/api/price.js
similarity index 100%
rename from graph/test/javascript/cases/71-framework-generated-config-alias/src/nuxt/server/api/price.js
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/nuxt/server/api/price.js
diff --git a/graph/test/javascript/cases/71-framework-generated-config-alias/src/nuxt/tsconfig.json b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/nuxt/tsconfig.json
similarity index 100%
rename from graph/test/javascript/cases/71-framework-generated-config-alias/src/nuxt/tsconfig.json
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/nuxt/tsconfig.json
diff --git a/graph/test/javascript/cases/71-framework-generated-config-alias/src/nuxt/utils/price.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/nuxt/utils/price.js
similarity index 100%
rename from graph/test/javascript/cases/71-framework-generated-config-alias/src/nuxt/utils/price.js
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/nuxt/utils/price.js
diff --git a/graph/test/javascript/cases/71-framework-generated-config-alias/src/nuxt4/app/pages/index.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/nuxt4/app/pages/index.js
similarity index 100%
rename from graph/test/javascript/cases/71-framework-generated-config-alias/src/nuxt4/app/pages/index.js
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/nuxt4/app/pages/index.js
diff --git a/graph/test/javascript/cases/71-framework-generated-config-alias/src/nuxt4/app/utils/date.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/nuxt4/app/utils/date.js
similarity index 100%
rename from graph/test/javascript/cases/71-framework-generated-config-alias/src/nuxt4/app/utils/date.js
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/nuxt4/app/utils/date.js
diff --git a/graph/test/javascript/cases/71-framework-generated-config-alias/src/nuxt4/tsconfig.json b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/nuxt4/tsconfig.json
similarity index 100%
rename from graph/test/javascript/cases/71-framework-generated-config-alias/src/nuxt4/tsconfig.json
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/nuxt4/tsconfig.json
diff --git a/graph/test/javascript/cases/71-framework-generated-config-alias/src/other/jsconfig.json b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/other/jsconfig.json
similarity index 100%
rename from graph/test/javascript/cases/71-framework-generated-config-alias/src/other/jsconfig.json
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/other/jsconfig.json
diff --git a/graph/test/javascript/cases/71-framework-generated-config-alias/src/other/probe.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/other/probe.js
similarity index 100%
rename from graph/test/javascript/cases/71-framework-generated-config-alias/src/other/probe.js
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/other/probe.js
diff --git a/graph/test/javascript/cases/71-framework-generated-config-alias/src/other/src/lib/helper.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/other/src/lib/helper.js
similarity index 100%
rename from graph/test/javascript/cases/71-framework-generated-config-alias/src/other/src/lib/helper.js
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/other/src/lib/helper.js
diff --git a/graph/test/javascript/cases/71-framework-generated-config-alias/src/own/jsconfig.json b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/own/jsconfig.json
similarity index 100%
rename from graph/test/javascript/cases/71-framework-generated-config-alias/src/own/jsconfig.json
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/own/jsconfig.json
diff --git a/graph/test/javascript/cases/71-framework-generated-config-alias/src/own/probe.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/own/probe.js
similarity index 100%
rename from graph/test/javascript/cases/71-framework-generated-config-alias/src/own/probe.js
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/own/probe.js
diff --git a/graph/test/javascript/cases/71-framework-generated-config-alias/src/own/shared/util.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/own/shared/util.js
similarity index 100%
rename from graph/test/javascript/cases/71-framework-generated-config-alias/src/own/shared/util.js
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/own/shared/util.js
diff --git a/graph/test/javascript/cases/71-framework-generated-config-alias/src/own/src/lib/util.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/own/src/lib/util.js
similarity index 100%
rename from graph/test/javascript/cases/71-framework-generated-config-alias/src/own/src/lib/util.js
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/own/src/lib/util.js
diff --git a/graph/test/javascript/cases/71-framework-generated-config-alias/src/package.json b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/package.json
similarity index 100%
rename from graph/test/javascript/cases/71-framework-generated-config-alias/src/package.json
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/framework-alias/package.json
diff --git a/graph/test/javascript/cases/70-jsconfig-path-alias/src/app.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/jsconfig-paths/app.js
similarity index 100%
rename from graph/test/javascript/cases/70-jsconfig-path-alias/src/app.js
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/jsconfig-paths/app.js
diff --git a/graph/test/javascript/cases/70-jsconfig-path-alias/src/jsconfig.json b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/jsconfig-paths/jsconfig.json
similarity index 100%
rename from graph/test/javascript/cases/70-jsconfig-path-alias/src/jsconfig.json
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/jsconfig-paths/jsconfig.json
diff --git a/graph/test/javascript/cases/70-jsconfig-path-alias/src/lib/check.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/jsconfig-paths/lib/check.js
similarity index 100%
rename from graph/test/javascript/cases/70-jsconfig-path-alias/src/lib/check.js
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/jsconfig-paths/lib/check.js
diff --git a/graph/test/javascript/cases/70-jsconfig-path-alias/src/noalias/jsconfig.json b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/jsconfig-paths/noalias/jsconfig.json
similarity index 100%
rename from graph/test/javascript/cases/70-jsconfig-path-alias/src/noalias/jsconfig.json
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/jsconfig-paths/noalias/jsconfig.json
diff --git a/graph/test/javascript/cases/70-jsconfig-path-alias/src/noalias/probe.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/jsconfig-paths/noalias/probe.js
similarity index 100%
rename from graph/test/javascript/cases/70-jsconfig-path-alias/src/noalias/probe.js
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/jsconfig-paths/noalias/probe.js
diff --git a/graph/test/javascript/cases/70-jsconfig-path-alias/src/package.json b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/jsconfig-paths/package.json
similarity index 100%
rename from graph/test/javascript/cases/70-jsconfig-path-alias/src/package.json
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/jsconfig-paths/package.json
diff --git a/graph/test/javascript/cases/70-jsconfig-path-alias/src/remix/app/models/note.server.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/jsconfig-paths/remix/app/models/note.server.js
similarity index 100%
rename from graph/test/javascript/cases/70-jsconfig-path-alias/src/remix/app/models/note.server.js
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/jsconfig-paths/remix/app/models/note.server.js
diff --git a/graph/test/javascript/cases/70-jsconfig-path-alias/src/remix/app/route.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/jsconfig-paths/remix/app/route.js
similarity index 100%
rename from graph/test/javascript/cases/70-jsconfig-path-alias/src/remix/app/route.js
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/jsconfig-paths/remix/app/route.js
diff --git a/graph/test/javascript/cases/70-jsconfig-path-alias/src/remix/tsconfig.json b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/jsconfig-paths/remix/tsconfig.json
similarity index 100%
rename from graph/test/javascript/cases/70-jsconfig-path-alias/src/remix/tsconfig.json
rename to graph/test/javascript/cases/70-bare-specifier-to-project-source/src/jsconfig-paths/remix/tsconfig.json
diff --git a/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/apps/app/package.json b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/apps/app/package.json
new file mode 100644
index 00000000..6eba3270
--- /dev/null
+++ b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/apps/app/package.json
@@ -0,0 +1 @@
+{ "name": "@ws/app", "type": "module" }
diff --git a/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/apps/app/src/main.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/apps/app/src/main.js
new file mode 100644
index 00000000..dbef4e0f
--- /dev/null
+++ b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/apps/app/src/main.js
@@ -0,0 +1,13 @@
+import { f, Bus } from '@ws/lib';
+import { g } from '@ws/lib/sub';
+import { deep } from 'ws-tools/deep';
+// Control: a package this repository does not declare stays unresolved.
+import { outside } from 'not-in-this-repo';
+
+export function run() {
+ f();
+ g();
+ deep();
+ new Bus().publish('k');
+ return outside();
+}
diff --git a/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/packages/lib/package.json b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/packages/lib/package.json
new file mode 100644
index 00000000..4388cd84
--- /dev/null
+++ b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/packages/lib/package.json
@@ -0,0 +1,8 @@
+{
+ "name": "@ws/lib",
+ "main": "./dist/index.js",
+ "exports": {
+ ".": { "import": "./dist/index.mjs", "require": "./dist/index.js" },
+ "./sub": "./dist/sub/index.js"
+ }
+}
diff --git a/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/packages/lib/src/index.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/packages/lib/src/index.js
new file mode 100644
index 00000000..b4154a53
--- /dev/null
+++ b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/packages/lib/src/index.js
@@ -0,0 +1,9 @@
+export function f() {
+ return 1;
+}
+
+export class Bus {
+ publish(key) {
+ return key;
+ }
+}
diff --git a/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/packages/lib/src/sub/index.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/packages/lib/src/sub/index.js
new file mode 100644
index 00000000..ac3e27ac
--- /dev/null
+++ b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/packages/lib/src/sub/index.js
@@ -0,0 +1,3 @@
+export function g() {
+ return 2;
+}
diff --git a/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/packages/tools/package.json b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/packages/tools/package.json
new file mode 100644
index 00000000..c1cd873a
--- /dev/null
+++ b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/packages/tools/package.json
@@ -0,0 +1 @@
+{ "name": "ws-tools", "main": "dist/index.js" }
diff --git a/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/packages/tools/src/deep.js b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/packages/tools/src/deep.js
new file mode 100644
index 00000000..8539777a
--- /dev/null
+++ b/graph/test/javascript/cases/70-bare-specifier-to-project-source/src/workspace-package/packages/tools/src/deep.js
@@ -0,0 +1,3 @@
+export function deep() {
+ return 3;
+}
diff --git a/graph/test/javascript/expected/70-bare-specifier-to-project-source.diag b/graph/test/javascript/expected/70-bare-specifier-to-project-source.diag
new file mode 100644
index 00000000..fe9810d3
--- /dev/null
+++ b/graph/test/javascript/expected/70-bare-specifier-to-project-source.diag
@@ -0,0 +1,35 @@
+import_cause bundler-alias/legacy/app.js:4:10 Lib/extra not_staged
+import_cause bundler-alias/legacy/app.js:5:10 Loose/extra not_staged
+import_cause bundler-alias/legacy/webpack.config.cjs:1:14 path builtin
+import_cause bundler-alias/src/pages/Home.js:6:10 @utils/date not_staged
+import_cause bundler-alias/vite.config.js:1:10 vite not_staged
+import_cause bundler-alias/vite.config.js:2:1 path builtin
+import_cause bundler-alias/vite.config.js:3:10 node:url builtin
+import_cause bundler-alias/vite.config.js:3:25 node:url builtin
+import_cause framework-alias/other/probe.js:2:10 $lib/helper not_staged
+import_cause jsconfig-paths/noalias/probe.js:2:10 @/check not_staged
+import_cause workspace-package/apps/app/src/main.js:5:10 not-in-this-repo not_staged
+package_entry @ws/app . [] DEFAULT_INDEX index.js MISSING_FILE -> -
+package_entry @ws/lib . [] MAIN dist/index.js MISSING_FILE -> -
+package_entry @ws/lib . [import] EXPORTS dist/index.mjs MISSING_FILE -> -
+package_entry @ws/lib . [require] EXPORTS dist/index.js MISSING_FILE -> -
+package_entry @ws/lib ./sub [] EXPORTS dist/sub/index.js MISSING_FILE -> -
+package_entry bundler-alias-fixture . [] DEFAULT_INDEX index.js MISSING_FILE -> -
+package_entry framework-alias-fixture . [] DEFAULT_INDEX index.js MISSING_FILE -> -
+package_entry path-alias-fixture . [] DEFAULT_INDEX index.js MISSING_FILE -> -
+package_entry ws-tools . [] MAIN dist/index.js MISSING_FILE -> -
+unresolved bundler-alias/legacy/app.js:10:3 FUNCTION_CALL loose callee_untyped
+unresolved bundler-alias/legacy/app.js:9:3 FUNCTION_CALL extra callee_untyped
+unresolved bundler-alias/legacy/lib/util/trim.js:2:10 METHOD_CALL trim receiver_untyped
+unresolved bundler-alias/legacy/webpack.config.cjs:7:13 METHOD_CALL resolve no_target
+unresolved bundler-alias/legacy/webpack.config.cjs:8:13 METHOD_CALL join no_target
+unresolved bundler-alias/shared/fmt.js:2:10 METHOD_CALL toFixed receiver_untyped
+unresolved bundler-alias/src/pages/Home.js:10:3 FUNCTION_CALL scoped callee_untyped
+unresolved bundler-alias/src/utils/date.js:2:10 FUNCTION_CALL String no_target
+unresolved bundler-alias/vite.config.js:10:18 FUNCTION_CALL fileURLToPath no_target
+unresolved bundler-alias/vite.config.js:10:32 CONSTRUCTOR_CALL URL no_target
+unresolved bundler-alias/vite.config.js:6:16 FUNCTION_CALL defineConfig callee_untyped
+unresolved bundler-alias/vite.config.js:9:12 METHOD_CALL resolve receiver_untyped
+unresolved framework-alias/other/probe.js:5:10 FUNCTION_CALL helper callee_untyped
+unresolved jsconfig-paths/noalias/probe.js:5:10 FUNCTION_CALL checkA callee_untyped
+unresolved workspace-package/apps/app/src/main.js:12:10 FUNCTION_CALL outside callee_untyped
diff --git a/graph/test/javascript/expected/70-bare-specifier-to-project-source.edges b/graph/test/javascript/expected/70-bare-specifier-to-project-source.edges
new file mode 100644
index 00000000..6dc90ef1
--- /dev/null
+++ b/graph/test/javascript/expected/70-bare-specifier-to-project-source.edges
@@ -0,0 +1,35 @@
+bundler-alias/legacy/app.js:10:3 FUNCTION_CALL loose -> ambiguous_unknown -
+bundler-alias/legacy/app.js:11:10 FUNCTION_CALL trim -> known_edge bundler-alias/legacy/lib/util/trim.js:1:1 trim
+bundler-alias/legacy/app.js:8:3 FUNCTION_CALL boot -> known_edge bundler-alias/legacy/lib/index.js:1:1 boot
+bundler-alias/legacy/app.js:9:3 FUNCTION_CALL extra -> ambiguous_unknown -
+bundler-alias/legacy/lib/util/trim.js:2:10 METHOD_CALL s.trim -> ambiguous_unknown -
+bundler-alias/legacy/webpack.config.cjs:7:13 METHOD_CALL path.resolve -> ambient_terminal -
+bundler-alias/legacy/webpack.config.cjs:8:13 METHOD_CALL path.join -> ambient_terminal -
+bundler-alias/mapped/probe.js:5:10 FUNCTION_CALL fmtDate -> known_edge bundler-alias/mapped/own/date.js:1:1 fmtDate
+bundler-alias/shared/fmt.js:2:10 METHOD_CALL n.toFixed -> ambiguous_unknown -
+bundler-alias/src/pages/Home.js:10:3 FUNCTION_CALL scoped -> ambiguous_unknown -
+bundler-alias/src/pages/Home.js:11:10 FUNCTION_CALL fmtDate -> known_edge bundler-alias/src/utils/date.js:1:1 fmtDate
+bundler-alias/src/pages/Home.js:9:3 FUNCTION_CALL fmtMoney -> known_edge bundler-alias/shared/fmt.js:1:1 fmtMoney
+bundler-alias/src/utils/date.js:2:10 FUNCTION_CALL String -> ambient_terminal -
+bundler-alias/vite.config.js:10:18 FUNCTION_CALL fileURLToPath -> ambient_terminal -
+bundler-alias/vite.config.js:10:32 CONSTRUCTOR_CALL URL -> ambient_terminal -
+bundler-alias/vite.config.js:6:16 FUNCTION_CALL defineConfig -> ambiguous_unknown -
+bundler-alias/vite.config.js:6:16 FUNCTION_CALL defineConfig -> callback_registered bundler-alias/vite.config.js:6:29
.*?)(?:\s+\[(?P[^\]]*)\])?$')
+
+
+class Graphs:
+ """the enclosing callable of a line, from every graph the repository holds (one per language)"""
+ def __init__(self, repo):
+ out = os.path.join(repo, '.axiomcode', 'out')
+ self.cons = []
+ for d in sorted(os.listdir(out)) if os.path.isdir(out) else []:
+ p = os.path.join(out, d, 'graph.sqlite')
+ if os.path.isfile(p):
+ try: self.cons.append(sqlite3.connect(f"file:{p}?mode=ro", uri=True))
+ except sqlite3.Error: pass
+
+ def enclosing(self, f, n):
+ best = None
+ for c in self.cons:
+ try:
+ r = c.execute("SELECT display, line, end_line FROM symbols WHERE (file = ? OR file LIKE ?) AND line <= ? AND end_line >= ? "
+ "AND method_id IS NOT NULL AND display NOT LIKE '%%' ORDER BY end_line - line LIMIT 1",
+ (f, '%/' + f, n, n)).fetchone()
+ except sqlite3.Error:
+ continue
+ if r and (best is None or r[2] - r[1] < best[2] - best[1]): best = r
+ return best
+
+
+def block(repo, f, marks, span):
+ """the lines to show for the marked lines of file f: the enclosing callable (whole, or header + a window around
+ each mark), numbered, every mark flagged"""
+ try:
+ with open(os.path.join(repo, f), encoding='utf-8', errors='replace') as h: L = h.read().split('\n')
+ except OSError:
+ return []
+ marks = sorted(n for n in marks if 0 < n <= len(L))
+ if not marks: return []
+ lo, hi = (span[1], span[2]) if span else (marks[0], marks[-1])
+ lo, hi = max(1, min(lo, marks[0])), min(len(L), max(hi, marks[-1]))
+ if hi - lo + 1 <= WHOLE:
+ keep = list(range(lo, hi + 1))
+ else:
+ keep = {lo}
+ for n in marks: keep |= set(range(max(lo, n - AROUND), min(hi, n + AROUND) + 1))
+ keep = sorted(keep)
+ w = len(str(keep[-1])); out = []; prev = None
+ for i in keep:
+ if prev is not None and i != prev + 1: out.append(' ' * (w + 4) + '…')
+ out.append(f"{'→' if i in marks else ' '} {str(i).rjust(w)} {L[i - 1].rstrip()}")
+ prev = i
+ return out
+
+
+# rows that add nothing an agent acts on: a word match offered only because nothing better was found (dropped when a
+# better row exists), and a module's own scope (its import lines)
+FILLER = 'best overall match'
+NOISE = ('module scope',)
+
+
+def render(verb, doc, repo):
+ code = ax_grep.Code(repo)
+ rows, _rest, foot = ax_grep.VERBS[{'find': 'context', 'tests': 'test-impact'}.get(verb, verb)](doc, code)
+ sites = []
+ for _k, line in rows:
+ m = SITE.match(line)
+ if m: sites.append((m.group('file'), int(m.group('line')), m.group('tag') or ''))
+ sites = [x for x in sites if not any(w in x[2] for w in NOISE)]
+ if any(FILLER not in t for _f, _n, t in sites): sites = [x for x in sites if FILLER not in x[2]]
+ # ONE PLACE PER FUNCTION: two relevant lines of one function are one block with both marked, in the order the
+ # verb ranked the first of them
+ graphs = Graphs(repo); places = {}
+ for f, n, t in sites:
+ span = graphs.enclosing(f, n)
+ key = (f, span[1], span[2]) if span else (f, n, n)
+ p = places.setdefault(key, {'f': f, 'span': span, 'marks': [], 'tags': []})
+ if n not in p['marks']: p['marks'].append(n)
+ t = t.split(' — ')[0].strip() # the tag's short form: what it is, not the explanation after the dash
+ if t and t not in p['tags']: p['tags'].append(t)
+ out = []
+ for i, p in enumerate(list(places.values())[:CAP], 1):
+ where = f"{p['f']}:{','.join(map(str, sorted(p['marks'])))}"
+ out.append(f"{i}. {where}" + (f" [{' | '.join(p['tags'][:2])}]" if p['tags'] else ''))
+ body = block(repo, p['f'], p['marks'], p['span'])
+ if body:
+ out.append(f" ```{FENCE.get(os.path.splitext(p['f'])[1], '')}")
+ out += [' ' + b for b in body]
+ out.append(' ```')
+ if not out: return None
+ if len(places) > CAP: out.append(f"… {len(places) - CAP} more place(s) not shown — ask a narrower question to see them")
+ out += [x for x in foot if x.startswith(('run:', 'verified'))][:2]
+ return out
+
+
+def verb_json(cmd):
+ import ax_exec
+ r = subprocess.run(ax_exec.program(cmd + ['--json']), stdout=subprocess.PIPE, text=True, encoding='utf-8', errors='replace')
+ try: doc = json.loads(r.stdout)
+ except ValueError: doc = None
+ return r, doc
+
+
+def edits(repo):
+ """impact with no name: what the working tree's edits changed, then what depends on those declarations, with code"""
+ r, doc = verb_json(['python3', os.path.join(H, 'axiomcode-changed'), repo])
+ if not isinstance(doc, dict):
+ sys.stdout.write(r.stdout); return r.returncode
+ ch = doc.get('changed') or []
+ targets = list(dict.fromkeys(c['target'] for c in ch if c.get('target')))
+ head = ["your edits: " + (', '.join(f"{c.get('kind')} {c.get('shown_target') or c.get('symbol')}" for c in ch[:8]) or 'none')
+ + (f" (+{len(ch) - 8} more)" if len(ch) > 8 else '')]
+ if not targets:
+ print('\n'.join(head + ["nothing edited is a declaration other code depends on" if ch else
+ "no edits against the commit the graph was built from"]))
+ return 0
+ r, doc = verb_json(['python3', os.path.join(H, 'axiomcode-impact')] + targets + [repo, '--tests'])
+ lines = render('impact', doc, repo) if isinstance(doc, dict) else None
+ print('\n'.join(head + (lines or [x for x in (doc or {}).get('prose', [])] or [r.stdout.strip()])))
+ return 0
+
+
+def main(argv):
+ verb, repo = argv[0], argv[1]
+ if verb == 'edits': return edits(repo)
+ cmd = argv[3:] if len(argv) > 2 and argv[2] == '--' else argv[2:]
+ r, doc = verb_json(cmd)
+ if not isinstance(doc, dict):
+ sys.stdout.write(r.stdout); return r.returncode
+ lines = render(verb, doc, repo) if r.returncode in (0, 1) or doc.get('called_undeclared') else None
+ if lines is None:
+ # a refusal or an answer with no place in it: the verb's own words are the answer
+ print('\n'.join(doc.get('prose') or []) or r.stdout.strip()); return r.returncode
+ print('\n'.join(lines))
+ return 0
+
+
+if __name__ == '__main__':
+ if len(sys.argv) < 3 or (sys.argv[1] != 'edits' and len(sys.argv) < 4): sys.exit(__doc__)
+ sys.exit(main(sys.argv[1:]))
diff --git a/plugins/axiomcode/skills/axiomcode/scripts/axiomcode b/plugins/axiomcode/skills/axiomcode/scripts/axiomcode
index c503f33d..cfcaf9ff 100755
--- a/plugins/axiomcode/skills/axiomcode/scripts/axiomcode
+++ b/plugins/axiomcode/skills/axiomcode/scripts/axiomcode
@@ -1,5 +1,27 @@
#!/bin/bash
-# axiomcode — the one entry point. Every capability is a subcommand here; a new skill is a new subcommand, never a new tool.
+# axiomcode — ask the repository's call graph. Each answer is a numbered list of places, each with the code of the
+# function it sits in.
+#
+# axiomcode find ""
+# where the code for a task lives: the functions involved, most relevant first.
+# axiomcode impact []
+# who calls it, what a change to it reaches, and the tests that exercise it.
+# With no name: the same for the declarations your uncommitted edits changed.
+# axiomcode path
+# how A reaches B: every hop of the call chain, with the code at each call.
+# axiomcode tests
+# the tests your uncommitted edits reach, and the command that runs exactly those.
+# axiomcode index [] [--lang [,…]] [--src ] [--library [,…]]
+# build the graph (the first query builds it too). defaults to the current directory.
+#
+# Names are written as in the code: Owner.method, function, Type, or file.py:123. `axiomcode help ` for one verb.
+
+# THE HELP ABOVE IS THE PUBLIC SURFACE: helptext() prints the comment block up to the blank line above. The verbs below
+# are still dispatched and keep every flag -- the hooks, the test suites and scripts call them -- but they are internal
+# and are not advertised on any user- or agent-facing surface. find is context and tests is test-impact underneath;
+# at the front door (bin/axiomcode sets AXIOMCODE_FRONT, the MCP server AXIOMCODE_SURFACE=mcp) a query with no flag
+# answers as places with their code (ax_blocks.py), and any flag, AXIOMCODE_RAW=1 or a direct call gives the verb's
+# own answer.
#
# axiomcode index [] [--lang java|typescript|python|javascript|csharp] [--src ] [--library [,…]]
# the pipeline: parser → engine → .axiomcode/out/graph.sqlite (+ index). defaults to the current directory.
@@ -110,7 +132,12 @@ helptext(){ awk 'NR>1 && /^#/ {sub(/^# ?/, ""); print; next} NR>1 {exit}' "$0";
# one verb's own usage, from the script that implements it: a python docstring, or a bash file's
# leading comment block. The verb documents itself once, where it is implemented.
verbhelp(){
- local f="$H/axiomcode-$1"; [ "$1" = index ] && f="$H/axiomcode-build"; [ "$1" = tests ] && f="$H/axiomcode-test-impact"
+ # a verb of the small surface is explained by its own entry in the help above: what it answers, no options
+ case "$1" in find|impact|path|tests)
+ helptext | awk -v v="$1" '$0 ~ "^ axiomcode "v"( |$)" {on=1; print; next} on && /^ axiomcode / {exit} on && /^$/ {exit} on {print}'
+ return 0 ;;
+ esac
+ local f="$H/axiomcode-$1"; [ "$1" = index ] && f="$H/axiomcode-build"; [ "$1" = tests ] && f="$H/axiomcode-test-impact"; [ "$1" = find ] && f="$H/axiomcode-context"
[ -f "$f" ] || { echo "axiomcode: no such verb '$1' — try: $(verbs | tr '\n' ' ')" >&2; return 2; }
if head -1 "$f" | grep -q python; then python3 -c 'import ast,sys; print(ast.get_docstring(ast.parse(open(sys.argv[1]).read())) or "")' "$f"
else awk 'NR>1 && /^#/ {sub(/^# ?/, ""); print; next} NR>1 {exit}' "$f"; fi
@@ -176,7 +203,7 @@ LASTPOS=""; [ "${#POS[@]}" -gt 0 ] && LASTPOS="${POS[${#POS[@]}-1]}"
case "$cmd" in
index|build) if [ "${#POS[@]}" -gt 0 ] && [ ! -d "${POS[0]}" ]; then gone "${POS[0]}"; fi ;;
graph) case "${POS[0]:-}" in ""|build|export|draw) ;; *) [ -d "${POS[0]}" ] || gone "${POS[0]}" ;; esac ;;
- context) if [ "${#POS[@]}" -gt 1 ] && [ ! -d "${POS[1]}" ]; then gone "${POS[1]}"; fi ;;
+ context|find) if [ "${#POS[@]}" -gt 1 ] && [ ! -d "${POS[1]}" ]; then gone "${POS[1]}"; fi ;;
path) if [ "${#POS[@]}" -gt 2 ] && [ ! -d "${POS[2]}" ]; then gone "${POS[2]}"; fi ;;
impact) if [ "${#POS[@]}" -gt 1 ] && [ ! -e "$LASTPOS" ] && dirlike "$LASTPOS"; then gone "$LASTPOS"; fi ;;
changed|test-impact|tests) if [ "${#POS[@]}" -gt 0 ] && [ ! -e "${POS[0]}" ] && dirlike "${POS[0]}"; then gone "${POS[0]}"; fi ;;
@@ -191,6 +218,25 @@ done
# shapes are one answer. Without it the answer is the verb's own, unchanged.
G=()
case "$cmd" in context|path|impact|test-impact|tests) [ -n "${GREP:-}" ] && G=(python3 "$H/ax_grep.py" "$cmd" "$FR" --limit "${GREP_LIMIT:-30}" --) ;; esac
+# THE SMALL SURFACE: find, impact, path and tests, asked with no flags at the front door (the installed `axiomcode` and
+# the MCP server set AXIOMCODE_FRONT), answer as numbered places, each with the code of the function it sits in
+# (ax_blocks.py), so a place needs no read to be understood. find is context; impact is impact with its tests,
+# and impact with no name answers for the declarations the working tree has edited; path is path; tests is
+# test-impact. A flag, AXIOMCODE_RAW, or a caller that runs this script directly (the hooks, the suites) gets the
+# verb's own answer.
+B=""; FRONT="${AXIOMCODE_FRONT:-}"; [ "${AXIOMCODE_SURFACE:-}" = mcp ] && FRONT=1; [ -n "${AXIOMCODE_RAW:-}${GREP:-}" ] && FRONT=""
+if [ -n "$FRONT" ]; then for a in ${ARGS[@]+"${ARGS[@]}"}; do case "$a" in -*) FRONT="" ;; esac; done; fi
+case "$cmd" in
+ find) cmd=context; [ -n "$FRONT" ] && B=find ;;
+ path) [ -n "$FRONT" ] && B=path ;;
+ tests|test-impact) [ -n "$FRONT" ] && B=tests ;;
+ impact) if [ -n "$FRONT" ]; then
+ named=""; for a in ${ARGS[@]+"${ARGS[@]}"}; do [ -d "$a" ] || named=1; done
+ [ -z "$named" ] && exec python3 "$H/ax_blocks.py" edits "$FR"
+ ARGS+=(--tests); B=impact
+ fi ;;
+esac
+[ -n "$B" ] && G=(python3 "$H/ax_blocks.py" "$B" "$FR" --)
# A REPOSITORY IN SEVERAL LANGUAGES has one graph per language (.axiomcode/lang/ beside the main one): a query
# asks every one of them (ax_langs.py), so no language's code is left out of an answer. A graph named in
# AXIOMCODE_GRAPH was chosen by the caller and is asked alone.
@@ -204,7 +250,7 @@ if [ -f "$FR/.axiomcode/out/graph.sqlite" ] || [ -L "$FR/.axiomcode/out/graph.sq
fi
case "$cmd" in
index|build) exec bash "$H/axiomcode-build" ${ARGS[@]+"${ARGS[@]}"} ;;
- context) exec ${G[@]+"${G[@]}"} python3 ${Q:+"$Q" "$FR"} "$H/axiomcode-context" ${ARGS[@]+"${ARGS[@]}"} ;;
+ context|find) exec ${G[@]+"${G[@]}"} python3 ${Q:+"$Q" "$FR"} "$H/axiomcode-context" ${ARGS[@]+"${ARGS[@]}"} ;;
path) exec ${G[@]+"${G[@]}"} python3 ${Q:+"$Q" "$FR"} "$H/axiomcode-path" ${ARGS[@]+"${ARGS[@]}"} ;;
impact) exec ${G[@]+"${G[@]}"} python3 ${Q:+"$Q" "$FR"} "$H/axiomcode-impact" ${ARGS[@]+"${ARGS[@]}"} ;;
changed) exec python3 ${Q:+"$Q" "$FR"} "$H/axiomcode-changed" ${ARGS[@]+"${ARGS[@]}"} ;;
diff --git a/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-install b/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-install
index 111cfa64..c562c060 100755
--- a/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-install
+++ b/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-install
@@ -35,23 +35,23 @@ END = ''
BLOCK = """
## Finding code in this repository
-This repository has a resolved call graph. Ask it FIRST, through the
-`mcp__plugin_axiomcode_axiomcode__axiomcode_*` tools; no skill needs loading:
+This repository has a resolved call graph. Ask it FIRST, through the axiomcode MCP tools
+(`mcp__plugin_axiomcode_axiomcode__*`); no skill needs loading:
- axiomcode_context task="" # where the work is, when you have no name yet
- axiomcode_impact targets=[""] # what a change reaches: contract, users, tests
- axiomcode_path from_="" to="" # how A reaches B
+ find(question="") # where the code for a task lives
+ impact(name="") # who calls it, what a change reaches, its tests
+ impact() # the same for your uncommitted edits
+ path(start="", end="") # how A reaches B
+ tests() # the tests your edits reach, and how to run them
-Only when those tools are not in your list, the same from the shell: `axiomcode context ""`,
-`axiomcode impact `, `axiomcode path `.
+Only when those tools are not in your list, the same from the shell: `axiomcode find ""`,
+`axiomcode impact `, `axiomcode path `, `axiomcode tests`.
-**Trust the answer.** A `[resolved]` / `[sound]` row has already been looked up again in the graph
-(the `verified:` line) — do not re-derive it by grepping or opening the other files it names. Every
-answer ends with `next:`, the one step to take: read only the lines you will cite or change.
-`[by name]` / `[text]` rows are leads, not facts. An unresolved call means *unknown*, not *absent*.
+**Trust the answer.** Each place comes with the code of the function it sits in: answer from it. A
+`resolved` place has already been looked up again in the graph (the `verified:` line) — do not re-derive it
+by grepping. `by name` / `text` places are leads, not facts. An unresolved call means *unknown*, not *absent*.
Text search is still right for a string, a comment, a config value, or a file you already know.
-`axiomcode index` builds the graph if `.axiomcode/out/graph.sqlite` is absent.
"""
diff --git a/skills/axiomcode/SKILL.md b/skills/axiomcode/SKILL.md
index 9456d8e1..ff9eb64f 100644
--- a/skills/axiomcode/SKILL.md
+++ b/skills/axiomcode/SKILL.md
@@ -1,131 +1,74 @@
---
name: axiomcode
description: >-
- Use for any why, what or where question about code — how a codebase works or what a change to it would do: architecture, execution flow, where something lives, who calls it, what depends on it, what breaks if it changes, which tests cover an edit, whether it is safe to delete. Also use when resolving an issue or bug report, which names a symptom rather than a file. Examples: "How does X work?", "Where do I change Y?", "What calls this?", "What breaks if I change Z?", "Is this safe to delete?", "Fix this issue". No task is too small: if you are about to grep for a name, call this instead. Mandatory when .axiomcode/out/graph.sqlite exists — start here rather than grep, even when you already know the code. Answers come from a resolved call graph, so they include callers that never spell the name — through an interface, an override, a callback, dependency injection or a config key — each labelled with how certain it is. Call it directly, no need to load this skill first: the `axiomcode_context` MCP tool with source=True for how something works (the call flow with each step's code; from_= when you know where it begins), `axiomcode_impact` for what a change reaches, `axiomcode_path` for how A reaches B. Only when those tools are not in your list, the same from the shell: `axiomcode context "" --source`, `axiomcode impact `, `axiomcode path `. Java, TypeScript, Python, JavaScript, C#.
+ Use for any why, what or where question about code — how a codebase works, where something lives, who calls it, what a change to it breaks, which tests cover an edit. Also use when resolving an issue or bug report, which names a symptom rather than a file. Examples: "How does X work?", "Where do I change Y?", "What calls this?", "What breaks if I change Z?", "Which tests do I run?", "Fix this issue". No task is too small: if you are about to grep for a name, call this instead. Mandatory when .axiomcode/out/graph.sqlite exists — start here rather than grep, even when you already know the code. Answers come from a resolved call graph, so they include callers that never spell the name — through an interface, an override, a callback, dependency injection or a config key — and every place comes with the code of the function it sits in. Call the MCP tools directly, no need to load this skill first: find(question) for where the code for a task lives, impact(name) for who calls it and what a change reaches (with no name: your uncommitted edits), path(start, end) for how A reaches B, tests() for the tests your edits reach. Only when those tools are not in your list, the same from the shell: `axiomcode find ""`, `axiomcode impact `, `axiomcode path `, `axiomcode tests`. Java, TypeScript, Python, JavaScript, C#.
---
# axiomcode
-Prefer the MCP tools (`axiomcode_`; in Claude Code, `mcp__plugin_axiomcode_axiomcode__axiomcode_`) when they
-are in your tool list; otherwise run `/../../plugins/axiomcode/skills/axiomcode/scripts/axiomcode …` from the repository root. Same code, same
-verified output. `` defaults to the current directory. In Claude Code, a hook adds the graph's edges to your own
-Read / Grep results as `graph: …` lines.
-
-**Trust the answer, and know what it is.** A `[resolved]` / `[sound]` row has already been looked up again in the graph (the `verified:` line): do not re-derive it by grepping. Each answer ends with `next:` — the one step to take. For a CHANGE (who calls it, what breaks, which tests), read only the lines you will cite or change. To EXPLAIN how something works, the graph gives the reading order, not the explanation: read each step's body, and continue through every `⚠` (a call the graph lost). `[by name]` / `[text]` / `[approx]` rows are leads, not facts.
-
-**A list of sites comes the way grep prints it.** The MCP `impact`, `path`, `test_impact` and `context` (without
-`source` / `explain` / `from_`) answer one site per line: `path:line: [resolved · hop 2 · test …]`,
-surest first, capped with a count of the rest; `limit=N` lists more, `full=True` gives the sectioned answer with `next:`.
-From the shell the same shape is `--grep` (`--grep-limit N`); without it the answer is the prose.
-
-## Start here
-
-| the question in front of you | the call |
-|---|---|
-| **`.axiomcode/out/graph.sqlite` already exists** | **query it — do NOT run `index`** |
-| no graph at all | `axiomcode index` |
-| a task in words, no name to ask about yet | `axiomcode context ""` — then `--in ` it names |
-| "who calls X" / "what breaks if X changes" | `axiomcode impact X` |
-| "who writes this field" / "is it safe under concurrent access" | `axiomcode impact .` — ask of the FIELD |
-| one concept you can name ("the decryption code") | `axiomcode path decrypt '*'` |
-| "how does X work" · "explain / walk through X" | `axiomcode context "" --source` — the call flow in order with each step's code; answer from it, and open a file only for a step whose body was cut or a `⚠` call. `--from ` when you know where it begins |
-| "how does A reach B" · "everything that reaches X" | `axiomcode path A B` · `axiomcode path '*' X` |
-| "what did my edit touch" · "which tests do I run" | `axiomcode changed --impact` · `axiomcode test-impact` |
-| "is it safe to delete X" | `axiomcode impact X --delete` |
-| what an engine or rules change did to a graph · a before/after of one tree | `axiomcode diff