agent-nuvira 2.6.14 → 2.7.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 (99) hide show
  1. package/README.md +4 -2
  2. package/dist/cli/chat.d.ts +2 -0
  3. package/dist/cli/chat.d.ts.map +1 -1
  4. package/dist/cli/chat.js +107 -4
  5. package/dist/cli/chat.js.map +1 -1
  6. package/dist/cli/eval.d.ts.map +1 -1
  7. package/dist/cli/eval.js +14 -1
  8. package/dist/cli/eval.js.map +1 -1
  9. package/dist/cli/execute.d.ts +8 -0
  10. package/dist/cli/execute.d.ts.map +1 -1
  11. package/dist/cli/execute.js +105 -1
  12. package/dist/cli/execute.js.map +1 -1
  13. package/dist/cli/loop-executor.d.ts +81 -0
  14. package/dist/cli/loop-executor.d.ts.map +1 -0
  15. package/dist/cli/loop-executor.js +246 -0
  16. package/dist/cli/loop-executor.js.map +1 -0
  17. package/dist/config/types.d.ts +18 -0
  18. package/dist/config/types.d.ts.map +1 -1
  19. package/dist/fresh.d.ts +2 -0
  20. package/dist/fresh.d.ts.map +1 -0
  21. package/dist/fresh.js +2 -0
  22. package/dist/fresh.js.map +1 -0
  23. package/dist/inference/anthropic-adapter.d.ts +9 -0
  24. package/dist/inference/anthropic-adapter.d.ts.map +1 -1
  25. package/dist/inference/anthropic-adapter.js +143 -0
  26. package/dist/inference/anthropic-adapter.js.map +1 -1
  27. package/dist/inference/gemini-adapter.d.ts +8 -0
  28. package/dist/inference/gemini-adapter.d.ts.map +1 -1
  29. package/dist/inference/gemini-adapter.js +145 -0
  30. package/dist/inference/gemini-adapter.js.map +1 -1
  31. package/dist/inference/model-probe.d.ts.map +1 -1
  32. package/dist/inference/model-probe.js +14 -0
  33. package/dist/inference/model-probe.js.map +1 -1
  34. package/dist/inference/native-tools.d.ts +226 -0
  35. package/dist/inference/native-tools.d.ts.map +1 -0
  36. package/dist/inference/native-tools.js +389 -0
  37. package/dist/inference/native-tools.js.map +1 -0
  38. package/dist/learning/auto-router.d.ts +36 -4
  39. package/dist/learning/auto-router.d.ts.map +1 -1
  40. package/dist/learning/auto-router.js +103 -2
  41. package/dist/learning/auto-router.js.map +1 -1
  42. package/dist/learning/context-pruner.d.ts.map +1 -1
  43. package/dist/learning/context-pruner.js +4 -2
  44. package/dist/learning/context-pruner.js.map +1 -1
  45. package/dist/learning/engine-router.d.ts +90 -0
  46. package/dist/learning/engine-router.d.ts.map +1 -0
  47. package/dist/learning/engine-router.js +128 -0
  48. package/dist/learning/engine-router.js.map +1 -0
  49. package/dist/learning/eval-framework.d.ts +42 -1
  50. package/dist/learning/eval-framework.d.ts.map +1 -1
  51. package/dist/learning/eval-framework.js +163 -7
  52. package/dist/learning/eval-framework.js.map +1 -1
  53. package/dist/learning/routing-cache.d.ts +64 -0
  54. package/dist/learning/routing-cache.d.ts.map +1 -0
  55. package/dist/learning/routing-cache.js +100 -0
  56. package/dist/learning/routing-cache.js.map +1 -0
  57. package/dist/tools/loop-project-context.d.ts +47 -0
  58. package/dist/tools/loop-project-context.d.ts.map +1 -0
  59. package/dist/tools/loop-project-context.js +210 -0
  60. package/dist/tools/loop-project-context.js.map +1 -0
  61. package/dist/tools/loop-skill-hint.d.ts +110 -0
  62. package/dist/tools/loop-skill-hint.d.ts.map +1 -0
  63. package/dist/tools/loop-skill-hint.js +266 -0
  64. package/dist/tools/loop-skill-hint.js.map +1 -0
  65. package/dist/tools/registry.d.ts +10 -0
  66. package/dist/tools/registry.d.ts.map +1 -1
  67. package/dist/tools/registry.js +66 -9
  68. package/dist/tools/registry.js.map +1 -1
  69. package/dist/tools/release-sync.d.ts.map +1 -1
  70. package/dist/tools/release-sync.js +5 -4
  71. package/dist/tools/release-sync.js.map +1 -1
  72. package/dist/tools/tool-loop.d.ts +28 -0
  73. package/dist/tools/tool-loop.d.ts.map +1 -1
  74. package/dist/tools/tool-loop.js +182 -6
  75. package/dist/tools/tool-loop.js.map +1 -1
  76. package/dist/tools/toolsets.d.ts +33 -0
  77. package/dist/tools/toolsets.d.ts.map +1 -1
  78. package/dist/tools/toolsets.js +84 -0
  79. package/dist/tools/toolsets.js.map +1 -1
  80. package/dist/web-dashboard/chat-console.d.ts +31 -0
  81. package/dist/web-dashboard/chat-console.d.ts.map +1 -1
  82. package/dist/web-dashboard/chat-console.js +73 -0
  83. package/dist/web-dashboard/chat-console.js.map +1 -1
  84. package/dist/web-dashboard/loop-turn-telemetry.d.ts +27 -0
  85. package/dist/web-dashboard/loop-turn-telemetry.d.ts.map +1 -0
  86. package/dist/web-dashboard/loop-turn-telemetry.js +43 -0
  87. package/dist/web-dashboard/loop-turn-telemetry.js.map +1 -0
  88. package/dist/web-dashboard/server.d.ts +62 -1
  89. package/dist/web-dashboard/server.d.ts.map +1 -1
  90. package/dist/web-dashboard/server.js +205 -4
  91. package/dist/web-dashboard/server.js.map +1 -1
  92. package/dist/web-dashboard/src/types.d.ts +44 -0
  93. package/dist/web-dashboard/src/types.d.ts.map +1 -1
  94. package/package.json +1 -1
  95. package/src/web-dashboard/public/assets/{index-Cg9LaToa.js → index-C4frng1Q.js} +79 -79
  96. package/src/web-dashboard/public/assets/{index-Cg9LaToa.js.map → index-C4frng1Q.js.map} +1 -1
  97. package/src/web-dashboard/public/assets/index-C507EUWf.css +1 -0
  98. package/src/web-dashboard/public/index.html +2 -2
  99. package/src/web-dashboard/public/assets/index-B47v8pr1.css +0 -1
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Routing decision cache (`src/learning/routing-cache.ts`) — AGENTIC_CAPABILITY_ASSESSMENT
3
+ * Addendum v4 Phase 2.
4
+ *
5
+ * The loop-first engine calls the AutoModelRouter on EVERY model turn. Each
6
+ * resolve() scores 22+ catalog providers across 5 dimensions (+ capability
7
+ * fit, context preflight, bandit sampling, registry filtering) — meaningful
8
+ * CPU work repeated for turns whose ROUTING INPUTS are identical.
9
+ *
10
+ * The cache keys on the STABLE routing inputs only — never the raw message
11
+ * text (every message is unique, so a message-keyed cache would never hit).
12
+ * Two turns hit the same entry when all of the following match:
13
+ * agent type · task intent · complexity · preference mode · provider-health
14
+ * signature (session exclusions + breaker + quota) · registry usable-count
15
+ * · cacheable resolve-option flags.
16
+ *
17
+ * Correctness rules:
18
+ * 1. Provider health is part of the KEY, so a provider failing mid-session
19
+ * changes the key and can never be served a stale healthy-route.
20
+ * 2. TTL (default 30s) bounds staleness of everything NOT in the key
21
+ * (benchmarks recorded by concurrent runs, bandit draws).
22
+ * 3. Non-deterministic layers are opt-out at the call site: when the caller
23
+ * enables `useBandit` or `useMlRouter` with default settings, the cache
24
+ * is still safe for SELECTION (deterministic at cold start) but a caller
25
+ * may force-bypass via `bypass` for benchmark/explain flows that must
26
+ * observe the live ranking.
27
+ * 4. `invalidateRoutingCache()` is called by the model registry refresh and
28
+ * is safe to call anywhere — worst case one extra resolve.
29
+ */
30
+ /** Module-level store — one cache per process (single-user CLI). */
31
+ const store = new Map();
32
+ /** Default TTL: short enough to bound staleness, long enough to cover a chat turn's repeated resolves. */
33
+ export const DEFAULT_ROUTING_CACHE_TTL_MS = 30_000;
34
+ /** Upper bound on entries — a pathological key-space cannot grow the map unbounded. */
35
+ const MAX_ENTRIES = 256;
36
+ /**
37
+ * Build the inputs signature from the STABLE routing inputs. Every part is
38
+ * stringified; null/undefined/'' parts are skipped (their absence IS signal —
39
+ * e.g. no NLU intent hint). Order-normalized: callers pass parts in a fixed
40
+ * order, but we join with '|' so collisions across part counts are visible.
41
+ */
42
+ export function routingCacheSignature(parts) {
43
+ return parts
44
+ .map((p) => (p === null || p === undefined || p === '' ? '∅' : String(p)))
45
+ .join('|');
46
+ }
47
+ /**
48
+ * Get a cached routing decision. Returns undefined on miss/expiry.
49
+ * Expired entries are lazily dropped (no background sweeper — the CLI is
50
+ * single-user and resolve-frequency is bounded by turn count).
51
+ */
52
+ export function getRoutingCache(signature) {
53
+ const entry = store.get(signature);
54
+ if (!entry)
55
+ return undefined;
56
+ if (Date.now() >= entry.expiresAt) {
57
+ store.delete(signature);
58
+ return undefined;
59
+ }
60
+ return entry.value;
61
+ }
62
+ /** Store a decision under a signature with the given TTL. */
63
+ export function setRoutingCache(signature, value, ttlMs = DEFAULT_ROUTING_CACHE_TTL_MS) {
64
+ // Bound the map: drop the EXPIRED entries first, then (rare) evict oldest.
65
+ if (store.size >= MAX_ENTRIES) {
66
+ const now = Date.now();
67
+ for (const [k, v] of store) {
68
+ if (now >= v.expiresAt)
69
+ store.delete(k);
70
+ }
71
+ if (store.size >= MAX_ENTRIES) {
72
+ const oldest = store.keys().next().value;
73
+ if (oldest !== undefined)
74
+ store.delete(oldest);
75
+ }
76
+ }
77
+ store.set(signature, { value, expiresAt: Date.now() + Math.max(0, ttlMs), signature });
78
+ }
79
+ /**
80
+ * Memoize wrapper: return the cached decision for this signature, or compute
81
+ * + store. `compute` throwing propagates (never cache a failure — a transient
82
+ * registry read failure must not pin a degraded route for the TTL).
83
+ */
84
+ export function withRoutingCache(signature, ttlMs, compute) {
85
+ const cached = getRoutingCache(signature);
86
+ if (cached !== undefined)
87
+ return cached;
88
+ const value = compute();
89
+ setRoutingCache(signature, value, ttlMs);
90
+ return value;
91
+ }
92
+ /** Clear the whole cache (registry refresh, tests, `nuvira models explain`). */
93
+ export function invalidateRoutingCache() {
94
+ store.clear();
95
+ }
96
+ /** Test/inspection helper: current entry count. */
97
+ export function routingCacheSize() {
98
+ return store.size;
99
+ }
100
+ //# sourceMappingURL=routing-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routing-cache.js","sourceRoot":"","sources":["../../src/learning/routing-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAUH,oEAAoE;AACpE,MAAM,KAAK,GAAG,IAAI,GAAG,EAAsC,CAAC;AAE5D,0GAA0G;AAC1G,MAAM,CAAC,MAAM,4BAA4B,GAAG,MAAM,CAAC;AAEnD,uFAAuF;AACvF,MAAM,WAAW,GAAG,GAAG,CAAC;AAExB;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CACnC,KAA0D;IAE1D,OAAO,KAAK;SACT,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;SACzE,IAAI,CAAC,GAAG,CAAC,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAI,SAAiB;IAClD,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAqC,CAAC;IACvE,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;QAClC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACxB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,KAAK,CAAC,KAAK,CAAC;AACrB,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,eAAe,CAAI,SAAiB,EAAE,KAAQ,EAAE,QAAgB,4BAA4B;IAC1G,2EAA2E;IAC3E,IAAI,KAAK,CAAC,IAAI,IAAI,WAAW,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC;YAC3B,IAAI,GAAG,IAAI,CAAC,CAAC,SAAS;gBAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC1C,CAAC;QACD,IAAI,KAAK,CAAC,IAAI,IAAI,WAAW,EAAE,CAAC;YAC9B,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YACzC,IAAI,MAAM,KAAK,SAAS;gBAAE,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;IACD,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;AACzF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAC9B,SAAiB,EACjB,KAAyB,EACzB,OAAgB;IAEhB,MAAM,MAAM,GAAG,eAAe,CAAI,SAAS,CAAC,CAAC;IAC7C,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACxC,MAAM,KAAK,GAAG,OAAO,EAAE,CAAC;IACxB,eAAe,CAAC,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IACzC,OAAO,KAAK,CAAC;AACf,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,sBAAsB;IACpC,KAAK,CAAC,KAAK,EAAE,CAAC;AAChB,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,gBAAgB;IAC9B,OAAO,KAAK,CAAC,IAAI,CAAC;AACpB,CAAC"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Loop project context (`src/tools/loop-project-context.ts`) — AGENTIC_CAPABILITY_ASSESSMENT
3
+ * Addendum v4 Phase 1.4: Freebuff-pattern AMBIENT CONTEXT for the tool loop.
4
+ *
5
+ * The assessment's core finding: a single-loop agent needs the project shape
6
+ * in its context FROM TURN ZERO — a token-budgeted file tree, a git-state
7
+ * digest, and a deterministic project assessment — instead of spending an
8
+ * entire ReasonerAgent + ContextGathererAgent call to re-discover it.
9
+ *
10
+ * The dashboard already builds a snapshot (its project-context module) and
11
+ * injects it via `ctxOverrides.projectContext`; the CLI never sent one. This
12
+ * module is the CLI twin: bounded (~2K tokens), best-effort — a failure
13
+ * yields an EMPTY string, never a broken turn.
14
+ *
15
+ * Consumers: chat.ts `runChatAnswer` — when no explicit projectContext was
16
+ * provided and the cwd looks like a project, inject this as the
17
+ * `[Project context]` message. The dashboard path is unchanged.
18
+ *
19
+ * Design notes:
20
+ * - The tree walk is a bounded BFS (readdirSync, depth-capped, ignore-dir
21
+ * filtered) rather than the orchestrator's full recursive builder — the
22
+ * loop needs SHAPE, not a complete index, and must never take >50ms on a
23
+ * huge repo. Entries past the line budget are truncated with an explicit
24
+ * note (honest truncation, like Freebuff's `truncate-file-tree`).
25
+ * - Git digests run read-only commands with a 3s cap each and are omitted
26
+ * entirely outside a git repo.
27
+ */
28
+ /** True when the directory plausibly contains a project worth describing. */
29
+ export declare function looksLikeProject(dir: string): boolean;
30
+ /**
31
+ * Bounded BFS tree walk. Returns lines like `├── src/` with directories
32
+ * suffixed `/`, sorted dirs-first then files (deterministic ordering — the
33
+ * model sees a stable tree across turns, which keeps the prompt cache warm).
34
+ * Appends an ellipsis note when entries/depth were capped.
35
+ */
36
+ export declare function walkBoundedTree(dir: string): string[];
37
+ /**
38
+ * Build the bounded `[Project context]` block for the loop system context.
39
+ * Returns '' when the directory is not a project (caller injects nothing).
40
+ *
41
+ * Layout (Freebuff system-prompt parity):
42
+ * ## Project — cwd + deterministic assessment (language/framework/tests)
43
+ * ## File tree — bounded BFS walk, honestly truncated
44
+ * ## Git state — branch, dirty files, recent commits
45
+ */
46
+ export declare function buildLoopProjectContext(dir: string): Promise<string>;
47
+ //# sourceMappingURL=loop-project-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop-project-context.d.ts","sourceRoot":"","sources":["../../src/tools/loop-project-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAyBH,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAgBrD;AAaD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAwCrD;AAED;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAkE1E"}
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Loop project context (`src/tools/loop-project-context.ts`) — AGENTIC_CAPABILITY_ASSESSMENT
3
+ * Addendum v4 Phase 1.4: Freebuff-pattern AMBIENT CONTEXT for the tool loop.
4
+ *
5
+ * The assessment's core finding: a single-loop agent needs the project shape
6
+ * in its context FROM TURN ZERO — a token-budgeted file tree, a git-state
7
+ * digest, and a deterministic project assessment — instead of spending an
8
+ * entire ReasonerAgent + ContextGathererAgent call to re-discover it.
9
+ *
10
+ * The dashboard already builds a snapshot (its project-context module) and
11
+ * injects it via `ctxOverrides.projectContext`; the CLI never sent one. This
12
+ * module is the CLI twin: bounded (~2K tokens), best-effort — a failure
13
+ * yields an EMPTY string, never a broken turn.
14
+ *
15
+ * Consumers: chat.ts `runChatAnswer` — when no explicit projectContext was
16
+ * provided and the cwd looks like a project, inject this as the
17
+ * `[Project context]` message. The dashboard path is unchanged.
18
+ *
19
+ * Design notes:
20
+ * - The tree walk is a bounded BFS (readdirSync, depth-capped, ignore-dir
21
+ * filtered) rather than the orchestrator's full recursive builder — the
22
+ * loop needs SHAPE, not a complete index, and must never take >50ms on a
23
+ * huge repo. Entries past the line budget are truncated with an explicit
24
+ * note (honest truncation, like Freebuff's `truncate-file-tree`).
25
+ * - Git digests run read-only commands with a 3s cap each and are omitted
26
+ * entirely outside a git repo.
27
+ */
28
+ import { existsSync, readdirSync, statSync } from 'node:fs';
29
+ import { join } from 'node:path';
30
+ import { spawnSync } from 'node:child_process';
31
+ import { assessProject } from '../agents/prompt-assembly.js';
32
+ /** Hard budget: the tree block is truncated to this many lines (~1.5K tokens). */
33
+ const MAX_TREE_LINES = 60;
34
+ /** Max tree depth (BFS) — deep node_modules-style nesting is noise at this budget. */
35
+ const MAX_TREE_DEPTH = 4;
36
+ /** Max entries per directory (a flat 300-file dir gets an ellipsis note). */
37
+ const MAX_ENTRIES_PER_DIR = 25;
38
+ /** Git status porcelain lines kept (a huge dirty tree truncates). */
39
+ const MAX_GIT_STATUS_LINES = 30;
40
+ /** Overall block budget (~2K tokens ≈ 8K chars) — hard-truncated with a note. */
41
+ const MAX_BLOCK_CHARS = 8_000;
42
+ /** Directories never worth showing in the ambient tree (build artifacts, deps). */
43
+ const IGNORE_DIRS = new Set([
44
+ 'node_modules', '.git', 'dist', 'build', '.next', 'out', 'coverage',
45
+ '.cache', '__pycache__', '.venv', 'venv', '.nuvira', '.turbo',
46
+ ]);
47
+ /** True when the directory plausibly contains a project worth describing. */
48
+ export function looksLikeProject(dir) {
49
+ try {
50
+ if (!existsSync(dir) || !statSync(dir).isDirectory())
51
+ return false;
52
+ const entries = readdirSync(dir);
53
+ if (entries.length === 0)
54
+ return false;
55
+ // A project has at least one source/config marker OR a .git dir — a bare
56
+ // home directory or an empty scratch dir adds noise, not signal.
57
+ const MARKERS = new Set([
58
+ 'package.json', 'tsconfig.json', 'pyproject.toml', 'setup.py', 'requirements.txt',
59
+ 'Cargo.toml', 'go.mod', 'pom.xml', 'build.gradle', 'Gemfile', 'composer.json',
60
+ '.git', 'Makefile', 'CMakeLists.txt', 'pubspec.yaml', 'mix.exs', 'buffconfig.json',
61
+ ]);
62
+ return entries.some((e) => MARKERS.has(e));
63
+ }
64
+ catch {
65
+ return false;
66
+ }
67
+ }
68
+ /** Run a read-only git command in `dir`; '' on any failure (best-effort). */
69
+ function git(dir, args) {
70
+ try {
71
+ const r = spawnSync('git', args, { cwd: dir, encoding: 'utf-8', timeout: 3_000 });
72
+ if (r.status !== 0 || !r.stdout)
73
+ return '';
74
+ return r.stdout.trim();
75
+ }
76
+ catch {
77
+ return '';
78
+ }
79
+ }
80
+ /**
81
+ * Bounded BFS tree walk. Returns lines like `├── src/` with directories
82
+ * suffixed `/`, sorted dirs-first then files (deterministic ordering — the
83
+ * model sees a stable tree across turns, which keeps the prompt cache warm).
84
+ * Appends an ellipsis note when entries/depth were capped.
85
+ */
86
+ export function walkBoundedTree(dir) {
87
+ const lines = [];
88
+ let truncatedNote = false;
89
+ const walk = (current, prefix, depth) => {
90
+ if (depth > MAX_TREE_DEPTH || lines.length >= MAX_TREE_LINES) {
91
+ if (lines.length >= MAX_TREE_LINES)
92
+ truncatedNote = true;
93
+ return;
94
+ }
95
+ let entries;
96
+ try {
97
+ entries = readdirSync(current, { withFileTypes: true })
98
+ .filter((e) => !IGNORE_DIRS.has(e.name) && !e.name.startsWith('.'))
99
+ .map((e) => ({ name: e.name, isDir: e.isDirectory() }))
100
+ .sort((a, b) => (a.isDir === b.isDir ? a.name.localeCompare(b.name) : a.isDir ? -1 : 1));
101
+ }
102
+ catch {
103
+ return; // unreadable dir — skip silently
104
+ }
105
+ if (entries.length > MAX_ENTRIES_PER_DIR) {
106
+ entries = entries.slice(0, MAX_ENTRIES_PER_DIR);
107
+ truncatedNote = true;
108
+ }
109
+ entries.forEach((e, idx) => {
110
+ if (lines.length >= MAX_TREE_LINES) {
111
+ truncatedNote = true;
112
+ return;
113
+ }
114
+ const last = idx === entries.length - 1;
115
+ const tee = last ? '└── ' : '├── ';
116
+ lines.push(`${prefix}${tee}${e.name}${e.isDir ? '/' : ''}`);
117
+ if (e.isDir) {
118
+ walk(join(current, e.name), prefix + (last ? ' ' : '│ '), depth + 1);
119
+ }
120
+ });
121
+ };
122
+ walk(dir, '', 1);
123
+ if (truncatedNote)
124
+ lines.push('… (tree truncated to fit the context budget)');
125
+ return lines;
126
+ }
127
+ /**
128
+ * Build the bounded `[Project context]` block for the loop system context.
129
+ * Returns '' when the directory is not a project (caller injects nothing).
130
+ *
131
+ * Layout (Freebuff system-prompt parity):
132
+ * ## Project — cwd + deterministic assessment (language/framework/tests)
133
+ * ## File tree — bounded BFS walk, honestly truncated
134
+ * ## Git state — branch, dirty files, recent commits
135
+ */
136
+ export async function buildLoopProjectContext(dir) {
137
+ try {
138
+ if (!looksLikeProject(dir))
139
+ return '';
140
+ const lines = [];
141
+ // ── Deterministic assessment (reuses the planner's own scanner) ──
142
+ try {
143
+ const a = assessProject(dir);
144
+ const bits = [];
145
+ if (a.language)
146
+ bits.push(`language: ${a.language}`);
147
+ if (a.framework)
148
+ bits.push(`framework: ${a.framework}`);
149
+ if (a.packageManager)
150
+ bits.push(`package manager: ${a.packageManager}`);
151
+ bits.push(a.isGreenfield ? 'empty/greenfield' : 'existing project');
152
+ bits.push(a.hasTests ? 'has tests' : 'no tests detected');
153
+ if (a.keyFiles?.length)
154
+ bits.push(`key files: ${a.keyFiles.slice(0, 8).join(', ')}`);
155
+ lines.push('## Project', `- path: ${dir}`, `- ${bits.join('; ')}`);
156
+ }
157
+ catch {
158
+ lines.push('## Project', `- path: ${dir}`);
159
+ }
160
+ // ── Bounded file tree ──
161
+ try {
162
+ const treeLines = walkBoundedTree(dir);
163
+ if (treeLines.length > 0) {
164
+ lines.push('## File tree', ...treeLines);
165
+ }
166
+ }
167
+ catch {
168
+ // Tree failure must never break the block — omit the section.
169
+ }
170
+ // ── Git state digest (read-only, 3s cap per command) ──
171
+ try {
172
+ const branchLine = git(dir, ['status', '--porcelain', '-b']).split('\n')[0] || '';
173
+ const statusLines = git(dir, ['status', '--porcelain']).split('\n').filter(Boolean);
174
+ const log = git(dir, ['log', '--oneline', '-5']).split('\n').filter(Boolean);
175
+ if (branchLine) {
176
+ lines.push('## Git state');
177
+ lines.push(`- ${branchLine}`);
178
+ if (statusLines.length > 0) {
179
+ lines.push(`- ${statusLines.length} uncommitted change(s):`);
180
+ for (const s of statusLines.slice(0, MAX_GIT_STATUS_LINES))
181
+ lines.push(` ${s}`);
182
+ if (statusLines.length > MAX_GIT_STATUS_LINES) {
183
+ lines.push(` … ${statusLines.length - MAX_GIT_STATUS_LINES} more`);
184
+ }
185
+ }
186
+ else {
187
+ lines.push('- working tree clean');
188
+ }
189
+ if (log.length > 0) {
190
+ lines.push('- recent commits:');
191
+ for (const c of log)
192
+ lines.push(` ${c}`);
193
+ }
194
+ }
195
+ // Outside a git repo: no Git state section — fine.
196
+ }
197
+ catch {
198
+ // Git digest is best-effort — omit on failure.
199
+ }
200
+ const body = lines.join('\n');
201
+ if (body.length > MAX_BLOCK_CHARS) {
202
+ return body.slice(0, MAX_BLOCK_CHARS) + '\n[project context truncated to fit the context budget]';
203
+ }
204
+ return body;
205
+ }
206
+ catch {
207
+ return '';
208
+ }
209
+ }
210
+ //# sourceMappingURL=loop-project-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop-project-context.js","sourceRoot":"","sources":["../../src/tools/loop-project-context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Loop skill hint (`src/tools/loop-skill-hint.ts`) — AGENTIC_CAPABILITY_ASSESSMENT
3
+ * Addendum v4 Phase 3.2: "The loop never hears about the orchestrator's skill
4
+ * layer: the pipeline consults SkillStore.findMatch + the hub catalog before
5
+ * planning and injects the matched methodology, but a chat/execute-loop goal
6
+ * starts with zero knowledge that a first-party playbook exists."
7
+ *
8
+ * This module closes that parity gap DETERMINISTICALLY (no LLM call): given
9
+ * the user's goal, it finds the best available skill the SAME way the
10
+ * orchestrator does —
11
+ *
12
+ * 1. compiled SkillStore.findMatch (the first-party capability batch),
13
+ * 2. the hub catalog (findHubSkillMatch — installed SKILL.md skills),
14
+ *
15
+ * then returns a system-prompt block that hands the model the skill's
16
+ * methodology with an EXPLICIT escape hatch ("this is a recommendation —
17
+ * ignore it when it does not fit") and the exact load syntax
18
+ * (`skill` tool, {"skill":"<name>"}).
19
+ *
20
+ * Why an evidence filter on top of findMatch: the compiled store's threshold
21
+ * is intentionally low (score >= 1, "manual discovery") and its scoring adds
22
+ * a quality/usage bonus to EVERY skill — so a goal merely containing a generic
23
+ * pattern word ("goal", "task") can false-positive. The chat loop runs on
24
+ * EVERY message (not just pipeline goals), so the loop hint requires REAL
25
+ * goal evidence: a name-word or tag hit, or two pattern-word hits. The
26
+ * orchestrator does not need this (its planner only sees pipeline goals); the
27
+ * hub catalog's own scoring is keyword-based and needs no filter.
28
+ *
29
+ * Safety rails (mirroring the orchestrator's injection contract):
30
+ * - skills.disabled[] gate — a dashboard/CLI-disabled skill is NEVER
31
+ * injected (the same "the toggle is never cosmetic" rule the match gates
32
+ * enforce elsewhere).
33
+ * - Website-deploy activation gate — the orchestrator requires
34
+ * hosting-specific intent before injecting website methodology; the loop
35
+ * hint applies the identical regex so "deploy the API" does not drag in
36
+ * static-site deployment steps.
37
+ * - Side-effect-free matching: the match itself marks nothing; usage is
38
+ * marked ONCE via markLoopSkillUsed by the caller (skillView()'s internal
39
+ * markUsed is deliberately avoided so the hint builder is idempotent).
40
+ * - Bounded injection: at most ONE methodology block per prompt, and the
41
+ * methodology text itself is capped (compiled: 8 steps; hub: 2000 chars)
42
+ * so a crowded catalog cannot balloon the system prompt.
43
+ * - Best-effort by construction: any store/catalog failure returns '' /
44
+ * null and the turn proceeds exactly as before (a hint must never break
45
+ * a turn).
46
+ *
47
+ * Consumers: chat's runChatAnswer (system prompt) and the execute loop's
48
+ * runLoopExecutor — the two runToolLoop callers that had no skill knowledge.
49
+ */
50
+ import type { ConfigManager } from '../config/manager.js';
51
+ /**
52
+ * The match the hint was built from (echoed to callers for telemetry/tests).
53
+ * `null` = no match (no skill scored, or it was gated out).
54
+ */
55
+ export interface LoopSkillHintMatch {
56
+ name: string;
57
+ id: string;
58
+ source: 'compiled' | 'hub';
59
+ }
60
+ /**
61
+ * Did the goal show REAL evidence for this skill — a name-word hit, a tag
62
+ * hit, or two pattern-word hits (meta-words excluded)? Guards the compiled
63
+ * store's intentionally loose threshold: findMatch adds a quality/usage bonus
64
+ * to every skill, so a generic word like "goal" alone must never inject
65
+ * methodology into a chat turn. Deterministic, no LLM.
66
+ */
67
+ export declare function hasRealGoalEvidence(goal: string, skill: {
68
+ name: string;
69
+ tags: string[];
70
+ goalPattern: string;
71
+ }): boolean;
72
+ /**
73
+ * Find the best skill for the goal across BOTH sources the orchestrator
74
+ * consults, honoring the disabled + website-deploy activation gates (+ the
75
+ * compiled evidence filter). Compiled wins ties (its id is the deterministic
76
+ * seed id). Returns null when nothing matches (never a forced match).
77
+ */
78
+ export declare function findLoopSkillMatch(goal: string, cm?: ConfigManager): Promise<LoopSkillHintMatch | null>;
79
+ /**
80
+ * Build the system-prompt block for a matched skill, or '' when there is no
81
+ * match. The block follows the orchestrator's injection contract:
82
+ *
83
+ * - the skill is a RECOMMENDATION, the model still owns the plan (the
84
+ * orchestrator's "model-selected activation" phrasing),
85
+ * - the methodology rides in as Level-2 content (progressive disclosure —
86
+ * the model sees the steps without paying a tool call for them),
87
+ * - the exact load syntax is included so the model can refresh/parameterize
88
+ * via the `skill` tool mid-turn,
89
+ * - ONE block max (bounded system-prompt growth).
90
+ *
91
+ * Marks nothing: usage tracking belongs to markLoopSkillUsed (the caller
92
+ * decides when a match actually got USED — i.e. was injected).
93
+ *
94
+ * @param goal the user's goal text (matched against skill triggers)
95
+ * @param cm ConfigManager for the disabled-skills gate (optional)
96
+ * @param injected out-param: when provided, receives the match that was
97
+ * injected (null when none).
98
+ */
99
+ export declare function buildLoopSkillHint(goal: string, cm?: ConfigManager, injected?: {
100
+ value: LoopSkillHintMatch | null;
101
+ }): Promise<string>;
102
+ /**
103
+ * Mark an injected skill as used (usage tracking parity with the orchestrator
104
+ * — compiled skills only; hub skills have no compiled usage counter). The
105
+ * SINGLE usage marker for the loop hint path (the hint builder never marks).
106
+ * Best-effort, fire-and-forget: never throws, never awaited by callers on the
107
+ * hot path.
108
+ */
109
+ export declare function markLoopSkillUsed(match: LoopSkillHintMatch | null): Promise<void>;
110
+ //# sourceMappingURL=loop-skill-hint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop-skill-hint.d.ts","sourceRoot":"","sources":["../../src/tools/loop-skill-hint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAG1D;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,UAAU,GAAG,KAAK,CAAC;CAC5B;AA0CD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAC3D,OAAO,CAsBT;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,EAAE,CAAC,EAAE,aAAa,GACjB,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAmCpC;AAmCD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,EAAE,CAAC,EAAE,aAAa,EAClB,QAAQ,CAAC,EAAE;IAAE,KAAK,EAAE,kBAAkB,GAAG,IAAI,CAAA;CAAE,GAC9C,OAAO,CAAC,MAAM,CAAC,CAsCjB;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAQvF"}