lynkr 9.9.1 → 9.11.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 (93) hide show
  1. package/README.md +50 -9
  2. package/bin/cli.js +2 -0
  3. package/bin/lynkr-init.js +11 -12
  4. package/bin/lynkr-reset.js +71 -0
  5. package/config/model-tiers.json +199 -52
  6. package/package.json +3 -3
  7. package/public/dashboard.html +29 -0
  8. package/scripts/validate-difficulty-classifier.js +27 -6
  9. package/src/api/providers-handler.js +0 -1
  10. package/src/api/router.js +309 -160
  11. package/src/clients/databricks.js +215 -71
  12. package/src/clients/gpt-utils.js +8 -1
  13. package/src/clients/ollama-utils.js +19 -10
  14. package/src/clients/prompt-cache-injection.js +93 -30
  15. package/src/config/index.js +82 -43
  16. package/src/context/compression.js +27 -8
  17. package/src/context/distill.js +2 -1
  18. package/src/dashboard/api.js +5 -1
  19. package/src/memory/distiller.js +350 -0
  20. package/src/memory/extractor.js +0 -8
  21. package/src/memory/format.js +17 -2
  22. package/src/memory/index.js +10 -0
  23. package/src/memory/retriever.js +7 -2
  24. package/src/memory/skills-cache.js +180 -0
  25. package/src/memory/tencentdb-launcher.js +459 -0
  26. package/src/memory/wiki.js +171 -0
  27. package/src/orchestrator/index.js +202 -1237
  28. package/src/orchestrator/passthrough-stream.js +382 -0
  29. package/src/orchestrator/sse-transformer.js +408 -0
  30. package/src/prompts/system.js +20 -6
  31. package/src/routing/affinity-store.js +85 -4
  32. package/src/routing/agentic-detector.js +9 -1
  33. package/src/routing/cache-economics.js +123 -0
  34. package/src/routing/cache-switch-cost.js +194 -0
  35. package/src/routing/calibration.js +8 -1
  36. package/src/routing/complexity-analyzer.js +7 -1
  37. package/src/routing/context-compressor.js +170 -0
  38. package/src/routing/difficulty-classifier.js +161 -17
  39. package/src/routing/index.js +196 -56
  40. package/src/routing/intent-score.js +20 -2
  41. package/src/routing/model-registry.js +35 -10
  42. package/src/routing/session-affinity.js +68 -1
  43. package/src/routing/side-channel-detector.js +103 -0
  44. package/src/routing/telemetry.js +139 -2
  45. package/src/routing/verifier.js +41 -2
  46. package/src/server.js +36 -49
  47. package/src/tools/code-graph.js +6 -4
  48. package/src/agents/context-manager.js +0 -236
  49. package/src/agents/decomposition/dispatcher.js +0 -185
  50. package/src/agents/decomposition/gate.js +0 -136
  51. package/src/agents/decomposition/index.js +0 -183
  52. package/src/agents/decomposition/model-call.js +0 -75
  53. package/src/agents/decomposition/planner.js +0 -223
  54. package/src/agents/decomposition/synthesizer.js +0 -89
  55. package/src/agents/decomposition/telemetry.js +0 -55
  56. package/src/agents/definitions/loader.js +0 -653
  57. package/src/agents/executor.js +0 -457
  58. package/src/agents/index.js +0 -165
  59. package/src/agents/parallel-coordinator.js +0 -68
  60. package/src/agents/reflector.js +0 -331
  61. package/src/agents/skillbook.js +0 -331
  62. package/src/agents/store.js +0 -259
  63. package/src/edits/index.js +0 -171
  64. package/src/indexer/babel-parser.js +0 -213
  65. package/src/indexer/index.js +0 -1629
  66. package/src/indexer/navigation/index.js +0 -32
  67. package/src/indexer/navigation/providers/treeSitter.js +0 -36
  68. package/src/indexer/parser.js +0 -443
  69. package/src/tasks/store.js +0 -349
  70. package/src/tests/coverage.js +0 -173
  71. package/src/tests/index.js +0 -171
  72. package/src/tests/store.js +0 -213
  73. package/src/tools/agent-task.js +0 -145
  74. package/src/tools/code-mode.js +0 -304
  75. package/src/tools/decompose.js +0 -91
  76. package/src/tools/edits.js +0 -94
  77. package/src/tools/execution.js +0 -171
  78. package/src/tools/git.js +0 -1346
  79. package/src/tools/index.js +0 -306
  80. package/src/tools/indexer.js +0 -360
  81. package/src/tools/lazy-loader.js +0 -366
  82. package/src/tools/mcp-remote.js +0 -88
  83. package/src/tools/mcp.js +0 -116
  84. package/src/tools/process.js +0 -167
  85. package/src/tools/smart-selection.js +0 -180
  86. package/src/tools/stubs.js +0 -55
  87. package/src/tools/tasks.js +0 -260
  88. package/src/tools/tests.js +0 -132
  89. package/src/tools/tinyfish.js +0 -358
  90. package/src/tools/truncate.js +0 -106
  91. package/src/tools/web-client.js +0 -71
  92. package/src/tools/web.js +0 -415
  93. package/src/tools/workspace.js +0 -204
