@agntk/agent-harness 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/NOTICE +41 -0
- package/README.md +445 -0
- package/defaults/agents/summarizer.md +49 -0
- package/defaults/instincts/lead-with-answer.md +24 -0
- package/defaults/instincts/qualify-before-recommending.md +40 -0
- package/defaults/instincts/read-before-edit.md +23 -0
- package/defaults/instincts/search-before-create.md +23 -0
- package/defaults/playbooks/ship-feature.md +31 -0
- package/defaults/rules/ask-before-assuming.md +35 -0
- package/defaults/rules/operations.md +35 -0
- package/defaults/rules/respect-the-user.md +39 -0
- package/defaults/skills/business-analyst.md +181 -0
- package/defaults/skills/content-marketer.md +184 -0
- package/defaults/skills/research.md +34 -0
- package/defaults/tools/example-web-search.md +60 -0
- package/defaults/workflows/daily-reflection.md +54 -0
- package/dist/agent-framework-K4GUIICH.js +344 -0
- package/dist/agent-framework-K4GUIICH.js.map +1 -0
- package/dist/analytics-RPT73WNM.js +12 -0
- package/dist/analytics-RPT73WNM.js.map +1 -0
- package/dist/auto-processor-OLE45UI3.js +13 -0
- package/dist/auto-processor-OLE45UI3.js.map +1 -0
- package/dist/chunk-274RV3YO.js +162 -0
- package/dist/chunk-274RV3YO.js.map +1 -0
- package/dist/chunk-4CWAGBNS.js +168 -0
- package/dist/chunk-4CWAGBNS.js.map +1 -0
- package/dist/chunk-4FDUOGSZ.js +69 -0
- package/dist/chunk-4FDUOGSZ.js.map +1 -0
- package/dist/chunk-5H34JPMB.js +199 -0
- package/dist/chunk-5H34JPMB.js.map +1 -0
- package/dist/chunk-6EMOEYGU.js +102 -0
- package/dist/chunk-6EMOEYGU.js.map +1 -0
- package/dist/chunk-A7BJPQQ6.js +236 -0
- package/dist/chunk-A7BJPQQ6.js.map +1 -0
- package/dist/chunk-AGAAFJEO.js +76 -0
- package/dist/chunk-AGAAFJEO.js.map +1 -0
- package/dist/chunk-BSKDOFRT.js +65 -0
- package/dist/chunk-BSKDOFRT.js.map +1 -0
- package/dist/chunk-CHJ5GNZC.js +100 -0
- package/dist/chunk-CHJ5GNZC.js.map +1 -0
- package/dist/chunk-CSL3ERUI.js +307 -0
- package/dist/chunk-CSL3ERUI.js.map +1 -0
- package/dist/chunk-DA7IKHC4.js +229 -0
- package/dist/chunk-DA7IKHC4.js.map +1 -0
- package/dist/chunk-DGUM43GV.js +11 -0
- package/dist/chunk-DGUM43GV.js.map +1 -0
- package/dist/chunk-DTTXPHFW.js +211 -0
- package/dist/chunk-DTTXPHFW.js.map +1 -0
- package/dist/chunk-FD55B3IO.js +204 -0
- package/dist/chunk-FD55B3IO.js.map +1 -0
- package/dist/chunk-FLZU44SV.js +230 -0
- package/dist/chunk-FLZU44SV.js.map +1 -0
- package/dist/chunk-GJNNR2RA.js +200 -0
- package/dist/chunk-GJNNR2RA.js.map +1 -0
- package/dist/chunk-GNUSHD2Y.js +111 -0
- package/dist/chunk-GNUSHD2Y.js.map +1 -0
- package/dist/chunk-GUJTBGVS.js +2212 -0
- package/dist/chunk-GUJTBGVS.js.map +1 -0
- package/dist/chunk-IZ6UZ3ZL.js +207 -0
- package/dist/chunk-IZ6UZ3ZL.js.map +1 -0
- package/dist/chunk-JKMGYWXB.js +197 -0
- package/dist/chunk-JKMGYWXB.js.map +1 -0
- package/dist/chunk-KFX54TQM.js +165 -0
- package/dist/chunk-KFX54TQM.js.map +1 -0
- package/dist/chunk-M7NXUK55.js +199 -0
- package/dist/chunk-M7NXUK55.js.map +1 -0
- package/dist/chunk-MPZ3BPUI.js +374 -0
- package/dist/chunk-MPZ3BPUI.js.map +1 -0
- package/dist/chunk-OC6YSTDX.js +119 -0
- package/dist/chunk-OC6YSTDX.js.map +1 -0
- package/dist/chunk-RC6MEZB6.js +469 -0
- package/dist/chunk-RC6MEZB6.js.map +1 -0
- package/dist/chunk-RY3ZFII7.js +3440 -0
- package/dist/chunk-RY3ZFII7.js.map +1 -0
- package/dist/chunk-TAT6JU3X.js +167 -0
- package/dist/chunk-TAT6JU3X.js.map +1 -0
- package/dist/chunk-UDZIS2AQ.js +79 -0
- package/dist/chunk-UDZIS2AQ.js.map +1 -0
- package/dist/chunk-UPLBF4RZ.js +115 -0
- package/dist/chunk-UPLBF4RZ.js.map +1 -0
- package/dist/chunk-UWQTZMNI.js +154 -0
- package/dist/chunk-UWQTZMNI.js.map +1 -0
- package/dist/chunk-W4T7PGI2.js +346 -0
- package/dist/chunk-W4T7PGI2.js.map +1 -0
- package/dist/chunk-XTBKL5BI.js +111 -0
- package/dist/chunk-XTBKL5BI.js.map +1 -0
- package/dist/chunk-YIJY5DBV.js +399 -0
- package/dist/chunk-YIJY5DBV.js.map +1 -0
- package/dist/chunk-YUFNYN2H.js +242 -0
- package/dist/chunk-YUFNYN2H.js.map +1 -0
- package/dist/chunk-Z2PUCXTZ.js +94 -0
- package/dist/chunk-Z2PUCXTZ.js.map +1 -0
- package/dist/chunk-ZZJOFKAT.js +13 -0
- package/dist/chunk-ZZJOFKAT.js.map +1 -0
- package/dist/cli/index.js +3661 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/config-WVMRUOCA.js +13 -0
- package/dist/config-WVMRUOCA.js.map +1 -0
- package/dist/context-loader-3ORBPMHJ.js +13 -0
- package/dist/context-loader-3ORBPMHJ.js.map +1 -0
- package/dist/conversation-QDEIDQPH.js +22 -0
- package/dist/conversation-QDEIDQPH.js.map +1 -0
- package/dist/cost-tracker-RS3W7SVY.js +24 -0
- package/dist/cost-tracker-RS3W7SVY.js.map +1 -0
- package/dist/delegate-VJCJLYEK.js +29 -0
- package/dist/delegate-VJCJLYEK.js.map +1 -0
- package/dist/emotional-state-VQVRA6ED.js +206 -0
- package/dist/emotional-state-VQVRA6ED.js.map +1 -0
- package/dist/env-discovery-2BLVMAIM.js +251 -0
- package/dist/env-discovery-2BLVMAIM.js.map +1 -0
- package/dist/export-6GCYHEHQ.js +165 -0
- package/dist/export-6GCYHEHQ.js.map +1 -0
- package/dist/graph-YUIPOSOO.js +14 -0
- package/dist/graph-YUIPOSOO.js.map +1 -0
- package/dist/harness-LCHA3DWP.js +10 -0
- package/dist/harness-LCHA3DWP.js.map +1 -0
- package/dist/harness-WE4SLCML.js +26 -0
- package/dist/harness-WE4SLCML.js.map +1 -0
- package/dist/health-NZ6WNIMV.js +23 -0
- package/dist/health-NZ6WNIMV.js.map +1 -0
- package/dist/index.d.ts +3612 -0
- package/dist/index.js +13501 -0
- package/dist/index.js.map +1 -0
- package/dist/indexer-LONANRRM.js +16 -0
- package/dist/indexer-LONANRRM.js.map +1 -0
- package/dist/instinct-learner-SRM72DHF.js +20 -0
- package/dist/instinct-learner-SRM72DHF.js.map +1 -0
- package/dist/intake-4M3HNU43.js +21 -0
- package/dist/intake-4M3HNU43.js.map +1 -0
- package/dist/intelligence-HJOCA4SJ.js +1081 -0
- package/dist/intelligence-HJOCA4SJ.js.map +1 -0
- package/dist/journal-WANJL3MI.js +24 -0
- package/dist/journal-WANJL3MI.js.map +1 -0
- package/dist/loader-C3TKIKZR.js +23 -0
- package/dist/loader-C3TKIKZR.js.map +1 -0
- package/dist/mcp-WTQJJZAO.js +15 -0
- package/dist/mcp-WTQJJZAO.js.map +1 -0
- package/dist/mcp-discovery-WPAQFL6S.js +377 -0
- package/dist/mcp-discovery-WPAQFL6S.js.map +1 -0
- package/dist/mcp-installer-6O2XXD3V.js +394 -0
- package/dist/mcp-installer-6O2XXD3V.js.map +1 -0
- package/dist/metrics-KXGNFAAB.js +20 -0
- package/dist/metrics-KXGNFAAB.js.map +1 -0
- package/dist/primitive-registry-I6VTIR4W.js +512 -0
- package/dist/primitive-registry-I6VTIR4W.js.map +1 -0
- package/dist/project-discovery-C4UMD7JI.js +246 -0
- package/dist/project-discovery-C4UMD7JI.js.map +1 -0
- package/dist/provider-LQHQX7Z7.js +26 -0
- package/dist/provider-LQHQX7Z7.js.map +1 -0
- package/dist/provider-SXPQZ74H.js +28 -0
- package/dist/provider-SXPQZ74H.js.map +1 -0
- package/dist/rate-limiter-RLRVM325.js +22 -0
- package/dist/rate-limiter-RLRVM325.js.map +1 -0
- package/dist/rule-engine-YGQ3RYZM.js +182 -0
- package/dist/rule-engine-YGQ3RYZM.js.map +1 -0
- package/dist/scaffold-A3VRRCBV.js +347 -0
- package/dist/scaffold-A3VRRCBV.js.map +1 -0
- package/dist/scheduler-XHHIVHRI.js +397 -0
- package/dist/scheduler-XHHIVHRI.js.map +1 -0
- package/dist/search-V3W5JMJG.js +75 -0
- package/dist/search-V3W5JMJG.js.map +1 -0
- package/dist/semantic-search-2DTOO5UX.js +241 -0
- package/dist/semantic-search-2DTOO5UX.js.map +1 -0
- package/dist/serve-DTQ3HENY.js +291 -0
- package/dist/serve-DTQ3HENY.js.map +1 -0
- package/dist/sessions-CZGVXKQE.js +21 -0
- package/dist/sessions-CZGVXKQE.js.map +1 -0
- package/dist/sources-RW5DT56F.js +32 -0
- package/dist/sources-RW5DT56F.js.map +1 -0
- package/dist/starter-packs-76YUVHEU.js +893 -0
- package/dist/starter-packs-76YUVHEU.js.map +1 -0
- package/dist/state-GMXILIHW.js +13 -0
- package/dist/state-GMXILIHW.js.map +1 -0
- package/dist/state-merge-NKO5FRBA.js +174 -0
- package/dist/state-merge-NKO5FRBA.js.map +1 -0
- package/dist/telemetry-UC6PBXC7.js +22 -0
- package/dist/telemetry-UC6PBXC7.js.map +1 -0
- package/dist/tool-executor-MJ7IG7PQ.js +28 -0
- package/dist/tool-executor-MJ7IG7PQ.js.map +1 -0
- package/dist/tools-DZ4KETET.js +20 -0
- package/dist/tools-DZ4KETET.js.map +1 -0
- package/dist/types-EW7AIB3R.js +18 -0
- package/dist/types-EW7AIB3R.js.map +1 -0
- package/dist/types-WGDLSPO6.js +16 -0
- package/dist/types-WGDLSPO6.js.map +1 -0
- package/dist/universal-installer-QGS4SJGX.js +578 -0
- package/dist/universal-installer-QGS4SJGX.js.map +1 -0
- package/dist/validator-7WXMDIHH.js +22 -0
- package/dist/validator-7WXMDIHH.js.map +1 -0
- package/dist/verification-gate-FYXUX6LH.js +246 -0
- package/dist/verification-gate-FYXUX6LH.js.map +1 -0
- package/dist/versioning-Z3XNE2Q2.js +271 -0
- package/dist/versioning-Z3XNE2Q2.js.map +1 -0
- package/dist/watcher-ISJC7YKL.js +109 -0
- package/dist/watcher-ISJC7YKL.js.map +1 -0
- package/dist/web-server-DD7ZOP46.js +28 -0
- package/dist/web-server-DD7ZOP46.js.map +1 -0
- package/package.json +76 -0
- package/sources.yaml +121 -0
- package/templates/assistant/CORE.md +24 -0
- package/templates/assistant/SYSTEM.md +24 -0
- package/templates/assistant/config.yaml +51 -0
- package/templates/base/CORE.md +17 -0
- package/templates/base/SYSTEM.md +24 -0
- package/templates/base/config.yaml +51 -0
- package/templates/claude-opus/config.yaml +51 -0
- package/templates/code-reviewer/CORE.md +25 -0
- package/templates/code-reviewer/SYSTEM.md +30 -0
- package/templates/code-reviewer/config.yaml +51 -0
- package/templates/gpt4/config.yaml +51 -0
- package/templates/local/config.yaml +51 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
// src/runtime/cost-tracker.ts
|
|
5
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
6
|
+
import { join } from "path";
|
|
7
|
+
var COST_FILE = "costs.json";
|
|
8
|
+
var MAX_ENTRIES = 5e3;
|
|
9
|
+
var DEFAULT_PRICING = [
|
|
10
|
+
// Anthropic via OpenRouter
|
|
11
|
+
{ model_pattern: "anthropic/claude-sonnet-4", input_per_million: 3, output_per_million: 15 },
|
|
12
|
+
{ model_pattern: "anthropic/claude-opus-4", input_per_million: 15, output_per_million: 75 },
|
|
13
|
+
{ model_pattern: "anthropic/claude-haiku-3.5", input_per_million: 0.8, output_per_million: 4 },
|
|
14
|
+
// Direct Anthropic
|
|
15
|
+
{ model_pattern: "claude-sonnet-4", input_per_million: 3, output_per_million: 15 },
|
|
16
|
+
{ model_pattern: "claude-opus-4", input_per_million: 15, output_per_million: 75 },
|
|
17
|
+
{ model_pattern: "claude-haiku-3.5", input_per_million: 0.8, output_per_million: 4 },
|
|
18
|
+
// OpenAI
|
|
19
|
+
{ model_pattern: "openai/gpt-4o", input_per_million: 2.5, output_per_million: 10 },
|
|
20
|
+
{ model_pattern: "gpt-4o", input_per_million: 2.5, output_per_million: 10 },
|
|
21
|
+
{ model_pattern: "openai/gpt-4o-mini", input_per_million: 0.15, output_per_million: 0.6 },
|
|
22
|
+
{ model_pattern: "gpt-4o-mini", input_per_million: 0.15, output_per_million: 0.6 },
|
|
23
|
+
// Local models
|
|
24
|
+
{ model_pattern: "local/", input_per_million: 0, output_per_million: 0 }
|
|
25
|
+
];
|
|
26
|
+
function getStorePath(harnessDir) {
|
|
27
|
+
return join(harnessDir, "memory", COST_FILE);
|
|
28
|
+
}
|
|
29
|
+
function loadCosts(harnessDir) {
|
|
30
|
+
const storePath = getStorePath(harnessDir);
|
|
31
|
+
if (!existsSync(storePath)) {
|
|
32
|
+
return { entries: [], updated: (/* @__PURE__ */ new Date()).toISOString() };
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const content = readFileSync(storePath, "utf-8");
|
|
36
|
+
const parsed = JSON.parse(content);
|
|
37
|
+
if (typeof parsed === "object" && parsed !== null && "entries" in parsed && Array.isArray(parsed.entries)) {
|
|
38
|
+
return parsed;
|
|
39
|
+
}
|
|
40
|
+
return { entries: [], updated: (/* @__PURE__ */ new Date()).toISOString() };
|
|
41
|
+
} catch {
|
|
42
|
+
return { entries: [], updated: (/* @__PURE__ */ new Date()).toISOString() };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function saveCosts(harnessDir, store) {
|
|
46
|
+
const memoryDir = join(harnessDir, "memory");
|
|
47
|
+
if (!existsSync(memoryDir)) {
|
|
48
|
+
mkdirSync(memoryDir, { recursive: true });
|
|
49
|
+
}
|
|
50
|
+
if (store.entries.length > MAX_ENTRIES) {
|
|
51
|
+
store.entries = store.entries.slice(store.entries.length - MAX_ENTRIES);
|
|
52
|
+
}
|
|
53
|
+
store.updated = (/* @__PURE__ */ new Date()).toISOString();
|
|
54
|
+
writeFileSync(getStorePath(harnessDir), JSON.stringify(store, null, 2), "utf-8");
|
|
55
|
+
}
|
|
56
|
+
function findPricing(modelId, customPricing) {
|
|
57
|
+
const allPricing = [...customPricing ?? [], ...DEFAULT_PRICING];
|
|
58
|
+
for (const pricing of allPricing) {
|
|
59
|
+
if (modelId === pricing.model_pattern || modelId.startsWith(pricing.model_pattern)) {
|
|
60
|
+
return pricing;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
function calculateCost(modelId, inputTokens, outputTokens, customPricing) {
|
|
66
|
+
const pricing = findPricing(modelId, customPricing);
|
|
67
|
+
if (!pricing) return 0;
|
|
68
|
+
const inputCost = inputTokens / 1e6 * pricing.input_per_million;
|
|
69
|
+
const outputCost = outputTokens / 1e6 * pricing.output_per_million;
|
|
70
|
+
return Math.round((inputCost + outputCost) * 1e6) / 1e6;
|
|
71
|
+
}
|
|
72
|
+
function recordCost(harnessDir, entry, customPricing) {
|
|
73
|
+
const store = loadCosts(harnessDir);
|
|
74
|
+
const costUsd = entry.cost_usd ?? calculateCost(
|
|
75
|
+
entry.model_id,
|
|
76
|
+
entry.input_tokens,
|
|
77
|
+
entry.output_tokens,
|
|
78
|
+
customPricing
|
|
79
|
+
);
|
|
80
|
+
const fullEntry = {
|
|
81
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
82
|
+
model_id: entry.model_id,
|
|
83
|
+
provider: entry.provider,
|
|
84
|
+
input_tokens: entry.input_tokens,
|
|
85
|
+
output_tokens: entry.output_tokens,
|
|
86
|
+
cost_usd: costUsd,
|
|
87
|
+
source: entry.source
|
|
88
|
+
};
|
|
89
|
+
store.entries.push(fullEntry);
|
|
90
|
+
saveCosts(harnessDir, store);
|
|
91
|
+
return fullEntry;
|
|
92
|
+
}
|
|
93
|
+
function getSpending(harnessDir, from, to) {
|
|
94
|
+
const store = loadCosts(harnessDir);
|
|
95
|
+
const fromDate = from ?? (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
96
|
+
const toDate = to ?? new Date(Date.now() + 864e5).toISOString().split("T")[0];
|
|
97
|
+
const filtered = store.entries.filter(
|
|
98
|
+
(e) => e.timestamp >= fromDate && e.timestamp < toDate + "T99"
|
|
99
|
+
);
|
|
100
|
+
const byModel = {};
|
|
101
|
+
const byProvider = {};
|
|
102
|
+
let totalCost = 0;
|
|
103
|
+
let totalInput = 0;
|
|
104
|
+
let totalOutput = 0;
|
|
105
|
+
for (const entry of filtered) {
|
|
106
|
+
totalCost += entry.cost_usd;
|
|
107
|
+
totalInput += entry.input_tokens;
|
|
108
|
+
totalOutput += entry.output_tokens;
|
|
109
|
+
if (!byModel[entry.model_id]) {
|
|
110
|
+
byModel[entry.model_id] = { cost_usd: 0, input_tokens: 0, output_tokens: 0, count: 0 };
|
|
111
|
+
}
|
|
112
|
+
byModel[entry.model_id].cost_usd += entry.cost_usd;
|
|
113
|
+
byModel[entry.model_id].input_tokens += entry.input_tokens;
|
|
114
|
+
byModel[entry.model_id].output_tokens += entry.output_tokens;
|
|
115
|
+
byModel[entry.model_id].count += 1;
|
|
116
|
+
if (!byProvider[entry.provider]) {
|
|
117
|
+
byProvider[entry.provider] = { cost_usd: 0, count: 0 };
|
|
118
|
+
}
|
|
119
|
+
byProvider[entry.provider].cost_usd += entry.cost_usd;
|
|
120
|
+
byProvider[entry.provider].count += 1;
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
total_cost_usd: Math.round(totalCost * 1e6) / 1e6,
|
|
124
|
+
total_input_tokens: totalInput,
|
|
125
|
+
total_output_tokens: totalOutput,
|
|
126
|
+
entries: filtered.length,
|
|
127
|
+
by_model: byModel,
|
|
128
|
+
by_provider: byProvider
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function checkBudget(harnessDir, budget) {
|
|
132
|
+
const now = /* @__PURE__ */ new Date();
|
|
133
|
+
const today = now.toISOString().split("T")[0];
|
|
134
|
+
const monthStart = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-01`;
|
|
135
|
+
const dailySpending = getSpending(harnessDir, today);
|
|
136
|
+
const monthlySpending = getSpending(harnessDir, monthStart);
|
|
137
|
+
const alerts = [];
|
|
138
|
+
const alertPct = budget.alert_threshold_pct ?? 80;
|
|
139
|
+
const dailyLimit = budget.daily_limit_usd ?? null;
|
|
140
|
+
const monthlyLimit = budget.monthly_limit_usd ?? null;
|
|
141
|
+
let dailyPct = null;
|
|
142
|
+
let dailyRemaining = null;
|
|
143
|
+
if (dailyLimit !== null) {
|
|
144
|
+
dailyPct = dailyLimit > 0 ? dailySpending.total_cost_usd / dailyLimit * 100 : 0;
|
|
145
|
+
dailyRemaining = Math.max(0, dailyLimit - dailySpending.total_cost_usd);
|
|
146
|
+
if (dailySpending.total_cost_usd >= dailyLimit) {
|
|
147
|
+
alerts.push(`Daily budget exceeded: $${dailySpending.total_cost_usd.toFixed(4)} / $${dailyLimit.toFixed(2)}`);
|
|
148
|
+
} else if (dailyPct >= alertPct) {
|
|
149
|
+
alerts.push(`Daily budget at ${dailyPct.toFixed(0)}%: $${dailySpending.total_cost_usd.toFixed(4)} / $${dailyLimit.toFixed(2)}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
let monthlyPct = null;
|
|
153
|
+
let monthlyRemaining = null;
|
|
154
|
+
if (monthlyLimit !== null) {
|
|
155
|
+
monthlyPct = monthlyLimit > 0 ? monthlySpending.total_cost_usd / monthlyLimit * 100 : 0;
|
|
156
|
+
monthlyRemaining = Math.max(0, monthlyLimit - monthlySpending.total_cost_usd);
|
|
157
|
+
if (monthlySpending.total_cost_usd >= monthlyLimit) {
|
|
158
|
+
alerts.push(`Monthly budget exceeded: $${monthlySpending.total_cost_usd.toFixed(4)} / $${monthlyLimit.toFixed(2)}`);
|
|
159
|
+
} else if (monthlyPct >= alertPct) {
|
|
160
|
+
alerts.push(`Monthly budget at ${monthlyPct.toFixed(0)}%: $${monthlySpending.total_cost_usd.toFixed(4)} / $${monthlyLimit.toFixed(2)}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
daily_spent_usd: dailySpending.total_cost_usd,
|
|
165
|
+
daily_limit_usd: dailyLimit,
|
|
166
|
+
daily_remaining_usd: dailyRemaining,
|
|
167
|
+
daily_pct: dailyPct,
|
|
168
|
+
monthly_spent_usd: monthlySpending.total_cost_usd,
|
|
169
|
+
monthly_limit_usd: monthlyLimit,
|
|
170
|
+
monthly_remaining_usd: monthlyRemaining,
|
|
171
|
+
monthly_pct: monthlyPct,
|
|
172
|
+
alerts
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
function clearCosts(harnessDir, modelId) {
|
|
176
|
+
const store = loadCosts(harnessDir);
|
|
177
|
+
const before = store.entries.length;
|
|
178
|
+
if (modelId) {
|
|
179
|
+
store.entries = store.entries.filter((e) => e.model_id !== modelId);
|
|
180
|
+
} else {
|
|
181
|
+
store.entries = [];
|
|
182
|
+
}
|
|
183
|
+
saveCosts(harnessDir, store);
|
|
184
|
+
return before - store.entries.length;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export {
|
|
188
|
+
loadCosts,
|
|
189
|
+
saveCosts,
|
|
190
|
+
findPricing,
|
|
191
|
+
calculateCost,
|
|
192
|
+
recordCost,
|
|
193
|
+
getSpending,
|
|
194
|
+
checkBudget,
|
|
195
|
+
clearCosts
|
|
196
|
+
};
|
|
197
|
+
//# sourceMappingURL=chunk-JKMGYWXB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runtime/cost-tracker.ts"],"sourcesContent":["import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';\nimport { join } from 'path';\n\n/** Cost per 1M tokens for a model (input and output separately) */\nexport interface ModelPricing {\n model_pattern: string;\n input_per_million: number;\n output_per_million: number;\n}\n\n/** A recorded cost event */\nexport interface CostEntry {\n timestamp: string;\n model_id: string;\n provider: string;\n input_tokens: number;\n output_tokens: number;\n cost_usd: number;\n source: string;\n}\n\n/** Budget configuration */\nexport interface BudgetConfig {\n daily_limit_usd?: number;\n monthly_limit_usd?: number;\n alert_threshold_pct?: number;\n}\n\n/** Budget status check result */\nexport interface BudgetStatus {\n daily_spent_usd: number;\n daily_limit_usd: number | null;\n daily_remaining_usd: number | null;\n daily_pct: number | null;\n monthly_spent_usd: number;\n monthly_limit_usd: number | null;\n monthly_remaining_usd: number | null;\n monthly_pct: number | null;\n alerts: string[];\n}\n\n/** Spending summary for a time period */\nexport interface SpendingSummary {\n total_cost_usd: number;\n total_input_tokens: number;\n total_output_tokens: number;\n entries: number;\n by_model: Record<string, { cost_usd: number; input_tokens: number; output_tokens: number; count: number }>;\n by_provider: Record<string, { cost_usd: number; count: number }>;\n}\n\n/** Persisted cost store */\nexport interface CostStore {\n entries: CostEntry[];\n updated: string;\n}\n\nconst COST_FILE = 'costs.json';\nconst MAX_ENTRIES = 5000;\n\n/** Default pricing for common models (per 1M tokens) */\nconst DEFAULT_PRICING: ModelPricing[] = [\n // Anthropic via OpenRouter\n { model_pattern: 'anthropic/claude-sonnet-4', input_per_million: 3.0, output_per_million: 15.0 },\n { model_pattern: 'anthropic/claude-opus-4', input_per_million: 15.0, output_per_million: 75.0 },\n { model_pattern: 'anthropic/claude-haiku-3.5', input_per_million: 0.8, output_per_million: 4.0 },\n // Direct Anthropic\n { model_pattern: 'claude-sonnet-4', input_per_million: 3.0, output_per_million: 15.0 },\n { model_pattern: 'claude-opus-4', input_per_million: 15.0, output_per_million: 75.0 },\n { model_pattern: 'claude-haiku-3.5', input_per_million: 0.8, output_per_million: 4.0 },\n // OpenAI\n { model_pattern: 'openai/gpt-4o', input_per_million: 2.5, output_per_million: 10.0 },\n { model_pattern: 'gpt-4o', input_per_million: 2.5, output_per_million: 10.0 },\n { model_pattern: 'openai/gpt-4o-mini', input_per_million: 0.15, output_per_million: 0.6 },\n { model_pattern: 'gpt-4o-mini', input_per_million: 0.15, output_per_million: 0.6 },\n // Local models\n { model_pattern: 'local/', input_per_million: 0, output_per_million: 0 },\n];\n\nfunction getStorePath(harnessDir: string): string {\n return join(harnessDir, 'memory', COST_FILE);\n}\n\n/**\n * Load cost entries from disk.\n */\nexport function loadCosts(harnessDir: string): CostStore {\n const storePath = getStorePath(harnessDir);\n if (!existsSync(storePath)) {\n return { entries: [], updated: new Date().toISOString() };\n }\n\n try {\n const content = readFileSync(storePath, 'utf-8');\n const parsed: unknown = JSON.parse(content);\n if (\n typeof parsed === 'object' &&\n parsed !== null &&\n 'entries' in parsed &&\n Array.isArray((parsed as CostStore).entries)\n ) {\n return parsed as CostStore;\n }\n return { entries: [], updated: new Date().toISOString() };\n } catch {\n return { entries: [], updated: new Date().toISOString() };\n }\n}\n\n/**\n * Save cost entries to disk. Trims to MAX_ENTRIES.\n */\nexport function saveCosts(harnessDir: string, store: CostStore): void {\n const memoryDir = join(harnessDir, 'memory');\n if (!existsSync(memoryDir)) {\n mkdirSync(memoryDir, { recursive: true });\n }\n\n if (store.entries.length > MAX_ENTRIES) {\n store.entries = store.entries.slice(store.entries.length - MAX_ENTRIES);\n }\n\n store.updated = new Date().toISOString();\n writeFileSync(getStorePath(harnessDir), JSON.stringify(store, null, 2), 'utf-8');\n}\n\n/**\n * Find pricing for a model ID. Uses prefix matching against DEFAULT_PRICING.\n * Custom pricing can be passed to override defaults.\n */\nexport function findPricing(\n modelId: string,\n customPricing?: ModelPricing[],\n): ModelPricing | null {\n const allPricing = [...(customPricing ?? []), ...DEFAULT_PRICING];\n\n for (const pricing of allPricing) {\n if (modelId === pricing.model_pattern || modelId.startsWith(pricing.model_pattern)) {\n return pricing;\n }\n }\n\n return null;\n}\n\n/**\n * Calculate cost in USD for a given usage.\n */\nexport function calculateCost(\n modelId: string,\n inputTokens: number,\n outputTokens: number,\n customPricing?: ModelPricing[],\n): number {\n const pricing = findPricing(modelId, customPricing);\n if (!pricing) return 0;\n\n const inputCost = (inputTokens / 1_000_000) * pricing.input_per_million;\n const outputCost = (outputTokens / 1_000_000) * pricing.output_per_million;\n return Math.round((inputCost + outputCost) * 1_000_000) / 1_000_000;\n}\n\n/**\n * Record a cost entry.\n */\nexport function recordCost(\n harnessDir: string,\n entry: Omit<CostEntry, 'timestamp' | 'cost_usd'> & { cost_usd?: number },\n customPricing?: ModelPricing[],\n): CostEntry {\n const store = loadCosts(harnessDir);\n\n const costUsd = entry.cost_usd ?? calculateCost(\n entry.model_id,\n entry.input_tokens,\n entry.output_tokens,\n customPricing,\n );\n\n const fullEntry: CostEntry = {\n timestamp: new Date().toISOString(),\n model_id: entry.model_id,\n provider: entry.provider,\n input_tokens: entry.input_tokens,\n output_tokens: entry.output_tokens,\n cost_usd: costUsd,\n source: entry.source,\n };\n\n store.entries.push(fullEntry);\n saveCosts(harnessDir, store);\n\n return fullEntry;\n}\n\n/**\n * Get spending summary for a date range.\n * Defaults to today if no range specified.\n */\nexport function getSpending(\n harnessDir: string,\n from?: string,\n to?: string,\n): SpendingSummary {\n const store = loadCosts(harnessDir);\n\n const fromDate = from ?? new Date().toISOString().split('T')[0];\n const toDate = to ?? new Date(Date.now() + 86400000).toISOString().split('T')[0];\n\n const filtered = store.entries.filter(\n (e) => e.timestamp >= fromDate && e.timestamp < toDate + 'T99',\n );\n\n const byModel: SpendingSummary['by_model'] = {};\n const byProvider: SpendingSummary['by_provider'] = {};\n\n let totalCost = 0;\n let totalInput = 0;\n let totalOutput = 0;\n\n for (const entry of filtered) {\n totalCost += entry.cost_usd;\n totalInput += entry.input_tokens;\n totalOutput += entry.output_tokens;\n\n if (!byModel[entry.model_id]) {\n byModel[entry.model_id] = { cost_usd: 0, input_tokens: 0, output_tokens: 0, count: 0 };\n }\n byModel[entry.model_id].cost_usd += entry.cost_usd;\n byModel[entry.model_id].input_tokens += entry.input_tokens;\n byModel[entry.model_id].output_tokens += entry.output_tokens;\n byModel[entry.model_id].count += 1;\n\n if (!byProvider[entry.provider]) {\n byProvider[entry.provider] = { cost_usd: 0, count: 0 };\n }\n byProvider[entry.provider].cost_usd += entry.cost_usd;\n byProvider[entry.provider].count += 1;\n }\n\n return {\n total_cost_usd: Math.round(totalCost * 1_000_000) / 1_000_000,\n total_input_tokens: totalInput,\n total_output_tokens: totalOutput,\n entries: filtered.length,\n by_model: byModel,\n by_provider: byProvider,\n };\n}\n\n/**\n * Check budget status against configured limits.\n */\nexport function checkBudget(\n harnessDir: string,\n budget: BudgetConfig,\n): BudgetStatus {\n const now = new Date();\n const today = now.toISOString().split('T')[0];\n const monthStart = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-01`;\n\n const dailySpending = getSpending(harnessDir, today);\n const monthlySpending = getSpending(harnessDir, monthStart);\n\n const alerts: string[] = [];\n const alertPct = budget.alert_threshold_pct ?? 80;\n\n const dailyLimit = budget.daily_limit_usd ?? null;\n const monthlyLimit = budget.monthly_limit_usd ?? null;\n\n let dailyPct: number | null = null;\n let dailyRemaining: number | null = null;\n\n if (dailyLimit !== null) {\n dailyPct = dailyLimit > 0 ? (dailySpending.total_cost_usd / dailyLimit) * 100 : 0;\n dailyRemaining = Math.max(0, dailyLimit - dailySpending.total_cost_usd);\n\n if (dailySpending.total_cost_usd >= dailyLimit) {\n alerts.push(`Daily budget exceeded: $${dailySpending.total_cost_usd.toFixed(4)} / $${dailyLimit.toFixed(2)}`);\n } else if (dailyPct >= alertPct) {\n alerts.push(`Daily budget at ${dailyPct.toFixed(0)}%: $${dailySpending.total_cost_usd.toFixed(4)} / $${dailyLimit.toFixed(2)}`);\n }\n }\n\n let monthlyPct: number | null = null;\n let monthlyRemaining: number | null = null;\n\n if (monthlyLimit !== null) {\n monthlyPct = monthlyLimit > 0 ? (monthlySpending.total_cost_usd / monthlyLimit) * 100 : 0;\n monthlyRemaining = Math.max(0, monthlyLimit - monthlySpending.total_cost_usd);\n\n if (monthlySpending.total_cost_usd >= monthlyLimit) {\n alerts.push(`Monthly budget exceeded: $${monthlySpending.total_cost_usd.toFixed(4)} / $${monthlyLimit.toFixed(2)}`);\n } else if (monthlyPct >= alertPct) {\n alerts.push(`Monthly budget at ${monthlyPct.toFixed(0)}%: $${monthlySpending.total_cost_usd.toFixed(4)} / $${monthlyLimit.toFixed(2)}`);\n }\n }\n\n return {\n daily_spent_usd: dailySpending.total_cost_usd,\n daily_limit_usd: dailyLimit,\n daily_remaining_usd: dailyRemaining,\n daily_pct: dailyPct,\n monthly_spent_usd: monthlySpending.total_cost_usd,\n monthly_limit_usd: monthlyLimit,\n monthly_remaining_usd: monthlyRemaining,\n monthly_pct: monthlyPct,\n alerts,\n };\n}\n\n/**\n * Clear all cost entries, or entries for a specific model.\n */\nexport function clearCosts(harnessDir: string, modelId?: string): number {\n const store = loadCosts(harnessDir);\n const before = store.entries.length;\n\n if (modelId) {\n store.entries = store.entries.filter((e) => e.model_id !== modelId);\n } else {\n store.entries = [];\n }\n\n saveCosts(harnessDir, store);\n return before - store.entries.length;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
// src/core/types.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
var FrontmatterSchema = z.object({
|
|
4
|
+
id: z.string(),
|
|
5
|
+
tags: z.array(z.string()).default([]),
|
|
6
|
+
created: z.string().optional(),
|
|
7
|
+
updated: z.string().optional(),
|
|
8
|
+
author: z.enum(["human", "agent", "infrastructure"]).default("human"),
|
|
9
|
+
status: z.enum(["active", "archived", "deprecated", "draft"]).default("active"),
|
|
10
|
+
related: z.array(z.string()).default([]),
|
|
11
|
+
schedule: z.string().optional(),
|
|
12
|
+
with: z.string().optional(),
|
|
13
|
+
channel: z.string().optional(),
|
|
14
|
+
duration_minutes: z.number().optional(),
|
|
15
|
+
max_retries: z.number().int().nonnegative().optional(),
|
|
16
|
+
retry_delay_ms: z.number().int().positive().optional()
|
|
17
|
+
});
|
|
18
|
+
var HarnessConfigSchema = z.object({
|
|
19
|
+
agent: z.object({
|
|
20
|
+
name: z.string().min(1),
|
|
21
|
+
version: z.string().default("0.1.0")
|
|
22
|
+
}).passthrough(),
|
|
23
|
+
model: z.object({
|
|
24
|
+
provider: z.string().default("openrouter"),
|
|
25
|
+
id: z.string().min(1),
|
|
26
|
+
max_tokens: z.number().int().positive().default(2e5),
|
|
27
|
+
max_retries: z.number().int().nonnegative().default(2),
|
|
28
|
+
timeout_ms: z.number().int().positive().optional(),
|
|
29
|
+
/** Cheap model for auto-generating summaries, tags, frontmatter (e.g. 'google/gemini-flash-1.5') */
|
|
30
|
+
summary_model: z.string().optional(),
|
|
31
|
+
/** Fast model for validation, checks, and quick decisions (e.g. 'google/gemini-flash-1.5') */
|
|
32
|
+
fast_model: z.string().optional()
|
|
33
|
+
}).passthrough(),
|
|
34
|
+
runtime: z.object({
|
|
35
|
+
scratchpad_budget: z.number().int().nonnegative().default(1e4),
|
|
36
|
+
/** Reserved: cron expression for periodic heartbeat check (not yet implemented) */
|
|
37
|
+
heartbeat: z.string().optional(),
|
|
38
|
+
/** Reserved: cron expression for daily summary generation (not yet implemented) */
|
|
39
|
+
daily_summary: z.string().optional(),
|
|
40
|
+
/** Auto-process primitives on save: generate frontmatter, L0/L1 summaries (default: true) */
|
|
41
|
+
auto_process: z.boolean().default(true),
|
|
42
|
+
quiet_hours: z.object({
|
|
43
|
+
start: z.number().int().min(0).max(23).default(23),
|
|
44
|
+
end: z.number().int().min(0).max(23).default(6)
|
|
45
|
+
}).passthrough().default({ start: 23, end: 6 }),
|
|
46
|
+
timezone: z.string().default("America/New_York")
|
|
47
|
+
}).passthrough(),
|
|
48
|
+
memory: z.object({
|
|
49
|
+
session_retention_days: z.number().int().positive().default(7),
|
|
50
|
+
journal_retention_days: z.number().int().positive().default(365)
|
|
51
|
+
}).passthrough(),
|
|
52
|
+
channels: z.object({
|
|
53
|
+
primary: z.string().default("cli")
|
|
54
|
+
}).passthrough(),
|
|
55
|
+
extensions: z.object({
|
|
56
|
+
directories: z.array(z.string()).default([])
|
|
57
|
+
}).passthrough().default({ directories: [] }),
|
|
58
|
+
rate_limits: z.object({
|
|
59
|
+
/** Max LLM calls per minute (default: unlimited) */
|
|
60
|
+
per_minute: z.number().int().positive().optional(),
|
|
61
|
+
/** Max LLM calls per hour (default: unlimited) */
|
|
62
|
+
per_hour: z.number().int().positive().optional(),
|
|
63
|
+
/** Max LLM calls per day (default: unlimited) */
|
|
64
|
+
per_day: z.number().int().positive().optional()
|
|
65
|
+
}).passthrough().default({}),
|
|
66
|
+
budget: z.object({
|
|
67
|
+
/** Max daily spend in USD (default: unlimited) */
|
|
68
|
+
daily_limit_usd: z.number().positive().optional(),
|
|
69
|
+
/** Max monthly spend in USD (default: unlimited) */
|
|
70
|
+
monthly_limit_usd: z.number().positive().optional(),
|
|
71
|
+
/** Block runs when budget exceeded (default: true) */
|
|
72
|
+
enforce: z.boolean().default(true)
|
|
73
|
+
}).passthrough().default({ enforce: true }),
|
|
74
|
+
mcp: z.object({
|
|
75
|
+
/** MCP server definitions keyed by server name */
|
|
76
|
+
servers: z.record(z.string(), z.object({
|
|
77
|
+
/** Transport type: 'stdio' for local processes, 'http' for remote, 'sse' for SSE */
|
|
78
|
+
transport: z.enum(["stdio", "http", "sse"]),
|
|
79
|
+
/** Command to spawn (stdio transport only) */
|
|
80
|
+
command: z.string().optional(),
|
|
81
|
+
/** Command arguments (stdio transport only) */
|
|
82
|
+
args: z.array(z.string()).optional(),
|
|
83
|
+
/** Environment variables for the spawned process (stdio transport only) */
|
|
84
|
+
env: z.record(z.string(), z.string()).optional(),
|
|
85
|
+
/** Working directory for the spawned process (stdio transport only) */
|
|
86
|
+
cwd: z.string().optional(),
|
|
87
|
+
/** URL endpoint (http/sse transport only) */
|
|
88
|
+
url: z.string().optional(),
|
|
89
|
+
/** Additional HTTP headers (http/sse transport only) */
|
|
90
|
+
headers: z.record(z.string(), z.string()).optional(),
|
|
91
|
+
/** Whether this server is enabled (default: true) */
|
|
92
|
+
enabled: z.boolean().default(true)
|
|
93
|
+
}).passthrough()).default({})
|
|
94
|
+
}).passthrough().default({ servers: {} }),
|
|
95
|
+
/** Intelligence & continuous learning config */
|
|
96
|
+
intelligence: z.object({
|
|
97
|
+
/** Auto-run journal synthesis on a cron schedule (default: off). Set to cron string e.g. "0 22 * * *" or true for default "0 22 * * *". */
|
|
98
|
+
auto_journal: z.union([z.boolean(), z.string()]).default(false),
|
|
99
|
+
/** Auto-run instinct learning after journal synthesis (default: off) */
|
|
100
|
+
auto_learn: z.boolean().default(false)
|
|
101
|
+
}).passthrough().default({ auto_journal: false, auto_learn: false }),
|
|
102
|
+
/** Proactive execution config (scheduler rate-limiting) */
|
|
103
|
+
proactive: z.object({
|
|
104
|
+
/** Enable proactive scheduled workflows (default: false) */
|
|
105
|
+
enabled: z.boolean().default(false),
|
|
106
|
+
/** Max proactive workflow executions per hour (default: 5) */
|
|
107
|
+
max_per_hour: z.number().int().positive().default(5),
|
|
108
|
+
/** Cooldown in minutes between proactive runs of the same workflow (default: 30) */
|
|
109
|
+
cooldown_minutes: z.number().int().nonnegative().default(30),
|
|
110
|
+
/** Override quiet hours for proactive execution (start/end hours, inherits runtime.quiet_hours if not set) */
|
|
111
|
+
quiet_hours: z.object({
|
|
112
|
+
start: z.number().int().min(0).max(23).optional(),
|
|
113
|
+
end: z.number().int().min(0).max(23).optional()
|
|
114
|
+
}).passthrough().optional()
|
|
115
|
+
}).passthrough().default({ enabled: false, max_per_hour: 5, cooldown_minutes: 30 }),
|
|
116
|
+
/** Primitive bundle registries for search/install */
|
|
117
|
+
registries: z.array(z.object({
|
|
118
|
+
/** Registry URL (HTTPS endpoint) */
|
|
119
|
+
url: z.string().url(),
|
|
120
|
+
/** Optional display name */
|
|
121
|
+
name: z.string().optional(),
|
|
122
|
+
/** Optional auth token for private registries */
|
|
123
|
+
token: z.string().optional()
|
|
124
|
+
}).passthrough()).default([])
|
|
125
|
+
}).passthrough();
|
|
126
|
+
var CONFIG_DEFAULTS = {
|
|
127
|
+
agent: { name: "agent", version: "0.1.0" },
|
|
128
|
+
model: { provider: "openrouter", id: "anthropic/claude-sonnet-4", max_tokens: 2e5, max_retries: 2 },
|
|
129
|
+
runtime: {
|
|
130
|
+
scratchpad_budget: 1e4,
|
|
131
|
+
auto_process: true,
|
|
132
|
+
quiet_hours: { start: 23, end: 6 },
|
|
133
|
+
timezone: "America/New_York"
|
|
134
|
+
},
|
|
135
|
+
memory: { session_retention_days: 7, journal_retention_days: 365 },
|
|
136
|
+
channels: { primary: "cli" },
|
|
137
|
+
extensions: { directories: [] },
|
|
138
|
+
rate_limits: {},
|
|
139
|
+
budget: { enforce: true },
|
|
140
|
+
intelligence: { auto_journal: false, auto_learn: false },
|
|
141
|
+
proactive: { enabled: false, max_per_hour: 5, cooldown_minutes: 30 },
|
|
142
|
+
mcp: { servers: {} },
|
|
143
|
+
registries: []
|
|
144
|
+
};
|
|
145
|
+
var CORE_PRIMITIVE_DIRS = ["rules", "instincts", "skills", "playbooks", "workflows", "tools", "agents"];
|
|
146
|
+
function getPrimitiveDirs(config) {
|
|
147
|
+
const dirs = [...CORE_PRIMITIVE_DIRS];
|
|
148
|
+
if (config?.extensions?.directories) {
|
|
149
|
+
for (const dir of config.extensions.directories) {
|
|
150
|
+
if (!dirs.includes(dir)) {
|
|
151
|
+
dirs.push(dir);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return dirs;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export {
|
|
159
|
+
FrontmatterSchema,
|
|
160
|
+
HarnessConfigSchema,
|
|
161
|
+
CONFIG_DEFAULTS,
|
|
162
|
+
CORE_PRIMITIVE_DIRS,
|
|
163
|
+
getPrimitiveDirs
|
|
164
|
+
};
|
|
165
|
+
//# sourceMappingURL=chunk-KFX54TQM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/types.ts"],"sourcesContent":["import { z } from 'zod';\n\n// --- Frontmatter ---\nexport const FrontmatterSchema = z.object({\n id: z.string(),\n tags: z.array(z.string()).default([]),\n created: z.string().optional(),\n updated: z.string().optional(),\n author: z.enum(['human', 'agent', 'infrastructure']).default('human'),\n status: z.enum(['active', 'archived', 'deprecated', 'draft']).default('active'),\n related: z.array(z.string()).default([]),\n schedule: z.string().optional(),\n with: z.string().optional(),\n channel: z.string().optional(),\n duration_minutes: z.number().optional(),\n max_retries: z.number().int().nonnegative().optional(),\n retry_delay_ms: z.number().int().positive().optional(),\n});\n\nexport type Frontmatter = z.infer<typeof FrontmatterSchema>;\n\n// --- Primitive Document ---\nexport interface HarnessDocument {\n path: string;\n frontmatter: Frontmatter;\n l0: string;\n l1: string;\n body: string;\n raw: string;\n}\n\n// --- Primitive Types ---\nexport type PrimitiveType =\n | 'rule'\n | 'instinct'\n | 'skill'\n | 'playbook'\n | 'workflow'\n | 'tool'\n | 'agent'\n | 'session'\n | 'journal';\n\nexport interface Primitive {\n type: PrimitiveType;\n doc: HarnessDocument;\n}\n\n// --- Config ---\nexport const HarnessConfigSchema = z.object({\n agent: z.object({\n name: z.string().min(1),\n version: z.string().default('0.1.0'),\n }).passthrough(),\n model: z.object({\n provider: z.string().default('openrouter'),\n id: z.string().min(1),\n max_tokens: z.number().int().positive().default(200000),\n max_retries: z.number().int().nonnegative().default(2),\n timeout_ms: z.number().int().positive().optional(),\n /** Cheap model for auto-generating summaries, tags, frontmatter (e.g. 'google/gemini-flash-1.5') */\n summary_model: z.string().optional(),\n /** Fast model for validation, checks, and quick decisions (e.g. 'google/gemini-flash-1.5') */\n fast_model: z.string().optional(),\n }).passthrough(),\n runtime: z.object({\n scratchpad_budget: z.number().int().nonnegative().default(10000),\n /** Reserved: cron expression for periodic heartbeat check (not yet implemented) */\n heartbeat: z.string().optional(),\n /** Reserved: cron expression for daily summary generation (not yet implemented) */\n daily_summary: z.string().optional(),\n /** Auto-process primitives on save: generate frontmatter, L0/L1 summaries (default: true) */\n auto_process: z.boolean().default(true),\n quiet_hours: z.object({\n start: z.number().int().min(0).max(23).default(23),\n end: z.number().int().min(0).max(23).default(6),\n }).passthrough().default({ start: 23, end: 6 }),\n timezone: z.string().default('America/New_York'),\n }).passthrough(),\n memory: z.object({\n session_retention_days: z.number().int().positive().default(7),\n journal_retention_days: z.number().int().positive().default(365),\n }).passthrough(),\n channels: z.object({\n primary: z.string().default('cli'),\n }).passthrough(),\n extensions: z.object({\n directories: z.array(z.string()).default([]),\n }).passthrough().default({ directories: [] }),\n rate_limits: z.object({\n /** Max LLM calls per minute (default: unlimited) */\n per_minute: z.number().int().positive().optional(),\n /** Max LLM calls per hour (default: unlimited) */\n per_hour: z.number().int().positive().optional(),\n /** Max LLM calls per day (default: unlimited) */\n per_day: z.number().int().positive().optional(),\n }).passthrough().default({}),\n budget: z.object({\n /** Max daily spend in USD (default: unlimited) */\n daily_limit_usd: z.number().positive().optional(),\n /** Max monthly spend in USD (default: unlimited) */\n monthly_limit_usd: z.number().positive().optional(),\n /** Block runs when budget exceeded (default: true) */\n enforce: z.boolean().default(true),\n }).passthrough().default({ enforce: true }),\n mcp: z.object({\n /** MCP server definitions keyed by server name */\n servers: z.record(z.string(), z.object({\n /** Transport type: 'stdio' for local processes, 'http' for remote, 'sse' for SSE */\n transport: z.enum(['stdio', 'http', 'sse']),\n /** Command to spawn (stdio transport only) */\n command: z.string().optional(),\n /** Command arguments (stdio transport only) */\n args: z.array(z.string()).optional(),\n /** Environment variables for the spawned process (stdio transport only) */\n env: z.record(z.string(), z.string()).optional(),\n /** Working directory for the spawned process (stdio transport only) */\n cwd: z.string().optional(),\n /** URL endpoint (http/sse transport only) */\n url: z.string().optional(),\n /** Additional HTTP headers (http/sse transport only) */\n headers: z.record(z.string(), z.string()).optional(),\n /** Whether this server is enabled (default: true) */\n enabled: z.boolean().default(true),\n }).passthrough()).default({}),\n }).passthrough().default({ servers: {} }),\n /** Intelligence & continuous learning config */\n intelligence: z.object({\n /** Auto-run journal synthesis on a cron schedule (default: off). Set to cron string e.g. \"0 22 * * *\" or true for default \"0 22 * * *\". */\n auto_journal: z.union([z.boolean(), z.string()]).default(false),\n /** Auto-run instinct learning after journal synthesis (default: off) */\n auto_learn: z.boolean().default(false),\n }).passthrough().default({ auto_journal: false, auto_learn: false }),\n /** Proactive execution config (scheduler rate-limiting) */\n proactive: z.object({\n /** Enable proactive scheduled workflows (default: false) */\n enabled: z.boolean().default(false),\n /** Max proactive workflow executions per hour (default: 5) */\n max_per_hour: z.number().int().positive().default(5),\n /** Cooldown in minutes between proactive runs of the same workflow (default: 30) */\n cooldown_minutes: z.number().int().nonnegative().default(30),\n /** Override quiet hours for proactive execution (start/end hours, inherits runtime.quiet_hours if not set) */\n quiet_hours: z.object({\n start: z.number().int().min(0).max(23).optional(),\n end: z.number().int().min(0).max(23).optional(),\n }).passthrough().optional(),\n }).passthrough().default({ enabled: false, max_per_hour: 5, cooldown_minutes: 30 }),\n /** Primitive bundle registries for search/install */\n registries: z.array(z.object({\n /** Registry URL (HTTPS endpoint) */\n url: z.string().url(),\n /** Optional display name */\n name: z.string().optional(),\n /** Optional auth token for private registries */\n token: z.string().optional(),\n }).passthrough()).default([]),\n}).passthrough();\n\nexport type HarnessConfig = z.infer<typeof HarnessConfigSchema>;\n\nexport const CONFIG_DEFAULTS: HarnessConfig = {\n agent: { name: 'agent', version: '0.1.0' },\n model: { provider: 'openrouter', id: 'anthropic/claude-sonnet-4', max_tokens: 200000, max_retries: 2 },\n runtime: {\n scratchpad_budget: 10000,\n auto_process: true,\n quiet_hours: { start: 23, end: 6 },\n timezone: 'America/New_York',\n },\n memory: { session_retention_days: 7, journal_retention_days: 365 },\n channels: { primary: 'cli' },\n extensions: { directories: [] },\n rate_limits: {},\n budget: { enforce: true },\n intelligence: { auto_journal: false, auto_learn: false },\n proactive: { enabled: false, max_per_hour: 5, cooldown_minutes: 30 },\n mcp: { servers: {} },\n registries: [],\n};\n\nexport const CORE_PRIMITIVE_DIRS = ['rules', 'instincts', 'skills', 'playbooks', 'workflows', 'tools', 'agents'] as const;\n\nexport function getPrimitiveDirs(config?: HarnessConfig): string[] {\n const dirs: string[] = [...CORE_PRIMITIVE_DIRS];\n if (config?.extensions?.directories) {\n for (const dir of config.extensions.directories) {\n if (!dirs.includes(dir)) {\n dirs.push(dir);\n }\n }\n }\n return dirs;\n}\n\n// --- Agent State ---\nexport interface AgentState {\n mode: string;\n goals: string[];\n active_workflows: string[];\n last_interaction: string;\n unfinished_business: string[];\n}\n\n// --- Context Budget ---\nexport interface ContextBudget {\n max_tokens: number;\n used_tokens: number;\n remaining: number;\n loaded_files: string[];\n}\n\n// --- Utility Types ---\nexport type DeepPartial<T> = {\n [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];\n};\n\n// --- Lifecycle Hooks ---\nexport interface HarnessHooks {\n /** Called after boot completes (context loaded, state ready) */\n onBoot?: (context: { agent: HarnessAgent; config: HarnessConfig; state: AgentState }) => void | Promise<void>;\n /** Called after each session completes (run or stream) */\n onSessionEnd?: (context: { agent: HarnessAgent; sessionId: string; prompt: string; result: AgentRunResult }) => void | Promise<void>;\n /** Called when an error occurs during run/stream */\n onError?: (context: { agent: HarnessAgent; error: Error; prompt?: string }) => void | Promise<void>;\n /** Called when agent state changes (boot, shutdown, after run) */\n onStateChange?: (context: { agent: HarnessAgent; previous: string; current: string }) => void | Promise<void>;\n /** Called before shutdown completes */\n onShutdown?: (context: { agent: HarnessAgent; state: AgentState }) => void | Promise<void>;\n}\n\n// --- Tool Executor Config (inline to avoid circular deps) ---\nexport interface ToolExecutorOptions {\n /** Maximum tool calls per run (default: 5) */\n maxToolCalls?: number;\n /** Timeout per tool call in ms (default: 30000) */\n toolTimeoutMs?: number;\n /** Whether to allow HTTP tool execution (default: true) */\n allowHttpExecution?: boolean;\n}\n\n// --- Agent Options (programmatic API) ---\nexport interface CreateHarnessOptions {\n dir: string;\n /** Model ID override (e.g., \"claude-sonnet-4-20250514\" or \"gpt-4o\") */\n model?: string;\n /** Provider override (e.g., \"anthropic\", \"openai\", \"openrouter\") */\n provider?: string;\n apiKey?: string;\n config?: DeepPartial<HarnessConfig>;\n /** Lifecycle hooks for agent events */\n hooks?: HarnessHooks;\n /** Tool execution configuration */\n toolExecutor?: ToolExecutorOptions;\n}\n\n/** Record of a single tool call made during a run */\nexport interface ToolCallInfo {\n toolName: string;\n args: Record<string, unknown>;\n result: unknown;\n}\n\n// --- Agent Interface ---\nexport interface AgentRunResult {\n text: string;\n usage: { inputTokens: number; outputTokens: number; totalTokens: number };\n session_id: string;\n steps: number;\n /** Tool calls made during the run (empty array if none) */\n toolCalls: ToolCallInfo[];\n}\n\nexport interface AgentStreamResult {\n /** Async iterable of text chunks — consume with for-await */\n textStream: AsyncIterable<string>;\n /** Resolves after the stream is fully consumed with session metadata */\n result: Promise<AgentRunResult>;\n}\n\nexport interface HarnessAgent {\n name: string;\n config: HarnessConfig;\n boot(): Promise<void>;\n run(prompt: string): Promise<AgentRunResult>;\n stream(prompt: string): AgentStreamResult;\n shutdown(): Promise<void>;\n getSystemPrompt(): string;\n getState(): AgentState;\n}\n\n// --- Index Entry ---\nexport interface IndexEntry {\n id: string;\n path: string;\n tags: string[];\n l0: string;\n created: string;\n status: string;\n}\n"],"mappings":";AAAA,SAAS,SAAS;AAGX,IAAM,oBAAoB,EAAE,OAAO;AAAA,EACxC,IAAI,EAAE,OAAO;AAAA,EACb,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,EACpC,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,QAAQ,EAAE,KAAK,CAAC,SAAS,SAAS,gBAAgB,CAAC,EAAE,QAAQ,OAAO;AAAA,EACpE,QAAQ,EAAE,KAAK,CAAC,UAAU,YAAY,cAAc,OAAO,CAAC,EAAE,QAAQ,QAAQ;AAAA,EAC9E,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,EACvC,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,kBAAkB,EAAE,OAAO,EAAE,SAAS;AAAA,EACtC,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AAAA,EACrD,gBAAgB,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AACvD,CAAC;AAgCM,IAAM,sBAAsB,EAAE,OAAO;AAAA,EAC1C,OAAO,EAAE,OAAO;AAAA,IACd,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IACtB,SAAS,EAAE,OAAO,EAAE,QAAQ,OAAO;AAAA,EACrC,CAAC,EAAE,YAAY;AAAA,EACf,OAAO,EAAE,OAAO;AAAA,IACd,UAAU,EAAE,OAAO,EAAE,QAAQ,YAAY;AAAA,IACzC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,IACpB,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,GAAM;AAAA,IACtD,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,CAAC;AAAA,IACrD,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA;AAAA,IAEjD,eAAe,EAAE,OAAO,EAAE,SAAS;AAAA;AAAA,IAEnC,YAAY,EAAE,OAAO,EAAE,SAAS;AAAA,EAClC,CAAC,EAAE,YAAY;AAAA,EACf,SAAS,EAAE,OAAO;AAAA,IAChB,mBAAmB,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,GAAK;AAAA;AAAA,IAE/D,WAAW,EAAE,OAAO,EAAE,SAAS;AAAA;AAAA,IAE/B,eAAe,EAAE,OAAO,EAAE,SAAS;AAAA;AAAA,IAEnC,cAAc,EAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,IACtC,aAAa,EAAE,OAAO;AAAA,MACpB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE;AAAA,MACjD,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,QAAQ,CAAC;AAAA,IAChD,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,IAAI,KAAK,EAAE,CAAC;AAAA,IAC9C,UAAU,EAAE,OAAO,EAAE,QAAQ,kBAAkB;AAAA,EACjD,CAAC,EAAE,YAAY;AAAA,EACf,QAAQ,EAAE,OAAO;AAAA,IACf,wBAAwB,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC;AAAA,IAC7D,wBAAwB,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,GAAG;AAAA,EACjE,CAAC,EAAE,YAAY;AAAA,EACf,UAAU,EAAE,OAAO;AAAA,IACjB,SAAS,EAAE,OAAO,EAAE,QAAQ,KAAK;AAAA,EACnC,CAAC,EAAE,YAAY;AAAA,EACf,YAAY,EAAE,OAAO;AAAA,IACnB,aAAa,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,EAC7C,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,CAAC,EAAE,CAAC;AAAA,EAC5C,aAAa,EAAE,OAAO;AAAA;AAAA,IAEpB,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA;AAAA,IAEjD,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA;AAAA,IAE/C,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,EAChD,CAAC,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;AAAA,EAC3B,QAAQ,EAAE,OAAO;AAAA;AAAA,IAEf,iBAAiB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA;AAAA,IAEhD,mBAAmB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA;AAAA,IAElD,SAAS,EAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EACnC,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,KAAK,CAAC;AAAA,EAC1C,KAAK,EAAE,OAAO;AAAA;AAAA,IAEZ,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO;AAAA;AAAA,MAErC,WAAW,EAAE,KAAK,CAAC,SAAS,QAAQ,KAAK,CAAC;AAAA;AAAA,MAE1C,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA;AAAA,MAE7B,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS;AAAA;AAAA,MAEnC,KAAK,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,EAAE,SAAS;AAAA;AAAA,MAE/C,KAAK,EAAE,OAAO,EAAE,SAAS;AAAA;AAAA,MAEzB,KAAK,EAAE,OAAO,EAAE,SAAS;AAAA;AAAA,MAEzB,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,EAAE,SAAS;AAAA;AAAA,MAEnD,SAAS,EAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,IACnC,CAAC,EAAE,YAAY,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,EAC9B,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE,CAAC;AAAA;AAAA,EAExC,cAAc,EAAE,OAAO;AAAA;AAAA,IAErB,cAAc,EAAE,MAAM,CAAC,EAAE,QAAQ,GAAG,EAAE,OAAO,CAAC,CAAC,EAAE,QAAQ,KAAK;AAAA;AAAA,IAE9D,YAAY,EAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EACvC,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,cAAc,OAAO,YAAY,MAAM,CAAC;AAAA;AAAA,EAEnE,WAAW,EAAE,OAAO;AAAA;AAAA,IAElB,SAAS,EAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA;AAAA,IAElC,cAAc,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC;AAAA;AAAA,IAEnD,kBAAkB,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE;AAAA;AAAA,IAE3D,aAAa,EAAE,OAAO;AAAA,MACpB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS;AAAA,MAChD,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS;AAAA,IAChD,CAAC,EAAE,YAAY,EAAE,SAAS;AAAA,EAC5B,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,OAAO,cAAc,GAAG,kBAAkB,GAAG,CAAC;AAAA;AAAA,EAElF,YAAY,EAAE,MAAM,EAAE,OAAO;AAAA;AAAA,IAE3B,KAAK,EAAE,OAAO,EAAE,IAAI;AAAA;AAAA,IAEpB,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA;AAAA,IAE1B,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,CAAC,EAAE,YAAY,CAAC,EAAE,QAAQ,CAAC,CAAC;AAC9B,CAAC,EAAE,YAAY;AAIR,IAAM,kBAAiC;AAAA,EAC5C,OAAO,EAAE,MAAM,SAAS,SAAS,QAAQ;AAAA,EACzC,OAAO,EAAE,UAAU,cAAc,IAAI,6BAA6B,YAAY,KAAQ,aAAa,EAAE;AAAA,EACrG,SAAS;AAAA,IACP,mBAAmB;AAAA,IACnB,cAAc;AAAA,IACd,aAAa,EAAE,OAAO,IAAI,KAAK,EAAE;AAAA,IACjC,UAAU;AAAA,EACZ;AAAA,EACA,QAAQ,EAAE,wBAAwB,GAAG,wBAAwB,IAAI;AAAA,EACjE,UAAU,EAAE,SAAS,MAAM;AAAA,EAC3B,YAAY,EAAE,aAAa,CAAC,EAAE;AAAA,EAC9B,aAAa,CAAC;AAAA,EACd,QAAQ,EAAE,SAAS,KAAK;AAAA,EACxB,cAAc,EAAE,cAAc,OAAO,YAAY,MAAM;AAAA,EACvD,WAAW,EAAE,SAAS,OAAO,cAAc,GAAG,kBAAkB,GAAG;AAAA,EACnE,KAAK,EAAE,SAAS,CAAC,EAAE;AAAA,EACnB,YAAY,CAAC;AACf;AAEO,IAAM,sBAAsB,CAAC,SAAS,aAAa,UAAU,aAAa,aAAa,SAAS,QAAQ;AAExG,SAAS,iBAAiB,QAAkC;AACjE,QAAM,OAAiB,CAAC,GAAG,mBAAmB;AAC9C,MAAI,QAAQ,YAAY,aAAa;AACnC,eAAW,OAAO,OAAO,WAAW,aAAa;AAC/C,UAAI,CAAC,KAAK,SAAS,GAAG,GAAG;AACvB,aAAK,KAAK,GAAG;AAAA,MACf;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;","names":[]}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
getPrimitiveDirs
|
|
5
|
+
} from "./chunk-4CWAGBNS.js";
|
|
6
|
+
|
|
7
|
+
// src/runtime/auto-processor.ts
|
|
8
|
+
import { readFileSync, writeFileSync, existsSync, readdirSync } from "fs";
|
|
9
|
+
import { basename, relative, join } from "path";
|
|
10
|
+
import matter from "gray-matter";
|
|
11
|
+
var L0_REGEX = /<!--\s*L0:\s*(.*?)\s*-->/;
|
|
12
|
+
var L1_REGEX = /<!--\s*L1:\s*([\s\S]*?)\s*-->/;
|
|
13
|
+
function inferTypeFromPath(filePath, harnessDir) {
|
|
14
|
+
const rel = relative(harnessDir, filePath);
|
|
15
|
+
const topDir = rel.split("/")[0];
|
|
16
|
+
const dirToType = {
|
|
17
|
+
rules: "rule",
|
|
18
|
+
instincts: "instinct",
|
|
19
|
+
skills: "skill",
|
|
20
|
+
playbooks: "playbook",
|
|
21
|
+
workflows: "workflow",
|
|
22
|
+
tools: "tool",
|
|
23
|
+
agents: "agent"
|
|
24
|
+
};
|
|
25
|
+
return dirToType[topDir] ?? null;
|
|
26
|
+
}
|
|
27
|
+
function deriveId(filePath) {
|
|
28
|
+
return basename(filePath, ".md").replace(/[^a-z0-9-]/gi, "-").toLowerCase();
|
|
29
|
+
}
|
|
30
|
+
function generateL0(content) {
|
|
31
|
+
const headingMatch = content.match(/^#\s+(.+)$/m);
|
|
32
|
+
if (headingMatch) {
|
|
33
|
+
const text = headingMatch[1].trim();
|
|
34
|
+
return text.length > 120 ? text.slice(0, 117) + "..." : text;
|
|
35
|
+
}
|
|
36
|
+
const lines = content.split("\n");
|
|
37
|
+
for (const line of lines) {
|
|
38
|
+
const trimmed = line.trim();
|
|
39
|
+
if (trimmed.length > 0 && !trimmed.startsWith("<!--") && !trimmed.startsWith("---")) {
|
|
40
|
+
return trimmed.length > 120 ? trimmed.slice(0, 117) + "..." : trimmed;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
function generateL1(content) {
|
|
46
|
+
const paragraphs = content.split(/\n{2,}/).filter((p) => {
|
|
47
|
+
const trimmed = p.trim();
|
|
48
|
+
return trimmed.length > 0 && !trimmed.startsWith("<!--") && !trimmed.startsWith("#") && !trimmed.startsWith("---");
|
|
49
|
+
});
|
|
50
|
+
if (paragraphs.length === 0) return null;
|
|
51
|
+
const para = paragraphs[0].replace(/\n/g, " ").trim();
|
|
52
|
+
return para.length > 300 ? para.slice(0, 297) + "..." : para;
|
|
53
|
+
}
|
|
54
|
+
function autoProcessFile(filePath, options) {
|
|
55
|
+
const result = {
|
|
56
|
+
path: filePath,
|
|
57
|
+
modified: false,
|
|
58
|
+
fixes: [],
|
|
59
|
+
errors: []
|
|
60
|
+
};
|
|
61
|
+
if (!existsSync(filePath) || !filePath.endsWith(".md")) {
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
const filename = basename(filePath);
|
|
65
|
+
if (filename.startsWith("_") || filename === "CORE.md" || filename === "SYSTEM.md" || filename === "state.md") {
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
let raw;
|
|
69
|
+
try {
|
|
70
|
+
raw = readFileSync(filePath, "utf-8");
|
|
71
|
+
} catch (err) {
|
|
72
|
+
result.errors.push(`Failed to read: ${err instanceof Error ? err.message : String(err)}`);
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
if (raw.trim().length === 0) {
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
const generateFrontmatter = options.generateFrontmatter !== false;
|
|
79
|
+
const generateSummaries = options.generateSummaries !== false;
|
|
80
|
+
let parsed;
|
|
81
|
+
try {
|
|
82
|
+
parsed = matter(raw);
|
|
83
|
+
} catch {
|
|
84
|
+
if (generateFrontmatter) {
|
|
85
|
+
const id = deriveId(filePath);
|
|
86
|
+
const type = inferTypeFromPath(filePath, options.harnessDir);
|
|
87
|
+
const tags = type ? [type] : [];
|
|
88
|
+
const data2 = {
|
|
89
|
+
id,
|
|
90
|
+
created: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
|
|
91
|
+
author: "infrastructure",
|
|
92
|
+
status: "active",
|
|
93
|
+
tags
|
|
94
|
+
};
|
|
95
|
+
const newContent = matter.stringify(raw, data2);
|
|
96
|
+
writeFileSync(filePath, newContent, "utf-8");
|
|
97
|
+
result.modified = true;
|
|
98
|
+
result.fixes.push(`Added frontmatter (id: ${id})`);
|
|
99
|
+
}
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
const data = { ...parsed.data };
|
|
103
|
+
let content = parsed.content;
|
|
104
|
+
let modified = false;
|
|
105
|
+
if (generateFrontmatter) {
|
|
106
|
+
if (!data.id) {
|
|
107
|
+
data.id = deriveId(filePath);
|
|
108
|
+
result.fixes.push(`Added id: "${data.id}"`);
|
|
109
|
+
modified = true;
|
|
110
|
+
}
|
|
111
|
+
if (!data.created) {
|
|
112
|
+
data.created = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
113
|
+
result.fixes.push("Added created date");
|
|
114
|
+
modified = true;
|
|
115
|
+
}
|
|
116
|
+
if (!data.author) {
|
|
117
|
+
data.author = "human";
|
|
118
|
+
result.fixes.push('Added author: "human"');
|
|
119
|
+
modified = true;
|
|
120
|
+
}
|
|
121
|
+
if (!data.status) {
|
|
122
|
+
data.status = "active";
|
|
123
|
+
result.fixes.push('Added status: "active"');
|
|
124
|
+
modified = true;
|
|
125
|
+
}
|
|
126
|
+
if (!Array.isArray(data.tags) || data.tags.length === 0) {
|
|
127
|
+
const type = inferTypeFromPath(filePath, options.harnessDir);
|
|
128
|
+
data.tags = type ? [type] : [];
|
|
129
|
+
if (type) {
|
|
130
|
+
result.fixes.push(`Added tag: "${type}"`);
|
|
131
|
+
modified = true;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (generateSummaries) {
|
|
136
|
+
if (!L0_REGEX.test(content)) {
|
|
137
|
+
const l0 = generateL0(content);
|
|
138
|
+
if (l0) {
|
|
139
|
+
content = `<!-- L0: ${l0} -->
|
|
140
|
+
${content}`;
|
|
141
|
+
result.fixes.push("Generated L0 summary");
|
|
142
|
+
modified = true;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (!L1_REGEX.test(content)) {
|
|
146
|
+
const l1 = generateL1(content);
|
|
147
|
+
if (l1) {
|
|
148
|
+
const l0Pos = content.indexOf("-->");
|
|
149
|
+
if (l0Pos !== -1) {
|
|
150
|
+
const insertPos = l0Pos + 3;
|
|
151
|
+
content = content.slice(0, insertPos) + `
|
|
152
|
+
<!-- L1: ${l1} -->` + content.slice(insertPos);
|
|
153
|
+
} else {
|
|
154
|
+
content = `<!-- L1: ${l1} -->
|
|
155
|
+
${content}`;
|
|
156
|
+
}
|
|
157
|
+
result.fixes.push("Generated L1 summary");
|
|
158
|
+
modified = true;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (modified) {
|
|
163
|
+
try {
|
|
164
|
+
const newRaw = matter.stringify(content, data);
|
|
165
|
+
writeFileSync(filePath, newRaw, "utf-8");
|
|
166
|
+
result.modified = true;
|
|
167
|
+
} catch (err) {
|
|
168
|
+
result.errors.push(`Failed to write: ${err instanceof Error ? err.message : String(err)}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return result;
|
|
172
|
+
}
|
|
173
|
+
function autoProcessAll(harnessDir, options) {
|
|
174
|
+
const results = [];
|
|
175
|
+
const dirs = getPrimitiveDirs();
|
|
176
|
+
for (const dir of dirs) {
|
|
177
|
+
const dirPath = join(harnessDir, dir);
|
|
178
|
+
if (!existsSync(dirPath)) continue;
|
|
179
|
+
const files = readdirSync(dirPath).filter((f) => f.endsWith(".md") && !f.startsWith("_"));
|
|
180
|
+
for (const file of files) {
|
|
181
|
+
const filePath = join(dirPath, file);
|
|
182
|
+
const result = autoProcessFile(filePath, {
|
|
183
|
+
harnessDir,
|
|
184
|
+
generateFrontmatter: options?.generateFrontmatter,
|
|
185
|
+
generateSummaries: options?.generateSummaries
|
|
186
|
+
});
|
|
187
|
+
if (result.modified || result.errors.length > 0) {
|
|
188
|
+
results.push(result);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return results;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export {
|
|
196
|
+
autoProcessFile,
|
|
197
|
+
autoProcessAll
|
|
198
|
+
};
|
|
199
|
+
//# sourceMappingURL=chunk-M7NXUK55.js.map
|