harmony-mcp 1.10.0 → 1.10.2
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/dist/cli.js +228 -202
- package/dist/index.js +221 -195
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -14371,6 +14371,187 @@ function getMemoryDir() {
|
|
|
14371
14371
|
return config.memoryDir;
|
|
14372
14372
|
return join(homedir(), ".harmony", "memory");
|
|
14373
14373
|
}
|
|
14374
|
+
// ../memory/src/graph-walk.ts
|
|
14375
|
+
async function discoverRelatedContext(client, startIds, maxDepth = 2, maxEntities = 20, minConfidence = 0.5) {
|
|
14376
|
+
const visited = new Set;
|
|
14377
|
+
const collectedEntities = [];
|
|
14378
|
+
const collectedRelations = [];
|
|
14379
|
+
let truncated = false;
|
|
14380
|
+
const queue = startIds.map((id) => [id, 0]);
|
|
14381
|
+
for (const id of startIds) {
|
|
14382
|
+
visited.add(id);
|
|
14383
|
+
}
|
|
14384
|
+
while (queue.length > 0) {
|
|
14385
|
+
const [entityId, depth] = queue.shift();
|
|
14386
|
+
if (collectedEntities.length >= maxEntities) {
|
|
14387
|
+
truncated = true;
|
|
14388
|
+
break;
|
|
14389
|
+
}
|
|
14390
|
+
if (depth > maxDepth)
|
|
14391
|
+
continue;
|
|
14392
|
+
try {
|
|
14393
|
+
const entityResult = await client.getMemoryEntity(entityId);
|
|
14394
|
+
const entity = entityResult.entity;
|
|
14395
|
+
if (entity) {
|
|
14396
|
+
collectedEntities.push({
|
|
14397
|
+
id: entity.id,
|
|
14398
|
+
type: entity.type,
|
|
14399
|
+
title: entity.title,
|
|
14400
|
+
confidence: entity.confidence ?? 1,
|
|
14401
|
+
memory_tier: entity.memory_tier || "reference"
|
|
14402
|
+
});
|
|
14403
|
+
}
|
|
14404
|
+
if (depth >= maxDepth)
|
|
14405
|
+
continue;
|
|
14406
|
+
const related = await client.getRelatedEntities(entityId);
|
|
14407
|
+
for (const raw of related.outgoing || []) {
|
|
14408
|
+
const rel = raw;
|
|
14409
|
+
const relConfidence = rel.confidence ?? 1;
|
|
14410
|
+
if (relConfidence < minConfidence)
|
|
14411
|
+
continue;
|
|
14412
|
+
const target = rel.target;
|
|
14413
|
+
const targetId = target?.id ?? rel.target_id;
|
|
14414
|
+
if (targetId && !visited.has(targetId)) {
|
|
14415
|
+
visited.add(targetId);
|
|
14416
|
+
queue.push([targetId, depth + 1]);
|
|
14417
|
+
collectedRelations.push({
|
|
14418
|
+
id: rel.id,
|
|
14419
|
+
source_id: entityId,
|
|
14420
|
+
target_id: targetId,
|
|
14421
|
+
relation_type: rel.relation_type,
|
|
14422
|
+
confidence: relConfidence
|
|
14423
|
+
});
|
|
14424
|
+
}
|
|
14425
|
+
}
|
|
14426
|
+
for (const raw of related.incoming || []) {
|
|
14427
|
+
const rel = raw;
|
|
14428
|
+
const relConfidence = rel.confidence ?? 1;
|
|
14429
|
+
if (relConfidence < minConfidence)
|
|
14430
|
+
continue;
|
|
14431
|
+
const source = rel.source;
|
|
14432
|
+
const sourceId = source?.id ?? rel.source_id;
|
|
14433
|
+
if (sourceId && !visited.has(sourceId)) {
|
|
14434
|
+
visited.add(sourceId);
|
|
14435
|
+
queue.push([sourceId, depth + 1]);
|
|
14436
|
+
collectedRelations.push({
|
|
14437
|
+
id: rel.id,
|
|
14438
|
+
source_id: sourceId,
|
|
14439
|
+
target_id: entityId,
|
|
14440
|
+
relation_type: rel.relation_type,
|
|
14441
|
+
confidence: relConfidence
|
|
14442
|
+
});
|
|
14443
|
+
}
|
|
14444
|
+
}
|
|
14445
|
+
} catch {}
|
|
14446
|
+
}
|
|
14447
|
+
return {
|
|
14448
|
+
entities: collectedEntities,
|
|
14449
|
+
relations: collectedRelations,
|
|
14450
|
+
depth: maxDepth,
|
|
14451
|
+
truncated
|
|
14452
|
+
};
|
|
14453
|
+
}
|
|
14454
|
+
// ../memory/src/lifecycle.ts
|
|
14455
|
+
var DECAY_HALF_LIVES = {
|
|
14456
|
+
draft: 7,
|
|
14457
|
+
episode: 30,
|
|
14458
|
+
reference: 180
|
|
14459
|
+
};
|
|
14460
|
+
var PROMOTION_RULES = {
|
|
14461
|
+
draftToEpisode: {
|
|
14462
|
+
minAccessCount: 5,
|
|
14463
|
+
minConfidence: 0.8,
|
|
14464
|
+
minAgeDays: 1
|
|
14465
|
+
},
|
|
14466
|
+
episodeToReference: {
|
|
14467
|
+
minAccessCount: 10,
|
|
14468
|
+
minConfidence: 0.9,
|
|
14469
|
+
minAgeDays: 7
|
|
14470
|
+
}
|
|
14471
|
+
};
|
|
14472
|
+
var ARCHIVE_THRESHOLD = 0.3;
|
|
14473
|
+
var STALE_DAYS = 90;
|
|
14474
|
+
var STALE_MIN_ACCESS = 3;
|
|
14475
|
+
function computeDecayScore(tier, lastAccessedAt, accessCount) {
|
|
14476
|
+
const halfLife = DECAY_HALF_LIVES[tier];
|
|
14477
|
+
const now = Date.now();
|
|
14478
|
+
let daysSinceAccess = 0;
|
|
14479
|
+
if (lastAccessedAt) {
|
|
14480
|
+
daysSinceAccess = (now - new Date(lastAccessedAt).getTime()) / (1000 * 60 * 60 * 24);
|
|
14481
|
+
}
|
|
14482
|
+
const timeDecay = 0.5 ** (daysSinceAccess / halfLife);
|
|
14483
|
+
const accessBonus = Math.log10(accessCount + 1) * 0.1;
|
|
14484
|
+
const score = Math.min(timeDecay + accessBonus, 1);
|
|
14485
|
+
return { score, daysSinceAccess, halfLife, accessBonus };
|
|
14486
|
+
}
|
|
14487
|
+
function checkPromotion(currentTier, accessCount, confidence, createdAt) {
|
|
14488
|
+
const ageDays = (Date.now() - new Date(createdAt).getTime()) / (1000 * 60 * 60 * 24);
|
|
14489
|
+
const base = {
|
|
14490
|
+
eligible: false,
|
|
14491
|
+
targetTier: null,
|
|
14492
|
+
reason: null,
|
|
14493
|
+
currentTier,
|
|
14494
|
+
accessCount,
|
|
14495
|
+
confidence,
|
|
14496
|
+
ageDays
|
|
14497
|
+
};
|
|
14498
|
+
if (currentTier === "draft") {
|
|
14499
|
+
const rules = PROMOTION_RULES.draftToEpisode;
|
|
14500
|
+
if (accessCount >= rules.minAccessCount && confidence >= rules.minConfidence && ageDays >= rules.minAgeDays) {
|
|
14501
|
+
return {
|
|
14502
|
+
...base,
|
|
14503
|
+
eligible: true,
|
|
14504
|
+
targetTier: "episode",
|
|
14505
|
+
reason: `Accessed ${accessCount} times (≥${rules.minAccessCount}), confidence ${confidence} (≥${rules.minConfidence}), age ${Math.round(ageDays)}d (≥${rules.minAgeDays}d)`
|
|
14506
|
+
};
|
|
14507
|
+
}
|
|
14508
|
+
}
|
|
14509
|
+
if (currentTier === "episode") {
|
|
14510
|
+
const rules = PROMOTION_RULES.episodeToReference;
|
|
14511
|
+
if (accessCount >= rules.minAccessCount && confidence >= rules.minConfidence && ageDays >= rules.minAgeDays) {
|
|
14512
|
+
return {
|
|
14513
|
+
...base,
|
|
14514
|
+
eligible: true,
|
|
14515
|
+
targetTier: "reference",
|
|
14516
|
+
reason: `Accessed ${accessCount} times (≥${rules.minAccessCount}), confidence ${confidence} (≥${rules.minConfidence}), age ${Math.round(ageDays)}d (≥${rules.minAgeDays}d)`
|
|
14517
|
+
};
|
|
14518
|
+
}
|
|
14519
|
+
}
|
|
14520
|
+
return base;
|
|
14521
|
+
}
|
|
14522
|
+
function evaluateLifecycle(entity) {
|
|
14523
|
+
const decay = computeDecayScore(entity.memory_tier, entity.last_accessed_at, entity.access_count);
|
|
14524
|
+
const promotion = checkPromotion(entity.memory_tier, entity.access_count, entity.confidence, entity.created_at);
|
|
14525
|
+
const shouldArchive = entity.confidence < ARCHIVE_THRESHOLD;
|
|
14526
|
+
const archiveReason = shouldArchive ? `Confidence ${entity.confidence} below threshold ${ARCHIVE_THRESHOLD}` : undefined;
|
|
14527
|
+
const shouldFlagForReview = decay.daysSinceAccess >= STALE_DAYS && entity.access_count < STALE_MIN_ACCESS;
|
|
14528
|
+
const reviewReason = shouldFlagForReview ? `Not accessed in ${Math.round(decay.daysSinceAccess)} days with only ${entity.access_count} accesses` : undefined;
|
|
14529
|
+
return {
|
|
14530
|
+
decay,
|
|
14531
|
+
promotion,
|
|
14532
|
+
shouldArchive,
|
|
14533
|
+
shouldFlagForReview,
|
|
14534
|
+
archiveReason,
|
|
14535
|
+
reviewReason
|
|
14536
|
+
};
|
|
14537
|
+
}
|
|
14538
|
+
function buildContradictionQuery(type, tags) {
|
|
14539
|
+
if (tags.length === 0)
|
|
14540
|
+
return null;
|
|
14541
|
+
return { type, tags };
|
|
14542
|
+
}
|
|
14543
|
+
// ../memory/src/sync.ts
|
|
14544
|
+
import { createHash } from "node:crypto";
|
|
14545
|
+
import {
|
|
14546
|
+
existsSync as existsSync2,
|
|
14547
|
+
mkdirSync as mkdirSync2,
|
|
14548
|
+
readdirSync,
|
|
14549
|
+
readFileSync as readFileSync2,
|
|
14550
|
+
rmSync,
|
|
14551
|
+
writeFileSync as writeFileSync2
|
|
14552
|
+
} from "node:fs";
|
|
14553
|
+
import { join as join2, relative, sep } from "node:path";
|
|
14554
|
+
|
|
14374
14555
|
// ../memory/src/sync-storage.ts
|
|
14375
14556
|
function parseSyncMarkdown(markdown) {
|
|
14376
14557
|
const trimmed = markdown.trim();
|
|
@@ -14486,17 +14667,8 @@ function parseYamlArray(value) {
|
|
|
14486
14667
|
return [];
|
|
14487
14668
|
return match[1].split(",").map((s) => s.trim()).filter(Boolean);
|
|
14488
14669
|
}
|
|
14670
|
+
|
|
14489
14671
|
// ../memory/src/sync.ts
|
|
14490
|
-
import { createHash } from "node:crypto";
|
|
14491
|
-
import {
|
|
14492
|
-
existsSync as existsSync2,
|
|
14493
|
-
mkdirSync as mkdirSync2,
|
|
14494
|
-
readdirSync,
|
|
14495
|
-
readFileSync as readFileSync2,
|
|
14496
|
-
rmSync,
|
|
14497
|
-
writeFileSync as writeFileSync2
|
|
14498
|
-
} from "node:fs";
|
|
14499
|
-
import { join as join2, relative, sep } from "node:path";
|
|
14500
14672
|
function computeFileHash(content) {
|
|
14501
14673
|
return `sha256:${createHash("sha256").update(content).digest("hex")}`;
|
|
14502
14674
|
}
|
|
@@ -14758,177 +14930,6 @@ async function syncFull(client, config, workspaceId, projectId) {
|
|
|
14758
14930
|
errors: [...pullResult.errors, ...pushResult.errors]
|
|
14759
14931
|
};
|
|
14760
14932
|
}
|
|
14761
|
-
// ../memory/src/lifecycle.ts
|
|
14762
|
-
var DECAY_HALF_LIVES = {
|
|
14763
|
-
draft: 7,
|
|
14764
|
-
episode: 30,
|
|
14765
|
-
reference: 180
|
|
14766
|
-
};
|
|
14767
|
-
var PROMOTION_RULES = {
|
|
14768
|
-
draftToEpisode: {
|
|
14769
|
-
minAccessCount: 5,
|
|
14770
|
-
minConfidence: 0.8,
|
|
14771
|
-
minAgeDays: 1
|
|
14772
|
-
},
|
|
14773
|
-
episodeToReference: {
|
|
14774
|
-
minAccessCount: 10,
|
|
14775
|
-
minConfidence: 0.9,
|
|
14776
|
-
minAgeDays: 7
|
|
14777
|
-
}
|
|
14778
|
-
};
|
|
14779
|
-
var ARCHIVE_THRESHOLD = 0.3;
|
|
14780
|
-
var STALE_DAYS = 90;
|
|
14781
|
-
var STALE_MIN_ACCESS = 3;
|
|
14782
|
-
function computeDecayScore(tier, lastAccessedAt, accessCount) {
|
|
14783
|
-
const halfLife = DECAY_HALF_LIVES[tier];
|
|
14784
|
-
const now = Date.now();
|
|
14785
|
-
let daysSinceAccess = 0;
|
|
14786
|
-
if (lastAccessedAt) {
|
|
14787
|
-
daysSinceAccess = (now - new Date(lastAccessedAt).getTime()) / (1000 * 60 * 60 * 24);
|
|
14788
|
-
}
|
|
14789
|
-
const timeDecay = Math.pow(0.5, daysSinceAccess / halfLife);
|
|
14790
|
-
const accessBonus = Math.log10(accessCount + 1) * 0.1;
|
|
14791
|
-
const score = Math.min(timeDecay + accessBonus, 1);
|
|
14792
|
-
return { score, daysSinceAccess, halfLife, accessBonus };
|
|
14793
|
-
}
|
|
14794
|
-
function checkPromotion(currentTier, accessCount, confidence, createdAt) {
|
|
14795
|
-
const ageDays = (Date.now() - new Date(createdAt).getTime()) / (1000 * 60 * 60 * 24);
|
|
14796
|
-
const base = {
|
|
14797
|
-
eligible: false,
|
|
14798
|
-
targetTier: null,
|
|
14799
|
-
reason: null,
|
|
14800
|
-
currentTier,
|
|
14801
|
-
accessCount,
|
|
14802
|
-
confidence,
|
|
14803
|
-
ageDays
|
|
14804
|
-
};
|
|
14805
|
-
if (currentTier === "draft") {
|
|
14806
|
-
const rules = PROMOTION_RULES.draftToEpisode;
|
|
14807
|
-
if (accessCount >= rules.minAccessCount && confidence >= rules.minConfidence && ageDays >= rules.minAgeDays) {
|
|
14808
|
-
return {
|
|
14809
|
-
...base,
|
|
14810
|
-
eligible: true,
|
|
14811
|
-
targetTier: "episode",
|
|
14812
|
-
reason: `Accessed ${accessCount} times (≥${rules.minAccessCount}), confidence ${confidence} (≥${rules.minConfidence}), age ${Math.round(ageDays)}d (≥${rules.minAgeDays}d)`
|
|
14813
|
-
};
|
|
14814
|
-
}
|
|
14815
|
-
}
|
|
14816
|
-
if (currentTier === "episode") {
|
|
14817
|
-
const rules = PROMOTION_RULES.episodeToReference;
|
|
14818
|
-
if (accessCount >= rules.minAccessCount && confidence >= rules.minConfidence && ageDays >= rules.minAgeDays) {
|
|
14819
|
-
return {
|
|
14820
|
-
...base,
|
|
14821
|
-
eligible: true,
|
|
14822
|
-
targetTier: "reference",
|
|
14823
|
-
reason: `Accessed ${accessCount} times (≥${rules.minAccessCount}), confidence ${confidence} (≥${rules.minConfidence}), age ${Math.round(ageDays)}d (≥${rules.minAgeDays}d)`
|
|
14824
|
-
};
|
|
14825
|
-
}
|
|
14826
|
-
}
|
|
14827
|
-
return base;
|
|
14828
|
-
}
|
|
14829
|
-
function evaluateLifecycle(entity) {
|
|
14830
|
-
const decay = computeDecayScore(entity.memory_tier, entity.last_accessed_at, entity.access_count);
|
|
14831
|
-
const promotion = checkPromotion(entity.memory_tier, entity.access_count, entity.confidence, entity.created_at);
|
|
14832
|
-
const shouldArchive = entity.confidence < ARCHIVE_THRESHOLD;
|
|
14833
|
-
const archiveReason = shouldArchive ? `Confidence ${entity.confidence} below threshold ${ARCHIVE_THRESHOLD}` : undefined;
|
|
14834
|
-
const shouldFlagForReview = decay.daysSinceAccess >= STALE_DAYS && entity.access_count < STALE_MIN_ACCESS;
|
|
14835
|
-
const reviewReason = shouldFlagForReview ? `Not accessed in ${Math.round(decay.daysSinceAccess)} days with only ${entity.access_count} accesses` : undefined;
|
|
14836
|
-
return {
|
|
14837
|
-
decay,
|
|
14838
|
-
promotion,
|
|
14839
|
-
shouldArchive,
|
|
14840
|
-
shouldFlagForReview,
|
|
14841
|
-
archiveReason,
|
|
14842
|
-
reviewReason
|
|
14843
|
-
};
|
|
14844
|
-
}
|
|
14845
|
-
function buildContradictionQuery(type, tags) {
|
|
14846
|
-
if (tags.length === 0)
|
|
14847
|
-
return null;
|
|
14848
|
-
return { type, tags };
|
|
14849
|
-
}
|
|
14850
|
-
// ../memory/src/graph-walk.ts
|
|
14851
|
-
async function discoverRelatedContext(client, startIds, maxDepth = 2, maxEntities = 20, minConfidence = 0.5) {
|
|
14852
|
-
const visited = new Set;
|
|
14853
|
-
const collectedEntities = [];
|
|
14854
|
-
const collectedRelations = [];
|
|
14855
|
-
let truncated = false;
|
|
14856
|
-
const queue = startIds.map((id) => [id, 0]);
|
|
14857
|
-
for (const id of startIds) {
|
|
14858
|
-
visited.add(id);
|
|
14859
|
-
}
|
|
14860
|
-
while (queue.length > 0) {
|
|
14861
|
-
const [entityId, depth] = queue.shift();
|
|
14862
|
-
if (collectedEntities.length >= maxEntities) {
|
|
14863
|
-
truncated = true;
|
|
14864
|
-
break;
|
|
14865
|
-
}
|
|
14866
|
-
if (depth > maxDepth)
|
|
14867
|
-
continue;
|
|
14868
|
-
try {
|
|
14869
|
-
const entityResult = await client.getMemoryEntity(entityId);
|
|
14870
|
-
const entity = entityResult.entity;
|
|
14871
|
-
if (entity) {
|
|
14872
|
-
collectedEntities.push({
|
|
14873
|
-
id: entity.id,
|
|
14874
|
-
type: entity.type,
|
|
14875
|
-
title: entity.title,
|
|
14876
|
-
confidence: entity.confidence ?? 1,
|
|
14877
|
-
memory_tier: entity.memory_tier || "reference"
|
|
14878
|
-
});
|
|
14879
|
-
}
|
|
14880
|
-
if (depth >= maxDepth)
|
|
14881
|
-
continue;
|
|
14882
|
-
const related = await client.getRelatedEntities(entityId);
|
|
14883
|
-
for (const raw of related.outgoing || []) {
|
|
14884
|
-
const rel = raw;
|
|
14885
|
-
const relConfidence = rel.confidence ?? 1;
|
|
14886
|
-
if (relConfidence < minConfidence)
|
|
14887
|
-
continue;
|
|
14888
|
-
const target = rel.target;
|
|
14889
|
-
const targetId = target?.id ?? rel.target_id;
|
|
14890
|
-
if (targetId && !visited.has(targetId)) {
|
|
14891
|
-
visited.add(targetId);
|
|
14892
|
-
queue.push([targetId, depth + 1]);
|
|
14893
|
-
collectedRelations.push({
|
|
14894
|
-
id: rel.id,
|
|
14895
|
-
source_id: entityId,
|
|
14896
|
-
target_id: targetId,
|
|
14897
|
-
relation_type: rel.relation_type,
|
|
14898
|
-
confidence: relConfidence
|
|
14899
|
-
});
|
|
14900
|
-
}
|
|
14901
|
-
}
|
|
14902
|
-
for (const raw of related.incoming || []) {
|
|
14903
|
-
const rel = raw;
|
|
14904
|
-
const relConfidence = rel.confidence ?? 1;
|
|
14905
|
-
if (relConfidence < minConfidence)
|
|
14906
|
-
continue;
|
|
14907
|
-
const source = rel.source;
|
|
14908
|
-
const sourceId = source?.id ?? rel.source_id;
|
|
14909
|
-
if (sourceId && !visited.has(sourceId)) {
|
|
14910
|
-
visited.add(sourceId);
|
|
14911
|
-
queue.push([sourceId, depth + 1]);
|
|
14912
|
-
collectedRelations.push({
|
|
14913
|
-
id: rel.id,
|
|
14914
|
-
source_id: sourceId,
|
|
14915
|
-
target_id: entityId,
|
|
14916
|
-
relation_type: rel.relation_type,
|
|
14917
|
-
confidence: relConfidence
|
|
14918
|
-
});
|
|
14919
|
-
}
|
|
14920
|
-
}
|
|
14921
|
-
} catch {
|
|
14922
|
-
continue;
|
|
14923
|
-
}
|
|
14924
|
-
}
|
|
14925
|
-
return {
|
|
14926
|
-
entities: collectedEntities,
|
|
14927
|
-
relations: collectedRelations,
|
|
14928
|
-
depth: maxDepth,
|
|
14929
|
-
truncated
|
|
14930
|
-
};
|
|
14931
|
-
}
|
|
14932
14933
|
// ../../node_modules/zod/v4/core/index.js
|
|
14933
14934
|
var exports_core2 = {};
|
|
14934
14935
|
__export(exports_core2, {
|
|
@@ -30731,7 +30732,7 @@ class StdioServerTransport {
|
|
|
30731
30732
|
}
|
|
30732
30733
|
}
|
|
30733
30734
|
// src/graph-expansion.ts
|
|
30734
|
-
async function autoExpandGraph(client2, entityId, title, content,
|
|
30735
|
+
async function autoExpandGraph(client2, entityId, title, content, _tags, workspaceId, projectId, maxRelations = 5) {
|
|
30735
30736
|
try {
|
|
30736
30737
|
const contentSnippet = content.slice(0, 200).trim();
|
|
30737
30738
|
const query = [title, contentSnippet].filter(Boolean).join(" ");
|
|
@@ -30809,7 +30810,11 @@ Agent: ${session.agentName}`
|
|
|
30809
30810
|
type: "lesson",
|
|
30810
30811
|
tier: "episode",
|
|
30811
30812
|
confidence: 0.7,
|
|
30812
|
-
tags: [
|
|
30813
|
+
tags: [
|
|
30814
|
+
"auto-extracted",
|
|
30815
|
+
"session-summary",
|
|
30816
|
+
...session.cardLabels.slice(0, 3)
|
|
30817
|
+
],
|
|
30813
30818
|
metadata: {
|
|
30814
30819
|
source: "active_learning",
|
|
30815
30820
|
card_id: session.cardId,
|
|
@@ -31003,7 +31008,7 @@ function isRetryableError(error48, status) {
|
|
|
31003
31008
|
return msg.includes("ECONNRESET") || msg.includes("ETIMEDOUT") || msg.includes("fetch failed");
|
|
31004
31009
|
}
|
|
31005
31010
|
function getRetryDelay(attempt) {
|
|
31006
|
-
const delay = Math.min(RETRY_CONFIG.baseDelayMs *
|
|
31011
|
+
const delay = Math.min(RETRY_CONFIG.baseDelayMs * 2 ** attempt, RETRY_CONFIG.maxDelayMs);
|
|
31007
31012
|
return Math.round(delay + delay * 0.25 * (Math.random() * 2 - 1));
|
|
31008
31013
|
}
|
|
31009
31014
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -31122,7 +31127,6 @@ class HarmonyApiClient {
|
|
|
31122
31127
|
throw lastError;
|
|
31123
31128
|
if (attempt < RETRY_CONFIG.maxRetries) {
|
|
31124
31129
|
await sleep(getRetryDelay(attempt));
|
|
31125
|
-
continue;
|
|
31126
31130
|
}
|
|
31127
31131
|
}
|
|
31128
31132
|
}
|
|
@@ -31169,7 +31173,6 @@ class HarmonyApiClient {
|
|
|
31169
31173
|
throw lastError;
|
|
31170
31174
|
if (attempt < RETRY_CONFIG.maxRetries) {
|
|
31171
31175
|
await sleep(getRetryDelay(attempt));
|
|
31172
|
-
continue;
|
|
31173
31176
|
}
|
|
31174
31177
|
}
|
|
31175
31178
|
}
|
|
@@ -31567,7 +31570,7 @@ function computeRelevanceScore(entity, taskContext, cardLabels) {
|
|
|
31567
31570
|
if (entity.last_accessed_at) {
|
|
31568
31571
|
const daysSinceAccess = (Date.now() - new Date(entity.last_accessed_at).getTime()) / (1000 * 60 * 60 * 24);
|
|
31569
31572
|
const halfLife = { draft: 7, episode: 30, reference: 180 }[entity.memory_tier];
|
|
31570
|
-
const recencyScore =
|
|
31573
|
+
const recencyScore = 0.5 ** (daysSinceAccess / halfLife) * 0.1;
|
|
31571
31574
|
score += recencyScore;
|
|
31572
31575
|
if (daysSinceAccess < 7)
|
|
31573
31576
|
reasons.push("recently_accessed");
|
|
@@ -31644,7 +31647,11 @@ async function assembleContext(options) {
|
|
|
31644
31647
|
episode: Math.floor(tokenBudget * TIER_BUDGET_ALLOCATION.episode),
|
|
31645
31648
|
draft: Math.floor(tokenBudget * TIER_BUDGET_ALLOCATION.draft)
|
|
31646
31649
|
};
|
|
31647
|
-
const tierUsed = {
|
|
31650
|
+
const tierUsed = {
|
|
31651
|
+
reference: 0,
|
|
31652
|
+
episode: 0,
|
|
31653
|
+
draft: 0
|
|
31654
|
+
};
|
|
31648
31655
|
const included = [];
|
|
31649
31656
|
let totalUsed = 0;
|
|
31650
31657
|
let referenceCount = 0;
|
|
@@ -31714,9 +31721,18 @@ ${text}`);
|
|
|
31714
31721
|
}
|
|
31715
31722
|
manifest.budgetUsed = totalUsed;
|
|
31716
31723
|
manifest.tierBreakdown = {
|
|
31717
|
-
reference: {
|
|
31718
|
-
|
|
31719
|
-
|
|
31724
|
+
reference: {
|
|
31725
|
+
count: included.filter((i) => i.entity.memory_tier === "reference").length,
|
|
31726
|
+
tokens: tierUsed.reference
|
|
31727
|
+
},
|
|
31728
|
+
episode: {
|
|
31729
|
+
count: included.filter((i) => i.entity.memory_tier === "episode").length,
|
|
31730
|
+
tokens: tierUsed.episode
|
|
31731
|
+
},
|
|
31732
|
+
draft: {
|
|
31733
|
+
count: included.filter((i) => i.entity.memory_tier === "draft").length,
|
|
31734
|
+
tokens: tierUsed.draft
|
|
31735
|
+
}
|
|
31720
31736
|
};
|
|
31721
31737
|
for (const item of included) {
|
|
31722
31738
|
manifest.included.push({
|
|
@@ -32008,7 +32024,15 @@ ${lines.join(`
|
|
|
32008
32024
|
`)}`;
|
|
32009
32025
|
}
|
|
32010
32026
|
function generatePrompt(options) {
|
|
32011
|
-
const {
|
|
32027
|
+
const {
|
|
32028
|
+
card,
|
|
32029
|
+
column,
|
|
32030
|
+
variant,
|
|
32031
|
+
customConstraints,
|
|
32032
|
+
memories,
|
|
32033
|
+
assembledContext,
|
|
32034
|
+
assemblyId
|
|
32035
|
+
} = options;
|
|
32012
32036
|
const contextOpts = {
|
|
32013
32037
|
includeTitle: true,
|
|
32014
32038
|
includeDescription: true,
|
|
@@ -32162,7 +32186,8 @@ var TOOLS = {
|
|
|
32162
32186
|
description: { type: "string" },
|
|
32163
32187
|
priority: { type: "string", enum: ["low", "medium", "high", "urgent"] },
|
|
32164
32188
|
assigneeId: { type: "string", nullable: true },
|
|
32165
|
-
dueDate: { type: "string", nullable: true }
|
|
32189
|
+
dueDate: { type: "string", nullable: true },
|
|
32190
|
+
done: { type: "boolean", description: "Mark card as done or not done" }
|
|
32166
32191
|
},
|
|
32167
32192
|
required: ["cardId"]
|
|
32168
32193
|
}
|
|
@@ -33482,7 +33507,8 @@ async function handleToolCall(name, args, deps) {
|
|
|
33482
33507
|
description: args.description,
|
|
33483
33508
|
priority: args.priority,
|
|
33484
33509
|
assigneeId: args.assigneeId,
|
|
33485
|
-
dueDate: args.dueDate
|
|
33510
|
+
dueDate: args.dueDate,
|
|
33511
|
+
done: args.done
|
|
33486
33512
|
});
|
|
33487
33513
|
return { success: true, ...result };
|
|
33488
33514
|
}
|
|
@@ -34299,7 +34325,7 @@ async function handleToolCall(name, args, deps) {
|
|
|
34299
34325
|
const card = cardResult.card;
|
|
34300
34326
|
await client3.updatePlanTask(planId, task.id, { cardId: card.id });
|
|
34301
34327
|
cardsCreated++;
|
|
34302
|
-
} catch (
|
|
34328
|
+
} catch (_e) {}
|
|
34303
34329
|
}
|
|
34304
34330
|
results.cardsCreated = cardsCreated;
|
|
34305
34331
|
}
|
|
@@ -34783,7 +34809,7 @@ import {
|
|
|
34783
34809
|
unlinkSync
|
|
34784
34810
|
} from "node:fs";
|
|
34785
34811
|
import { homedir as homedir4 } from "node:os";
|
|
34786
|
-
import { dirname as
|
|
34812
|
+
import { dirname as dirname2, join as join4 } from "node:path";
|
|
34787
34813
|
|
|
34788
34814
|
// ../../node_modules/@clack/core/dist/index.mjs
|
|
34789
34815
|
var import_sisteransi = __toESM(require_src(), 1);
|
|
@@ -35617,7 +35643,7 @@ function formatPath(path, homeDir) {
|
|
|
35617
35643
|
// src/tui/writer.ts
|
|
35618
35644
|
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
35619
35645
|
import { homedir as homedir3 } from "node:os";
|
|
35620
|
-
import { dirname
|
|
35646
|
+
import { dirname } from "node:path";
|
|
35621
35647
|
function ensureDir(dirPath) {
|
|
35622
35648
|
if (!existsSync4(dirPath)) {
|
|
35623
35649
|
mkdirSync3(dirPath, { recursive: true, mode: 493 });
|
|
@@ -35629,7 +35655,7 @@ function writeFile(filePath, content, options = {}) {
|
|
|
35629
35655
|
return { path: filePath, action: "skip" };
|
|
35630
35656
|
}
|
|
35631
35657
|
try {
|
|
35632
|
-
ensureDir(
|
|
35658
|
+
ensureDir(dirname(filePath));
|
|
35633
35659
|
const mode = filePath.includes(".harmony-mcp") ? 384 : 420;
|
|
35634
35660
|
writeFileSync3(filePath, content, { mode });
|
|
35635
35661
|
return { path: filePath, action: exists ? "update" : "create" };
|
|
@@ -35645,7 +35671,7 @@ function mergeJsonFile(filePath, updates, options = {}) {
|
|
|
35645
35671
|
const exists = existsSync4(filePath);
|
|
35646
35672
|
if (!exists) {
|
|
35647
35673
|
try {
|
|
35648
|
-
ensureDir(
|
|
35674
|
+
ensureDir(dirname(filePath));
|
|
35649
35675
|
writeFileSync3(filePath, JSON.stringify(updates, null, 2), {
|
|
35650
35676
|
mode: 420
|
|
35651
35677
|
});
|
|
@@ -35695,7 +35721,7 @@ function appendToToml(filePath, section, content, options = {}) {
|
|
|
35695
35721
|
const exists = existsSync4(filePath);
|
|
35696
35722
|
if (!exists) {
|
|
35697
35723
|
try {
|
|
35698
|
-
ensureDir(
|
|
35724
|
+
ensureDir(dirname(filePath));
|
|
35699
35725
|
writeFileSync3(filePath, content, { mode: 420 });
|
|
35700
35726
|
return { path: filePath, action: "create" };
|
|
35701
35727
|
} catch (error48) {
|
|
@@ -36010,7 +36036,7 @@ async function registerMcpServer() {
|
|
|
36010
36036
|
async function writeMcpConfigFallback(home) {
|
|
36011
36037
|
const { readFileSync: readFileSync4, writeFileSync: writeFileSync4, mkdirSync: mkdirSync5, existsSync: existsSync6 } = await import("node:fs");
|
|
36012
36038
|
const settingsPath = join4(home, ".claude", "settings.json");
|
|
36013
|
-
const settingsDir =
|
|
36039
|
+
const settingsDir = dirname2(settingsPath);
|
|
36014
36040
|
if (!existsSync6(settingsDir)) {
|
|
36015
36041
|
mkdirSync5(settingsDir, { recursive: true });
|
|
36016
36042
|
}
|
|
@@ -36578,7 +36604,7 @@ async function runSetup(options = {}) {
|
|
|
36578
36604
|
if (allSymlinks.length > 0) {
|
|
36579
36605
|
for (const symlink of allSymlinks) {
|
|
36580
36606
|
try {
|
|
36581
|
-
const linkDir =
|
|
36607
|
+
const linkDir = dirname2(symlink.link);
|
|
36582
36608
|
if (!existsSync5(linkDir)) {
|
|
36583
36609
|
mkdirSync4(linkDir, { recursive: true });
|
|
36584
36610
|
}
|
package/dist/index.js
CHANGED
|
@@ -11946,6 +11946,187 @@ var require_dist = __commonJS((exports, module) => {
|
|
|
11946
11946
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11947
11947
|
exports.default = formatsPlugin;
|
|
11948
11948
|
});
|
|
11949
|
+
// ../memory/src/graph-walk.ts
|
|
11950
|
+
async function discoverRelatedContext(client, startIds, maxDepth = 2, maxEntities = 20, minConfidence = 0.5) {
|
|
11951
|
+
const visited = new Set;
|
|
11952
|
+
const collectedEntities = [];
|
|
11953
|
+
const collectedRelations = [];
|
|
11954
|
+
let truncated = false;
|
|
11955
|
+
const queue = startIds.map((id) => [id, 0]);
|
|
11956
|
+
for (const id of startIds) {
|
|
11957
|
+
visited.add(id);
|
|
11958
|
+
}
|
|
11959
|
+
while (queue.length > 0) {
|
|
11960
|
+
const [entityId, depth] = queue.shift();
|
|
11961
|
+
if (collectedEntities.length >= maxEntities) {
|
|
11962
|
+
truncated = true;
|
|
11963
|
+
break;
|
|
11964
|
+
}
|
|
11965
|
+
if (depth > maxDepth)
|
|
11966
|
+
continue;
|
|
11967
|
+
try {
|
|
11968
|
+
const entityResult = await client.getMemoryEntity(entityId);
|
|
11969
|
+
const entity = entityResult.entity;
|
|
11970
|
+
if (entity) {
|
|
11971
|
+
collectedEntities.push({
|
|
11972
|
+
id: entity.id,
|
|
11973
|
+
type: entity.type,
|
|
11974
|
+
title: entity.title,
|
|
11975
|
+
confidence: entity.confidence ?? 1,
|
|
11976
|
+
memory_tier: entity.memory_tier || "reference"
|
|
11977
|
+
});
|
|
11978
|
+
}
|
|
11979
|
+
if (depth >= maxDepth)
|
|
11980
|
+
continue;
|
|
11981
|
+
const related = await client.getRelatedEntities(entityId);
|
|
11982
|
+
for (const raw of related.outgoing || []) {
|
|
11983
|
+
const rel = raw;
|
|
11984
|
+
const relConfidence = rel.confidence ?? 1;
|
|
11985
|
+
if (relConfidence < minConfidence)
|
|
11986
|
+
continue;
|
|
11987
|
+
const target = rel.target;
|
|
11988
|
+
const targetId = target?.id ?? rel.target_id;
|
|
11989
|
+
if (targetId && !visited.has(targetId)) {
|
|
11990
|
+
visited.add(targetId);
|
|
11991
|
+
queue.push([targetId, depth + 1]);
|
|
11992
|
+
collectedRelations.push({
|
|
11993
|
+
id: rel.id,
|
|
11994
|
+
source_id: entityId,
|
|
11995
|
+
target_id: targetId,
|
|
11996
|
+
relation_type: rel.relation_type,
|
|
11997
|
+
confidence: relConfidence
|
|
11998
|
+
});
|
|
11999
|
+
}
|
|
12000
|
+
}
|
|
12001
|
+
for (const raw of related.incoming || []) {
|
|
12002
|
+
const rel = raw;
|
|
12003
|
+
const relConfidence = rel.confidence ?? 1;
|
|
12004
|
+
if (relConfidence < minConfidence)
|
|
12005
|
+
continue;
|
|
12006
|
+
const source = rel.source;
|
|
12007
|
+
const sourceId = source?.id ?? rel.source_id;
|
|
12008
|
+
if (sourceId && !visited.has(sourceId)) {
|
|
12009
|
+
visited.add(sourceId);
|
|
12010
|
+
queue.push([sourceId, depth + 1]);
|
|
12011
|
+
collectedRelations.push({
|
|
12012
|
+
id: rel.id,
|
|
12013
|
+
source_id: sourceId,
|
|
12014
|
+
target_id: entityId,
|
|
12015
|
+
relation_type: rel.relation_type,
|
|
12016
|
+
confidence: relConfidence
|
|
12017
|
+
});
|
|
12018
|
+
}
|
|
12019
|
+
}
|
|
12020
|
+
} catch {}
|
|
12021
|
+
}
|
|
12022
|
+
return {
|
|
12023
|
+
entities: collectedEntities,
|
|
12024
|
+
relations: collectedRelations,
|
|
12025
|
+
depth: maxDepth,
|
|
12026
|
+
truncated
|
|
12027
|
+
};
|
|
12028
|
+
}
|
|
12029
|
+
// ../memory/src/lifecycle.ts
|
|
12030
|
+
var DECAY_HALF_LIVES = {
|
|
12031
|
+
draft: 7,
|
|
12032
|
+
episode: 30,
|
|
12033
|
+
reference: 180
|
|
12034
|
+
};
|
|
12035
|
+
var PROMOTION_RULES = {
|
|
12036
|
+
draftToEpisode: {
|
|
12037
|
+
minAccessCount: 5,
|
|
12038
|
+
minConfidence: 0.8,
|
|
12039
|
+
minAgeDays: 1
|
|
12040
|
+
},
|
|
12041
|
+
episodeToReference: {
|
|
12042
|
+
minAccessCount: 10,
|
|
12043
|
+
minConfidence: 0.9,
|
|
12044
|
+
minAgeDays: 7
|
|
12045
|
+
}
|
|
12046
|
+
};
|
|
12047
|
+
var ARCHIVE_THRESHOLD = 0.3;
|
|
12048
|
+
var STALE_DAYS = 90;
|
|
12049
|
+
var STALE_MIN_ACCESS = 3;
|
|
12050
|
+
function computeDecayScore(tier, lastAccessedAt, accessCount) {
|
|
12051
|
+
const halfLife = DECAY_HALF_LIVES[tier];
|
|
12052
|
+
const now = Date.now();
|
|
12053
|
+
let daysSinceAccess = 0;
|
|
12054
|
+
if (lastAccessedAt) {
|
|
12055
|
+
daysSinceAccess = (now - new Date(lastAccessedAt).getTime()) / (1000 * 60 * 60 * 24);
|
|
12056
|
+
}
|
|
12057
|
+
const timeDecay = 0.5 ** (daysSinceAccess / halfLife);
|
|
12058
|
+
const accessBonus = Math.log10(accessCount + 1) * 0.1;
|
|
12059
|
+
const score = Math.min(timeDecay + accessBonus, 1);
|
|
12060
|
+
return { score, daysSinceAccess, halfLife, accessBonus };
|
|
12061
|
+
}
|
|
12062
|
+
function checkPromotion(currentTier, accessCount, confidence, createdAt) {
|
|
12063
|
+
const ageDays = (Date.now() - new Date(createdAt).getTime()) / (1000 * 60 * 60 * 24);
|
|
12064
|
+
const base = {
|
|
12065
|
+
eligible: false,
|
|
12066
|
+
targetTier: null,
|
|
12067
|
+
reason: null,
|
|
12068
|
+
currentTier,
|
|
12069
|
+
accessCount,
|
|
12070
|
+
confidence,
|
|
12071
|
+
ageDays
|
|
12072
|
+
};
|
|
12073
|
+
if (currentTier === "draft") {
|
|
12074
|
+
const rules = PROMOTION_RULES.draftToEpisode;
|
|
12075
|
+
if (accessCount >= rules.minAccessCount && confidence >= rules.minConfidence && ageDays >= rules.minAgeDays) {
|
|
12076
|
+
return {
|
|
12077
|
+
...base,
|
|
12078
|
+
eligible: true,
|
|
12079
|
+
targetTier: "episode",
|
|
12080
|
+
reason: `Accessed ${accessCount} times (≥${rules.minAccessCount}), confidence ${confidence} (≥${rules.minConfidence}), age ${Math.round(ageDays)}d (≥${rules.minAgeDays}d)`
|
|
12081
|
+
};
|
|
12082
|
+
}
|
|
12083
|
+
}
|
|
12084
|
+
if (currentTier === "episode") {
|
|
12085
|
+
const rules = PROMOTION_RULES.episodeToReference;
|
|
12086
|
+
if (accessCount >= rules.minAccessCount && confidence >= rules.minConfidence && ageDays >= rules.minAgeDays) {
|
|
12087
|
+
return {
|
|
12088
|
+
...base,
|
|
12089
|
+
eligible: true,
|
|
12090
|
+
targetTier: "reference",
|
|
12091
|
+
reason: `Accessed ${accessCount} times (≥${rules.minAccessCount}), confidence ${confidence} (≥${rules.minConfidence}), age ${Math.round(ageDays)}d (≥${rules.minAgeDays}d)`
|
|
12092
|
+
};
|
|
12093
|
+
}
|
|
12094
|
+
}
|
|
12095
|
+
return base;
|
|
12096
|
+
}
|
|
12097
|
+
function evaluateLifecycle(entity) {
|
|
12098
|
+
const decay = computeDecayScore(entity.memory_tier, entity.last_accessed_at, entity.access_count);
|
|
12099
|
+
const promotion = checkPromotion(entity.memory_tier, entity.access_count, entity.confidence, entity.created_at);
|
|
12100
|
+
const shouldArchive = entity.confidence < ARCHIVE_THRESHOLD;
|
|
12101
|
+
const archiveReason = shouldArchive ? `Confidence ${entity.confidence} below threshold ${ARCHIVE_THRESHOLD}` : undefined;
|
|
12102
|
+
const shouldFlagForReview = decay.daysSinceAccess >= STALE_DAYS && entity.access_count < STALE_MIN_ACCESS;
|
|
12103
|
+
const reviewReason = shouldFlagForReview ? `Not accessed in ${Math.round(decay.daysSinceAccess)} days with only ${entity.access_count} accesses` : undefined;
|
|
12104
|
+
return {
|
|
12105
|
+
decay,
|
|
12106
|
+
promotion,
|
|
12107
|
+
shouldArchive,
|
|
12108
|
+
shouldFlagForReview,
|
|
12109
|
+
archiveReason,
|
|
12110
|
+
reviewReason
|
|
12111
|
+
};
|
|
12112
|
+
}
|
|
12113
|
+
function buildContradictionQuery(type, tags) {
|
|
12114
|
+
if (tags.length === 0)
|
|
12115
|
+
return null;
|
|
12116
|
+
return { type, tags };
|
|
12117
|
+
}
|
|
12118
|
+
// ../memory/src/sync.ts
|
|
12119
|
+
import { createHash } from "node:crypto";
|
|
12120
|
+
import {
|
|
12121
|
+
existsSync,
|
|
12122
|
+
mkdirSync,
|
|
12123
|
+
readdirSync,
|
|
12124
|
+
readFileSync,
|
|
12125
|
+
rmSync,
|
|
12126
|
+
writeFileSync
|
|
12127
|
+
} from "node:fs";
|
|
12128
|
+
import { join, relative, sep } from "node:path";
|
|
12129
|
+
|
|
11949
12130
|
// ../memory/src/sync-storage.ts
|
|
11950
12131
|
function parseSyncMarkdown(markdown) {
|
|
11951
12132
|
const trimmed = markdown.trim();
|
|
@@ -12061,17 +12242,8 @@ function parseYamlArray(value) {
|
|
|
12061
12242
|
return [];
|
|
12062
12243
|
return match[1].split(",").map((s) => s.trim()).filter(Boolean);
|
|
12063
12244
|
}
|
|
12245
|
+
|
|
12064
12246
|
// ../memory/src/sync.ts
|
|
12065
|
-
import { createHash } from "node:crypto";
|
|
12066
|
-
import {
|
|
12067
|
-
existsSync,
|
|
12068
|
-
mkdirSync,
|
|
12069
|
-
readdirSync,
|
|
12070
|
-
readFileSync,
|
|
12071
|
-
rmSync,
|
|
12072
|
-
writeFileSync
|
|
12073
|
-
} from "node:fs";
|
|
12074
|
-
import { join, relative, sep } from "node:path";
|
|
12075
12247
|
function computeFileHash(content) {
|
|
12076
12248
|
return `sha256:${createHash("sha256").update(content).digest("hex")}`;
|
|
12077
12249
|
}
|
|
@@ -12333,177 +12505,6 @@ async function syncFull(client, config, workspaceId, projectId) {
|
|
|
12333
12505
|
errors: [...pullResult.errors, ...pushResult.errors]
|
|
12334
12506
|
};
|
|
12335
12507
|
}
|
|
12336
|
-
// ../memory/src/lifecycle.ts
|
|
12337
|
-
var DECAY_HALF_LIVES = {
|
|
12338
|
-
draft: 7,
|
|
12339
|
-
episode: 30,
|
|
12340
|
-
reference: 180
|
|
12341
|
-
};
|
|
12342
|
-
var PROMOTION_RULES = {
|
|
12343
|
-
draftToEpisode: {
|
|
12344
|
-
minAccessCount: 5,
|
|
12345
|
-
minConfidence: 0.8,
|
|
12346
|
-
minAgeDays: 1
|
|
12347
|
-
},
|
|
12348
|
-
episodeToReference: {
|
|
12349
|
-
minAccessCount: 10,
|
|
12350
|
-
minConfidence: 0.9,
|
|
12351
|
-
minAgeDays: 7
|
|
12352
|
-
}
|
|
12353
|
-
};
|
|
12354
|
-
var ARCHIVE_THRESHOLD = 0.3;
|
|
12355
|
-
var STALE_DAYS = 90;
|
|
12356
|
-
var STALE_MIN_ACCESS = 3;
|
|
12357
|
-
function computeDecayScore(tier, lastAccessedAt, accessCount) {
|
|
12358
|
-
const halfLife = DECAY_HALF_LIVES[tier];
|
|
12359
|
-
const now = Date.now();
|
|
12360
|
-
let daysSinceAccess = 0;
|
|
12361
|
-
if (lastAccessedAt) {
|
|
12362
|
-
daysSinceAccess = (now - new Date(lastAccessedAt).getTime()) / (1000 * 60 * 60 * 24);
|
|
12363
|
-
}
|
|
12364
|
-
const timeDecay = Math.pow(0.5, daysSinceAccess / halfLife);
|
|
12365
|
-
const accessBonus = Math.log10(accessCount + 1) * 0.1;
|
|
12366
|
-
const score = Math.min(timeDecay + accessBonus, 1);
|
|
12367
|
-
return { score, daysSinceAccess, halfLife, accessBonus };
|
|
12368
|
-
}
|
|
12369
|
-
function checkPromotion(currentTier, accessCount, confidence, createdAt) {
|
|
12370
|
-
const ageDays = (Date.now() - new Date(createdAt).getTime()) / (1000 * 60 * 60 * 24);
|
|
12371
|
-
const base = {
|
|
12372
|
-
eligible: false,
|
|
12373
|
-
targetTier: null,
|
|
12374
|
-
reason: null,
|
|
12375
|
-
currentTier,
|
|
12376
|
-
accessCount,
|
|
12377
|
-
confidence,
|
|
12378
|
-
ageDays
|
|
12379
|
-
};
|
|
12380
|
-
if (currentTier === "draft") {
|
|
12381
|
-
const rules = PROMOTION_RULES.draftToEpisode;
|
|
12382
|
-
if (accessCount >= rules.minAccessCount && confidence >= rules.minConfidence && ageDays >= rules.minAgeDays) {
|
|
12383
|
-
return {
|
|
12384
|
-
...base,
|
|
12385
|
-
eligible: true,
|
|
12386
|
-
targetTier: "episode",
|
|
12387
|
-
reason: `Accessed ${accessCount} times (≥${rules.minAccessCount}), confidence ${confidence} (≥${rules.minConfidence}), age ${Math.round(ageDays)}d (≥${rules.minAgeDays}d)`
|
|
12388
|
-
};
|
|
12389
|
-
}
|
|
12390
|
-
}
|
|
12391
|
-
if (currentTier === "episode") {
|
|
12392
|
-
const rules = PROMOTION_RULES.episodeToReference;
|
|
12393
|
-
if (accessCount >= rules.minAccessCount && confidence >= rules.minConfidence && ageDays >= rules.minAgeDays) {
|
|
12394
|
-
return {
|
|
12395
|
-
...base,
|
|
12396
|
-
eligible: true,
|
|
12397
|
-
targetTier: "reference",
|
|
12398
|
-
reason: `Accessed ${accessCount} times (≥${rules.minAccessCount}), confidence ${confidence} (≥${rules.minConfidence}), age ${Math.round(ageDays)}d (≥${rules.minAgeDays}d)`
|
|
12399
|
-
};
|
|
12400
|
-
}
|
|
12401
|
-
}
|
|
12402
|
-
return base;
|
|
12403
|
-
}
|
|
12404
|
-
function evaluateLifecycle(entity) {
|
|
12405
|
-
const decay = computeDecayScore(entity.memory_tier, entity.last_accessed_at, entity.access_count);
|
|
12406
|
-
const promotion = checkPromotion(entity.memory_tier, entity.access_count, entity.confidence, entity.created_at);
|
|
12407
|
-
const shouldArchive = entity.confidence < ARCHIVE_THRESHOLD;
|
|
12408
|
-
const archiveReason = shouldArchive ? `Confidence ${entity.confidence} below threshold ${ARCHIVE_THRESHOLD}` : undefined;
|
|
12409
|
-
const shouldFlagForReview = decay.daysSinceAccess >= STALE_DAYS && entity.access_count < STALE_MIN_ACCESS;
|
|
12410
|
-
const reviewReason = shouldFlagForReview ? `Not accessed in ${Math.round(decay.daysSinceAccess)} days with only ${entity.access_count} accesses` : undefined;
|
|
12411
|
-
return {
|
|
12412
|
-
decay,
|
|
12413
|
-
promotion,
|
|
12414
|
-
shouldArchive,
|
|
12415
|
-
shouldFlagForReview,
|
|
12416
|
-
archiveReason,
|
|
12417
|
-
reviewReason
|
|
12418
|
-
};
|
|
12419
|
-
}
|
|
12420
|
-
function buildContradictionQuery(type, tags) {
|
|
12421
|
-
if (tags.length === 0)
|
|
12422
|
-
return null;
|
|
12423
|
-
return { type, tags };
|
|
12424
|
-
}
|
|
12425
|
-
// ../memory/src/graph-walk.ts
|
|
12426
|
-
async function discoverRelatedContext(client, startIds, maxDepth = 2, maxEntities = 20, minConfidence = 0.5) {
|
|
12427
|
-
const visited = new Set;
|
|
12428
|
-
const collectedEntities = [];
|
|
12429
|
-
const collectedRelations = [];
|
|
12430
|
-
let truncated = false;
|
|
12431
|
-
const queue = startIds.map((id) => [id, 0]);
|
|
12432
|
-
for (const id of startIds) {
|
|
12433
|
-
visited.add(id);
|
|
12434
|
-
}
|
|
12435
|
-
while (queue.length > 0) {
|
|
12436
|
-
const [entityId, depth] = queue.shift();
|
|
12437
|
-
if (collectedEntities.length >= maxEntities) {
|
|
12438
|
-
truncated = true;
|
|
12439
|
-
break;
|
|
12440
|
-
}
|
|
12441
|
-
if (depth > maxDepth)
|
|
12442
|
-
continue;
|
|
12443
|
-
try {
|
|
12444
|
-
const entityResult = await client.getMemoryEntity(entityId);
|
|
12445
|
-
const entity = entityResult.entity;
|
|
12446
|
-
if (entity) {
|
|
12447
|
-
collectedEntities.push({
|
|
12448
|
-
id: entity.id,
|
|
12449
|
-
type: entity.type,
|
|
12450
|
-
title: entity.title,
|
|
12451
|
-
confidence: entity.confidence ?? 1,
|
|
12452
|
-
memory_tier: entity.memory_tier || "reference"
|
|
12453
|
-
});
|
|
12454
|
-
}
|
|
12455
|
-
if (depth >= maxDepth)
|
|
12456
|
-
continue;
|
|
12457
|
-
const related = await client.getRelatedEntities(entityId);
|
|
12458
|
-
for (const raw of related.outgoing || []) {
|
|
12459
|
-
const rel = raw;
|
|
12460
|
-
const relConfidence = rel.confidence ?? 1;
|
|
12461
|
-
if (relConfidence < minConfidence)
|
|
12462
|
-
continue;
|
|
12463
|
-
const target = rel.target;
|
|
12464
|
-
const targetId = target?.id ?? rel.target_id;
|
|
12465
|
-
if (targetId && !visited.has(targetId)) {
|
|
12466
|
-
visited.add(targetId);
|
|
12467
|
-
queue.push([targetId, depth + 1]);
|
|
12468
|
-
collectedRelations.push({
|
|
12469
|
-
id: rel.id,
|
|
12470
|
-
source_id: entityId,
|
|
12471
|
-
target_id: targetId,
|
|
12472
|
-
relation_type: rel.relation_type,
|
|
12473
|
-
confidence: relConfidence
|
|
12474
|
-
});
|
|
12475
|
-
}
|
|
12476
|
-
}
|
|
12477
|
-
for (const raw of related.incoming || []) {
|
|
12478
|
-
const rel = raw;
|
|
12479
|
-
const relConfidence = rel.confidence ?? 1;
|
|
12480
|
-
if (relConfidence < minConfidence)
|
|
12481
|
-
continue;
|
|
12482
|
-
const source = rel.source;
|
|
12483
|
-
const sourceId = source?.id ?? rel.source_id;
|
|
12484
|
-
if (sourceId && !visited.has(sourceId)) {
|
|
12485
|
-
visited.add(sourceId);
|
|
12486
|
-
queue.push([sourceId, depth + 1]);
|
|
12487
|
-
collectedRelations.push({
|
|
12488
|
-
id: rel.id,
|
|
12489
|
-
source_id: sourceId,
|
|
12490
|
-
target_id: entityId,
|
|
12491
|
-
relation_type: rel.relation_type,
|
|
12492
|
-
confidence: relConfidence
|
|
12493
|
-
});
|
|
12494
|
-
}
|
|
12495
|
-
}
|
|
12496
|
-
} catch {
|
|
12497
|
-
continue;
|
|
12498
|
-
}
|
|
12499
|
-
}
|
|
12500
|
-
return {
|
|
12501
|
-
entities: collectedEntities,
|
|
12502
|
-
relations: collectedRelations,
|
|
12503
|
-
depth: maxDepth,
|
|
12504
|
-
truncated
|
|
12505
|
-
};
|
|
12506
|
-
}
|
|
12507
12508
|
// ../../node_modules/zod/v4/core/index.js
|
|
12508
12509
|
var exports_core2 = {};
|
|
12509
12510
|
__export(exports_core2, {
|
|
@@ -28491,7 +28492,7 @@ function getMemoryDir() {
|
|
|
28491
28492
|
}
|
|
28492
28493
|
|
|
28493
28494
|
// src/graph-expansion.ts
|
|
28494
|
-
async function autoExpandGraph(client2, entityId, title, content,
|
|
28495
|
+
async function autoExpandGraph(client2, entityId, title, content, _tags, workspaceId, projectId, maxRelations = 5) {
|
|
28495
28496
|
try {
|
|
28496
28497
|
const contentSnippet = content.slice(0, 200).trim();
|
|
28497
28498
|
const query = [title, contentSnippet].filter(Boolean).join(" ");
|
|
@@ -28569,7 +28570,11 @@ Agent: ${session.agentName}`
|
|
|
28569
28570
|
type: "lesson",
|
|
28570
28571
|
tier: "episode",
|
|
28571
28572
|
confidence: 0.7,
|
|
28572
|
-
tags: [
|
|
28573
|
+
tags: [
|
|
28574
|
+
"auto-extracted",
|
|
28575
|
+
"session-summary",
|
|
28576
|
+
...session.cardLabels.slice(0, 3)
|
|
28577
|
+
],
|
|
28573
28578
|
metadata: {
|
|
28574
28579
|
source: "active_learning",
|
|
28575
28580
|
card_id: session.cardId,
|
|
@@ -28763,7 +28768,7 @@ function isRetryableError(error48, status) {
|
|
|
28763
28768
|
return msg.includes("ECONNRESET") || msg.includes("ETIMEDOUT") || msg.includes("fetch failed");
|
|
28764
28769
|
}
|
|
28765
28770
|
function getRetryDelay(attempt) {
|
|
28766
|
-
const delay = Math.min(RETRY_CONFIG.baseDelayMs *
|
|
28771
|
+
const delay = Math.min(RETRY_CONFIG.baseDelayMs * 2 ** attempt, RETRY_CONFIG.maxDelayMs);
|
|
28767
28772
|
return Math.round(delay + delay * 0.25 * (Math.random() * 2 - 1));
|
|
28768
28773
|
}
|
|
28769
28774
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -28882,7 +28887,6 @@ class HarmonyApiClient {
|
|
|
28882
28887
|
throw lastError;
|
|
28883
28888
|
if (attempt < RETRY_CONFIG.maxRetries) {
|
|
28884
28889
|
await sleep(getRetryDelay(attempt));
|
|
28885
|
-
continue;
|
|
28886
28890
|
}
|
|
28887
28891
|
}
|
|
28888
28892
|
}
|
|
@@ -28929,7 +28933,6 @@ class HarmonyApiClient {
|
|
|
28929
28933
|
throw lastError;
|
|
28930
28934
|
if (attempt < RETRY_CONFIG.maxRetries) {
|
|
28931
28935
|
await sleep(getRetryDelay(attempt));
|
|
28932
|
-
continue;
|
|
28933
28936
|
}
|
|
28934
28937
|
}
|
|
28935
28938
|
}
|
|
@@ -29327,7 +29330,7 @@ function computeRelevanceScore(entity, taskContext, cardLabels) {
|
|
|
29327
29330
|
if (entity.last_accessed_at) {
|
|
29328
29331
|
const daysSinceAccess = (Date.now() - new Date(entity.last_accessed_at).getTime()) / (1000 * 60 * 60 * 24);
|
|
29329
29332
|
const halfLife = { draft: 7, episode: 30, reference: 180 }[entity.memory_tier];
|
|
29330
|
-
const recencyScore =
|
|
29333
|
+
const recencyScore = 0.5 ** (daysSinceAccess / halfLife) * 0.1;
|
|
29331
29334
|
score += recencyScore;
|
|
29332
29335
|
if (daysSinceAccess < 7)
|
|
29333
29336
|
reasons.push("recently_accessed");
|
|
@@ -29404,7 +29407,11 @@ async function assembleContext(options) {
|
|
|
29404
29407
|
episode: Math.floor(tokenBudget * TIER_BUDGET_ALLOCATION.episode),
|
|
29405
29408
|
draft: Math.floor(tokenBudget * TIER_BUDGET_ALLOCATION.draft)
|
|
29406
29409
|
};
|
|
29407
|
-
const tierUsed = {
|
|
29410
|
+
const tierUsed = {
|
|
29411
|
+
reference: 0,
|
|
29412
|
+
episode: 0,
|
|
29413
|
+
draft: 0
|
|
29414
|
+
};
|
|
29408
29415
|
const included = [];
|
|
29409
29416
|
let totalUsed = 0;
|
|
29410
29417
|
let referenceCount = 0;
|
|
@@ -29474,9 +29481,18 @@ ${text}`);
|
|
|
29474
29481
|
}
|
|
29475
29482
|
manifest.budgetUsed = totalUsed;
|
|
29476
29483
|
manifest.tierBreakdown = {
|
|
29477
|
-
reference: {
|
|
29478
|
-
|
|
29479
|
-
|
|
29484
|
+
reference: {
|
|
29485
|
+
count: included.filter((i) => i.entity.memory_tier === "reference").length,
|
|
29486
|
+
tokens: tierUsed.reference
|
|
29487
|
+
},
|
|
29488
|
+
episode: {
|
|
29489
|
+
count: included.filter((i) => i.entity.memory_tier === "episode").length,
|
|
29490
|
+
tokens: tierUsed.episode
|
|
29491
|
+
},
|
|
29492
|
+
draft: {
|
|
29493
|
+
count: included.filter((i) => i.entity.memory_tier === "draft").length,
|
|
29494
|
+
tokens: tierUsed.draft
|
|
29495
|
+
}
|
|
29480
29496
|
};
|
|
29481
29497
|
for (const item of included) {
|
|
29482
29498
|
manifest.included.push({
|
|
@@ -29768,7 +29784,15 @@ ${lines.join(`
|
|
|
29768
29784
|
`)}`;
|
|
29769
29785
|
}
|
|
29770
29786
|
function generatePrompt(options) {
|
|
29771
|
-
const {
|
|
29787
|
+
const {
|
|
29788
|
+
card,
|
|
29789
|
+
column,
|
|
29790
|
+
variant,
|
|
29791
|
+
customConstraints,
|
|
29792
|
+
memories,
|
|
29793
|
+
assembledContext,
|
|
29794
|
+
assemblyId
|
|
29795
|
+
} = options;
|
|
29772
29796
|
const contextOpts = {
|
|
29773
29797
|
includeTitle: true,
|
|
29774
29798
|
includeDescription: true,
|
|
@@ -29922,7 +29946,8 @@ var TOOLS = {
|
|
|
29922
29946
|
description: { type: "string" },
|
|
29923
29947
|
priority: { type: "string", enum: ["low", "medium", "high", "urgent"] },
|
|
29924
29948
|
assigneeId: { type: "string", nullable: true },
|
|
29925
|
-
dueDate: { type: "string", nullable: true }
|
|
29949
|
+
dueDate: { type: "string", nullable: true },
|
|
29950
|
+
done: { type: "boolean", description: "Mark card as done or not done" }
|
|
29926
29951
|
},
|
|
29927
29952
|
required: ["cardId"]
|
|
29928
29953
|
}
|
|
@@ -31242,7 +31267,8 @@ async function handleToolCall(name, args, deps) {
|
|
|
31242
31267
|
description: args.description,
|
|
31243
31268
|
priority: args.priority,
|
|
31244
31269
|
assigneeId: args.assigneeId,
|
|
31245
|
-
dueDate: args.dueDate
|
|
31270
|
+
dueDate: args.dueDate,
|
|
31271
|
+
done: args.done
|
|
31246
31272
|
});
|
|
31247
31273
|
return { success: true, ...result };
|
|
31248
31274
|
}
|
|
@@ -32059,7 +32085,7 @@ async function handleToolCall(name, args, deps) {
|
|
|
32059
32085
|
const card = cardResult.card;
|
|
32060
32086
|
await client3.updatePlanTask(planId, task.id, { cardId: card.id });
|
|
32061
32087
|
cardsCreated++;
|
|
32062
|
-
} catch (
|
|
32088
|
+
} catch (_e) {}
|
|
32063
32089
|
}
|
|
32064
32090
|
results.cardsCreated = cardsCreated;
|
|
32065
32091
|
}
|