@@ -1,91 +0,0 @@
1
- const { registerTool } = require(".");
2
- const { runDecomposedTask } = require("../agents/decomposition");
3
- const logger = require("../logger");
4
-
5
- /**
6
- * DecomposeTask tool — breaks a complex task into focused subtasks with isolated
7
- * context, runs them (parallel where independent), and synthesizes the result.
8
- *
9
- * Opt-in: requires TASK_DECOMPOSITION_ENABLED=true and AGENTS_ENABLED=true.
10
- * Degrades gracefully — if the gate decides decomposition isn't worth it (or
11
- * planning fails), it returns ok:true with decomposed:false and a reason so the
12
- * caller can solve the task monolithically.
13
- */
14
- function registerDecomposeTool() {
15
- registerTool(
16
- "DecomposeTask",
17
- async ({ args = {} }, context = {}) => {
18
- const task = args.task || args.prompt || args.description;
19
-
20
- if (!task || typeof task !== "string") {
21
- return {
22
- ok: false,
23
- status: 400,
24
- content: JSON.stringify({ error: "task is required" }, null, 2),
25
- };
26
- }
27
-
28
- logger.info(
29
- { task: task.slice(0, 100), sessionId: context.sessionId },
30
- "DecomposeTask: evaluating task for decomposition"
31
- );
32
-
33
- try {
34
- const result = await runDecomposedTask(task, {
35
- sessionId: context.sessionId,
36
- cwd: context.cwd,
37
- riskLevel: args.riskLevel || context.riskLevel,
38
- });
39
-
40
- if (result.decomposed) {
41
- return {
42
- ok: true,
43
- status: 200,
44
- content: result.result,
45
- metadata: {
46
- decomposed: true,
47
- subtasks: result.plan?.subtasks?.length,
48
- levels: result.stats?.levels,
49
- strategy: result.plan?.strategy,
50
- confidence: result.quality?.confidence,
51
- recommendFallback: result.recommendFallback,
52
- savedTokens: result.savings?.savedTokens,
53
- },
54
- };
55
- }
56
-
57
- // Not decomposed — signal the caller to solve monolithically.
58
- return {
59
- ok: true,
60
- status: 200,
61
- content: JSON.stringify(
62
- {
63
- decomposed: false,
64
- reason: result.reason,
65
- guidance: "Solve this task directly without decomposition.",
66
- },
67
- null,
68
- 2
69
- ),
70
- metadata: { decomposed: false, reason: result.reason },
71
- };
72
- } catch (error) {
73
- logger.error({ error: error.message }, "DecomposeTask: error");
74
- return {
75
- ok: false,
76
- status: 500,
77
- content: JSON.stringify(
78
- { error: "Decomposition error", message: error.message },
79
- null,
80
- 2
81
- ),
82
- };
83
- }
84
- },
85
- { category: "decompose" }
86
- );
87
-
88
- logger.info("DecomposeTask tool registered");
89
- }
90
-
91
- module.exports = { registerDecomposeTool };
@@ -1,94 +0,0 @@
1
- const { getEditHistory, revertEdit } = require("../edits");
2
- const { registerTool } = require(".");
3
- const logger = require("../logger");
4
-
5
- function registerEditHistoryTool() {
6
- registerTool(
7
- "workspace_edit_history",
8
- async ({ args = {} }) => {
9
- const limit =
10
- typeof args.limit === "number" && args.limit > 0 ? Math.min(args.limit, 100) : 20;
11
- const filePath =
12
- typeof args.path === "string"
13
- ? args.path
14
- : typeof args.file === "string"
15
- ? args.file
16
- : undefined;
17
- const sessionId =
18
- typeof args.session_id === "string"
19
- ? args.session_id
20
- : typeof args.sessionId === "string"
21
- ? args.sessionId
22
- : undefined;
23
-
24
- const history = getEditHistory({ filePath, sessionId, limit });
25
- return {
26
- ok: true,
27
- status: 200,
28
- content: JSON.stringify(
29
- {
30
- edits: history,
31
- limit,
32
- filePath,
33
- sessionId,
34
- },
35
- null,
36
- 2,
37
- ),
38
- metadata: {
39
- count: history.length,
40
- },
41
- };
42
- },
43
- { category: "workspace" },
44
- );
45
- }
46
-
47
- function registerEditRevertTool() {
48
- registerTool(
49
- "workspace_edit_revert",
50
- async ({ args = {} }, context = {}) => {
51
- const editId = args.id ?? args.edit_id ?? args.editId;
52
- if (typeof editId !== "number" && typeof editId !== "string") {
53
- throw new Error("workspace_edit_revert requires an edit id (numeric).");
54
- }
55
- const numericId = Number(editId);
56
- if (Number.isNaN(numericId)) {
57
- throw new Error("Edit id must be numeric.");
58
- }
59
- const sessionId = context.session?.id ?? context.sessionId ?? null;
60
- try {
61
- const result = await revertEdit({ editId: numericId, sessionId });
62
- return {
63
- ok: true,
64
- status: 200,
65
- content: JSON.stringify(
66
- {
67
- revertedEditId: result.revertedEditId,
68
- filePath: result.filePath,
69
- },
70
- null,
71
- 2,
72
- ),
73
- metadata: {
74
- revertedEditId: result.revertedEditId,
75
- filePath: result.filePath,
76
- },
77
- };
78
- } catch (err) {
79
- logger.warn({ err, editId: numericId }, "Failed to revert edit");
80
- throw err;
81
- }
82
- },
83
- { category: "workspace" },
84
- );
85
- }
86
-
87
- function registerEditTools() {
88
- registerEditHistoryTool();
89
- registerEditRevertTool();
90
- }
91
-
92
- module.exports = {
93
- registerEditTools,
94
- };
@@ -1,171 +0,0 @@
1
- const path = require("path");
2
- const { runProcess, MAX_TIMEOUT_MS, DEFAULT_TIMEOUT_MS } = require("./process");
3
- const { registerTool } = require(".");
4
- const { workspaceRoot, resolveWorkspacePath } = require("../workspace");
5
-
6
- function parseTimeout(value) {
7
- if (value === undefined || value === null) return DEFAULT_TIMEOUT_MS;
8
- const parsed = Number.parseInt(value, 10);
9
- if (Number.isNaN(parsed) || parsed <= 0) return DEFAULT_TIMEOUT_MS;
10
- return Math.min(parsed, MAX_TIMEOUT_MS);
11
- }
12
-
13
- function normaliseCwd(cwd, contextCwd) {
14
- // Priority: explicit cwd arg > context.cwd > workspaceRoot
15
- if (cwd) return resolveWorkspacePath(cwd);
16
- if (contextCwd) return contextCwd; // Already validated absolute path
17
- return workspaceRoot;
18
- }
19
-
20
- function parseSandboxMode(value) {
21
- if (typeof value !== "string") return "auto";
22
- const mode = value.trim().toLowerCase();
23
- if (mode === "always" || mode === "never" || mode === "auto") {
24
- return mode;
25
- }
26
- return "auto";
27
- }
28
-
29
- function formatProcessResult(result) {
30
- return JSON.stringify(
31
- {
32
- stdout: result.stdout,
33
- stderr: result.stderr,
34
- exit_code: result.exitCode,
35
- signal: result.signal,
36
- timed_out: result.timedOut,
37
- duration_ms: result.durationMs,
38
- stdout_overflow: result.stdoutOverflow,
39
- stderr_overflow: result.stderrOverflow,
40
- },
41
- null,
42
- 2,
43
- );
44
- }
45
-
46
- function registerShellTool() {
47
- registerTool(
48
- "shell",
49
- async ({ args = {} }, context = {}) => {
50
- const command = args.command ?? args.cmd ?? args.run ?? args.input;
51
- const commandArgs = Array.isArray(args.args) ? args.args.map(String) : [];
52
- const cwd = normaliseCwd(args.cwd, context.cwd);
53
- const timeoutMs = parseTimeout(args.timeout_ms ?? args.timeout);
54
-
55
- let spawnCommand;
56
- let spawnArgs;
57
- let useShell = false;
58
-
59
- if (typeof command === "string" && command.trim().length > 0) {
60
- spawnCommand = "bash";
61
- spawnArgs = ["-lc", command];
62
- useShell = false;
63
- } else if (Array.isArray(command) && command.length > 0) {
64
- spawnCommand = String(command[0]);
65
- spawnArgs = command.slice(1).map(String).concat(commandArgs);
66
- } else if (
67
- typeof args.args === "string" &&
68
- args.args.trim().length > 0 &&
69
- !command
70
- ) {
71
- spawnCommand = "bash";
72
- spawnArgs = ["-lc", args.args];
73
- } else {
74
- throw new Error("shell tool requires a command string or array.");
75
- }
76
-
77
- const sandbox = parseSandboxMode(args.sandbox ?? args.isolation);
78
-
79
- const result = await runProcess({
80
- command: spawnCommand,
81
- args: spawnArgs,
82
- cwd,
83
- env: args.env,
84
- timeoutMs,
85
- shell: useShell,
86
- sandbox,
87
- sessionId: args.session_id ?? args.sessionId ?? null,
88
- });
89
-
90
- const ok = result.exitCode === 0 && !result.timedOut;
91
- const status = result.timedOut ? 408 : ok ? 200 : 500;
92
-
93
- return {
94
- ok,
95
- status,
96
- content: formatProcessResult(result),
97
- metadata: {
98
- command: spawnCommand,
99
- args: spawnArgs,
100
- cwd,
101
- },
102
- };
103
- },
104
- { category: "execution" },
105
- );
106
- }
107
-
108
- function registerPythonTool() {
109
- registerTool(
110
- "python_exec",
111
- async ({ args = {} }, context = {}) => {
112
- const code =
113
- typeof args.code === "string"
114
- ? args.code
115
- : typeof args.script === "string"
116
- ? args.script
117
- : typeof args.input === "string"
118
- ? args.input
119
- : null;
120
-
121
- if (!code) {
122
- throw new Error("python_exec requires a code string.");
123
- }
124
-
125
- const executable = args.executable ?? args.python ?? "python3";
126
- const cwd = normaliseCwd(args.cwd, context.cwd);
127
- const timeoutMs = parseTimeout(args.timeout_ms ?? args.timeout);
128
- const requirements = Array.isArray(args.requirements) ? args.requirements : [];
129
-
130
- // Basic support: write code to stdin; requirements handling is TODO.
131
- const sandbox = parseSandboxMode(args.sandbox ?? args.isolation);
132
-
133
- const result = await runProcess({
134
- command: executable,
135
- args: ["-"],
136
- cwd,
137
- env: args.env,
138
- timeoutMs,
139
- input: code,
140
- sandbox,
141
- sessionId: args.session_id ?? args.sessionId ?? null,
142
- });
143
-
144
- const ok = result.exitCode === 0 && !result.timedOut;
145
- const status = result.timedOut ? 408 : ok ? 200 : 500;
146
-
147
- return {
148
- ok,
149
- status,
150
- content: formatProcessResult(result),
151
- metadata: {
152
- executable: path.basename(executable),
153
- cwd,
154
- requirements,
155
- },
156
- };
157
- },
158
- { category: "execution" },
159
- );
160
- }
161
-
162
- function registerExecutionTools() {
163
- registerShellTool();
164
- registerPythonTool();
165
- }
166
-
167
- module.exports = {
168
- registerExecutionTools,
169
- registerShellTool,
170
- registerPythonTool,
171
- };