@goondocks/myco 0.4.3 → 0.4.4
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-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/dist/chunk-2AMAOSRF.js +105 -0
- package/dist/chunk-2AMAOSRF.js.map +1 -0
- package/dist/chunk-3F63SFZZ.js +381 -0
- package/dist/chunk-3F63SFZZ.js.map +1 -0
- package/dist/{chunk-WBT5DWGC.js → chunk-42R7KVAW.js} +2 -2
- package/dist/{chunk-GFBG73P4.js → chunk-5FIIK27E.js} +3 -3
- package/dist/{chunk-XCPQHC4X.js → chunk-6CAKKNGD.js} +2 -2
- package/dist/{chunk-I7PNZEBO.js → chunk-6LTNFMXO.js} +12 -1
- package/dist/{chunk-I7PNZEBO.js.map → chunk-6LTNFMXO.js.map} +1 -1
- package/dist/{chunk-V2OWD2VV.js → chunk-DKHYIA2V.js} +24 -146
- package/dist/chunk-DKHYIA2V.js.map +1 -0
- package/dist/{chunk-BNIYWCST.js → chunk-EQVQEFOA.js} +2 -2
- package/dist/{chunk-FPEDTLQ6.js → chunk-JJL6AMDA.js} +3 -101
- package/dist/chunk-JJL6AMDA.js.map +1 -0
- package/dist/{chunk-OUFSLZTX.js → chunk-KDWBZSOB.js} +21 -9
- package/dist/chunk-KDWBZSOB.js.map +1 -0
- package/dist/{chunk-67R6EMYD.js → chunk-OPO47BVS.js} +31 -52
- package/dist/chunk-OPO47BVS.js.map +1 -0
- package/dist/{chunk-IYFKPSRP.js → chunk-OSZRLHIJ.js} +3 -3
- package/dist/chunk-PD7LV22R.js +150 -0
- package/dist/chunk-PD7LV22R.js.map +1 -0
- package/dist/{chunk-JBD5KP5G.js → chunk-TDLQBGKA.js} +6 -2
- package/dist/chunk-TDLQBGKA.js.map +1 -0
- package/dist/{chunk-2GJFTIWX.js → chunk-TK2ZYIAL.js} +2 -2
- package/dist/{chunk-ZCBL5HER.js → chunk-XIIVIMFC.js} +2 -2
- package/dist/{cli-PMOFCZQL.js → cli-WOM4Z2Z4.js} +21 -18
- package/dist/cli-WOM4Z2Z4.js.map +1 -0
- package/dist/{client-5SUO2UYH.js → client-XCNF6NFT.js} +5 -5
- package/dist/{detect-providers-IRL2TTLK.js → detect-providers-CQSPTW2B.js} +3 -3
- package/dist/digest-WTS6S4XP.js +96 -0
- package/dist/digest-WTS6S4XP.js.map +1 -0
- package/dist/{init-NUF5UBUJ.js → init-VPLUEULI.js} +5 -5
- package/dist/{main-2XEBVUR6.js → main-OGXH6XWO.js} +230 -575
- package/dist/main-OGXH6XWO.js.map +1 -0
- package/dist/{rebuild-E6YFIRYZ.js → rebuild-Z4YUY6HT.js} +8 -7
- package/dist/{rebuild-E6YFIRYZ.js.map → rebuild-Z4YUY6HT.js.map} +1 -1
- package/dist/{reprocess-7G7KQWCN.js → reprocess-DMGPZTLC.js} +91 -20
- package/dist/reprocess-DMGPZTLC.js.map +1 -0
- package/dist/{restart-ABW4ZK3P.js → restart-QCQQ55KX.js} +6 -6
- package/dist/{search-MPD7SFK6.js → search-ACEFQOUW.js} +6 -6
- package/dist/{server-NZLZRITH.js → server-BQ3DWKZ6.js} +16 -14
- package/dist/{server-NZLZRITH.js.map → server-BQ3DWKZ6.js.map} +1 -1
- package/dist/{session-start-YB4A4PZB.js → session-start-BXRTKS4X.js} +6 -6
- package/dist/{setup-digest-K732MGOJ.js → setup-digest-EJXSQGZ5.js} +5 -5
- package/dist/{setup-llm-XCCH5LYD.js → setup-llm-P3MLWUDR.js} +5 -5
- package/dist/src/cli.js +4 -4
- package/dist/src/daemon/main.js +4 -4
- package/dist/src/hooks/post-tool-use.js +5 -5
- package/dist/src/hooks/session-end.js +5 -5
- package/dist/src/hooks/session-start.js +4 -4
- package/dist/src/hooks/stop.js +6 -6
- package/dist/src/hooks/stop.js.map +1 -1
- package/dist/src/hooks/user-prompt-submit.js +5 -5
- package/dist/src/mcp/server.js +4 -4
- package/dist/src/prompts/extraction.md +1 -1
- package/dist/src/prompts/summary.md +1 -11
- package/dist/{stats-6G7SN5YZ.js → stats-3FAP5FKV.js} +5 -5
- package/dist/{verify-JFHQH55Z.js → verify-3FTCOULE.js} +4 -4
- package/dist/{version-5B2TWXQJ.js → version-AL67JH7X.js} +4 -4
- package/package.json +1 -1
- package/skills/setup/SKILL.md +56 -28
- package/skills/setup/references/model-recommendations.md +49 -43
- package/dist/chunk-67R6EMYD.js.map +0 -1
- package/dist/chunk-FPEDTLQ6.js.map +0 -1
- package/dist/chunk-JBD5KP5G.js.map +0 -1
- package/dist/chunk-OUFSLZTX.js.map +0 -1
- package/dist/chunk-V2OWD2VV.js.map +0 -1
- package/dist/cli-PMOFCZQL.js.map +0 -1
- package/dist/main-2XEBVUR6.js.map +0 -1
- package/dist/reprocess-7G7KQWCN.js.map +0 -1
- /package/dist/{chunk-WBT5DWGC.js.map → chunk-42R7KVAW.js.map} +0 -0
- /package/dist/{chunk-GFBG73P4.js.map → chunk-5FIIK27E.js.map} +0 -0
- /package/dist/{chunk-XCPQHC4X.js.map → chunk-6CAKKNGD.js.map} +0 -0
- /package/dist/{chunk-BNIYWCST.js.map → chunk-EQVQEFOA.js.map} +0 -0
- /package/dist/{chunk-IYFKPSRP.js.map → chunk-OSZRLHIJ.js.map} +0 -0
- /package/dist/{chunk-2GJFTIWX.js.map → chunk-TK2ZYIAL.js.map} +0 -0
- /package/dist/{chunk-ZCBL5HER.js.map → chunk-XIIVIMFC.js.map} +0 -0
- /package/dist/{client-5SUO2UYH.js.map → client-XCNF6NFT.js.map} +0 -0
- /package/dist/{detect-providers-IRL2TTLK.js.map → detect-providers-CQSPTW2B.js.map} +0 -0
- /package/dist/{init-NUF5UBUJ.js.map → init-VPLUEULI.js.map} +0 -0
- /package/dist/{restart-ABW4ZK3P.js.map → restart-QCQQ55KX.js.map} +0 -0
- /package/dist/{search-MPD7SFK6.js.map → search-ACEFQOUW.js.map} +0 -0
- /package/dist/{session-start-YB4A4PZB.js.map → session-start-BXRTKS4X.js.map} +0 -0
- /package/dist/{setup-digest-K732MGOJ.js.map → setup-digest-EJXSQGZ5.js.map} +0 -0
- /package/dist/{setup-llm-XCCH5LYD.js.map → setup-llm-P3MLWUDR.js.map} +0 -0
- /package/dist/{stats-6G7SN5YZ.js.map → stats-3FAP5FKV.js.map} +0 -0
- /package/dist/{verify-JFHQH55Z.js.map → verify-3FTCOULE.js.map} +0 -0
- /package/dist/{version-5B2TWXQJ.js.map → version-AL67JH7X.js.map} +0 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
external_exports
|
|
4
|
+
} from "./chunk-6UJWI4IW.js";
|
|
5
|
+
|
|
6
|
+
// src/vault/types.ts
|
|
7
|
+
var SessionFrontmatterSchema = external_exports.object({
|
|
8
|
+
type: external_exports.literal("session"),
|
|
9
|
+
id: external_exports.string(),
|
|
10
|
+
agent: external_exports.string(),
|
|
11
|
+
user: external_exports.string(),
|
|
12
|
+
started: external_exports.string(),
|
|
13
|
+
ended: external_exports.string().optional(),
|
|
14
|
+
parent: external_exports.string().optional(),
|
|
15
|
+
parent_reason: external_exports.string().optional(),
|
|
16
|
+
plan: external_exports.string().optional(),
|
|
17
|
+
// backward compat read path
|
|
18
|
+
plans: external_exports.array(external_exports.string()).optional(),
|
|
19
|
+
// new: multiple plans
|
|
20
|
+
branch: external_exports.string().optional(),
|
|
21
|
+
tags: external_exports.array(external_exports.string()).default([]),
|
|
22
|
+
tools_used: external_exports.number().int().optional(),
|
|
23
|
+
files_changed: external_exports.number().int().optional()
|
|
24
|
+
});
|
|
25
|
+
var PLAN_STATUSES = ["active", "in_progress", "completed", "abandoned"];
|
|
26
|
+
var PlanFrontmatterSchema = external_exports.object({
|
|
27
|
+
type: external_exports.literal("plan"),
|
|
28
|
+
id: external_exports.string(),
|
|
29
|
+
status: external_exports.enum(PLAN_STATUSES).default("active"),
|
|
30
|
+
created: external_exports.string(),
|
|
31
|
+
author: external_exports.string().optional(),
|
|
32
|
+
tags: external_exports.array(external_exports.string()).default([])
|
|
33
|
+
});
|
|
34
|
+
var OBSERVATION_TYPES = ["gotcha", "bug_fix", "decision", "discovery", "trade_off", "cross-cutting"];
|
|
35
|
+
var SPORE_STATUSES = ["active", "superseded", "archived"];
|
|
36
|
+
var SporeFrontmatterSchema = external_exports.object({
|
|
37
|
+
type: external_exports.literal("spore"),
|
|
38
|
+
id: external_exports.string(),
|
|
39
|
+
observation_type: external_exports.string(),
|
|
40
|
+
status: external_exports.enum(SPORE_STATUSES).default("active"),
|
|
41
|
+
session: external_exports.string().optional(),
|
|
42
|
+
plan: external_exports.string().optional(),
|
|
43
|
+
superseded_by: external_exports.string().optional(),
|
|
44
|
+
consolidated_from: external_exports.array(external_exports.string()).optional(),
|
|
45
|
+
created: external_exports.string(),
|
|
46
|
+
tags: external_exports.array(external_exports.string()).default([])
|
|
47
|
+
});
|
|
48
|
+
var ARTIFACT_TYPES = ["spec", "plan", "rfc", "doc", "other"];
|
|
49
|
+
var ArtifactFrontmatterSchema = external_exports.object({
|
|
50
|
+
type: external_exports.literal("artifact"),
|
|
51
|
+
id: external_exports.string(),
|
|
52
|
+
artifact_type: external_exports.enum(ARTIFACT_TYPES).default("other"),
|
|
53
|
+
source_path: external_exports.string(),
|
|
54
|
+
title: external_exports.string(),
|
|
55
|
+
last_captured_by: external_exports.string(),
|
|
56
|
+
created: external_exports.string(),
|
|
57
|
+
updated: external_exports.string(),
|
|
58
|
+
tags: external_exports.array(external_exports.string()).default([])
|
|
59
|
+
});
|
|
60
|
+
var TeamMemberFrontmatterSchema = external_exports.object({
|
|
61
|
+
type: external_exports.literal("team-member"),
|
|
62
|
+
user: external_exports.string(),
|
|
63
|
+
joined: external_exports.string(),
|
|
64
|
+
role: external_exports.string().optional(),
|
|
65
|
+
tags: external_exports.array(external_exports.string()).default([])
|
|
66
|
+
});
|
|
67
|
+
var schemasByType = {
|
|
68
|
+
session: SessionFrontmatterSchema,
|
|
69
|
+
plan: PlanFrontmatterSchema,
|
|
70
|
+
spore: SporeFrontmatterSchema,
|
|
71
|
+
artifact: ArtifactFrontmatterSchema,
|
|
72
|
+
"team-member": TeamMemberFrontmatterSchema
|
|
73
|
+
};
|
|
74
|
+
function parseNoteFrontmatter(data) {
|
|
75
|
+
const type = data.type;
|
|
76
|
+
const schema = schemasByType[type];
|
|
77
|
+
if (!schema) {
|
|
78
|
+
throw new Error(`Unknown note type: ${type}. Known types: ${Object.keys(schemasByType).join(", ")}`);
|
|
79
|
+
}
|
|
80
|
+
const coerced = coerceDatesToStrings(data);
|
|
81
|
+
return schema.parse(coerced);
|
|
82
|
+
}
|
|
83
|
+
function coerceDatesToStrings(obj) {
|
|
84
|
+
const result = {};
|
|
85
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
86
|
+
if (value instanceof Date) {
|
|
87
|
+
result[key] = value.toISOString();
|
|
88
|
+
} else if (Array.isArray(value)) {
|
|
89
|
+
result[key] = value.map((item) => item instanceof Date ? item.toISOString() : item);
|
|
90
|
+
} else if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
91
|
+
result[key] = coerceDatesToStrings(value);
|
|
92
|
+
} else {
|
|
93
|
+
result[key] = value;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export {
|
|
100
|
+
PLAN_STATUSES,
|
|
101
|
+
OBSERVATION_TYPES,
|
|
102
|
+
ARTIFACT_TYPES,
|
|
103
|
+
parseNoteFrontmatter
|
|
104
|
+
};
|
|
105
|
+
//# sourceMappingURL=chunk-2AMAOSRF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/vault/types.ts"],"sourcesContent":["import { z } from 'zod';\n\nexport const SessionFrontmatterSchema = z.object({\n type: z.literal('session'),\n id: z.string(),\n agent: z.string(),\n user: z.string(),\n started: z.string(),\n ended: z.string().optional(),\n parent: z.string().optional(),\n parent_reason: z.string().optional(),\n plan: z.string().optional(), // backward compat read path\n plans: z.array(z.string()).optional(), // new: multiple plans\n branch: z.string().optional(),\n tags: z.array(z.string()).default([]),\n tools_used: z.number().int().optional(),\n files_changed: z.number().int().optional(),\n});\n\nexport const PLAN_STATUSES = ['active', 'in_progress', 'completed', 'abandoned'] as const;\n\nexport const PlanFrontmatterSchema = z.object({\n type: z.literal('plan'),\n id: z.string(),\n status: z.enum(PLAN_STATUSES).default('active'),\n created: z.string(),\n author: z.string().optional(),\n tags: z.array(z.string()).default([]),\n});\n\nexport const OBSERVATION_TYPES = ['gotcha', 'bug_fix', 'decision', 'discovery', 'trade_off', 'cross-cutting'] as const;\n\nexport const SPORE_STATUSES = ['active', 'superseded', 'archived'] as const;\nexport type SporeStatus = (typeof SPORE_STATUSES)[number];\n\nexport const SporeFrontmatterSchema = z.object({\n type: z.literal('spore'),\n id: z.string(),\n observation_type: z.string(),\n status: z.enum(SPORE_STATUSES).default('active'),\n session: z.string().optional(),\n plan: z.string().optional(),\n superseded_by: z.string().optional(),\n consolidated_from: z.array(z.string()).optional(),\n created: z.string(),\n tags: z.array(z.string()).default([]),\n});\n\nexport const ARTIFACT_TYPES = ['spec', 'plan', 'rfc', 'doc', 'other'] as const;\nexport type ArtifactType = (typeof ARTIFACT_TYPES)[number];\n\nexport const ArtifactFrontmatterSchema = z.object({\n type: z.literal('artifact'),\n id: z.string(),\n artifact_type: z.enum(ARTIFACT_TYPES).default('other'),\n source_path: z.string(),\n title: z.string(),\n last_captured_by: z.string(),\n created: z.string(),\n updated: z.string(),\n tags: z.array(z.string()).default([]),\n});\n\nexport const TeamMemberFrontmatterSchema = z.object({\n type: z.literal('team-member'),\n user: z.string(),\n joined: z.string(),\n role: z.string().optional(),\n tags: z.array(z.string()).default([]),\n});\n\nexport type SessionFrontmatter = z.infer<typeof SessionFrontmatterSchema>;\nexport type PlanFrontmatter = z.infer<typeof PlanFrontmatterSchema>;\nexport type SporeFrontmatter = z.infer<typeof SporeFrontmatterSchema>;\nexport type ObservationType = SporeFrontmatter['observation_type'];\nexport type ArtifactFrontmatter = z.infer<typeof ArtifactFrontmatterSchema>;\nexport type TeamMemberFrontmatter = z.infer<typeof TeamMemberFrontmatterSchema>;\n\nexport type NoteFrontmatter =\n | SessionFrontmatter\n | PlanFrontmatter\n | SporeFrontmatter\n | ArtifactFrontmatter\n | TeamMemberFrontmatter;\n\nexport interface VaultNote<T extends NoteFrontmatter = NoteFrontmatter> {\n path: string;\n frontmatter: T;\n content: string;\n}\n\nconst schemasByType: Record<string, z.ZodSchema> = {\n session: SessionFrontmatterSchema,\n plan: PlanFrontmatterSchema,\n spore: SporeFrontmatterSchema,\n artifact: ArtifactFrontmatterSchema,\n 'team-member': TeamMemberFrontmatterSchema,\n};\n\nexport function parseNoteFrontmatter(data: Record<string, unknown>): NoteFrontmatter {\n const type = data.type as string;\n const schema = schemasByType[type];\n if (!schema) {\n throw new Error(`Unknown note type: ${type}. Known types: ${Object.keys(schemasByType).join(', ')}`);\n }\n // gray-matter and YAML.parse return Date objects for ISO date strings.\n // Coerce them to strings before Zod validation.\n const coerced = coerceDatesToStrings(data);\n return schema.parse(coerced) as NoteFrontmatter;\n}\n\nfunction coerceDatesToStrings(obj: Record<string, unknown>): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n if (value instanceof Date) {\n result[key] = value.toISOString();\n } else if (Array.isArray(value)) {\n result[key] = value.map((item) => item instanceof Date ? item.toISOString() : item);\n } else if (value !== null && typeof value === 'object' && !Array.isArray(value)) {\n result[key] = coerceDatesToStrings(value as Record<string, unknown>);\n } else {\n result[key] = value;\n }\n }\n return result;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
loadPrompt,
|
|
4
|
+
stripReasoningTokens
|
|
5
|
+
} from "./chunk-PD7LV22R.js";
|
|
6
|
+
import {
|
|
7
|
+
stripFrontmatter
|
|
8
|
+
} from "./chunk-MIU3DKLN.js";
|
|
9
|
+
import {
|
|
10
|
+
require_dist
|
|
11
|
+
} from "./chunk-6UJWI4IW.js";
|
|
12
|
+
import {
|
|
13
|
+
CHARS_PER_TOKEN,
|
|
14
|
+
DIGEST_LLM_REQUEST_TIMEOUT_MS,
|
|
15
|
+
DIGEST_SUBSTRATE_TYPE_WEIGHTS,
|
|
16
|
+
DIGEST_TIER_MIN_CONTEXT,
|
|
17
|
+
LLM_REASONING_MODE,
|
|
18
|
+
estimateTokens
|
|
19
|
+
} from "./chunk-TDLQBGKA.js";
|
|
20
|
+
import {
|
|
21
|
+
__toESM
|
|
22
|
+
} from "./chunk-PZUWP5VK.js";
|
|
23
|
+
|
|
24
|
+
// src/daemon/digest.ts
|
|
25
|
+
var import_yaml = __toESM(require_dist(), 1);
|
|
26
|
+
import fs from "fs";
|
|
27
|
+
import path from "path";
|
|
28
|
+
import crypto from "crypto";
|
|
29
|
+
var PREVIOUS_EXTRACT_OVERHEAD_TOKENS = 50;
|
|
30
|
+
var CONTEXT_SAFETY_MARGIN = 0.7;
|
|
31
|
+
var EXTRACT_TYPE = "extract";
|
|
32
|
+
var DigestEngine = class {
|
|
33
|
+
vaultDir;
|
|
34
|
+
index;
|
|
35
|
+
llm;
|
|
36
|
+
config;
|
|
37
|
+
log;
|
|
38
|
+
lastCycleTimestampCache = void 0;
|
|
39
|
+
cycleInProgress = false;
|
|
40
|
+
constructor(engineConfig) {
|
|
41
|
+
this.vaultDir = engineConfig.vaultDir;
|
|
42
|
+
this.index = engineConfig.index;
|
|
43
|
+
this.llm = engineConfig.llmProvider;
|
|
44
|
+
this.config = engineConfig.config;
|
|
45
|
+
this.log = engineConfig.log ?? (() => {
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Query index for recent vault notes to feed into the digest.
|
|
50
|
+
* Filters out extract notes (our own output) and caps at max_notes_per_cycle.
|
|
51
|
+
*/
|
|
52
|
+
discoverSubstrate(lastCycleTimestamp) {
|
|
53
|
+
const maxNotes = this.config.digest.substrate.max_notes_per_cycle;
|
|
54
|
+
const notes = lastCycleTimestamp ? this.index.query({ updatedSince: lastCycleTimestamp, limit: maxNotes }) : this.index.query({ limit: maxNotes });
|
|
55
|
+
const filtered = notes.filter((n) => n.type !== EXTRACT_TYPE);
|
|
56
|
+
filtered.sort((a, b) => {
|
|
57
|
+
const weightA = DIGEST_SUBSTRATE_TYPE_WEIGHTS[a.type] ?? 0;
|
|
58
|
+
const weightB = DIGEST_SUBSTRATE_TYPE_WEIGHTS[b.type] ?? 0;
|
|
59
|
+
if (weightB !== weightA) return weightB - weightA;
|
|
60
|
+
return b.created.localeCompare(a.created);
|
|
61
|
+
});
|
|
62
|
+
return filtered.slice(0, maxNotes);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Filter configured tiers by the context window available.
|
|
66
|
+
* Only tiers whose minimum context requirement is met are eligible.
|
|
67
|
+
*/
|
|
68
|
+
getEligibleTiers() {
|
|
69
|
+
const contextWindow = this.config.digest.intelligence.context_window;
|
|
70
|
+
return this.config.digest.tiers.filter((tier) => {
|
|
71
|
+
const minContext = DIGEST_TIER_MIN_CONTEXT[tier];
|
|
72
|
+
return minContext !== void 0 && minContext <= contextWindow;
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Format notes compactly for inclusion in the digest prompt.
|
|
77
|
+
* Stops adding notes once the token budget is exceeded.
|
|
78
|
+
*/
|
|
79
|
+
formatSubstrate(notes, tokenBudget) {
|
|
80
|
+
const charBudget = tokenBudget * CHARS_PER_TOKEN;
|
|
81
|
+
const parts = [];
|
|
82
|
+
let usedChars = 0;
|
|
83
|
+
for (const note of notes) {
|
|
84
|
+
const entry = `### [${note.type}] ${note.id} \u2014 "${note.title}"
|
|
85
|
+
${note.content}`;
|
|
86
|
+
if (usedChars + entry.length > charBudget && parts.length > 0) break;
|
|
87
|
+
parts.push(entry);
|
|
88
|
+
usedChars += entry.length;
|
|
89
|
+
}
|
|
90
|
+
return parts.join("\n\n");
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Read a previously generated extract for a given tier.
|
|
94
|
+
* Returns the body (stripped of YAML frontmatter), or null if not found.
|
|
95
|
+
*/
|
|
96
|
+
readPreviousExtract(tier) {
|
|
97
|
+
const extractPath = path.join(this.vaultDir, "digest", `extract-${tier}.md`);
|
|
98
|
+
let content;
|
|
99
|
+
try {
|
|
100
|
+
content = fs.readFileSync(extractPath, "utf-8");
|
|
101
|
+
} catch {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
return stripFrontmatter(content).body;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Write a digest extract to the vault with YAML frontmatter.
|
|
108
|
+
* Uses atomic write pattern (temp file + rename).
|
|
109
|
+
*/
|
|
110
|
+
writeExtract(tier, body, cycleId, model, substrateCount) {
|
|
111
|
+
const digestDir = path.join(this.vaultDir, "digest");
|
|
112
|
+
fs.mkdirSync(digestDir, { recursive: true });
|
|
113
|
+
const frontmatter = {
|
|
114
|
+
type: EXTRACT_TYPE,
|
|
115
|
+
tier,
|
|
116
|
+
generated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
117
|
+
cycle_id: cycleId,
|
|
118
|
+
substrate_count: substrateCount,
|
|
119
|
+
model
|
|
120
|
+
};
|
|
121
|
+
const fmYaml = import_yaml.default.stringify(frontmatter, {
|
|
122
|
+
defaultStringType: "QUOTE_DOUBLE",
|
|
123
|
+
defaultKeyType: "PLAIN"
|
|
124
|
+
}).trim();
|
|
125
|
+
const file = `---
|
|
126
|
+
${fmYaml}
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
${body}
|
|
130
|
+
`;
|
|
131
|
+
const fullPath = path.join(digestDir, `extract-${tier}.md`);
|
|
132
|
+
const tmpPath = `${fullPath}.tmp`;
|
|
133
|
+
fs.writeFileSync(tmpPath, file, "utf-8");
|
|
134
|
+
fs.renameSync(tmpPath, fullPath);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Append a digest cycle result as a JSON line to trace.jsonl.
|
|
138
|
+
*/
|
|
139
|
+
appendTrace(record) {
|
|
140
|
+
const digestDir = path.join(this.vaultDir, "digest");
|
|
141
|
+
fs.mkdirSync(digestDir, { recursive: true });
|
|
142
|
+
const tracePath = path.join(digestDir, "trace.jsonl");
|
|
143
|
+
fs.appendFileSync(tracePath, JSON.stringify(record) + "\n", "utf-8");
|
|
144
|
+
this.lastCycleTimestampCache = record.timestamp;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Read the last cycle timestamp from trace.jsonl.
|
|
148
|
+
* Cached in memory after first read — subsequent calls are O(1).
|
|
149
|
+
*/
|
|
150
|
+
getLastCycleTimestamp() {
|
|
151
|
+
if (this.lastCycleTimestampCache !== void 0) return this.lastCycleTimestampCache;
|
|
152
|
+
const tracePath = path.join(this.vaultDir, "digest", "trace.jsonl");
|
|
153
|
+
let content;
|
|
154
|
+
try {
|
|
155
|
+
content = fs.readFileSync(tracePath, "utf-8").trim();
|
|
156
|
+
} catch {
|
|
157
|
+
this.lastCycleTimestampCache = null;
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
if (!content) {
|
|
161
|
+
this.lastCycleTimestampCache = null;
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
const lines = content.split("\n");
|
|
165
|
+
const lastLine = lines[lines.length - 1];
|
|
166
|
+
try {
|
|
167
|
+
const record = JSON.parse(lastLine);
|
|
168
|
+
this.lastCycleTimestampCache = record.timestamp;
|
|
169
|
+
return record.timestamp;
|
|
170
|
+
} catch {
|
|
171
|
+
this.lastCycleTimestampCache = null;
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Run a full digest cycle: discover substrate, generate extracts for each tier.
|
|
177
|
+
* Returns the cycle result, or null if no substrate was found.
|
|
178
|
+
*/
|
|
179
|
+
async runCycle(opts) {
|
|
180
|
+
if (this.cycleInProgress) {
|
|
181
|
+
this.log("debug", "Cycle already in progress \u2014 skipping");
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
this.cycleInProgress = true;
|
|
185
|
+
try {
|
|
186
|
+
return await this.runCycleInternal(opts);
|
|
187
|
+
} finally {
|
|
188
|
+
this.cycleInProgress = false;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
async runCycleInternal(opts) {
|
|
192
|
+
if (this.llm.ensureLoaded) {
|
|
193
|
+
const { context_window: contextWindow, gpu_kv_cache: gpuKvCache } = this.config.digest.intelligence;
|
|
194
|
+
this.log("debug", "Verifying digest model", { contextWindow, gpuKvCache });
|
|
195
|
+
await this.llm.ensureLoaded(contextWindow, gpuKvCache);
|
|
196
|
+
}
|
|
197
|
+
const startTime = Date.now();
|
|
198
|
+
const fullReprocess = opts?.fullReprocess ?? false;
|
|
199
|
+
const lastTimestamp = fullReprocess ? null : this.getLastCycleTimestamp();
|
|
200
|
+
const substrate = this.discoverSubstrate(lastTimestamp);
|
|
201
|
+
this.log("debug", "Discovering substrate", { lastTimestamp: lastTimestamp ?? "full reprocess", substrateCount: substrate.length });
|
|
202
|
+
if (substrate.length === 0) {
|
|
203
|
+
this.log("debug", "No substrate found \u2014 skipping cycle");
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
this.log("info", `Starting digest cycle`, { substrateCount: substrate.length, fullReprocess });
|
|
207
|
+
const cycleId = crypto.randomUUID();
|
|
208
|
+
const allEligible = this.getEligibleTiers();
|
|
209
|
+
const eligibleTiers = opts?.tiers ? allEligible.filter((t) => opts.tiers.includes(t)) : allEligible;
|
|
210
|
+
this.log("debug", `Eligible tiers: [${eligibleTiers.join(", ")}]`);
|
|
211
|
+
const tiersGenerated = [];
|
|
212
|
+
let totalTokensUsed = 0;
|
|
213
|
+
let model = "";
|
|
214
|
+
const typeToKey = {
|
|
215
|
+
session: "sessions",
|
|
216
|
+
spore: "spores",
|
|
217
|
+
plan: "plans",
|
|
218
|
+
artifact: "artifacts",
|
|
219
|
+
"team-member": "team"
|
|
220
|
+
};
|
|
221
|
+
const substrateIndex = {
|
|
222
|
+
sessions: [],
|
|
223
|
+
spores: [],
|
|
224
|
+
plans: [],
|
|
225
|
+
artifacts: [],
|
|
226
|
+
team: []
|
|
227
|
+
};
|
|
228
|
+
for (const note of substrate) {
|
|
229
|
+
const key = typeToKey[note.type];
|
|
230
|
+
if (key) {
|
|
231
|
+
substrateIndex[key].push(note.id);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
const cycleTimestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
235
|
+
const systemPrompt = loadPrompt("digest-system");
|
|
236
|
+
for (const tier of eligibleTiers) {
|
|
237
|
+
const tierPrompt = loadPrompt(`digest-${tier}`);
|
|
238
|
+
const previousExtract = opts?.cleanSlate ? null : this.readPreviousExtract(tier);
|
|
239
|
+
const contextWindow = this.config.digest.intelligence.context_window;
|
|
240
|
+
const systemPromptTokens = estimateTokens(systemPrompt);
|
|
241
|
+
const tierPromptTokens = estimateTokens(tierPrompt);
|
|
242
|
+
const previousExtractTokens = previousExtract ? estimateTokens(previousExtract) + PREVIOUS_EXTRACT_OVERHEAD_TOKENS : 0;
|
|
243
|
+
const availableTokens = Math.floor(contextWindow * CONTEXT_SAFETY_MARGIN);
|
|
244
|
+
const substrateBudget = availableTokens - tier - systemPromptTokens - tierPromptTokens - previousExtractTokens;
|
|
245
|
+
if (substrateBudget <= 0) continue;
|
|
246
|
+
const formattedSubstrate = this.formatSubstrate(substrate, substrateBudget);
|
|
247
|
+
const promptParts = [tierPrompt];
|
|
248
|
+
if (previousExtract) {
|
|
249
|
+
promptParts.push("", "## Previous Synthesis", "", previousExtract);
|
|
250
|
+
}
|
|
251
|
+
promptParts.push("", "## New Substrate", "", formattedSubstrate);
|
|
252
|
+
promptParts.push(
|
|
253
|
+
"",
|
|
254
|
+
"---",
|
|
255
|
+
"Produce your updated synthesis now. Stay within the token budget specified above."
|
|
256
|
+
);
|
|
257
|
+
const userPrompt = promptParts.join("\n");
|
|
258
|
+
const promptTokens = estimateTokens(systemPrompt + userPrompt);
|
|
259
|
+
this.log("debug", `Tier ${tier}: sending LLM request`, { promptTokens, maxTokens: tier, substrateBudget });
|
|
260
|
+
try {
|
|
261
|
+
const tierStart = Date.now();
|
|
262
|
+
const digestConfig = this.config.digest.intelligence;
|
|
263
|
+
const opts2 = {
|
|
264
|
+
maxTokens: tier,
|
|
265
|
+
timeoutMs: DIGEST_LLM_REQUEST_TIMEOUT_MS,
|
|
266
|
+
contextLength: contextWindow,
|
|
267
|
+
reasoning: LLM_REASONING_MODE,
|
|
268
|
+
systemPrompt,
|
|
269
|
+
keepAlive: digestConfig.keep_alive ?? void 0
|
|
270
|
+
};
|
|
271
|
+
const response = await this.llm.summarize(userPrompt, opts2);
|
|
272
|
+
const tierDuration = Date.now() - tierStart;
|
|
273
|
+
const extractText = stripReasoningTokens(response.text);
|
|
274
|
+
model = response.model;
|
|
275
|
+
const responseTokens = estimateTokens(extractText);
|
|
276
|
+
totalTokensUsed += promptTokens + responseTokens;
|
|
277
|
+
this.log("info", `Tier ${tier}: completed`, { durationMs: tierDuration, responseTokens, model: response.model });
|
|
278
|
+
this.writeExtract(tier, extractText, cycleId, response.model, substrate.length);
|
|
279
|
+
tiersGenerated.push(tier);
|
|
280
|
+
} catch (err) {
|
|
281
|
+
this.log("warn", `Tier ${tier}: failed`, { error: err.message });
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
const result = {
|
|
285
|
+
cycleId,
|
|
286
|
+
timestamp: cycleTimestamp,
|
|
287
|
+
substrate: substrateIndex,
|
|
288
|
+
tiersGenerated,
|
|
289
|
+
model,
|
|
290
|
+
durationMs: Date.now() - startTime,
|
|
291
|
+
tokensUsed: totalTokensUsed
|
|
292
|
+
};
|
|
293
|
+
this.appendTrace(result);
|
|
294
|
+
return result;
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
var MS_PER_SECOND = 1e3;
|
|
298
|
+
var Metabolism = class {
|
|
299
|
+
state = "active";
|
|
300
|
+
currentIntervalMs;
|
|
301
|
+
cooldownStep = 0;
|
|
302
|
+
lastSubstrateTime;
|
|
303
|
+
timer = null;
|
|
304
|
+
activeIntervalMs;
|
|
305
|
+
cooldownIntervalsMs;
|
|
306
|
+
dormancyThresholdMs;
|
|
307
|
+
constructor(config) {
|
|
308
|
+
this.activeIntervalMs = config.active_interval * MS_PER_SECOND;
|
|
309
|
+
this.cooldownIntervalsMs = config.cooldown_intervals.map((s) => s * MS_PER_SECOND);
|
|
310
|
+
this.dormancyThresholdMs = config.dormancy_threshold * MS_PER_SECOND;
|
|
311
|
+
this.currentIntervalMs = this.activeIntervalMs;
|
|
312
|
+
this.lastSubstrateTime = Date.now();
|
|
313
|
+
}
|
|
314
|
+
/** Reset to active state when new substrate is found. */
|
|
315
|
+
onSubstrateFound() {
|
|
316
|
+
this.state = "active";
|
|
317
|
+
this.cooldownStep = 0;
|
|
318
|
+
this.currentIntervalMs = this.activeIntervalMs;
|
|
319
|
+
this.lastSubstrateTime = Date.now();
|
|
320
|
+
}
|
|
321
|
+
/** Advance cooldown when a cycle finds no new substrate. */
|
|
322
|
+
onEmptyCycle() {
|
|
323
|
+
if (this.state === "dormant") return;
|
|
324
|
+
this.state = "cooling";
|
|
325
|
+
if (this.cooldownStep < this.cooldownIntervalsMs.length) {
|
|
326
|
+
this.currentIntervalMs = this.cooldownIntervalsMs[this.cooldownStep];
|
|
327
|
+
this.cooldownStep++;
|
|
328
|
+
}
|
|
329
|
+
this.checkDormancy();
|
|
330
|
+
}
|
|
331
|
+
/** Enter dormant state if enough time has elapsed since last substrate. */
|
|
332
|
+
checkDormancy() {
|
|
333
|
+
const elapsed = Date.now() - this.lastSubstrateTime;
|
|
334
|
+
if (elapsed >= this.dormancyThresholdMs) {
|
|
335
|
+
this.state = "dormant";
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
/** Return to active from any state, resetting timers and rescheduling immediately. */
|
|
339
|
+
activate() {
|
|
340
|
+
this.onSubstrateFound();
|
|
341
|
+
if (this.callback) {
|
|
342
|
+
this.reschedule();
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
/** Set lastSubstrateTime explicitly (for testing). */
|
|
346
|
+
markLastSubstrate(time) {
|
|
347
|
+
this.lastSubstrateTime = time;
|
|
348
|
+
}
|
|
349
|
+
/** Begin scheduling digest cycles with adaptive intervals. */
|
|
350
|
+
start(callback) {
|
|
351
|
+
this.callback = callback;
|
|
352
|
+
this.reschedule();
|
|
353
|
+
}
|
|
354
|
+
/** Stop the timer. */
|
|
355
|
+
stop() {
|
|
356
|
+
if (this.timer) {
|
|
357
|
+
clearTimeout(this.timer);
|
|
358
|
+
this.timer = null;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
callback = null;
|
|
362
|
+
reschedule() {
|
|
363
|
+
this.stop();
|
|
364
|
+
if (!this.callback) return;
|
|
365
|
+
const cb = this.callback;
|
|
366
|
+
const schedule = () => {
|
|
367
|
+
this.timer = setTimeout(async () => {
|
|
368
|
+
await cb();
|
|
369
|
+
schedule();
|
|
370
|
+
}, this.currentIntervalMs);
|
|
371
|
+
this.timer.unref();
|
|
372
|
+
};
|
|
373
|
+
schedule();
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
export {
|
|
378
|
+
DigestEngine,
|
|
379
|
+
Metabolism
|
|
380
|
+
};
|
|
381
|
+
//# sourceMappingURL=chunk-3F63SFZZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/daemon/digest.ts"],"sourcesContent":["/**\n * DigestEngine — synthesizes vault knowledge into tiered context extracts.\n * Metabolism — adaptive timer that throttles digest cycles based on activity.\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport crypto from 'node:crypto';\nimport YAML from 'yaml';\n\nimport type { MycoIndex, IndexedNote } from '@myco/index/sqlite.js';\nimport type { LlmProvider, LlmRequestOptions } from '@myco/intelligence/llm.js';\nimport type { MycoConfig } from '@myco/config/schema.js';\nimport { loadPrompt } from '@myco/prompts/index.js';\nimport { stripReasoningTokens } from '@myco/intelligence/response.js';\nimport { stripFrontmatter } from '@myco/vault/frontmatter.js';\nimport {\n estimateTokens,\n CHARS_PER_TOKEN,\n DIGEST_TIER_MIN_CONTEXT,\n DIGEST_SUBSTRATE_TYPE_WEIGHTS,\n DIGEST_LLM_REQUEST_TIMEOUT_MS,\n LLM_REASONING_MODE,\n} from '@myco/constants.js';\n\n// --- Interfaces ---\n\nexport interface DigestCycleResult {\n cycleId: string;\n timestamp: string;\n substrate: {\n sessions: string[];\n spores: string[];\n plans: string[];\n artifacts: string[];\n team: string[];\n };\n tiersGenerated: number[];\n model: string;\n durationMs: number;\n tokensUsed: number;\n}\n\n/** Simple log function signature for digest progress reporting. */\nexport type DigestLogFn = (level: 'debug' | 'info' | 'warn', message: string, data?: Record<string, unknown>) => void;\n\nexport interface DigestCycleOptions {\n /** Process all substrate regardless of last cycle timestamp. */\n fullReprocess?: boolean;\n /** Only generate these tiers (default: all eligible). */\n tiers?: number[];\n /** Skip previous extract — start from clean slate. */\n cleanSlate?: boolean;\n}\n\nexport interface DigestEngineConfig {\n vaultDir: string;\n index: MycoIndex;\n llmProvider: LlmProvider;\n config: MycoConfig;\n log?: DigestLogFn;\n}\n\n// --- Constants ---\n\n/** Token overhead estimate for previous extract section wrapper. */\nconst PREVIOUS_EXTRACT_OVERHEAD_TOKENS = 50;\n\n/** Safety margin for context window — our CHARS_PER_TOKEN=4 heuristic significantly\n * underestimates real token counts (observed ~3.2 chars/token for mixed content).\n * 0.70 provides a safe buffer: 32K * 0.70 = 22.4K usable tokens. */\nconst CONTEXT_SAFETY_MARGIN = 0.70;\n\n/** Types that are digest output — excluded from substrate to avoid self-digestion. */\nconst EXTRACT_TYPE = 'extract';\n\n// --- DigestEngine ---\n\nexport class DigestEngine {\n private vaultDir: string;\n private index: MycoIndex;\n private llm: LlmProvider;\n private config: MycoConfig;\n private log: DigestLogFn;\n private lastCycleTimestampCache: string | null | undefined = undefined;\n private cycleInProgress = false;\n\n constructor(engineConfig: DigestEngineConfig) {\n this.vaultDir = engineConfig.vaultDir;\n this.index = engineConfig.index;\n this.llm = engineConfig.llmProvider;\n this.config = engineConfig.config;\n this.log = engineConfig.log ?? (() => {});\n }\n\n /**\n * Query index for recent vault notes to feed into the digest.\n * Filters out extract notes (our own output) and caps at max_notes_per_cycle.\n */\n discoverSubstrate(lastCycleTimestamp: string | null): IndexedNote[] {\n const maxNotes = this.config.digest.substrate.max_notes_per_cycle;\n\n const notes = lastCycleTimestamp\n ? this.index.query({ updatedSince: lastCycleTimestamp, limit: maxNotes })\n : this.index.query({ limit: maxNotes });\n\n // Guard against self-digestion: extract files are not currently indexed,\n // but this filter prevents feedback loops if they ever are (e.g., via rebuild)\n const filtered = notes.filter((n) => n.type !== EXTRACT_TYPE);\n\n // Sort by type weight (descending) then by recency (descending)\n filtered.sort((a, b) => {\n const weightA = DIGEST_SUBSTRATE_TYPE_WEIGHTS[a.type] ?? 0;\n const weightB = DIGEST_SUBSTRATE_TYPE_WEIGHTS[b.type] ?? 0;\n if (weightB !== weightA) return weightB - weightA;\n // More recent first — created is ISO string, lexicographic sort works\n return b.created.localeCompare(a.created);\n });\n\n return filtered.slice(0, maxNotes);\n }\n\n /**\n * Filter configured tiers by the context window available.\n * Only tiers whose minimum context requirement is met are eligible.\n */\n getEligibleTiers(): number[] {\n const contextWindow = this.config.digest.intelligence.context_window;\n return this.config.digest.tiers.filter((tier) => {\n const minContext = DIGEST_TIER_MIN_CONTEXT[tier];\n return minContext !== undefined && minContext <= contextWindow;\n });\n }\n\n /**\n * Format notes compactly for inclusion in the digest prompt.\n * Stops adding notes once the token budget is exceeded.\n */\n formatSubstrate(notes: IndexedNote[], tokenBudget: number): string {\n const charBudget = tokenBudget * CHARS_PER_TOKEN;\n const parts: string[] = [];\n let usedChars = 0;\n\n for (const note of notes) {\n const entry = `### [${note.type}] ${note.id} — \"${note.title}\"\\n${note.content}`;\n if (usedChars + entry.length > charBudget && parts.length > 0) break;\n parts.push(entry);\n usedChars += entry.length;\n }\n\n return parts.join('\\n\\n');\n }\n\n /**\n * Read a previously generated extract for a given tier.\n * Returns the body (stripped of YAML frontmatter), or null if not found.\n */\n readPreviousExtract(tier: number): string | null {\n const extractPath = path.join(this.vaultDir, 'digest', `extract-${tier}.md`);\n let content: string;\n try {\n content = fs.readFileSync(extractPath, 'utf-8');\n } catch {\n return null;\n }\n\n return stripFrontmatter(content).body;\n }\n\n /**\n * Write a digest extract to the vault with YAML frontmatter.\n * Uses atomic write pattern (temp file + rename).\n */\n writeExtract(\n tier: number,\n body: string,\n cycleId: string,\n model: string,\n substrateCount: number,\n ): void {\n const digestDir = path.join(this.vaultDir, 'digest');\n fs.mkdirSync(digestDir, { recursive: true });\n\n const frontmatter: Record<string, unknown> = {\n type: EXTRACT_TYPE,\n tier,\n generated: new Date().toISOString(),\n cycle_id: cycleId,\n substrate_count: substrateCount,\n model,\n };\n\n const fmYaml = YAML.stringify(frontmatter, {\n defaultStringType: 'QUOTE_DOUBLE',\n defaultKeyType: 'PLAIN',\n }).trim();\n const file = `---\\n${fmYaml}\\n---\\n\\n${body}\\n`;\n\n const fullPath = path.join(digestDir, `extract-${tier}.md`);\n const tmpPath = `${fullPath}.tmp`;\n fs.writeFileSync(tmpPath, file, 'utf-8');\n fs.renameSync(tmpPath, fullPath);\n }\n\n /**\n * Append a digest cycle result as a JSON line to trace.jsonl.\n */\n appendTrace(record: DigestCycleResult): void {\n const digestDir = path.join(this.vaultDir, 'digest');\n fs.mkdirSync(digestDir, { recursive: true });\n const tracePath = path.join(digestDir, 'trace.jsonl');\n fs.appendFileSync(tracePath, JSON.stringify(record) + '\\n', 'utf-8');\n this.lastCycleTimestampCache = record.timestamp;\n }\n\n /**\n * Read the last cycle timestamp from trace.jsonl.\n * Cached in memory after first read — subsequent calls are O(1).\n */\n getLastCycleTimestamp(): string | null {\n if (this.lastCycleTimestampCache !== undefined) return this.lastCycleTimestampCache;\n\n const tracePath = path.join(this.vaultDir, 'digest', 'trace.jsonl');\n let content: string;\n try {\n content = fs.readFileSync(tracePath, 'utf-8').trim();\n } catch {\n this.lastCycleTimestampCache = null;\n return null;\n }\n\n if (!content) {\n this.lastCycleTimestampCache = null;\n return null;\n }\n\n const lines = content.split('\\n');\n const lastLine = lines[lines.length - 1];\n try {\n const record = JSON.parse(lastLine) as DigestCycleResult;\n this.lastCycleTimestampCache = record.timestamp;\n return record.timestamp;\n } catch {\n this.lastCycleTimestampCache = null;\n return null;\n }\n }\n\n /**\n * Run a full digest cycle: discover substrate, generate extracts for each tier.\n * Returns the cycle result, or null if no substrate was found.\n */\n async runCycle(opts?: DigestCycleOptions): Promise<DigestCycleResult | null> {\n if (this.cycleInProgress) {\n this.log('debug', 'Cycle already in progress — skipping');\n return null;\n }\n this.cycleInProgress = true;\n\n try {\n return await this.runCycleInternal(opts);\n } finally {\n this.cycleInProgress = false;\n }\n }\n\n private async runCycleInternal(opts?: DigestCycleOptions): Promise<DigestCycleResult | null> {\n // Ensure model is loaded with correct settings every cycle.\n // LM Studio's idle TTL can evict our instance between cycles — without\n // re-running ensureLoaded, the auto-reloaded instance would use LM Studio's\n // UI defaults (wrong KV cache setting). This is fast (~26ms) when the\n // instance is still alive (just a getLoadedInstances check).\n if (this.llm.ensureLoaded) {\n const { context_window: contextWindow, gpu_kv_cache: gpuKvCache } = this.config.digest.intelligence;\n this.log('debug', 'Verifying digest model', { contextWindow, gpuKvCache });\n await this.llm.ensureLoaded(contextWindow, gpuKvCache);\n }\n\n const startTime = Date.now();\n const fullReprocess = opts?.fullReprocess ?? false;\n const lastTimestamp = fullReprocess ? null : this.getLastCycleTimestamp();\n const substrate = this.discoverSubstrate(lastTimestamp);\n\n this.log('debug', 'Discovering substrate', { lastTimestamp: lastTimestamp ?? 'full reprocess', substrateCount: substrate.length });\n if (substrate.length === 0) {\n this.log('debug', 'No substrate found — skipping cycle');\n return null;\n }\n\n this.log('info', `Starting digest cycle`, { substrateCount: substrate.length, fullReprocess });\n const cycleId = crypto.randomUUID();\n const allEligible = this.getEligibleTiers();\n const eligibleTiers = opts?.tiers\n ? allEligible.filter((t) => opts.tiers!.includes(t))\n : allEligible;\n this.log('debug', `Eligible tiers: [${eligibleTiers.join(', ')}]`);\n const tiersGenerated: number[] = [];\n let totalTokensUsed = 0;\n let model = '';\n\n // Categorize substrate by type for the result\n const typeToKey: Record<string, keyof DigestCycleResult['substrate']> = {\n session: 'sessions',\n spore: 'spores',\n plan: 'plans',\n artifact: 'artifacts',\n 'team-member': 'team',\n };\n const substrateIndex: DigestCycleResult['substrate'] = {\n sessions: [],\n spores: [],\n plans: [],\n artifacts: [],\n team: [],\n };\n for (const note of substrate) {\n const key = typeToKey[note.type];\n if (key) {\n substrateIndex[key].push(note.id);\n }\n }\n\n // Record the cycle timestamp NOW, before tier processing. This ensures the\n // timestamp advances even if LLM calls fail, preventing the same substrate\n // from being rediscovered on every subsequent timer fire.\n const cycleTimestamp = new Date().toISOString();\n\n const systemPrompt = loadPrompt('digest-system');\n\n for (const tier of eligibleTiers) {\n const tierPrompt = loadPrompt(`digest-${tier}`);\n const previousExtract = opts?.cleanSlate ? null : this.readPreviousExtract(tier);\n\n // Calculate token budget for substrate:\n // (context_window * safety_margin) - output - system_prompt - tier_prompt - previous_extract\n const contextWindow = this.config.digest.intelligence.context_window;\n const systemPromptTokens = estimateTokens(systemPrompt);\n const tierPromptTokens = estimateTokens(tierPrompt);\n const previousExtractTokens = previousExtract\n ? estimateTokens(previousExtract) + PREVIOUS_EXTRACT_OVERHEAD_TOKENS\n : 0;\n const availableTokens = Math.floor(contextWindow * CONTEXT_SAFETY_MARGIN);\n const substrateBudget = availableTokens - tier - systemPromptTokens - tierPromptTokens - previousExtractTokens;\n\n if (substrateBudget <= 0) continue;\n\n const formattedSubstrate = this.formatSubstrate(substrate, substrateBudget);\n\n // Build user prompt (system prompt sent separately via LlmRequestOptions)\n const promptParts = [tierPrompt];\n\n if (previousExtract) {\n promptParts.push('', '## Previous Synthesis', '', previousExtract);\n }\n\n promptParts.push('', '## New Substrate', '', formattedSubstrate);\n promptParts.push(\n '',\n '---',\n 'Produce your updated synthesis now. Stay within the token budget specified above.',\n );\n\n const userPrompt = promptParts.join('\\n');\n const promptTokens = estimateTokens(systemPrompt + userPrompt);\n this.log('debug', `Tier ${tier}: sending LLM request`, { promptTokens, maxTokens: tier, substrateBudget });\n\n try {\n const tierStart = Date.now();\n const digestConfig = this.config.digest.intelligence;\n const opts: LlmRequestOptions = {\n maxTokens: tier,\n timeoutMs: DIGEST_LLM_REQUEST_TIMEOUT_MS,\n contextLength: contextWindow,\n reasoning: LLM_REASONING_MODE,\n systemPrompt,\n keepAlive: digestConfig.keep_alive ?? undefined,\n };\n const response = await this.llm.summarize(userPrompt, opts);\n const tierDuration = Date.now() - tierStart;\n\n // Strip reasoning tokens if present (some models output chain-of-thought)\n const extractText = stripReasoningTokens(response.text);\n model = response.model;\n const responseTokens = estimateTokens(extractText);\n totalTokensUsed += promptTokens + responseTokens;\n\n this.log('info', `Tier ${tier}: completed`, { durationMs: tierDuration, responseTokens, model: response.model });\n this.writeExtract(tier, extractText, cycleId, response.model, substrate.length);\n tiersGenerated.push(tier);\n } catch (err) {\n this.log('warn', `Tier ${tier}: failed`, { error: (err as Error).message });\n }\n }\n\n const result: DigestCycleResult = {\n cycleId,\n timestamp: cycleTimestamp,\n substrate: substrateIndex,\n tiersGenerated,\n model,\n durationMs: Date.now() - startTime,\n tokensUsed: totalTokensUsed,\n };\n\n this.appendTrace(result);\n return result;\n }\n}\n\n// --- Metabolism (Adaptive Timer) ---\n\nexport type MetabolismState = 'active' | 'cooling' | 'dormant';\n\n/** Milliseconds per second for config conversion. */\nconst MS_PER_SECOND = 1000;\n\nexport class Metabolism {\n state: MetabolismState = 'active';\n currentIntervalMs: number;\n\n private cooldownStep = 0;\n private lastSubstrateTime: number;\n private timer: ReturnType<typeof setTimeout> | null = null;\n private activeIntervalMs: number;\n private cooldownIntervalsMs: number[];\n private dormancyThresholdMs: number;\n\n constructor(config: MycoConfig['digest']['metabolism']) {\n this.activeIntervalMs = config.active_interval * MS_PER_SECOND;\n this.cooldownIntervalsMs = config.cooldown_intervals.map((s) => s * MS_PER_SECOND);\n this.dormancyThresholdMs = config.dormancy_threshold * MS_PER_SECOND;\n this.currentIntervalMs = this.activeIntervalMs;\n this.lastSubstrateTime = Date.now();\n }\n\n /** Reset to active state when new substrate is found. */\n onSubstrateFound(): void {\n this.state = 'active';\n this.cooldownStep = 0;\n this.currentIntervalMs = this.activeIntervalMs;\n this.lastSubstrateTime = Date.now();\n }\n\n /** Advance cooldown when a cycle finds no new substrate. */\n onEmptyCycle(): void {\n if (this.state === 'dormant') return;\n\n this.state = 'cooling';\n if (this.cooldownStep < this.cooldownIntervalsMs.length) {\n this.currentIntervalMs = this.cooldownIntervalsMs[this.cooldownStep];\n this.cooldownStep++;\n }\n\n this.checkDormancy();\n }\n\n /** Enter dormant state if enough time has elapsed since last substrate. */\n checkDormancy(): void {\n const elapsed = Date.now() - this.lastSubstrateTime;\n if (elapsed >= this.dormancyThresholdMs) {\n this.state = 'dormant';\n // Keep the last cooldown interval as the dormant polling rate\n }\n }\n\n /** Return to active from any state, resetting timers and rescheduling immediately. */\n activate(): void {\n this.onSubstrateFound();\n // Reschedule with the new active interval — without this, the old\n // (possibly dormant) timer continues ticking at the wrong rate\n if (this.callback) {\n this.reschedule();\n }\n }\n\n /** Set lastSubstrateTime explicitly (for testing). */\n markLastSubstrate(time: number): void {\n this.lastSubstrateTime = time;\n }\n\n /** Begin scheduling digest cycles with adaptive intervals. */\n start(callback: () => Promise<void>): void {\n this.callback = callback;\n this.reschedule();\n }\n\n /** Stop the timer. */\n stop(): void {\n if (this.timer) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n }\n\n private callback: (() => Promise<void>) | null = null;\n\n private reschedule(): void {\n this.stop();\n if (!this.callback) return;\n const cb = this.callback;\n const schedule = (): void => {\n this.timer = setTimeout(async () => {\n await cb();\n schedule();\n }, this.currentIntervalMs);\n this.timer.unref();\n };\n schedule();\n }\n}\n"],"mappings":"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","names":["YAML","opts"]}
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-MIU3DKLN.js";
|
|
5
5
|
import {
|
|
6
6
|
DIGEST_TIERS
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-TDLQBGKA.js";
|
|
8
8
|
|
|
9
9
|
// src/mcp/tools/context.ts
|
|
10
10
|
import fs from "fs";
|
|
@@ -46,4 +46,4 @@ function handleMycoContext(vaultDir, input) {
|
|
|
46
46
|
export {
|
|
47
47
|
handleMycoContext
|
|
48
48
|
};
|
|
49
|
-
//# sourceMappingURL=chunk-
|
|
49
|
+
//# sourceMappingURL=chunk-42R7KVAW.js.map
|
|
@@ -2,10 +2,10 @@ import { createRequire as __cr } from 'node:module'; const require = __cr(import
|
|
|
2
2
|
import {
|
|
3
3
|
LmStudioBackend,
|
|
4
4
|
OllamaBackend
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-OPO47BVS.js";
|
|
6
6
|
import {
|
|
7
7
|
AgentRegistry
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-EQVQEFOA.js";
|
|
9
9
|
|
|
10
10
|
// src/cli/shared.ts
|
|
11
11
|
import fs from "fs";
|
|
@@ -116,4 +116,4 @@ export {
|
|
|
116
116
|
VAULT_GITIGNORE,
|
|
117
117
|
configureVaultEnv
|
|
118
118
|
};
|
|
119
|
-
//# sourceMappingURL=chunk-
|
|
119
|
+
//# sourceMappingURL=chunk-5FIIK27E.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
AgentRegistry
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-EQVQEFOA.js";
|
|
5
5
|
|
|
6
6
|
// src/native-deps.ts
|
|
7
7
|
import { execFileSync } from "child_process";
|
|
@@ -53,4 +53,4 @@ function ensureNativeDeps() {
|
|
|
53
53
|
export {
|
|
54
54
|
ensureNativeDeps
|
|
55
55
|
};
|
|
56
|
-
//# sourceMappingURL=chunk-
|
|
56
|
+
//# sourceMappingURL=chunk-6CAKKNGD.js.map
|
|
@@ -201,6 +201,15 @@ ${links.join("\n")}`);
|
|
|
201
201
|
sections.push(footerTags(allTags));
|
|
202
202
|
return sections.join("\n\n");
|
|
203
203
|
}
|
|
204
|
+
var FOOTER_TAG_PREFIX = "\n#type/";
|
|
205
|
+
function extractSection(body, heading) {
|
|
206
|
+
const start = body.indexOf(heading);
|
|
207
|
+
if (start === -1) return "";
|
|
208
|
+
const section = body.slice(start + heading.length);
|
|
209
|
+
const footerIdx = section.lastIndexOf(FOOTER_TAG_PREFIX);
|
|
210
|
+
if (footerIdx !== -1) return section.slice(0, footerIdx).trim();
|
|
211
|
+
return section.trim();
|
|
212
|
+
}
|
|
204
213
|
function capitalize(s) {
|
|
205
214
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
206
215
|
}
|
|
@@ -418,8 +427,10 @@ export {
|
|
|
418
427
|
bareSessionId,
|
|
419
428
|
sessionWikilink,
|
|
420
429
|
sessionRelativePath,
|
|
430
|
+
callout,
|
|
421
431
|
formatSessionBody,
|
|
422
432
|
formatSporeBody,
|
|
433
|
+
extractSection,
|
|
423
434
|
VaultWriter
|
|
424
435
|
};
|
|
425
|
-
//# sourceMappingURL=chunk-
|
|
436
|
+
//# sourceMappingURL=chunk-6LTNFMXO.js.map
|