@mrclrchtr/supi-code-intelligence 4.0.0 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +8 -3
  2. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/package.json +1 -1
  3. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-action-menu.ts +1 -0
  4. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-schema.ts +9 -0
  5. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings.ts +1 -0
  6. package/node_modules/@mrclrchtr/supi-code-runtime/package.json +2 -2
  7. package/node_modules/@mrclrchtr/supi-core/package.json +1 -1
  8. package/node_modules/@mrclrchtr/supi-core/src/settings/settings-action-menu.ts +1 -0
  9. package/node_modules/@mrclrchtr/supi-core/src/settings/settings-schema.ts +9 -0
  10. package/node_modules/@mrclrchtr/supi-core/src/settings.ts +1 -0
  11. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/package.json +1 -5
  12. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-action-menu.ts +1 -0
  13. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-schema.ts +9 -0
  14. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings.ts +1 -0
  15. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/package.json +2 -2
  16. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/package.json +1 -1
  17. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/settings/settings-action-menu.ts +1 -0
  18. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/settings/settings-schema.ts +9 -0
  19. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/settings.ts +1 -0
  20. package/node_modules/@mrclrchtr/supi-lsp/package.json +3 -3
  21. package/node_modules/@mrclrchtr/supi-lsp/src/utils.ts +2 -2
  22. package/node_modules/@mrclrchtr/supi-tree-sitter/README.md +5 -5
  23. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/package.json +1 -5
  24. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-action-menu.ts +1 -0
  25. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-schema.ts +9 -0
  26. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings.ts +1 -0
  27. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/package.json +2 -2
  28. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/package.json +1 -1
  29. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/settings/settings-action-menu.ts +1 -0
  30. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/settings/settings-schema.ts +9 -0
  31. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/settings.ts +1 -0
  32. package/node_modules/@mrclrchtr/supi-tree-sitter/package.json +3 -3
  33. package/node_modules/@mrclrchtr/supi-tree-sitter/src/language.ts +2 -1
  34. package/node_modules/@mrclrchtr/supi-tree-sitter/src/operation-support.ts +19 -0
  35. package/node_modules/@mrclrchtr/supi-tree-sitter/src/syntax-node.ts +1 -0
  36. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/outline-c-family.ts +230 -0
  37. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/outline-html-sql.ts +186 -0
  38. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/outline-jvm.ts +311 -0
  39. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/outline-polyglot.ts +218 -0
  40. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/outline-scripting.ts +307 -0
  41. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/outline.ts +9 -5
  42. package/node_modules/@mrclrchtr/supi-tree-sitter/src/types.ts +6 -2
  43. package/package.json +6 -5
  44. package/src/analysis/search/pattern.ts +2 -2
  45. package/src/analysis/target/symbol.ts +5 -2
  46. package/src/app/app.ts +4 -1
  47. package/src/extension.ts +6 -84
  48. package/src/headless.ts +41 -0
  49. package/src/session/orientation/collect.ts +134 -180
  50. package/src/session/orientation/context-sections.ts +14 -48
  51. package/src/session/orientation-types.ts +14 -4
  52. package/src/session/orientation-workflow.ts +20 -48
  53. package/src/substrate/lsp/lifecycle.ts +25 -39
  54. package/src/substrate/lsp/state.ts +3 -0
  55. package/src/substrate/workspace-provider-host.ts +129 -0
  56. package/src/tool/graph/execute.ts +1 -1
  57. package/src/tool/graph/markdown.ts +222 -0
  58. package/src/tool/orientation/markdown.ts +66 -11
  59. package/src/tool/register.ts +10 -0
  60. package/src/ui/markdown/overview-data.ts +3 -15
  61. package/src/ui/markdown/overview.ts +4 -10
  62. package/src/ui/markdown/types.ts +0 -1
  63. package/src/substrate/tree-sitter/lifecycle.ts +0 -52
  64. package/src/tool/graph/calls-md.ts +0 -41
  65. package/src/tool/graph/implementations-md.ts +0 -57
  66. package/src/tool/graph/markdown-base.ts +0 -88
  67. package/src/tool/graph/provider-location-md.ts +0 -9
  68. package/src/tool/graph/references-md.ts +0 -41
package/README.md CHANGED
@@ -41,6 +41,8 @@ The extension detects project languages and starts matching language servers. In
41
41
  | Kotlin | `kotlin-lsp` |
