claude-flow 3.57.2 → 3.58.1
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/.claude/proven-config.json +1 -1
- package/.claude-plugin/marketplace.json +11 -0
- package/README.md +1 -0
- package/node_modules/@claude-flow/codex/README.md +78 -0
- package/node_modules/@claude-flow/codex/dist/activity/cli.d.ts +3 -0
- package/node_modules/@claude-flow/codex/dist/activity/cli.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/activity/cli.js +115 -0
- package/node_modules/@claude-flow/codex/dist/activity/cli.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/activity/files.d.ts +14 -0
- package/node_modules/@claude-flow/codex/dist/activity/files.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/activity/files.js +142 -0
- package/node_modules/@claude-flow/codex/dist/activity/files.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/activity/parser.d.ts +21 -0
- package/node_modules/@claude-flow/codex/dist/activity/parser.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/activity/parser.js +179 -0
- package/node_modules/@claude-flow/codex/dist/activity/parser.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/activity/reader.d.ts +20 -0
- package/node_modules/@claude-flow/codex/dist/activity/reader.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/activity/reader.js +106 -0
- package/node_modules/@claude-flow/codex/dist/activity/reader.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/activity/sanitize.d.ts +4 -0
- package/node_modules/@claude-flow/codex/dist/activity/sanitize.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/activity/sanitize.js +27 -0
- package/node_modules/@claude-flow/codex/dist/activity/sanitize.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/activity/types.d.ts +31 -0
- package/node_modules/@claude-flow/codex/dist/activity/types.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/activity/types.js +5 -0
- package/node_modules/@claude-flow/codex/dist/activity/types.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/activity/viewer.d.ts +21 -0
- package/node_modules/@claude-flow/codex/dist/activity/viewer.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/activity/viewer.js +168 -0
- package/node_modules/@claude-flow/codex/dist/activity/viewer.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/cli.js +3 -0
- package/node_modules/@claude-flow/codex/dist/cli.js.map +1 -1
- package/node_modules/@claude-flow/mcp/dist/server.d.ts.map +1 -1
- package/node_modules/@claude-flow/mcp/dist/server.js +5 -3
- package/node_modules/@claude-flow/mcp/dist/server.js.map +1 -1
- package/node_modules/@claude-flow/mcp/dist/types.d.ts +11 -0
- package/node_modules/@claude-flow/mcp/dist/types.d.ts.map +1 -1
- package/node_modules/@claude-flow/mcp/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/v3/@claude-flow/cli/README.md +1 -0
- package/v3/@claude-flow/cli/catalog-manifest.json +2 -2
- package/v3/@claude-flow/cli/dist/src/commands/agent.js +4 -1
- package/v3/@claude-flow/cli/dist/src/commands/mcp.js +66 -6
- package/v3/@claude-flow/cli/dist/src/commands/memory.js +53 -2
- package/v3/@claude-flow/cli/dist/src/mcp-server.d.ts +5 -0
- package/v3/@claude-flow/cli/dist/src/mcp-server.js +39 -0
- package/v3/@claude-flow/cli/dist/src/mcp-tools/agent-tools.js +28 -0
- package/v3/@claude-flow/cli/dist/src/mcp-tools/claims-tools.js +25 -15
- package/v3/@claude-flow/cli/dist/src/mcp-tools/hooks-tools.js +13 -3
- package/v3/@claude-flow/cli/dist/src/memory/memory-initializer.js +43 -4
- package/v3/@claude-flow/cli/dist/src/memory/memory-peek.d.ts +28 -0
- package/v3/@claude-flow/cli/dist/src/memory/memory-peek.js +222 -0
- package/v3/@claude-flow/cli/dist/src/memory/model-cache-dir.d.ts +11 -0
- package/v3/@claude-flow/cli/dist/src/memory/model-cache-dir.js +17 -0
- package/v3/@claude-flow/cli/dist/src/parser.js +3 -2
- package/v3/@claude-flow/cli/dist/src/ruvector/task-embedder.js +38 -4
- package/v3/@claude-flow/cli/package.json +1 -1
|
@@ -216,6 +216,7 @@ export const agentTools = [
|
|
|
216
216
|
properties: {
|
|
217
217
|
agentType: { type: 'string', description: 'Type of agent to spawn' },
|
|
218
218
|
agentId: { type: 'string', description: 'Optional custom agent ID' },
|
|
219
|
+
name: { type: 'string', description: 'Optional display name for the agent (shown by agent_list, agent_status and ruflo-console)' },
|
|
219
220
|
// #2085 — accept swarmId so spawned agents register in the
|
|
220
221
|
// swarm.agents array that swarm_status reports. Omit to register
|
|
221
222
|
// with the most-recently-created swarm.
|
|
@@ -241,6 +242,18 @@ export const agentTools = [
|
|
|
241
242
|
}
|
|
242
243
|
const agentId = input.agentId || `agent-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
243
244
|
const agentType = input.agentType;
|
|
245
|
+
// #4300 — older callers (including `agent spawn` before this fix) send
|
|
246
|
+
// the name only as metadata.name.
|
|
247
|
+
const metadata = input.metadata;
|
|
248
|
+
const rawName = input.name ?? metadata?.name;
|
|
249
|
+
let name;
|
|
250
|
+
if (rawName !== undefined && rawName !== '') {
|
|
251
|
+
const vName = validateText(rawName, 'name', 200);
|
|
252
|
+
if (!vName.valid) {
|
|
253
|
+
return { success: false, error: `Input validation failed: ${vName.error}` };
|
|
254
|
+
}
|
|
255
|
+
name = vName.sanitized;
|
|
256
|
+
}
|
|
244
257
|
const config = input.config || {};
|
|
245
258
|
// Add explicit model to config if provided
|
|
246
259
|
if (input.model) {
|
|
@@ -262,6 +275,7 @@ export const agentTools = [
|
|
|
262
275
|
const agent = {
|
|
263
276
|
agentId,
|
|
264
277
|
agentType,
|
|
278
|
+
...(name ? { name } : {}),
|
|
265
279
|
status: 'idle',
|
|
266
280
|
health: 1.0,
|
|
267
281
|
taskCount: 0,
|
|
@@ -347,6 +361,7 @@ export const agentTools = [
|
|
|
347
361
|
success: true,
|
|
348
362
|
agentId,
|
|
349
363
|
agentType: agent.agentType,
|
|
364
|
+
...(agent.name ? { name: agent.name } : {}),
|
|
350
365
|
model: agent.model,
|
|
351
366
|
modelRoutedBy: routingResult.routedBy,
|
|
352
367
|
...(routingResult.modelId ? { modelId: routingResult.modelId } : {}),
|
|
@@ -501,6 +516,7 @@ export const agentTools = [
|
|
|
501
516
|
return {
|
|
502
517
|
agentId: agent.agentId,
|
|
503
518
|
agentType: agent.agentType,
|
|
519
|
+
...(agent.name ? { name: agent.name } : {}),
|
|
504
520
|
status: agent.status,
|
|
505
521
|
health: agent.health,
|
|
506
522
|
taskCount: agent.taskCount,
|
|
@@ -525,6 +541,7 @@ export const agentTools = [
|
|
|
525
541
|
properties: {
|
|
526
542
|
status: { type: 'string', description: 'Filter by status' },
|
|
527
543
|
domain: { type: 'string', description: 'Filter by domain' },
|
|
544
|
+
agentType: { type: 'string', description: 'Filter by agent type' },
|
|
528
545
|
includeTerminated: { type: 'boolean', description: 'Include terminated agents' },
|
|
529
546
|
},
|
|
530
547
|
},
|
|
@@ -539,6 +556,11 @@ export const agentTools = [
|
|
|
539
556
|
if (!v.valid)
|
|
540
557
|
return { agents: [], total: 0, error: `Input validation failed: ${v.error}` };
|
|
541
558
|
}
|
|
559
|
+
if (input.agentType) {
|
|
560
|
+
const v = validateIdentifier(input.agentType, 'agentType');
|
|
561
|
+
if (!v.valid)
|
|
562
|
+
return { agents: [], total: 0, error: `Input validation failed: ${v.error}` };
|
|
563
|
+
}
|
|
542
564
|
let agents = Object.values(loadAllAgents()); // #1916: includes hive-mind-spawned workers
|
|
543
565
|
// Filter by status
|
|
544
566
|
if (input.status) {
|
|
@@ -551,10 +573,15 @@ export const agentTools = [
|
|
|
551
573
|
if (input.domain) {
|
|
552
574
|
agents = agents.filter(a => a.domain === input.domain);
|
|
553
575
|
}
|
|
576
|
+
// Filter by agent type
|
|
577
|
+
if (input.agentType) {
|
|
578
|
+
agents = agents.filter(a => a.agentType === input.agentType);
|
|
579
|
+
}
|
|
554
580
|
return {
|
|
555
581
|
agents: agents.map(a => ({
|
|
556
582
|
agentId: a.agentId,
|
|
557
583
|
agentType: a.agentType,
|
|
584
|
+
...(a.name ? { name: a.name } : {}),
|
|
558
585
|
status: a.status,
|
|
559
586
|
health: a.health,
|
|
560
587
|
taskCount: a.taskCount,
|
|
@@ -565,6 +592,7 @@ export const agentTools = [
|
|
|
565
592
|
filters: {
|
|
566
593
|
status: input.status,
|
|
567
594
|
domain: input.domain,
|
|
595
|
+
agentType: input.agentType,
|
|
568
596
|
includeTerminated: input.includeTerminated,
|
|
569
597
|
},
|
|
570
598
|
};
|
|
@@ -13,6 +13,7 @@ import { existsSync, writeFileSync, mkdirSync } from 'fs';
|
|
|
13
13
|
import { join, resolve } from 'path';
|
|
14
14
|
const CLAIMS_DIR = '.claude-flow/claims';
|
|
15
15
|
const CLAIMS_FILE = 'claims.json';
|
|
16
|
+
const DEFAULT_MAX_CLAIMS = 5;
|
|
16
17
|
function getClaimsPath() {
|
|
17
18
|
return resolve(join(CLAIMS_DIR, CLAIMS_FILE));
|
|
18
19
|
}
|
|
@@ -47,7 +48,7 @@ function parseClaimant(str) {
|
|
|
47
48
|
export const claimsTools = [
|
|
48
49
|
{
|
|
49
50
|
name: 'claims_claim',
|
|
50
|
-
description: 'Claim an issue for work (human or agent) Use when
|
|
51
|
+
description: 'Claim an issue for work (human or agent). Use when multiple agents might pick up the same issue — claiming makes ownership visible via claims_list before work starts.',
|
|
51
52
|
category: 'claims',
|
|
52
53
|
inputSchema: {
|
|
53
54
|
type: 'object',
|
|
@@ -64,6 +65,10 @@ export const claimsTools = [
|
|
|
64
65
|
type: 'string',
|
|
65
66
|
description: 'Optional context about the work approach',
|
|
66
67
|
},
|
|
68
|
+
ttlMs: {
|
|
69
|
+
type: 'number',
|
|
70
|
+
description: 'Optional time-to-live in milliseconds; when set, the claim records an expiresAt timestamp. Informational only today — no handler currently enforces it (e.g. claims_steal still requires claims_mark-stealable rather than checking expiry).',
|
|
71
|
+
},
|
|
67
72
|
},
|
|
68
73
|
required: ['issueId', 'claimant'],
|
|
69
74
|
},
|
|
@@ -71,6 +76,7 @@ export const claimsTools = [
|
|
|
71
76
|
const issueId = input.issueId;
|
|
72
77
|
const claimantStr = input.claimant;
|
|
73
78
|
const context = input.context;
|
|
79
|
+
const ttlMs = input.ttlMs;
|
|
74
80
|
{
|
|
75
81
|
const v = validateIdentifier(issueId, 'issueId');
|
|
76
82
|
if (!v.valid)
|
|
@@ -86,6 +92,9 @@ export const claimsTools = [
|
|
|
86
92
|
if (!v.valid)
|
|
87
93
|
return { success: false, error: v.error };
|
|
88
94
|
}
|
|
95
|
+
if (ttlMs !== undefined && (typeof ttlMs !== 'number' || !Number.isFinite(ttlMs) || ttlMs <= 0)) {
|
|
96
|
+
return { success: false, error: 'ttlMs must be a positive number' };
|
|
97
|
+
}
|
|
89
98
|
const claimant = parseClaimant(claimantStr);
|
|
90
99
|
if (!claimant) {
|
|
91
100
|
return { success: false, error: 'Invalid claimant format. Use "human:userId:name" or "agent:agentId:agentType"' };
|
|
@@ -109,6 +118,7 @@ export const claimsTools = [
|
|
|
109
118
|
statusChangedAt: now,
|
|
110
119
|
progress: 0,
|
|
111
120
|
context,
|
|
121
|
+
expiresAt: ttlMs !== undefined ? new Date(Date.now() + ttlMs).toISOString() : undefined,
|
|
112
122
|
};
|
|
113
123
|
store.claims[issueId] = claim;
|
|
114
124
|
saveClaims(store);
|
|
@@ -121,7 +131,7 @@ export const claimsTools = [
|
|
|
121
131
|
},
|
|
122
132
|
{
|
|
123
133
|
name: 'claims_release',
|
|
124
|
-
description: 'Release a claim on an issue Use when
|
|
134
|
+
description: 'Release a claim on an issue. Use when the claimant stops working on it, freeing it for another claims_claim instead of leaving it claimed indefinitely.',
|
|
125
135
|
category: 'claims',
|
|
126
136
|
inputSchema: {
|
|
127
137
|
type: 'object',
|
|
@@ -186,7 +196,7 @@ export const claimsTools = [
|
|
|
186
196
|
},
|
|
187
197
|
{
|
|
188
198
|
name: 'claims_handoff',
|
|
189
|
-
description: 'Request handoff of an issue to another claimant Use when
|
|
199
|
+
description: 'Request handoff of an issue to another claimant. Use when transferring in-progress work to a different agent, instead of releasing and having them claim it fresh.',
|
|
190
200
|
category: 'claims',
|
|
191
201
|
inputSchema: {
|
|
192
202
|
type: 'object',
|
|
@@ -270,7 +280,7 @@ export const claimsTools = [
|
|
|
270
280
|
},
|
|
271
281
|
{
|
|
272
282
|
name: 'claims_accept-handoff',
|
|
273
|
-
description: 'Accept a pending handoff Use when
|
|
283
|
+
description: 'Accept a pending handoff. Use when the receiving claimant confirms a claims_handoff request, completing the ownership transfer.',
|
|
274
284
|
category: 'claims',
|
|
275
285
|
inputSchema: {
|
|
276
286
|
type: 'object',
|
|
@@ -333,7 +343,7 @@ export const claimsTools = [
|
|
|
333
343
|
},
|
|
334
344
|
{
|
|
335
345
|
name: 'claims_status',
|
|
336
|
-
description: 'Update claim status Use when
|
|
346
|
+
description: 'Update claim status. Use when progress changes (active, blocked, review-requested, etc.) so claims_list and claims_load reflect current state.',
|
|
337
347
|
category: 'claims',
|
|
338
348
|
inputSchema: {
|
|
339
349
|
type: 'object',
|
|
@@ -398,7 +408,7 @@ export const claimsTools = [
|
|
|
398
408
|
},
|
|
399
409
|
{
|
|
400
410
|
name: 'claims_list',
|
|
401
|
-
description: 'List all claims or filter by criteria Use when
|
|
411
|
+
description: 'List all claims or filter by criteria. Use when checking what is already claimed before starting new work, instead of guessing from issue comments.',
|
|
402
412
|
category: 'claims',
|
|
403
413
|
inputSchema: {
|
|
404
414
|
type: 'object',
|
|
@@ -453,7 +463,7 @@ export const claimsTools = [
|
|
|
453
463
|
},
|
|
454
464
|
{
|
|
455
465
|
name: 'claims_mark-stealable',
|
|
456
|
-
description: 'Mark an issue as stealable by other agents Use when
|
|
466
|
+
description: 'Mark an issue as stealable by other agents. Use when a claimant is overloaded or stalled and wants another agent to pick it up via claims_steal.',
|
|
457
467
|
category: 'claims',
|
|
458
468
|
inputSchema: {
|
|
459
469
|
type: 'object',
|
|
@@ -521,7 +531,7 @@ export const claimsTools = [
|
|
|
521
531
|
},
|
|
522
532
|
{
|
|
523
533
|
name: 'claims_steal',
|
|
524
|
-
description: 'Steal a stealable issue Use when
|
|
534
|
+
description: 'Steal a stealable issue. Use when picking up work already marked stealable via claims_mark-stealable, rather than claiming an issue someone else still owns.',
|
|
525
535
|
category: 'claims',
|
|
526
536
|
inputSchema: {
|
|
527
537
|
type: 'object',
|
|
@@ -592,7 +602,7 @@ export const claimsTools = [
|
|
|
592
602
|
},
|
|
593
603
|
{
|
|
594
604
|
name: 'claims_stealable',
|
|
595
|
-
description: 'List all stealable issues Use when
|
|
605
|
+
description: 'List all stealable issues. Use when looking for available work that has been freed up via claims_mark-stealable.',
|
|
596
606
|
category: 'claims',
|
|
597
607
|
inputSchema: {
|
|
598
608
|
type: 'object',
|
|
@@ -628,7 +638,7 @@ export const claimsTools = [
|
|
|
628
638
|
},
|
|
629
639
|
{
|
|
630
640
|
name: 'claims_load',
|
|
631
|
-
description: 'Get agent load information Use when
|
|
641
|
+
description: 'Get agent load information. Use when deciding which agent should take new work by comparing claim counts against claims_rebalance targets.',
|
|
632
642
|
category: 'claims',
|
|
633
643
|
inputSchema: {
|
|
634
644
|
type: 'object',
|
|
@@ -689,8 +699,8 @@ export const claimsTools = [
|
|
|
689
699
|
agentId: l.agentId,
|
|
690
700
|
agentType: l.agentType,
|
|
691
701
|
claimCount: l.claims.length,
|
|
692
|
-
maxClaims:
|
|
693
|
-
utilization: l.claims.length /
|
|
702
|
+
maxClaims: DEFAULT_MAX_CLAIMS,
|
|
703
|
+
utilization: l.claims.length / DEFAULT_MAX_CLAIMS,
|
|
694
704
|
blockedCount: l.blockedCount,
|
|
695
705
|
claims: l.claims.map(c => ({
|
|
696
706
|
issueId: c.issueId,
|
|
@@ -711,7 +721,7 @@ export const claimsTools = [
|
|
|
711
721
|
},
|
|
712
722
|
{
|
|
713
723
|
name: 'claims_board',
|
|
714
|
-
description: 'Get a visual board view of all claims Use when
|
|
724
|
+
description: 'Get a visual board view of all claims. Use when scanning overall claim status across issues and agents instead of composing the view from claims_list yourself.',
|
|
715
725
|
category: 'claims',
|
|
716
726
|
inputSchema: {
|
|
717
727
|
type: 'object',
|
|
@@ -760,7 +770,7 @@ export const claimsTools = [
|
|
|
760
770
|
},
|
|
761
771
|
{
|
|
762
772
|
name: 'claims_rebalance',
|
|
763
|
-
description: 'Suggest or apply load rebalancing across agents Use when
|
|
773
|
+
description: 'Suggest or apply load rebalancing across agents. Use when some agents are overloaded and others idle, instead of manually reassigning claims one at a time.',
|
|
764
774
|
category: 'claims',
|
|
765
775
|
inputSchema: {
|
|
766
776
|
type: 'object',
|
|
@@ -794,7 +804,7 @@ export const claimsTools = [
|
|
|
794
804
|
agentLoads.get(key).claims.push(claim);
|
|
795
805
|
}
|
|
796
806
|
const loads = Array.from(agentLoads.values());
|
|
797
|
-
const maxClaims =
|
|
807
|
+
const maxClaims = DEFAULT_MAX_CLAIMS;
|
|
798
808
|
const avgLoad = loads.length > 0
|
|
799
809
|
? loads.reduce((sum, l) => sum + l.claims.length, 0) / loads.length
|
|
800
810
|
: 0;
|
|
@@ -5,7 +5,7 @@ import { feedbackPatternsSchema, validateFeedbackPatterns } from '../memory/feed
|
|
|
5
5
|
*/
|
|
6
6
|
import { mkdirSync, writeFileSync, existsSync, readFileSync, statSync, unlinkSync, readdirSync } from 'fs';
|
|
7
7
|
import * as nodeFs from 'fs';
|
|
8
|
-
import { dirname, join, resolve } from 'path';
|
|
8
|
+
import { dirname, join, resolve, sep } from 'path';
|
|
9
9
|
import { getProjectCwd } from './types.js';
|
|
10
10
|
import { validateIdentifier, validateText, validatePath } from './validate-input.js';
|
|
11
11
|
import { commandRecordingDisabled, redactCommandForStorage } from '../services/command-recording.js';
|
|
@@ -5136,7 +5136,17 @@ export const hooksCodemod = {
|
|
|
5136
5136
|
if (!v.valid)
|
|
5137
5137
|
return v.error;
|
|
5138
5138
|
const abs = resolve(cwd, v.sanitized);
|
|
5139
|
-
|
|
5139
|
+
// Anchor containment at a path-separator boundary — an unanchored
|
|
5140
|
+
// `abs.startsWith(cwd)` string-prefix check would let an absolute
|
|
5141
|
+
// path like `${cwd}-staging/x.ts` pass as "inside" `cwd`. Matches
|
|
5142
|
+
// the pattern already used correctly elsewhere in this codebase
|
|
5143
|
+
// (@claude-flow/security's `isWithinPrefix`, hooks/workers, plugins/security).
|
|
5144
|
+
// KNOWN LIMITATION (disclosed 2026-10-20, not fixed here): this
|
|
5145
|
+
// compares the resolved-but-not-realpath'd path, so a symlink
|
|
5146
|
+
// inside cwd pointing outside it still escapes containment
|
|
5147
|
+
// (CWE-59, a distinct/broader gap than the CWE-22 prefix bug this
|
|
5148
|
+
// anchors). Needs fs.realpathSync-based containment as a follow-up.
|
|
5149
|
+
if (abs !== cwd && !abs.startsWith(cwd + sep))
|
|
5140
5150
|
return `path escapes project root: ${p}`;
|
|
5141
5151
|
out.add(abs);
|
|
5142
5152
|
return undefined;
|
|
@@ -5169,7 +5179,7 @@ export const hooksCodemod = {
|
|
|
5169
5179
|
}
|
|
5170
5180
|
for (const m of matches) {
|
|
5171
5181
|
const abs = resolve(cwd, m);
|
|
5172
|
-
if (abs.startsWith(cwd) && CODEMOD_EXTENSIONS.has(abs.slice(abs.lastIndexOf('.')).toLowerCase())) {
|
|
5182
|
+
if ((abs === cwd || abs.startsWith(cwd + sep)) && CODEMOD_EXTENSIONS.has(abs.slice(abs.lastIndexOf('.')).toLowerCase())) {
|
|
5173
5183
|
out.add(abs);
|
|
5174
5184
|
}
|
|
5175
5185
|
}
|
|
@@ -10,6 +10,7 @@ import { createRequire } from 'node:module';
|
|
|
10
10
|
import { readFileMaybeEncrypted, writeDbImagePreservingFormat, writeFileRestricted } from '../fs-secure.js';
|
|
11
11
|
import { restoreMemoryDbFromBackup } from '../services/memory-backup.js';
|
|
12
12
|
import { validateIdentifier } from '../mcp-tools/validate-input.js';
|
|
13
|
+
import { resolveModelCacheDir } from './model-cache-dir.js';
|
|
13
14
|
/**
|
|
14
15
|
* ADR-323 — typed memory provenance. Distinguishes WHO/WHAT wrote a memory
|
|
15
16
|
* entry (a user's stated claim vs an agent's own output vs a tool result vs
|
|
@@ -2009,6 +2010,8 @@ export async function applyTemporalDecay(dbPath) {
|
|
|
2009
2010
|
};
|
|
2010
2011
|
}
|
|
2011
2012
|
}
|
|
2013
|
+
/** ADR-454: minimum interval before a 'retryable' degraded state re-attempts real init. */
|
|
2014
|
+
const MODEL_INIT_RETRY_INTERVAL_MS = 60_000;
|
|
2012
2015
|
/**
|
|
2013
2016
|
* State of the LOCAL embedding chain only (transformers.js / agentic-flow /
|
|
2014
2017
|
* ruvector ONNX / hash). #3375: the AgentDB bridge's result is cached
|
|
@@ -2058,8 +2061,15 @@ export async function loadEmbeddingModel(options) {
|
|
|
2058
2061
|
*/
|
|
2059
2062
|
async function loadLocalEmbeddingChain(verbose = false, startTime = Date.now()) {
|
|
2060
2063
|
if (embeddingModelState?.loaded) {
|
|
2061
|
-
|
|
2064
|
+
const isRetryableDue = embeddingModelState.degradedReason === 'retryable' &&
|
|
2065
|
+
Date.now() - (embeddingModelState.lastAttemptAt ?? 0) >= MODEL_INIT_RETRY_INTERVAL_MS;
|
|
2066
|
+
if (!isRetryableDue) {
|
|
2067
|
+
return { success: true, dimensions: embeddingModelState.dimensions, modelName: 'cached', loadTime: 0 };
|
|
2068
|
+
}
|
|
2069
|
+
// Fall through to re-attempt real initialization — the retryable
|
|
2070
|
+
// failure (e.g. EACCES on the model cache dir) may now be fixed.
|
|
2062
2071
|
}
|
|
2072
|
+
let sawRetryableFailure = false;
|
|
2063
2073
|
try {
|
|
2064
2074
|
// ADR-094: prefer @huggingface/transformers (clears protobufjs <7.5.5
|
|
2065
2075
|
// critical RCE chain), fall back to legacy @xenova/transformers.
|
|
@@ -2068,6 +2078,7 @@ async function loadLocalEmbeddingChain(verbose = false, startTime = Date.now())
|
|
|
2068
2078
|
// @claude-flow/embeddings/src/transformers-loader.ts.
|
|
2069
2079
|
let transformersSource = null;
|
|
2070
2080
|
let pipelineFn = null;
|
|
2081
|
+
let transformersModule = null;
|
|
2071
2082
|
{
|
|
2072
2083
|
const tryLoad = async (specifier) => {
|
|
2073
2084
|
try {
|
|
@@ -2081,12 +2092,14 @@ async function loadLocalEmbeddingChain(verbose = false, startTime = Date.now())
|
|
|
2081
2092
|
if (hf && typeof hf.pipeline === 'function') {
|
|
2082
2093
|
pipelineFn = hf.pipeline;
|
|
2083
2094
|
transformersSource = '@huggingface/transformers';
|
|
2095
|
+
transformersModule = hf;
|
|
2084
2096
|
}
|
|
2085
2097
|
else {
|
|
2086
2098
|
const xen = await tryLoad('@xenova/transformers');
|
|
2087
2099
|
if (xen && typeof xen.pipeline === 'function') {
|
|
2088
2100
|
pipelineFn = xen.pipeline;
|
|
2089
2101
|
transformersSource = '@xenova/transformers';
|
|
2102
|
+
transformersModule = xen;
|
|
2090
2103
|
}
|
|
2091
2104
|
}
|
|
2092
2105
|
}
|
|
@@ -2103,6 +2116,14 @@ async function loadLocalEmbeddingChain(verbose = false, startTime = Date.now())
|
|
|
2103
2116
|
if (verbose) {
|
|
2104
2117
|
console.log(`Loading ONNX embedding model via ${transformersSource} (all-MiniLM-L6-v2)...`);
|
|
2105
2118
|
}
|
|
2119
|
+
// ADR-454: route model downloads to a user-writable cache dir —
|
|
2120
|
+
// the package-relative default is root-owned under a system-prefix
|
|
2121
|
+
// global install, which throws EACCES for the runtime user.
|
|
2122
|
+
const cacheDir = resolveModelCacheDir();
|
|
2123
|
+
fs.mkdirSync(cacheDir, { recursive: true });
|
|
2124
|
+
const env = transformersModule?.env;
|
|
2125
|
+
if (env)
|
|
2126
|
+
env.cacheDir = cacheDir;
|
|
2106
2127
|
const embedder = await pipelineFn('feature-extraction', 'Xenova/all-MiniLM-L6-v2');
|
|
2107
2128
|
embeddingModelState = {
|
|
2108
2129
|
loaded: true,
|
|
@@ -2118,6 +2139,10 @@ async function loadLocalEmbeddingChain(verbose = false, startTime = Date.now())
|
|
|
2118
2139
|
};
|
|
2119
2140
|
}
|
|
2120
2141
|
catch (err) {
|
|
2142
|
+
// ADR-454: a real backend was importable and callable — this failure
|
|
2143
|
+
// (EACCES, ENOSPC, transient network error, etc.) is environmental,
|
|
2144
|
+
// not a missing dependency, so it must not be memoized permanently.
|
|
2145
|
+
sawRetryableFailure = true;
|
|
2121
2146
|
if (verbose) {
|
|
2122
2147
|
console.warn(`${transformersSource} pipeline init failed (${err instanceof Error ? err.message : String(err)}); ` +
|
|
2123
2148
|
'falling through to ruvector ONNX / agentic-flow / hash fallback.');
|
|
@@ -2186,12 +2211,18 @@ async function loadLocalEmbeddingChain(verbose = false, startTime = Date.now())
|
|
|
2186
2211
|
}
|
|
2187
2212
|
// No agentic-flow root-entry fallback: no published root exports
|
|
2188
2213
|
// `embeddings`, and importing it runs its CLI main() in 3.0.0-alpha.x.
|
|
2189
|
-
// No ONNX model available - use fallback
|
|
2214
|
+
// No ONNX model available - use fallback.
|
|
2215
|
+
// ADR-454: mark whether this is a permanent (no backend importable at
|
|
2216
|
+
// all) or retryable (a backend existed but init failed for an
|
|
2217
|
+
// environmental reason) degraded state, so a later call can re-attempt
|
|
2218
|
+
// real initialization once the condition is fixed.
|
|
2190
2219
|
embeddingModelState = {
|
|
2191
2220
|
loaded: true,
|
|
2192
2221
|
model: null, // Will use simple hash-based fallback
|
|
2193
2222
|
tokenizer: null,
|
|
2194
|
-
dimensions: 128 // Smaller fallback dimensions
|
|
2223
|
+
dimensions: 128, // Smaller fallback dimensions
|
|
2224
|
+
degradedReason: sawRetryableFailure ? 'retryable' : 'permanent',
|
|
2225
|
+
lastAttemptAt: Date.now()
|
|
2195
2226
|
};
|
|
2196
2227
|
return {
|
|
2197
2228
|
success: true,
|
|
@@ -2257,7 +2288,15 @@ export async function generateLocalEmbedding(text) {
|
|
|
2257
2288
|
// loadEmbeddingModel(), which is bridge-first — when the bridge answered
|
|
2258
2289
|
// there, no local model was ever loaded and this function always returned
|
|
2259
2290
|
// the hash fallback.
|
|
2260
|
-
|
|
2291
|
+
//
|
|
2292
|
+
// ADR-454: also re-attempt when the memoized state is a 'retryable'
|
|
2293
|
+
// degraded fallback whose retry interval has elapsed — otherwise this
|
|
2294
|
+
// guard short-circuits past loadLocalEmbeddingChain()'s own retry check
|
|
2295
|
+
// and the fix (e.g. a now-writable cache dir) never gets exercised.
|
|
2296
|
+
const shouldRetryLoad = !embeddingModelState?.loaded ||
|
|
2297
|
+
(embeddingModelState.degradedReason === 'retryable' &&
|
|
2298
|
+
Date.now() - (embeddingModelState.lastAttemptAt ?? 0) >= MODEL_INIT_RETRY_INTERVAL_MS);
|
|
2299
|
+
if (shouldRetryLoad) {
|
|
2261
2300
|
await loadLocalEmbeddingChain();
|
|
2262
2301
|
}
|
|
2263
2302
|
// #2461: loadEmbeddingModel() can leave embeddingModelState null when an
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export type MemoryRootSource = 'path' | 'CLAUDE_FLOW_DB_PATH' | 'CLAUDE_FLOW_MEMORY_PATH' | 'config' | 'default';
|
|
2
|
+
export interface MemoryPeekStore {
|
|
3
|
+
role: 'cli' | 'mcp';
|
|
4
|
+
path: string;
|
|
5
|
+
exists: boolean;
|
|
6
|
+
rows: number | null;
|
|
7
|
+
lastWrite: string | null;
|
|
8
|
+
sizeBytes: number | null;
|
|
9
|
+
walBytes: number | null;
|
|
10
|
+
encrypted?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface MemoryPeekResult {
|
|
13
|
+
cwd: string;
|
|
14
|
+
root: {
|
|
15
|
+
path: string;
|
|
16
|
+
source: MemoryRootSource;
|
|
17
|
+
};
|
|
18
|
+
stores: MemoryPeekStore[];
|
|
19
|
+
sharedKeys: number | null;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Resolve the route and report both stores, read-only. Never creates,
|
|
23
|
+
* initializes, or migrates anything, on an empty project or any other.
|
|
24
|
+
*/
|
|
25
|
+
export declare function memoryPeek(opts?: {
|
|
26
|
+
path?: string;
|
|
27
|
+
}): Promise<MemoryPeekResult>;
|
|
28
|
+
//# sourceMappingURL=memory-peek.d.ts.map
|