@specship/specship-win32-arm64 0.15.0 → 0.17.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.
- package/lib/dist/activation/steering.d.ts +35 -0
- package/lib/dist/activation/steering.d.ts.map +1 -0
- package/lib/dist/activation/steering.js +92 -0
- package/lib/dist/activation/steering.js.map +1 -0
- package/lib/dist/bin/specship.js +78 -4
- package/lib/dist/bin/specship.js.map +1 -1
- package/lib/dist/extraction/specs/markdown-spec-extractor.d.ts +9 -7
- package/lib/dist/extraction/specs/markdown-spec-extractor.d.ts.map +1 -1
- package/lib/dist/extraction/specs/markdown-spec-extractor.js +17 -10
- package/lib/dist/extraction/specs/markdown-spec-extractor.js.map +1 -1
- package/lib/dist/extraction/specs/spec-file-writeback.d.ts +37 -0
- package/lib/dist/extraction/specs/spec-file-writeback.d.ts.map +1 -0
- package/lib/dist/extraction/specs/spec-file-writeback.js +159 -0
- package/lib/dist/extraction/specs/spec-file-writeback.js.map +1 -0
- package/lib/dist/extraction/tree-sitter-helpers.d.ts.map +1 -1
- package/lib/dist/extraction/tree-sitter-helpers.js +12 -1
- package/lib/dist/extraction/tree-sitter-helpers.js.map +1 -1
- package/lib/dist/installer/index.d.ts +7 -0
- package/lib/dist/installer/index.d.ts.map +1 -1
- package/lib/dist/installer/index.js +7 -1
- package/lib/dist/installer/index.js.map +1 -1
- package/lib/dist/installer/targets/claude.d.ts +11 -2
- package/lib/dist/installer/targets/claude.d.ts.map +1 -1
- package/lib/dist/installer/targets/claude.js +83 -7
- package/lib/dist/installer/targets/claude.js.map +1 -1
- package/lib/dist/installer/targets/shared.d.ts +10 -2
- package/lib/dist/installer/targets/shared.d.ts.map +1 -1
- package/lib/dist/installer/targets/shared.js +22 -11
- package/lib/dist/installer/targets/shared.js.map +1 -1
- package/lib/dist/installer/targets/types.d.ts +10 -0
- package/lib/dist/installer/targets/types.d.ts.map +1 -1
- package/lib/dist/mcp/model-context.d.ts +51 -0
- package/lib/dist/mcp/model-context.d.ts.map +1 -0
- package/lib/dist/mcp/model-context.js +234 -0
- package/lib/dist/mcp/model-context.js.map +1 -0
- package/lib/dist/mcp/session.d.ts +1 -0
- package/lib/dist/mcp/session.d.ts.map +1 -1
- package/lib/dist/mcp/session.js +13 -0
- package/lib/dist/mcp/session.js.map +1 -1
- package/lib/dist/mcp/spec-tools.d.ts.map +1 -1
- package/lib/dist/mcp/spec-tools.js +44 -1
- package/lib/dist/mcp/spec-tools.js.map +1 -1
- package/lib/dist/mcp/tools.d.ts +42 -0
- package/lib/dist/mcp/tools.d.ts.map +1 -1
- package/lib/dist/mcp/tools.js +176 -16
- package/lib/dist/mcp/tools.js.map +1 -1
- package/lib/dist/resolution/spec-link-resolver.d.ts.map +1 -1
- package/lib/dist/resolution/spec-link-resolver.js +42 -28
- package/lib/dist/resolution/spec-link-resolver.js.map +1 -1
- package/lib/dist/server/ingest/index.js +1 -1
- package/lib/dist/server/ingest/ingestor.js +24 -4
- package/lib/dist/server/routes/claude.js +31 -5
- package/lib/dist/server/routes/spec.js +13 -0
- package/lib/dist/server/routes/workflow.js +15 -1
- package/lib/dist/server/server.js +2 -2
- package/lib/dist/statusline/index.d.ts.map +1 -1
- package/lib/dist/statusline/index.js +6 -0
- package/lib/dist/statusline/index.js.map +1 -1
- package/lib/dist/statusline/paths.d.ts +2 -0
- package/lib/dist/statusline/paths.d.ts.map +1 -1
- package/lib/dist/statusline/paths.js +5 -0
- package/lib/dist/statusline/paths.js.map +1 -1
- package/lib/dist/types.d.ts +8 -3
- package/lib/dist/types.d.ts.map +1 -1
- package/lib/dist/ui/assets/index-CjjaftDw.js +50 -0
- package/lib/dist/ui/index.html +1 -1
- package/lib/dist/workflows/defaults/spec-implement.yaml +5 -0
- package/lib/dist/workflows/defaults/spec-verify.yaml +23 -9
- package/lib/dist/workflows/executor.d.ts +19 -0
- package/lib/dist/workflows/executor.d.ts.map +1 -1
- package/lib/dist/workflows/executor.js +131 -18
- package/lib/dist/workflows/executor.js.map +1 -1
- package/lib/dist/workflows/runners/bash.d.ts.map +1 -1
- package/lib/dist/workflows/runners/bash.js +14 -1
- package/lib/dist/workflows/runners/bash.js.map +1 -1
- package/lib/node_modules/.package-lock.json +1 -1
- package/lib/package.json +1 -1
- package/package.json +1 -1
- package/lib/dist/server/chat/classify.js +0 -130
- package/lib/dist/server/routes/chat-answer.js +0 -499
- package/lib/dist/server/routes/chat.js +0 -144
- package/lib/dist/ui/assets/index-CpBBlEO2.js +0 -51
package/lib/dist/mcp/tools.js
CHANGED
|
@@ -10,9 +10,13 @@ exports.getExploreBudget = getExploreBudget;
|
|
|
10
10
|
exports.getExploreOutputBudget = getExploreOutputBudget;
|
|
11
11
|
exports.formatStaleBanner = formatStaleBanner;
|
|
12
12
|
exports.formatStaleFooter = formatStaleFooter;
|
|
13
|
+
exports.integrationEnabled = integrationEnabled;
|
|
14
|
+
exports.toolIntegration = toolIntegration;
|
|
15
|
+
exports.filterIntegrationTools = filterIntegrationTools;
|
|
13
16
|
exports.getStaticTools = getStaticTools;
|
|
14
17
|
const directory_1 = require("../directory");
|
|
15
18
|
const statusline_1 = require("../statusline");
|
|
19
|
+
const model_context_1 = require("./model-context");
|
|
16
20
|
// Lazy-load the heavy SpecShip chain off the MCP startup path — see the same
|
|
17
21
|
// helper in engine.ts. ToolHandler must load to answer tools/list (static
|
|
18
22
|
// schemas), but it must NOT drag in sqlite/query layers before the daemon binds;
|
|
@@ -469,6 +473,25 @@ exports.tools = [
|
|
|
469
473
|
// Independent of the code graph.
|
|
470
474
|
...jira_tools_1.jiraToolDefinitions,
|
|
471
475
|
];
|
|
476
|
+
function integrationEnabled(name, env = process.env) {
|
|
477
|
+
const raw = env.SPECSHIP_INTEGRATIONS ?? '';
|
|
478
|
+
return raw.split(',').map((s) => s.trim().toLowerCase()).includes(name);
|
|
479
|
+
}
|
|
480
|
+
/** Which integration (if any) a tool belongs to. Core tools return null. */
|
|
481
|
+
function toolIntegration(toolName) {
|
|
482
|
+
if (toolName.startsWith('designer_'))
|
|
483
|
+
return 'designer';
|
|
484
|
+
if (toolName.startsWith('specship_jira_'))
|
|
485
|
+
return 'jira';
|
|
486
|
+
return null;
|
|
487
|
+
}
|
|
488
|
+
/** Drop tools whose integration isn't enabled (REQ-INTEG-001.A1/A2). */
|
|
489
|
+
function filterIntegrationTools(list, env = process.env) {
|
|
490
|
+
return list.filter((t) => {
|
|
491
|
+
const integ = toolIntegration(t.name);
|
|
492
|
+
return integ === null || integrationEnabled(integ, env);
|
|
493
|
+
});
|
|
494
|
+
}
|
|
472
495
|
/**
|
|
473
496
|
* Allowlist-filtered tool definitions WITHOUT an engine — the static surface the
|
|
474
497
|
* proxy answers `tools/list` with before any project is open. Mirrors
|
|
@@ -476,11 +499,12 @@ exports.tools = [
|
|
|
476
499
|
* note in a description only adds once `cg` is loaded; the schemas are static).
|
|
477
500
|
*/
|
|
478
501
|
function getStaticTools() {
|
|
502
|
+
const base = filterIntegrationTools(exports.tools);
|
|
479
503
|
const raw = process.env.SPECSHIP_MCP_TOOLS;
|
|
480
504
|
if (!raw || !raw.trim())
|
|
481
|
-
return
|
|
505
|
+
return base;
|
|
482
506
|
const allow = new Set(raw.split(',').map(s => s.trim().replace(/^specship_/, '')).filter(Boolean));
|
|
483
|
-
return allow.size ?
|
|
507
|
+
return allow.size ? base.filter(t => allow.has(t.name.replace(/^specship_/, ''))) : base;
|
|
484
508
|
}
|
|
485
509
|
/**
|
|
486
510
|
* Tool handler that executes tools against a SpecShip instance
|
|
@@ -572,10 +596,13 @@ class ToolHandler {
|
|
|
572
596
|
* allowlist so a trimmed surface is reflected in ListTools.
|
|
573
597
|
*/
|
|
574
598
|
getTools() {
|
|
599
|
+
// Integration tier first (INTEG-TIER-DOC): jira/designer tools exist only
|
|
600
|
+
// when explicitly enabled, before any allowlist/size gating applies.
|
|
601
|
+
const base = filterIntegrationTools(exports.tools);
|
|
575
602
|
const allow = this.toolAllowlist();
|
|
576
603
|
let visible = allow
|
|
577
|
-
?
|
|
578
|
-
:
|
|
604
|
+
? base.filter(t => allow.has(t.name.replace(/^specship_/, '')))
|
|
605
|
+
: base;
|
|
579
606
|
if (!this.cg)
|
|
580
607
|
return visible;
|
|
581
608
|
try {
|
|
@@ -614,6 +641,22 @@ class ToolHandler {
|
|
|
614
641
|
// economics that justify trimming don't apply, so they always survive.
|
|
615
642
|
visible = visible.filter(t => TINY_REPO_CORE_TOOLS.has(t.name) || t.name.startsWith('designer_'));
|
|
616
643
|
}
|
|
644
|
+
// Haiku-tier menu trim (LOWMODEL-DOC, REQ-LOWMODEL-004): small-model
|
|
645
|
+
// tool choice degrades with menu size, so the code-graph group trims
|
|
646
|
+
// to the core three; spec/link tools and enabled integrations are
|
|
647
|
+
// untouched. Composes with the tiny-repo gate as an intersection.
|
|
648
|
+
// Schemas never vary — only the list; `execute()` still answers a
|
|
649
|
+
// trimmed-away tool for clients that cached the full list (A2).
|
|
650
|
+
if ((0, model_context_1.detectModelTier)(this.cg.getProjectRoot()) === 'haiku') {
|
|
651
|
+
const HAIKU_CORE = new Set(['specship_explore', 'specship_search', 'specship_node']);
|
|
652
|
+
const CODE_GRAPH_GROUP = new Set([
|
|
653
|
+
'specship_explore', 'specship_search', 'specship_node',
|
|
654
|
+
'specship_callers', 'specship_callees', 'specship_impact',
|
|
655
|
+
'specship_files', 'specship_status',
|
|
656
|
+
'specship_maintainability', 'specship_fitness',
|
|
657
|
+
]);
|
|
658
|
+
visible = visible.filter(t => !CODE_GRAPH_GROUP.has(t.name) || HAIKU_CORE.has(t.name));
|
|
659
|
+
}
|
|
617
660
|
return visible.map(tool => {
|
|
618
661
|
if (tool.name === 'specship_explore') {
|
|
619
662
|
return {
|
|
@@ -798,6 +841,58 @@ class ToolHandler {
|
|
|
798
841
|
* Cost when nothing is pending — the common case — is one boolean check.
|
|
799
842
|
* No I/O, no parsing of markdown beyond a per-pending-file substring scan.
|
|
800
843
|
*/
|
|
844
|
+
/**
|
|
845
|
+
* Model-aware compaction (MODCTX-DOC, REQ-MODCTX-002/003). Resolves the
|
|
846
|
+
* session's model tier (status-line marker / SPECSHIP_MODEL; SPECSHIP_COMPACT=0
|
|
847
|
+
* disables) and, on haiku/sonnet, compresses the response's prose
|
|
848
|
+
* scaffolding — fenced code stays byte-verbatim. Full tier is identity.
|
|
849
|
+
*/
|
|
850
|
+
/**
|
|
851
|
+
* Tier-change listeners (LOWMODEL-DOC, REQ-LOWMODEL-004.A3): the haiku
|
|
852
|
+
* menu trim changes `tools/list`, so a mid-session /model switch must ride
|
|
853
|
+
* an MCP `notifications/tools/list_changed`. Sessions subscribe here; the
|
|
854
|
+
* change is detected on the next code-graph call (the same funnel that
|
|
855
|
+
* reads the tier for compaction).
|
|
856
|
+
*/
|
|
857
|
+
tierListeners = new Set();
|
|
858
|
+
lastTier = null;
|
|
859
|
+
addTierChangeListener(cb) {
|
|
860
|
+
this.tierListeners.add(cb);
|
|
861
|
+
return () => this.tierListeners.delete(cb);
|
|
862
|
+
}
|
|
863
|
+
noteTier(tier) {
|
|
864
|
+
if (this.lastTier !== null && tier !== this.lastTier) {
|
|
865
|
+
for (const cb of this.tierListeners) {
|
|
866
|
+
try {
|
|
867
|
+
cb(tier);
|
|
868
|
+
}
|
|
869
|
+
catch { /* a listener must never break a tool call */ }
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
this.lastTier = tier;
|
|
873
|
+
}
|
|
874
|
+
withModelCompaction(result) {
|
|
875
|
+
if (result.isError)
|
|
876
|
+
return result;
|
|
877
|
+
let root = null;
|
|
878
|
+
try {
|
|
879
|
+
root = this.cg?.getProjectRoot() ?? null;
|
|
880
|
+
}
|
|
881
|
+
catch {
|
|
882
|
+
root = null;
|
|
883
|
+
}
|
|
884
|
+
const tier = (0, model_context_1.detectModelTier)(root);
|
|
885
|
+
this.noteTier(tier);
|
|
886
|
+
if (tier === 'full')
|
|
887
|
+
return result;
|
|
888
|
+
const first = result.content?.[0];
|
|
889
|
+
if (!first || first.type !== 'text' || typeof first.text !== 'string')
|
|
890
|
+
return result;
|
|
891
|
+
return {
|
|
892
|
+
...result,
|
|
893
|
+
content: [{ ...first, text: (0, model_context_1.compactToolResult)(first.text, tier) }, ...result.content.slice(1)],
|
|
894
|
+
};
|
|
895
|
+
}
|
|
801
896
|
withStalenessNotice(result, projectPath) {
|
|
802
897
|
if (result.isError)
|
|
803
898
|
return result;
|
|
@@ -900,6 +995,13 @@ class ToolHandler {
|
|
|
900
995
|
if (!this.isToolAllowed(toolName)) {
|
|
901
996
|
return this.errorResult(`Tool ${toolName} is disabled via SPECSHIP_MCP_TOOLS`);
|
|
902
997
|
}
|
|
998
|
+
// Integration tier (INTEG-TIER-DOC, REQ-INTEG-001): a jira/designer
|
|
999
|
+
// call without the opt-in is rejected even if a client cached the tool.
|
|
1000
|
+
const integ = toolIntegration(toolName);
|
|
1001
|
+
if (integ && !integrationEnabled(integ)) {
|
|
1002
|
+
return this.errorResult(`Tool ${toolName} belongs to the optional "${integ}" integration, which is not enabled. ` +
|
|
1003
|
+
`Enable it with: specship install --with-${integ} (it talks to ${integ === 'jira' ? 'your Atlassian instance' : 'claude.ai — experimental'}).`);
|
|
1004
|
+
}
|
|
903
1005
|
// Cross-cutting input validation. All tools accept an optional
|
|
904
1006
|
// `projectPath` and most accept either `query`, `task`, or
|
|
905
1007
|
// `symbol` — bound their lengths centrally so individual handlers
|
|
@@ -1018,7 +1120,12 @@ class ToolHandler {
|
|
|
1018
1120
|
return this.errorResult(`Unknown tool: ${toolName}`);
|
|
1019
1121
|
}
|
|
1020
1122
|
const withWorktree = this.withWorktreeNotice(result, args.projectPath);
|
|
1021
|
-
|
|
1123
|
+
const withStaleness = this.withStalenessNotice(withWorktree, args.projectPath);
|
|
1124
|
+
// Model-aware compaction (MODCTX-DOC): on haiku/sonnet sessions the
|
|
1125
|
+
// prose scaffolding compresses; code stays byte-verbatim. Only the
|
|
1126
|
+
// code-graph tools reach this funnel — designer/jira returned above
|
|
1127
|
+
// (REQ-MODCTX-004).
|
|
1128
|
+
return this.withModelCompaction(withStaleness);
|
|
1022
1129
|
}
|
|
1023
1130
|
catch (err) {
|
|
1024
1131
|
return this.errorResult(`Tool execution failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -1040,7 +1147,7 @@ class ToolHandler {
|
|
|
1040
1147
|
kinds: kind ? [kind] : undefined,
|
|
1041
1148
|
});
|
|
1042
1149
|
if (results.length === 0) {
|
|
1043
|
-
return this.
|
|
1150
|
+
return this.missWithSuggestions(cg, 'Query', query);
|
|
1044
1151
|
}
|
|
1045
1152
|
// Down-rank generated files within the FTS-returned set so a search
|
|
1046
1153
|
// for "Send" surfaces the hand-written keeper before .pb.go stubs
|
|
@@ -1053,6 +1160,47 @@ class ToolHandler {
|
|
|
1053
1160
|
const formatted = this.formatSearchResults(ranked);
|
|
1054
1161
|
return this.textResult(this.truncateOutput(formatted));
|
|
1055
1162
|
}
|
|
1163
|
+
/**
|
|
1164
|
+
* Anti-flounder miss template (LOWMODEL-DOC, REQ-LOWMODEL-001): a "not
|
|
1165
|
+
* found" that just says "not found" leaves the agent — small models
|
|
1166
|
+
* especially — to guess its next move, and the guess is usually grep/Read.
|
|
1167
|
+
* Instead: name the nearest REAL symbols (token-level lookup, since the
|
|
1168
|
+
* full query already failed FTS+LIKE) and end with a copy-pasteable next
|
|
1169
|
+
* call. Applies at every tier.
|
|
1170
|
+
*/
|
|
1171
|
+
missWithSuggestions(cg, kindLabel, query) {
|
|
1172
|
+
// Split on separators AND camelCase so "AuthServic.logn" still yields
|
|
1173
|
+
// useful probes ("Auth", "Servic", "logn" → LIKE finds AuthService/login).
|
|
1174
|
+
const tokens = [...new Set(query
|
|
1175
|
+
.split(/[\s._:\->#/\\]+/)
|
|
1176
|
+
.flatMap((t) => t.split(/(?=[A-Z])/))
|
|
1177
|
+
.map((t) => t.trim())
|
|
1178
|
+
.filter((t) => t.length >= 3))].slice(0, 6);
|
|
1179
|
+
const seen = new Set();
|
|
1180
|
+
const suggestions = [];
|
|
1181
|
+
for (const token of tokens) {
|
|
1182
|
+
for (const r of cg.searchNodes(token, { limit: 3 })) {
|
|
1183
|
+
const key = r.node.qualifiedName;
|
|
1184
|
+
if (seen.has(key))
|
|
1185
|
+
continue;
|
|
1186
|
+
seen.add(key);
|
|
1187
|
+
suggestions.push({ name: key, where: `${r.node.filePath}:${r.node.startLine}` });
|
|
1188
|
+
if (suggestions.length >= 4)
|
|
1189
|
+
break;
|
|
1190
|
+
}
|
|
1191
|
+
if (suggestions.length >= 4)
|
|
1192
|
+
break;
|
|
1193
|
+
}
|
|
1194
|
+
const lines = [`${kindLabel} "${query}" not found in the index.`];
|
|
1195
|
+
if (suggestions.length > 0) {
|
|
1196
|
+
lines.push(`Closest indexed symbols: ${suggestions.map((s) => `${s.name} (${s.where})`).join(' · ')}`);
|
|
1197
|
+
lines.push(`Next: specship_explore "${suggestions.map((s) => s.name).join(' ')}"`);
|
|
1198
|
+
}
|
|
1199
|
+
else {
|
|
1200
|
+
lines.push('Nothing close in the index either. Next: specship_explore with broader words from the question — it also matches file names and doc text.');
|
|
1201
|
+
}
|
|
1202
|
+
return this.textResult(lines.join('\n'));
|
|
1203
|
+
}
|
|
1056
1204
|
/**
|
|
1057
1205
|
* Handle specship_callers
|
|
1058
1206
|
*/
|
|
@@ -1064,7 +1212,7 @@ class ToolHandler {
|
|
|
1064
1212
|
const limit = (0, utils_1.clamp)(args.limit || 20, 1, 100);
|
|
1065
1213
|
const allMatches = this.findAllSymbols(cg, symbol);
|
|
1066
1214
|
if (allMatches.nodes.length === 0) {
|
|
1067
|
-
return this.
|
|
1215
|
+
return this.missWithSuggestions(cg, 'Symbol', symbol);
|
|
1068
1216
|
}
|
|
1069
1217
|
// Aggregate callers across all matching symbols
|
|
1070
1218
|
const seen = new Set();
|
|
@@ -1094,7 +1242,7 @@ class ToolHandler {
|
|
|
1094
1242
|
const limit = (0, utils_1.clamp)(args.limit || 20, 1, 100);
|
|
1095
1243
|
const allMatches = this.findAllSymbols(cg, symbol);
|
|
1096
1244
|
if (allMatches.nodes.length === 0) {
|
|
1097
|
-
return this.
|
|
1245
|
+
return this.missWithSuggestions(cg, 'Symbol', symbol);
|
|
1098
1246
|
}
|
|
1099
1247
|
// Aggregate callees across all matching symbols
|
|
1100
1248
|
const seen = new Set();
|
|
@@ -1124,7 +1272,7 @@ class ToolHandler {
|
|
|
1124
1272
|
const depth = (0, utils_1.clamp)(args.depth || 2, 1, 10);
|
|
1125
1273
|
const allMatches = this.findAllSymbols(cg, symbol);
|
|
1126
1274
|
if (allMatches.nodes.length === 0) {
|
|
1127
|
-
return this.
|
|
1275
|
+
return this.missWithSuggestions(cg, 'Symbol', symbol);
|
|
1128
1276
|
}
|
|
1129
1277
|
// Aggregate impact across all matching symbols
|
|
1130
1278
|
const mergedNodes = new Map();
|
|
@@ -1267,7 +1415,7 @@ class ToolHandler {
|
|
|
1267
1415
|
* whose qualifiedName contains another named token (`PmsProductServiceImpl::list`),
|
|
1268
1416
|
* dropping unrelated `OmsOrderService::list`.
|
|
1269
1417
|
*/
|
|
1270
|
-
buildFlowFromNamedSymbols(cg, query) {
|
|
1418
|
+
buildFlowFromNamedSymbols(cg, query, tier = 'full') {
|
|
1271
1419
|
const EMPTY = { text: '', pathNodeIds: new Set(), namedNodeIds: new Set(), uniqueNamedNodeIds: new Set() };
|
|
1272
1420
|
try {
|
|
1273
1421
|
const CALLABLE = new Set(['method', 'function', 'component', 'constructor']);
|
|
@@ -1402,11 +1550,23 @@ class ToolHandler {
|
|
|
1402
1550
|
out.push('## Flow (call path among the symbols you queried)', '');
|
|
1403
1551
|
for (let i = 0; i < best.length; i++) {
|
|
1404
1552
|
const step = best[i];
|
|
1405
|
-
if (
|
|
1406
|
-
|
|
1407
|
-
|
|
1553
|
+
if (tier === 'haiku') {
|
|
1554
|
+
// LOWMODEL-DOC REQ-LOWMODEL-003: small models don't synthesize
|
|
1555
|
+
// the flow from evidence — render each hop as ONE explicit line
|
|
1556
|
+
// with its mechanism inline. Additive formatting only; the code
|
|
1557
|
+
// bodies below are identical to the full tier's (A2).
|
|
1558
|
+
const mech = step.edge
|
|
1559
|
+
? ` — via ${(this.synthEdgeNote(step.edge)?.compact ?? step.edge.kind)}`
|
|
1560
|
+
: '';
|
|
1561
|
+
out.push(`${i + 1}. ${i > 0 ? '→ ' : ''}${step.node.name} (${step.node.filePath}:${step.node.startLine})${mech}`);
|
|
1562
|
+
}
|
|
1563
|
+
else {
|
|
1564
|
+
if (step.edge) {
|
|
1565
|
+
const sy = this.synthEdgeNote(step.edge);
|
|
1566
|
+
out.push(` ↓ ${sy ? sy.compact : step.edge.kind}`);
|
|
1567
|
+
}
|
|
1568
|
+
out.push(`${i + 1}. ${step.node.name} (${step.node.filePath}:${step.node.startLine})`);
|
|
1408
1569
|
}
|
|
1409
|
-
out.push(`${i + 1}. ${step.node.name} (${step.node.filePath}:${step.node.startLine})`);
|
|
1410
1570
|
}
|
|
1411
1571
|
out.push('');
|
|
1412
1572
|
}
|
|
@@ -2016,7 +2176,7 @@ class ToolHandler {
|
|
|
2016
2176
|
// Compute the flow spine once — used both to prepend the Flow section (below)
|
|
2017
2177
|
// and to gate adaptive source sizing: files on the spine get full source,
|
|
2018
2178
|
// off-spine peers skeletonize.
|
|
2019
|
-
const flow = this.buildFlowFromNamedSymbols(cg, query);
|
|
2179
|
+
const flow = this.buildFlowFromNamedSymbols(cg, query, (0, model_context_1.detectModelTier)(cg.getProjectRoot()));
|
|
2020
2180
|
// Polymorphic-sibling detector for adaptive sizing. A class that implements/
|
|
2021
2181
|
// extends a supertype shared by >= MIN_SIBLINGS classes is one of many
|
|
2022
2182
|
// INTERCHANGEABLE implementations (OkHttp's 14 `: Interceptor` classes —
|
|
@@ -2597,7 +2757,7 @@ class ToolHandler {
|
|
|
2597
2757
|
const lineHint = typeof args.line === 'number' && args.line > 0 ? args.line : undefined;
|
|
2598
2758
|
let matches = this.findSymbolMatches(cg, symbol);
|
|
2599
2759
|
if (matches.length === 0) {
|
|
2600
|
-
return this.
|
|
2760
|
+
return this.missWithSuggestions(cg, 'Symbol', symbol);
|
|
2601
2761
|
}
|
|
2602
2762
|
// Disambiguate a heavily-overloaded name to a specific definition the caller
|
|
2603
2763
|
// pinned by file/line (the `file:line` a trail or another tool showed it) —
|