42
42
  | R | `R` with `languageserver` |
43
43
 
44
+ Semantic and structural support intentionally differ where the syntax differs: Ruby LSP handles ERB templates, and gopls handles `go.mod`, while AST search excludes both rather than parsing them with the wrong Tree-sitter grammar. Ruby gemspecs and KornShell files use the existing Ruby and Bash structural grammars.
45
+
44
46
  Check runtime status with:
45
47
 
46
48
  ```text
@@ -64,7 +66,7 @@ The extension registers exactly eight `code_*` tools:
64
66
 
65
67
  `code_impact`, `code_context`, `code_brief`, `code_references`, `code_calls`, and `code_implementations` are not compatibility aliases.
66
68
 
67
- A lightweight architecture overview may be injected once near session start when a project model is available.
69
+ A complete manifest-derived architecture overview is injected once near session start when a project model is available; discovered modules, descriptions, entrypoints, and relationships are not truncated.
68
70
 
69
71
  ## Exact-one target selectors
70
72
 
@@ -157,7 +159,7 @@ code_find({ query: "@scope/package", mode: "ast", kind: "import", scope: ["src"]
157
159
 
158
160
  Use PI's `grep` tool for literal or regex source search when it is active. `code_find` does not redirect removed text/regex calls to another tool.
159
161
 
160
- AST `kind` accepts exactly `definition`, `import`, `export`, `call`, `type`, `interface`, `class`, `method`, and `enum`. AST `call` finds written call-site names, not symbol identity. Use `code_graph` references on a resolved target for symbol-identity relationships.
162
+ AST `kind` accepts exactly `definition`, `import`, `export`, `call`, `type`, `interface`, `class`, `method`, and `enum`. Outline-backed kinds support every vendored grammar family; HTML definitions are elements with non-empty `id` attributes, while SQL definitions are supported `CREATE` declarations and shallow table/type members. Imports and exports remain JavaScript/TypeScript-only. AST `call` finds written call-site names, not symbol identity. Use `code_graph` references on a resolved target for symbol-identity relationships.
161
163
 
162
164
  #### AST Scan universe
163
165
 
@@ -251,6 +253,8 @@ The old global `lsp.enabled` and `lsp.active` keys are deprecated and ignored. M
251
253
  - `supi-code-runtime` owns canonical provider contracts and workspace capability state.
252
254
  - `supi-lsp` owns semantic lifecycle and the Workspace LSP runtime.
253
255
  - `supi-tree-sitter` owns structural parser reuse.
256
+ - The process-shared Workspace provider host starts LSP and Tree-sitter once per canonical workspace and releases them after the final session lease. Target and refactor handles remain session-local.
257
+ - The Headless inspection profile is for managed child sessions and registers only the six non-mutating inspection tools; it omits refactors, settings, UI, commands, and overview injection.
254
258
 
255
259
  Markdown and TUI are adapters over assembled typed results. Providers, clients, mutable targets, and the LSP manager do not cross the workflow seam.
256
260
 
@@ -264,4 +268,5 @@ See:
264
268
  ## Package exports
265
269
 
266
270
  - `@mrclrchtr/supi-code-intelligence/api` — reusable type contracts
267
- - `@mrclrchtr/supi-code-intelligence/extension` — PI extension entrypoint
271
+ - `@mrclrchtr/supi-code-intelligence/extension` — full interactive PI extension entrypoint
272
+ - `@mrclrchtr/supi-code-intelligence/headless` — managed-child inspection profile
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-core",
3
- "version": "4.0.0",
3
+ "version": "4.2.0",
4
4
  "description": "SuPi core — shared infrastructure for SuPi extensions (XML context tags, config system)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -34,6 +34,7 @@ export function buildActionMenu(field: ScopedFieldValue, scope: SettingsScope):
34
34
  if (choices.length > 0) {
35
35
  for (const choice of choices) menu.push({ value: `set:${choice}`, label: choice });
36
36
  } else if (field.field.kind === "number") menu.push({ value: "edit", label: "Edit value…" });
37
+ else if (field.field.kind === "string") menu.push({ value: "edit", label: "Edit value…" });
37
38
  else if (field.field.kind === "stringList") menu.push({ value: "edit", label: "Edit values…" });
38
39
  else if (field.field.kind === "modelPicker")
39
40
  menu.push({ value: "edit", label: "Choose model…" });
@@ -86,6 +86,11 @@ export interface NumberField extends BaseField {
86
86
  values?: string[];
87
87
  }
88
88
 
89
+ /** One free-form string. */
90
+ export interface StringField extends BaseField {
91
+ kind: "string";
92
+ }
93
+
89
94
  /** Comma-separated string list. */
90
95
  export interface StringListField extends BaseField {
91
96
  kind: "stringList";
@@ -164,6 +169,7 @@ export type SettingsField =
164
169
  | BoolField
165
170
  | EnumField
166
171
  | NumberField
172
+ | StringField
167
173
  | StringListField
168
174
  | ModelPickerField
169
175
  | CustomField;
@@ -248,6 +254,8 @@ export function formatValue(value: unknown, field: SettingsField): string {
248
254
  return value ? "on" : "off";
249
255
  case "number":
250
256
  return String(value ?? "");
257
+ case "string":
258
+ return typeof value === "string" && value ? value : "none";
251
259
  case "stringList": {
252
260
  const arr = Array.isArray(value) ? value : [];
253
261
  return arr.length > 0 ? arr.map(String).join(", ") : "none";
@@ -271,6 +279,7 @@ export function sourceBadge(displayValue: string, source: ValueSource): string {
271
279
 
272
280
  /** Format the value used to prefill editors and compare concrete choices. */
273
281
  export function formatEditValue(value: unknown, field: SettingsField): string {
282
+ if (field.kind === "string") return typeof value === "string" ? value : "";
274
283
  if (field.kind === "stringList") {
275
284
  const arr = Array.isArray(value) ? value : [];
276
285
  return arr.map(String).join(", ");
@@ -26,6 +26,7 @@ export type {
26
26
  SettingsField,
27
27
  SettingsFieldAction,
28
28
  SettingsPersistedChange,
29
+ StringField,
29
30
  StringListField,
30
31
  ValueSource,
31
32
  } from "./settings/settings-schema.ts";
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-code-runtime",
3
- "version": "4.0.0",
3
+ "version": "4.2.0",
4
4
  "description": "SuPi code-runtime — shared workspace context, capability contracts, and canonical types for the code-understanding stack",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -29,7 +29,7 @@
29
29
  "!__tests__"
30
30
  ],
31
31
  "dependencies": {
32
- "@mrclrchtr/supi-core": "4.0.0"
32
+ "@mrclrchtr/supi-core": "4.2.0"
33
33
  },
34
34
  "bundledDependencies": [
35
35
  "@mrclrchtr/supi-core"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-core",
3
- "version": "4.0.0",
3
+ "version": "4.2.0",
4
4
  "description": "SuPi core — shared infrastructure for SuPi extensions (XML context tags, config system)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -34,6 +34,7 @@ export function buildActionMenu(field: ScopedFieldValue, scope: SettingsScope):
34
34
  if (choices.length > 0) {
35
35
  for (const choice of choices) menu.push({ value: `set:${choice}`, label: choice });
36
36
  } else if (field.field.kind === "number") menu.push({ value: "edit", label: "Edit value…" });
37
+ else if (field.field.kind === "string") menu.push({ value: "edit", label: "Edit value…" });
37
38
  else if (field.field.kind === "stringList") menu.push({ value: "edit", label: "Edit values…" });
38
39
  else if (field.field.kind === "modelPicker")
39
40
  menu.push({ value: "edit", label: "Choose model…" });
@@ -86,6 +86,11 @@ export interface NumberField extends BaseField {
86
86
  values?: string[];
87
87
  }
88
88
 
89
+ /** One free-form string. */
90
+ export interface StringField extends BaseField {
91
+ kind: "string";
92
+ }
93
+
89
94
  /** Comma-separated string list. */
90
95
  export interface StringListField extends BaseField {
91
96
  kind: "stringList";
@@ -164,6 +169,7 @@ export type SettingsField =
164
169
  | BoolField
165
170
  | EnumField
166
171
  | NumberField
172
+ | StringField
167
173
  | StringListField
168
174
  | ModelPickerField
169
175
  | CustomField;
@@ -248,6 +254,8 @@ export function formatValue(value: unknown, field: SettingsField): string {
248
254
  return value ? "on" : "off";
249
255
  case "number":
250
256
  return String(value ?? "");
257
+ case "string":
258
+ return typeof value === "string" && value ? value : "none";
251
259
  case "stringList": {
252
260
  const arr = Array.isArray(value) ? value : [];
253
261
  return arr.length > 0 ? arr.map(String).join(", ") : "none";
@@ -271,6 +279,7 @@ export function sourceBadge(displayValue: string, source: ValueSource): string {
271
279
 
272
280
  /** Format the value used to prefill editors and compare concrete choices. */
273
281
  export function formatEditValue(value: unknown, field: SettingsField): string {
282
+ if (field.kind === "string") return typeof value === "string" ? value : "";
274
283
  if (field.kind === "stringList") {
275
284
  const arr = Array.isArray(value) ? value : [];
276
285
  return arr.map(String).join(", ");
@@ -26,6 +26,7 @@ export type {
26
26
  SettingsField,
27
27
  SettingsFieldAction,
28
28
  SettingsPersistedChange,
29
+ StringField,
29
30
  StringListField,
30
31
  ValueSource,
31
32
  } from "./settings/settings-schema.ts";
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-core",
3
- "version": "4.0.0",
3
+ "version": "4.2.0",
4
4
  "description": "SuPi core — shared infrastructure for SuPi extensions (XML context tags, config system)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -48,10 +48,6 @@
48
48
  "optional": true
49
49
  }
50
50
  },
51
- "devDependencies": {
52
- "@types/node": "25.9.5",
53
- "vitest": "4.1.10"
54
- },
55
51
  "main": "src/api.ts",
56
52
  "exports": {
57
53
  "./api": "./src/api.ts",
@@ -34,6 +34,7 @@ export function buildActionMenu(field: ScopedFieldValue, scope: SettingsScope):
34
34
  if (choices.length > 0) {
35
35
  for (const choice of choices) menu.push({ value: `set:${choice}`, label: choice });
36
36
  } else if (field.field.kind === "number") menu.push({ value: "edit", label: "Edit value…" });
37
+ else if (field.field.kind === "string") menu.push({ value: "edit", label: "Edit value…" });
37
38
  else if (field.field.kind === "stringList") menu.push({ value: "edit", label: "Edit values…" });
38
39
  else if (field.field.kind === "modelPicker")
39
40
  menu.push({ value: "edit", label: "Choose model…" });
@@ -86,6 +86,11 @@ export interface NumberField extends BaseField {
86
86
  values?: string[];
87
87
  }
88
88
 
89
+ /** One free-form string. */
90
+ export interface StringField extends BaseField {
91
+ kind: "string";
92
+ }
93
+
89
94
  /** Comma-separated string list. */
90
95
  export interface StringListField extends BaseField {
91
96
  kind: "stringList";
@@ -164,6 +169,7 @@ export type SettingsField =
164
169
  | BoolField
165
170
  | EnumField
166
171
  | NumberField
172
+ | StringField
167
173
  | StringListField
168
174
  | ModelPickerField
169
175
  | CustomField;
@@ -248,6 +254,8 @@ export function formatValue(value: unknown, field: SettingsField): string {
248
254
  return value ? "on" : "off";
249
255
  case "number":
250
256
  return String(value ?? "");
257
+ case "string":
258
+ return typeof value === "string" && value ? value : "none";
251
259
  case "stringList": {
252
260
  const arr = Array.isArray(value) ? value : [];
253
261
  return arr.length > 0 ? arr.map(String).join(", ") : "none";
@@ -271,6 +279,7 @@ export function sourceBadge(displayValue: string, source: ValueSource): string {
271
279
 
272
280
  /** Format the value used to prefill editors and compare concrete choices. */
273
281
  export function formatEditValue(value: unknown, field: SettingsField): string {
282
+ if (field.kind === "string") return typeof value === "string" ? value : "";
274
283
  if (field.kind === "stringList") {
275
284
  const arr = Array.isArray(value) ? value : [];
276
285
  return arr.map(String).join(", ");
@@ -26,6 +26,7 @@ export type {
26
26
  SettingsField,
27
27
  SettingsFieldAction,
28
28
  SettingsPersistedChange,
29
+ StringField,
29
30
  StringListField,
30
31
  ValueSource,
31
32
  } from "./settings/settings-schema.ts";
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-code-runtime",
3
- "version": "4.0.0",
3
+ "version": "4.2.0",
4
4
  "description": "SuPi code-runtime — shared workspace context, capability contracts, and canonical types for the code-understanding stack",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -29,7 +29,7 @@
29
29
  "!__tests__"
30
30
  ],
31
31
  "dependencies": {
32
- "@mrclrchtr/supi-core": "4.0.0"
32
+ "@mrclrchtr/supi-core": "4.2.0"
33
33
  },
34
34
  "bundledDependencies": [
35
35
  "@mrclrchtr/supi-core"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-core",
3
- "version": "4.0.0",
3
+ "version": "4.2.0",
4
4
  "description": "SuPi core — shared infrastructure for SuPi extensions (XML context tags, config system)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -34,6 +34,7 @@ export function buildActionMenu(field: ScopedFieldValue, scope: SettingsScope):
34
34
  if (choices.length > 0) {
35
35
  for (const choice of choices) menu.push({ value: `set:${choice}`, label: choice });
36
36
  } else if (field.field.kind === "number") menu.push({ value: "edit", label: "Edit value…" });
37
+ else if (field.field.kind === "string") menu.push({ value: "edit", label: "Edit value…" });
37
38
  else if (field.field.kind === "stringList") menu.push({ value: "edit", label: "Edit values…" });
38
39
  else if (field.field.kind === "modelPicker")
39
40
  menu.push({ value: "edit", label: "Choose model…" });
@@ -86,6 +86,11 @@ export interface NumberField extends BaseField {
86
86
  values?: string[];
87
87
  }
88
88
 
89
+ /** One free-form string. */
90
+ export interface StringField extends BaseField {
91
+ kind: "string";
92
+ }
93
+
89
94
  /** Comma-separated string list. */
90
95
  export interface StringListField extends BaseField {
91
96
  kind: "stringList";
@@ -164,6 +169,7 @@ export type SettingsField =
164
169
  | BoolField
165
170
  | EnumField
166
171
  | NumberField
172
+ | StringField
167
173
  | StringListField
168
174
  | ModelPickerField
169
175
  | CustomField;
@@ -248,6 +254,8 @@ export function formatValue(value: unknown, field: SettingsField): string {
248
254
  return value ? "on" : "off";
249
255
  case "number":
250
256
  return String(value ?? "");
257
+ case "string":
258
+ return typeof value === "string" && value ? value : "none";
251
259
  case "stringList": {
252
260
  const arr = Array.isArray(value) ? value : [];
253
261
  return arr.length > 0 ? arr.map(String).join(", ") : "none";
@@ -271,6 +279,7 @@ export function sourceBadge(displayValue: string, source: ValueSource): string {
271
279
 
272
280
  /** Format the value used to prefill editors and compare concrete choices. */
273
281
  export function formatEditValue(value: unknown, field: SettingsField): string {
282
+ if (field.kind === "string") return typeof value === "string" ? value : "";
274
283
  if (field.kind === "stringList") {
275
284
  const arr = Array.isArray(value) ? value : [];
276
285
  return arr.map(String).join(", ");
@@ -26,6 +26,7 @@ export type {
26
26
  SettingsField,
27
27
  SettingsFieldAction,
28
28
  SettingsPersistedChange,
29
+ StringField,
29
30
  StringListField,
30
31
  ValueSource,
31
32
  } from "./settings/settings-schema.ts";
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-lsp",
3
- "version": "4.0.0",
3
+ "version": "4.2.0",
4
4
  "description": "SuPi LSP runtime — Language Server Protocol integration library for pi",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -37,8 +37,8 @@
37
37
  "vscode-jsonrpc": "^9.0.0",
38
38
  "vscode-languageserver-protocol": "^3.17.5",
39
39
  "vscode-languageserver-types": "^3.17.5",
40
- "@mrclrchtr/supi-code-runtime": "4.0.0",
41
- "@mrclrchtr/supi-core": "4.0.0"
40
+ "@mrclrchtr/supi-core": "4.2.0",
41
+ "@mrclrchtr/supi-code-runtime": "4.2.0"
42
42
  },
43
43
  "bundledDependencies": [
44
44
  "@mrclrchtr/supi-code-runtime",
@@ -24,7 +24,7 @@ const EXT_TO_LANGUAGE: Record<string, string> = {
24
24
  pyi: "python",
25
25
  rs: "rust",
26
26
  go: "go",
27
- mod: "go",
27
+ mod: "go.mod",
28
28
  c: "c",
29
29
  h: "c",
30
30
  cpp: "cpp",
@@ -52,7 +52,7 @@ const EXT_TO_LANGUAGE: Record<string, string> = {
52
52
  sql: "sql",
53
53
  r: "r",
54
54
  rb: "ruby",
55
- erb: "ruby",
55
+ erb: "erb",
56
56
  gemspec: "ruby",
57
57
  java: "java",
58
58
  kt: "kotlin",
@@ -40,17 +40,17 @@ Coordinates in the library APIs use **1-based** line and character columns. Char
40
40
  - JavaScript / TypeScript (`.js`, `.jsx`, `.ts`, `.tsx`, `.mjs`, `.cjs`, `.mts`, `.cts`)
41
41
  - Python (`.py`, `.pyi`)
42
42
  - Rust (`.rs`)
43
- - Go (`.go`, `.mod`)
43
+ - Go (`.go`)
44
44
  - C / C++ (`.c`, `.h`, `.cpp`, `.hpp`, `.cc`, `.cxx`, `.hxx`, `.c++`, `.h++`)
45
45
  - Java (`.java`)
46
46
  - Kotlin (`.kt`, `.kts`)
47
- - Ruby (`.rb`)
48
- - Bash / shell (`.sh`, `.bash`, `.zsh`)
47
+ - Ruby (`.rb`, `.gemspec`)
48
+ - Bash / shell (`.sh`, `.bash`, `.zsh`, `.ksh`)
49
49
  - HTML (`.html`, `.htm`, `.xhtml`)
50
50
  - R (`.r`)
51
51
  - SQL (`.sql`)
52
52
 
53
- Parser support is broader than extractor support. Outline, import, and export collection currently support JavaScript/TypeScript-family grammars. Call-site collection supports every listed family except HTML and SQL. Consumers performing a bulk structural scan should use `getStructuralSearchSupportedExtensions(operation)` rather than treating every parseable extension as eligible.
53
+ Outline collection supports every listed family. HTML outlines contain elements with non-empty `id` attributes; SQL outlines contain `CREATE` declarations and shallow table/type members. Import and export collection remains JavaScript/TypeScript-only, and call-site collection supports every listed family except HTML and SQL. Go module manifests and ERB templates are intentionally excluded because the Go and Ruby grammars do not parse those mixed or separate syntaxes; `supi-lsp` still handles them semantically. Consumers performing a bulk structural scan should use `getStructuralSearchSupportedExtensions(operation)` rather than treating parser support as operation support.
54
54
 
55
55
  ## Architecture
56
56
 
@@ -107,4 +107,4 @@ if (state.kind === "ready") {
107
107
  - `src/operation-support.ts` — authoritative operation-specific extension support
108
108
  - `src/session/service-registry.ts` — shared session-scoped structural service registry
109
109
  - `src/provider/tree-sitter-provider.ts` — `StructuralProvider` adapter consumed by `@mrclrchtr/supi-code-intelligence`
110
- - `src/tool/outline.ts`, `src/tool/imports.ts`, `src/tool/exports.ts`, `src/tool/node-at.ts`, `src/tool/callees.ts`, `src/tool/call-sites.ts` — structural analyses exposed through the library surface
110
+ - `src/tool/outline.ts`, `src/tool/outline-*.ts`, `src/tool/imports.ts`, `src/tool/exports.ts`, `src/tool/node-at.ts`, `src/tool/callees.ts`, `src/tool/call-sites.ts` — structural analyses exposed through the library surface
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-core",
3
- "version": "4.0.0",
3
+ "version": "4.2.0",
4
4
  "description": "SuPi core — shared infrastructure for SuPi extensions (XML context tags, config system)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -48,10 +48,6 @@
48
48
  "optional": true
49
49
  }
50
50
  },
51
- "devDependencies": {
52
- "@types/node": "25.9.5",
53
- "vitest": "4.1.10"
54
- },
55
51
  "main": "src/api.ts",
56
52
  "exports": {
57
53
  "./api": "./src/api.ts",
@@ -34,6 +34,7 @@ export function buildActionMenu(field: ScopedFieldValue, scope: SettingsScope):
34
34
  if (choices.length > 0) {
35
35
  for (const choice of choices) menu.push({ value: `set:${choice}`, label: choice });
36
36
  } else if (field.field.kind === "number") menu.push({ value: "edit", label: "Edit value…" });
37
+ else if (field.field.kind === "string") menu.push({ value: "edit", label: "Edit value…" });
37
38
  else if (field.field.kind === "stringList") menu.push({ value: "edit", label: "Edit values…" });
38
39
  else if (field.field.kind === "modelPicker")
39
40
  menu.push({ value: "edit", label: "Choose model…" });
@@ -86,6 +86,11 @@ export interface NumberField extends BaseField {
86
86
  values?: string[];
87
87
  }
88
88
 
89
+ /** One free-form string. */
90
+ export interface StringField extends BaseField {
91
+ kind: "string";
92
+ }
93
+
89
94
  /** Comma-separated string list. */
90
95
  export interface StringListField extends BaseField {
91
96
  kind: "stringList";
@@ -164,6 +169,7 @@ export type SettingsField =
164
169
  | BoolField
165
170
  | EnumField
166
171
  | NumberField
172
+ | StringField
167
173
  | StringListField
168
174
  | ModelPickerField
169
175
  | CustomField;
@@ -248,6 +254,8 @@ export function formatValue(value: unknown, field: SettingsField): string {
248
254
  return value ? "on" : "off";
249
255
  case "number":
250
256
  return String(value ?? "");
257
+ case "string":
258
+ return typeof value === "string" && value ? value : "none";
251
259
  case "stringList": {
252
260
  const arr = Array.isArray(value) ? value : [];
253
261
  return arr.length > 0 ? arr.map(String).join(", ") : "none";
@@ -271,6 +279,7 @@ export function sourceBadge(displayValue: string, source: ValueSource): string {
271
279
 
272
280
  /** Format the value used to prefill editors and compare concrete choices. */
273
281
  export function formatEditValue(value: unknown, field: SettingsField): string {
282
+ if (field.kind === "string") return typeof value === "string" ? value : "";
274
283
  if (field.kind === "stringList") {
275
284
  const arr = Array.isArray(value) ? value : [];
276
285
  return arr.map(String).join(", ");
@@ -26,6 +26,7 @@ export type {
26
26
  SettingsField,
27
27
  SettingsFieldAction,
28
28
  SettingsPersistedChange,
29
+ StringField,
29
30
  StringListField,
30
31
  ValueSource,
31
32
  } from "./settings/settings-schema.ts";
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-code-runtime",
3
- "version": "4.0.0",
3
+ "version": "4.2.0",
4
4
  "description": "SuPi code-runtime — shared workspace context, capability contracts, and canonical types for the code-understanding stack",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -29,7 +29,7 @@
29
29
  "!__tests__"
30
30
  ],
31
31
  "dependencies": {
32
- "@mrclrchtr/supi-core": "4.0.0"
32
+ "@mrclrchtr/supi-core": "4.2.0"
33
33
  },
34
34
  "bundledDependencies": [
35
35
  "@mrclrchtr/supi-core"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-core",
3
- "version": "4.0.0",
3
+ "version": "4.2.0",
4
4
  "description": "SuPi core — shared infrastructure for SuPi extensions (XML context tags, config system)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -34,6 +34,7 @@ export function buildActionMenu(field: ScopedFieldValue, scope: SettingsScope):
34
34
  if (choices.length > 0) {
35
35
  for (const choice of choices) menu.push({ value: `set:${choice}`, label: choice });
36
36
  } else if (field.field.kind === "number") menu.push({ value: "edit", label: "Edit value…" });
37
+ else if (field.field.kind === "string") menu.push({ value: "edit", label: "Edit value…" });
37
38
  else if (field.field.kind === "stringList") menu.push({ value: "edit", label: "Edit values…" });
38
39
  else if (field.field.kind === "modelPicker")
39
40
  menu.push({ value: "edit", label: "Choose model…" });
@@ -86,6 +86,11 @@ export interface NumberField extends BaseField {
86
86
  values?: string[];
87
87
  }
88
88
 
89
+ /** One free-form string. */
90
+ export interface StringField extends BaseField {
91
+ kind: "string";
92
+ }
93
+
89
94
  /** Comma-separated string list. */
90
95
  export interface StringListField extends BaseField {
91
96
  kind: "stringList";
@@ -164,6 +169,7 @@ export type SettingsField =
164
169
  | BoolField
165
170
  | EnumField
166
171
  | NumberField
172
+ | StringField
167
173
  | StringListField
168
174
  | ModelPickerField
169
175
  | CustomField;
@@ -248,6 +254,8 @@ export function formatValue(value: unknown, field: SettingsField): string {
248
254
  return value ? "on" : "off";
249
255
  case "number":
250
256
  return String(value ?? "");
257
+ case "string":
258
+ return typeof value === "string" && value ? value : "none";
251
259
  case "stringList": {
252
260
  const arr = Array.isArray(value) ? value : [];
253
261
  return arr.length > 0 ? arr.map(String).join(", ") : "none";
@@ -271,6 +279,7 @@ export function sourceBadge(displayValue: string, source: ValueSource): string {
271
279
 
272
280
  /** Format the value used to prefill editors and compare concrete choices. */
273
281
  export function formatEditValue(value: unknown, field: SettingsField): string {
282
+ if (field.kind === "string") return typeof value === "string" ? value : "";
274
283
  if (field.kind === "stringList") {
275
284
  const arr = Array.isArray(value) ? value : [];
276
285
  return arr.map(String).join(", ");
@@ -26,6 +26,7 @@ export type {
26
26
  SettingsField,
27
27
  SettingsFieldAction,
28
28
  SettingsPersistedChange,
29
+ StringField,
29
30
  StringListField,
30
31
  ValueSource,
31
32
  } from "./settings/settings-schema.ts";
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-tree-sitter",
3
- "version": "4.0.0",
3
+ "version": "4.2.0",
4
4
  "description": "SuPi Tree-sitter library — structural AST analysis for pi",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -34,8 +34,8 @@
34
34
  ],
35
35
  "dependencies": {
36
36
  "web-tree-sitter": "^0.26.8",
37
- "@mrclrchtr/supi-code-runtime": "4.0.0",
38
- "@mrclrchtr/supi-core": "4.0.0"
37
+ "@mrclrchtr/supi-code-runtime": "4.2.0",
38
+ "@mrclrchtr/supi-core": "4.2.0"
39
39
  },
40
40
  "bundledDependencies": [
41
41
  "@mrclrchtr/supi-code-runtime",
@@ -25,7 +25,6 @@ const EXTENSION_GRAMMAR: Record<string, GrammarId> = {
25
25
  ".pyi": "python",
26
26
  ".rs": "rust",
27
27
  ".go": "go",
28
- ".mod": "go",
29
28
  ".c": "c",
30
29
  ".h": "c",
31
30
  ".cpp": "cpp",
@@ -39,9 +38,11 @@ const EXTENSION_GRAMMAR: Record<string, GrammarId> = {
39
38
  ".kt": "kotlin",
40
39
  ".kts": "kotlin",
41
40
  ".rb": "ruby",
41
+ ".gemspec": "ruby",
42
42
  ".sh": "bash",
43
43
  ".bash": "bash",
44
44
  ".zsh": "bash",
45
+ ".ksh": "bash",
45
46
  ".html": "html",
46
47
  ".htm": "html",
47
48
  ".xhtml": "html",
@@ -2,6 +2,24 @@ import { getSupportedExtensionGrammarEntries, isJsTsGrammar } from "./language.t
2
2
  import { supportsCallSitesGrammar } from "./tool/call-sites.ts";
3
3
  import type { GrammarId, SupportedExtension } from "./types.ts";
4
4
 
5
+ const OUTLINE_GRAMMARS: ReadonlySet<GrammarId> = new Set([
6
+ "javascript",
7
+ "typescript",
8
+ "tsx",
9
+ "python",
10
+ "rust",
11
+ "go",
12
+ "c",
13
+ "cpp",
14
+ "java",
15
+ "kotlin",
16
+ "ruby",
17
+ "bash",
18
+ "html",
19
+ "r",
20
+ "sql",
21
+ ]);
22
+
5
23
  /** Structural collection operations whose language support defines an AST Scan universe. */
6
24
  const STRUCTURAL_SEARCH_OPERATIONS = ["outline", "imports", "exports", "call-sites"] as const;
7
25
 
@@ -31,6 +49,7 @@ export function supportsGrammarOperation(
31
49
  case "call-sites":
32
50
  return supportsCallSitesGrammar(grammar);
33
51
  case "outline":
52
+ return OUTLINE_GRAMMARS.has(grammar);
34
53
  case "imports":
35
54
  case "exports":
36
55
  return isJsTsGrammar(grammar);