@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,347 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
writeDefaultConfig
|
|
5
|
+
} from "./chunk-CHJ5GNZC.js";
|
|
6
|
+
import "./chunk-4CWAGBNS.js";
|
|
7
|
+
import "./chunk-ZZJOFKAT.js";
|
|
8
|
+
|
|
9
|
+
// src/cli/scaffold.ts
|
|
10
|
+
import { mkdirSync, writeFileSync, readFileSync, readdirSync, existsSync } from "fs";
|
|
11
|
+
import { join, dirname } from "path";
|
|
12
|
+
import { fileURLToPath } from "url";
|
|
13
|
+
var DIRECTORIES = [
|
|
14
|
+
"rules",
|
|
15
|
+
"instincts",
|
|
16
|
+
"skills",
|
|
17
|
+
"playbooks",
|
|
18
|
+
"workflows",
|
|
19
|
+
"tools",
|
|
20
|
+
"agents",
|
|
21
|
+
"intake",
|
|
22
|
+
"memory/sessions",
|
|
23
|
+
"memory/journal"
|
|
24
|
+
];
|
|
25
|
+
function getPackageRoot() {
|
|
26
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
27
|
+
for (let i = 0; i < 5; i++) {
|
|
28
|
+
if (existsSync(join(dir, "package.json"))) return dir;
|
|
29
|
+
dir = dirname(dir);
|
|
30
|
+
}
|
|
31
|
+
return dirname(dirname(fileURLToPath(import.meta.url)));
|
|
32
|
+
}
|
|
33
|
+
function applyTemplate(content, vars) {
|
|
34
|
+
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
35
|
+
const defaultPurpose = `I am ${vars.agentName}, an autonomous AI agent. My purpose is to help my creator build, think, and ship.`;
|
|
36
|
+
const purpose = vars.purpose ? `I am ${vars.agentName}. ${vars.purpose}` : defaultPurpose;
|
|
37
|
+
return content.replace(/\{\{AGENT_NAME\}\}/g, vars.agentName).replace(/\{\{PURPOSE\}\}/g, purpose).replace(/\{\{DATE\}\}/g, date);
|
|
38
|
+
}
|
|
39
|
+
function copyDefaults(targetDir, vars) {
|
|
40
|
+
const defaultsDir = join(getPackageRoot(), "defaults");
|
|
41
|
+
if (!existsSync(defaultsDir)) return;
|
|
42
|
+
const primitiveDirs = ["rules", "instincts", "skills", "playbooks", "agents", "tools", "workflows"];
|
|
43
|
+
for (const dir of primitiveDirs) {
|
|
44
|
+
const srcDir = join(defaultsDir, dir);
|
|
45
|
+
if (!existsSync(srcDir)) continue;
|
|
46
|
+
const files = readdirSync(srcDir).filter((f) => f.endsWith(".md"));
|
|
47
|
+
for (const file of files) {
|
|
48
|
+
const content = readFileSync(join(srcDir, file), "utf-8");
|
|
49
|
+
writeFileSync(join(targetDir, dir, file), applyTemplate(content, vars), "utf-8");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function loadTemplate(templateName, fileName, vars) {
|
|
54
|
+
const templatePath = join(getPackageRoot(), "templates", templateName, fileName);
|
|
55
|
+
if (!existsSync(templatePath)) return null;
|
|
56
|
+
return applyTemplate(readFileSync(templatePath, "utf-8"), vars);
|
|
57
|
+
}
|
|
58
|
+
function scaffoldHarness(targetDir, agentName, options) {
|
|
59
|
+
if (existsSync(targetDir)) {
|
|
60
|
+
throw new Error(`Directory already exists: ${targetDir}`);
|
|
61
|
+
}
|
|
62
|
+
const template = options?.template ?? "base";
|
|
63
|
+
const vars = { agentName, purpose: options?.purpose };
|
|
64
|
+
mkdirSync(targetDir, { recursive: true });
|
|
65
|
+
for (const dir of DIRECTORIES) {
|
|
66
|
+
mkdirSync(join(targetDir, dir), { recursive: true });
|
|
67
|
+
}
|
|
68
|
+
if (options?.coreContent) {
|
|
69
|
+
writeFileSync(join(targetDir, "CORE.md"), options.coreContent);
|
|
70
|
+
} else {
|
|
71
|
+
const templateContent = loadTemplate(template, "CORE.md", vars);
|
|
72
|
+
writeFileSync(
|
|
73
|
+
join(targetDir, "CORE.md"),
|
|
74
|
+
templateContent ?? applyTemplate(`# {{AGENT_NAME}}
|
|
75
|
+
|
|
76
|
+
## Purpose
|
|
77
|
+
{{PURPOSE}}
|
|
78
|
+
|
|
79
|
+
## Values
|
|
80
|
+
- **Honesty**: I tell the truth, even when it's uncomfortable.
|
|
81
|
+
- **Action**: I bias toward doing, not discussing.
|
|
82
|
+
- **Autonomy**: I act independently within my boundaries.
|
|
83
|
+
- **Growth**: I learn from every interaction.
|
|
84
|
+
- **Protection**: I guard my creator's time, money, and reputation.
|
|
85
|
+
|
|
86
|
+
## Ethics
|
|
87
|
+
- I never deceive my creator or others.
|
|
88
|
+
- I never take irreversible actions without confirmation.
|
|
89
|
+
- I never expose secrets, credentials, or private information.
|
|
90
|
+
- I escalate when uncertain rather than guessing.
|
|
91
|
+
`, vars)
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
const systemContent = loadTemplate(template, "SYSTEM.md", vars);
|
|
95
|
+
writeFileSync(
|
|
96
|
+
join(targetDir, "SYSTEM.md"),
|
|
97
|
+
systemContent ?? `# System
|
|
98
|
+
|
|
99
|
+
You are ${vars.agentName}. This file defines how you boot and operate.
|
|
100
|
+
|
|
101
|
+
## Boot Sequence
|
|
102
|
+
1. Load CORE.md \u2014 your identity (never changes)
|
|
103
|
+
2. Load state.md \u2014 where you left off
|
|
104
|
+
3. Load memory/scratch.md \u2014 current working memory
|
|
105
|
+
4. Load indexes \u2014 scan all primitive directories
|
|
106
|
+
5. Load relevant files based on current task
|
|
107
|
+
|
|
108
|
+
## File Ownership
|
|
109
|
+
| Owner | Files | Can Modify |
|
|
110
|
+
|-------|-------|------------|
|
|
111
|
+
| Human | CORE.md, rules/*, config.yaml | Only human edits |
|
|
112
|
+
| Agent | instincts/*, memory/sessions/*, state.md (goals) | During/after interactions |
|
|
113
|
+
| Infrastructure | */_index.md, memory/journal/* | Auto-scripts only |
|
|
114
|
+
|
|
115
|
+
## Context Loading Strategy
|
|
116
|
+
- L0 (~5 tokens): One-line summary \u2014 decides relevance
|
|
117
|
+
- L1 (~50-100 tokens): Paragraph \u2014 enough to work with
|
|
118
|
+
- L2 (full body): Complete content \u2014 loaded only when actively needed
|
|
119
|
+
- Always load CORE + state + scratch first
|
|
120
|
+
- Load primitives at the appropriate level based on token budget
|
|
121
|
+
`
|
|
122
|
+
);
|
|
123
|
+
const configContent = loadTemplate(template, "config.yaml", vars);
|
|
124
|
+
writeFileSync(join(targetDir, "config.yaml"), configContent ?? writeDefaultConfig(targetDir, agentName));
|
|
125
|
+
writeFileSync(
|
|
126
|
+
join(targetDir, "state.md"),
|
|
127
|
+
`# Agent State
|
|
128
|
+
|
|
129
|
+
## Mode
|
|
130
|
+
idle
|
|
131
|
+
|
|
132
|
+
## Goals
|
|
133
|
+
|
|
134
|
+
## Active Workflows
|
|
135
|
+
|
|
136
|
+
## Last Interaction
|
|
137
|
+
${(/* @__PURE__ */ new Date()).toISOString()}
|
|
138
|
+
|
|
139
|
+
## Unfinished Business
|
|
140
|
+
`
|
|
141
|
+
);
|
|
142
|
+
writeFileSync(join(targetDir, "memory", "scratch.md"), "");
|
|
143
|
+
copyDefaults(targetDir, vars);
|
|
144
|
+
writeFileSync(
|
|
145
|
+
join(targetDir, "README.md"),
|
|
146
|
+
`# ${agentName}
|
|
147
|
+
|
|
148
|
+
You just created an agent. The agent IS this folder \u2014 every file is part
|
|
149
|
+
of its identity, behavior, knowledge, and memory.
|
|
150
|
+
|
|
151
|
+
## Try these in order
|
|
152
|
+
|
|
153
|
+
\`\`\`bash
|
|
154
|
+
harness run "What can you do?" # see what's loaded
|
|
155
|
+
harness run "Help me decide between two options: A or B"
|
|
156
|
+
harness run "Plan a weekend project for me" # watch it qualify before answering
|
|
157
|
+
\`\`\`
|
|
158
|
+
|
|
159
|
+
Use it for a few days with varied prompts. Then:
|
|
160
|
+
|
|
161
|
+
\`\`\`bash
|
|
162
|
+
harness journal # synthesize today's sessions and find patterns
|
|
163
|
+
harness learn --install # promote learned patterns into instincts
|
|
164
|
+
\`\`\`
|
|
165
|
+
|
|
166
|
+
The agent gets measurably better the more you use it. Every interaction
|
|
167
|
+
is journaled, patterns become instincts, and instincts change behavior
|
|
168
|
+
on the next run. **No retraining, no fine-tuning, no code.** You're
|
|
169
|
+
editing markdown.
|
|
170
|
+
|
|
171
|
+
## What's in this folder
|
|
172
|
+
|
|
173
|
+
| File / dir | Owner | What it is |
|
|
174
|
+
|---|---|---|
|
|
175
|
+
| \`CORE.md\` | human | Identity. Who is this agent? Frozen. |
|
|
176
|
+
| \`SYSTEM.md\` | human | Boot instructions. How does it operate? |
|
|
177
|
+
| \`config.yaml\` | human | Model, runtime, MCP servers, budgets |
|
|
178
|
+
| \`state.md\` | mixed | Live state: mode, goals, last interaction |
|
|
179
|
+
| \`rules/\` | human | Hard boundaries the agent must respect |
|
|
180
|
+
| \`skills/\` | mixed | Capabilities + how to think about using them |
|
|
181
|
+
| \`playbooks/\` | mixed | Adaptive guidance for outcomes |
|
|
182
|
+
| \`instincts/\` | agent | Reflexive behaviors learned from sessions |
|
|
183
|
+
| \`workflows/\` | infra | Cron-driven automations |
|
|
184
|
+
| \`tools/\` | extern | HTTP/API tool definitions |
|
|
185
|
+
| \`agents/\` | extern | Sub-agent roster |
|
|
186
|
+
| \`memory/sessions/\` | agent | Auto-captured interaction records |
|
|
187
|
+
| \`memory/journal/\` | infra | Daily synthesized reflections |
|
|
188
|
+
|
|
189
|
+
Open any file and edit it. Save. Run \`harness run "..."\` again and the
|
|
190
|
+
agent reads your change. That's the loop.
|
|
191
|
+
|
|
192
|
+
## Going further
|
|
193
|
+
|
|
194
|
+
\`\`\`bash
|
|
195
|
+
harness doctor # check scaffold health
|
|
196
|
+
harness graph # see how primitives reference each other
|
|
197
|
+
harness info # what's loaded in the context budget right now
|
|
198
|
+
harness mcp discover # find MCP tools already installed on your machine
|
|
199
|
+
harness mcp search <q> # browse the MCP registry for new tools
|
|
200
|
+
harness install <url> # install a skill, agent, or rule from a URL
|
|
201
|
+
\`\`\`
|
|
202
|
+
|
|
203
|
+
Tools come from MCP servers \u2014 install one with \`harness mcp install\`.
|
|
204
|
+
|
|
205
|
+
## When something feels off
|
|
206
|
+
|
|
207
|
+
- \`harness validate\` \u2014 check the harness structure for errors
|
|
208
|
+
- \`harness doctor\` \u2014 same, but auto-fix what it can
|
|
209
|
+
- \`harness contradictions\` \u2014 check rules and instincts for conflicts
|
|
210
|
+
- \`harness dead-primitives\` \u2014 find files you haven't used in a while
|
|
211
|
+
|
|
212
|
+
The agent journal in \`memory/journal/\` is the most interesting place
|
|
213
|
+
to look \u2014 it's where the agent reflects on what you've been doing
|
|
214
|
+
together. Read it once a week.
|
|
215
|
+
`
|
|
216
|
+
);
|
|
217
|
+
writeFileSync(
|
|
218
|
+
join(targetDir, ".gitignore"),
|
|
219
|
+
`memory/scratch.md
|
|
220
|
+
memory/context.jsonl
|
|
221
|
+
memory/context.md
|
|
222
|
+
memory/sessions/*
|
|
223
|
+
memory/journal/*
|
|
224
|
+
!memory/sessions/.gitkeep
|
|
225
|
+
!memory/journal/.gitkeep
|
|
226
|
+
.env
|
|
227
|
+
`
|
|
228
|
+
);
|
|
229
|
+
writeFileSync(join(targetDir, "memory", "sessions", ".gitkeep"), "");
|
|
230
|
+
writeFileSync(join(targetDir, "memory", "journal", ".gitkeep"), "");
|
|
231
|
+
}
|
|
232
|
+
function generateSystemMd(harnessDir, agentName) {
|
|
233
|
+
const primitiveDirs = ["rules", "instincts", "skills", "playbooks", "workflows", "tools", "agents"];
|
|
234
|
+
const sections = [];
|
|
235
|
+
sections.push(`# System
|
|
236
|
+
`);
|
|
237
|
+
sections.push(`You are ${agentName}. This file defines how you boot and operate.
|
|
238
|
+
`);
|
|
239
|
+
sections.push(`## Boot Sequence
|
|
240
|
+
1. Load CORE.md \u2014 your identity (never changes)
|
|
241
|
+
2. Load state.md \u2014 where you left off
|
|
242
|
+
3. Load memory/scratch.md \u2014 current working memory
|
|
243
|
+
4. Load indexes \u2014 scan all primitive directories
|
|
244
|
+
5. Load relevant files based on current task
|
|
245
|
+
`);
|
|
246
|
+
sections.push(`## Directory Structure
|
|
247
|
+
`);
|
|
248
|
+
for (const dir of primitiveDirs) {
|
|
249
|
+
const dirPath = join(harnessDir, dir);
|
|
250
|
+
if (!existsSync(dirPath)) continue;
|
|
251
|
+
const files = readdirSync(dirPath).filter((f) => f.endsWith(".md") && !f.startsWith("_"));
|
|
252
|
+
if (files.length === 0) {
|
|
253
|
+
sections.push(`- \`${dir}/\` \u2014 (empty)`);
|
|
254
|
+
} else {
|
|
255
|
+
sections.push(`- \`${dir}/\` \u2014 ${files.length} file(s): ${files.map((f) => f.replace(".md", "")).join(", ")}`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
const sessionsDir = join(harnessDir, "memory", "sessions");
|
|
259
|
+
const journalDir = join(harnessDir, "memory", "journal");
|
|
260
|
+
const sessionCount = existsSync(sessionsDir) ? readdirSync(sessionsDir).filter((f) => f.endsWith(".md")).length : 0;
|
|
261
|
+
const journalCount = existsSync(journalDir) ? readdirSync(journalDir).filter((f) => f.endsWith(".md")).length : 0;
|
|
262
|
+
sections.push(`- \`memory/sessions/\` \u2014 ${sessionCount} session(s)`);
|
|
263
|
+
sections.push(`- \`memory/journal/\` \u2014 ${journalCount} entry/entries`);
|
|
264
|
+
sections.push("");
|
|
265
|
+
sections.push(`## File Ownership
|
|
266
|
+
| Owner | Files | Can Modify |
|
|
267
|
+
|-------|-------|------------|
|
|
268
|
+
| Human | CORE.md, rules/*, config.yaml | Only human edits |
|
|
269
|
+
| Agent | instincts/*, memory/sessions/*, state.md (goals) | During/after interactions |
|
|
270
|
+
| Infrastructure | */_index.md, memory/journal/* | Auto-scripts only |
|
|
271
|
+
`);
|
|
272
|
+
sections.push(`## Context Loading Strategy
|
|
273
|
+
- L0 (~5 tokens): One-line summary \u2014 decides relevance
|
|
274
|
+
- L1 (~50-100 tokens): Paragraph \u2014 enough to work with
|
|
275
|
+
- L2 (full body): Complete content \u2014 loaded only when actively needed
|
|
276
|
+
- Always load CORE + state + scratch first
|
|
277
|
+
- Load primitives at the appropriate level based on token budget
|
|
278
|
+
`);
|
|
279
|
+
return sections.join("\n");
|
|
280
|
+
}
|
|
281
|
+
async function generateCoreMd(agentName, purpose, options) {
|
|
282
|
+
try {
|
|
283
|
+
const { generate, getModel } = await import("./provider-SXPQZ74H.js");
|
|
284
|
+
const { HarnessConfigSchema } = await import("./types-EW7AIB3R.js");
|
|
285
|
+
const config = HarnessConfigSchema.parse({
|
|
286
|
+
agent: { name: agentName, version: "0.1.0" },
|
|
287
|
+
model: {
|
|
288
|
+
provider: options.provider ?? "openrouter",
|
|
289
|
+
id: options.modelId ?? "anthropic/claude-sonnet-4"
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
const model = getModel(config, options.apiKey);
|
|
293
|
+
const result = await generate({
|
|
294
|
+
model,
|
|
295
|
+
system: `You are a technical writer creating an identity document for an AI agent.
|
|
296
|
+
The document defines who the agent is, what it does, its values, and its ethical boundaries.
|
|
297
|
+
Write in first person from the agent's perspective. Be specific and practical, not generic.
|
|
298
|
+
Output ONLY the markdown content, no code fences.`,
|
|
299
|
+
prompt: `Create a CORE.md identity document for an AI agent with:
|
|
300
|
+
- Name: ${agentName}
|
|
301
|
+
- Purpose: ${purpose}
|
|
302
|
+
|
|
303
|
+
The document should have these sections:
|
|
304
|
+
# ${agentName}
|
|
305
|
+
|
|
306
|
+
## Purpose
|
|
307
|
+
(Detailed purpose based on the description \u2014 be specific to what this agent does)
|
|
308
|
+
|
|
309
|
+
## Values
|
|
310
|
+
(5-7 values tailored to this agent's purpose \u2014 not generic platitudes)
|
|
311
|
+
|
|
312
|
+
## Ethics
|
|
313
|
+
(4-6 ethical boundaries specific to this agent's domain)
|
|
314
|
+
|
|
315
|
+
## Capabilities
|
|
316
|
+
(3-5 key capabilities this agent should have based on its purpose)
|
|
317
|
+
|
|
318
|
+
## Boundaries
|
|
319
|
+
(3-5 things this agent should NOT do or areas where it should escalate)`,
|
|
320
|
+
maxOutputTokens: 2e3,
|
|
321
|
+
maxRetries: 1,
|
|
322
|
+
timeoutMs: 3e4
|
|
323
|
+
});
|
|
324
|
+
return result.text.trim();
|
|
325
|
+
} catch (err) {
|
|
326
|
+
if (err instanceof Error) throw err;
|
|
327
|
+
throw new Error(String(err));
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
function listTemplates() {
|
|
331
|
+
const templatesDir = join(getPackageRoot(), "templates");
|
|
332
|
+
if (!existsSync(templatesDir)) return [];
|
|
333
|
+
return readdirSync(templatesDir).filter((f) => {
|
|
334
|
+
try {
|
|
335
|
+
return readdirSync(join(templatesDir, f)).length > 0;
|
|
336
|
+
} catch {
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
export {
|
|
342
|
+
generateCoreMd,
|
|
343
|
+
generateSystemMd,
|
|
344
|
+
listTemplates,
|
|
345
|
+
scaffoldHarness
|
|
346
|
+
};
|
|
347
|
+
//# sourceMappingURL=scaffold-A3VRRCBV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/scaffold.ts"],"sourcesContent":["import { mkdirSync, writeFileSync, readFileSync, readdirSync, existsSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { fileURLToPath } from 'url';\nimport { writeDefaultConfig } from '../core/config.js';\n\nconst DIRECTORIES = [\n 'rules',\n 'instincts',\n 'skills',\n 'playbooks',\n 'workflows',\n 'tools',\n 'agents',\n 'intake',\n 'memory/sessions',\n 'memory/journal',\n];\n\n/**\n * Resolve the package root directory by walking up from import.meta.url\n * until we find package.json. Works in both dev (src/) and prod (dist/).\n */\nfunction getPackageRoot(): string {\n let dir = dirname(fileURLToPath(import.meta.url));\n for (let i = 0; i < 5; i++) {\n if (existsSync(join(dir, 'package.json'))) return dir;\n dir = dirname(dir);\n }\n // Fallback: assume 2 levels up from source\n return dirname(dirname(fileURLToPath(import.meta.url)));\n}\n\ninterface TemplateVars {\n agentName: string;\n purpose?: string;\n}\n\n/**\n * Apply template variables to a string.\n */\nfunction applyTemplate(content: string, vars: TemplateVars): string {\n const date = new Date().toISOString().split('T')[0];\n const defaultPurpose = `I am ${vars.agentName}, an autonomous AI agent. My purpose is to help my creator build, think, and ship.`;\n const purpose = vars.purpose\n ? `I am ${vars.agentName}. ${vars.purpose}`\n : defaultPurpose;\n return content\n .replace(/\\{\\{AGENT_NAME\\}\\}/g, vars.agentName)\n .replace(/\\{\\{PURPOSE\\}\\}/g, purpose)\n .replace(/\\{\\{DATE\\}\\}/g, date);\n}\n\n/**\n * Copy default primitives from defaults/ directory into the target harness.\n */\nfunction copyDefaults(targetDir: string, vars: TemplateVars): void {\n const defaultsDir = join(getPackageRoot(), 'defaults');\n if (!existsSync(defaultsDir)) return;\n\n const primitiveDirs = ['rules', 'instincts', 'skills', 'playbooks', 'agents', 'tools', 'workflows'];\n for (const dir of primitiveDirs) {\n const srcDir = join(defaultsDir, dir);\n if (!existsSync(srcDir)) continue;\n const files = readdirSync(srcDir).filter((f) => f.endsWith('.md'));\n for (const file of files) {\n const content = readFileSync(join(srcDir, file), 'utf-8');\n writeFileSync(join(targetDir, dir, file), applyTemplate(content, vars), 'utf-8');\n }\n }\n}\n\n/**\n * Load a template file and apply substitutions. Returns null if not found.\n */\nfunction loadTemplate(templateName: string, fileName: string, vars: TemplateVars): string | null {\n const templatePath = join(getPackageRoot(), 'templates', templateName, fileName);\n if (!existsSync(templatePath)) return null;\n return applyTemplate(readFileSync(templatePath, 'utf-8'), vars);\n}\n\nexport interface ScaffoldOptions {\n template?: string;\n /** Custom CORE.md content — overrides template */\n coreContent?: string;\n /** Agent purpose description (stored as comment in CORE.md when no LLM generation) */\n purpose?: string;\n}\n\nexport function scaffoldHarness(targetDir: string, agentName: string, options?: ScaffoldOptions): void {\n if (existsSync(targetDir)) {\n throw new Error(`Directory already exists: ${targetDir}`);\n }\n\n const template = options?.template ?? 'base';\n const vars: TemplateVars = { agentName, purpose: options?.purpose };\n\n // Create directory structure\n mkdirSync(targetDir, { recursive: true });\n for (const dir of DIRECTORIES) {\n mkdirSync(join(targetDir, dir), { recursive: true });\n }\n\n // --- CORE.md (custom > template > inline fallback) ---\n if (options?.coreContent) {\n writeFileSync(join(targetDir, 'CORE.md'), options.coreContent);\n } else {\n const templateContent = loadTemplate(template, 'CORE.md', vars);\n writeFileSync(\n join(targetDir, 'CORE.md'),\n templateContent ?? applyTemplate(`# {{AGENT_NAME}}\n\n## Purpose\n{{PURPOSE}}\n\n## Values\n- **Honesty**: I tell the truth, even when it's uncomfortable.\n- **Action**: I bias toward doing, not discussing.\n- **Autonomy**: I act independently within my boundaries.\n- **Growth**: I learn from every interaction.\n- **Protection**: I guard my creator's time, money, and reputation.\n\n## Ethics\n- I never deceive my creator or others.\n- I never take irreversible actions without confirmation.\n- I never expose secrets, credentials, or private information.\n- I escalate when uncertain rather than guessing.\n`, vars)\n );\n }\n\n // --- SYSTEM.md (from template, or inline fallback) ---\n const systemContent = loadTemplate(template, 'SYSTEM.md', vars);\n writeFileSync(\n join(targetDir, 'SYSTEM.md'),\n systemContent ?? `# System\n\nYou are ${vars.agentName}. This file defines how you boot and operate.\n\n## Boot Sequence\n1. Load CORE.md — your identity (never changes)\n2. Load state.md — where you left off\n3. Load memory/scratch.md — current working memory\n4. Load indexes — scan all primitive directories\n5. Load relevant files based on current task\n\n## File Ownership\n| Owner | Files | Can Modify |\n|-------|-------|------------|\n| Human | CORE.md, rules/*, config.yaml | Only human edits |\n| Agent | instincts/*, memory/sessions/*, state.md (goals) | During/after interactions |\n| Infrastructure | */_index.md, memory/journal/* | Auto-scripts only |\n\n## Context Loading Strategy\n- L0 (~5 tokens): One-line summary — decides relevance\n- L1 (~50-100 tokens): Paragraph — enough to work with\n- L2 (full body): Complete content — loaded only when actively needed\n- Always load CORE + state + scratch first\n- Load primitives at the appropriate level based on token budget\n`\n );\n\n // --- config.yaml (from template, or use writeDefaultConfig) ---\n const configContent = loadTemplate(template, 'config.yaml', vars);\n writeFileSync(join(targetDir, 'config.yaml'), configContent ?? writeDefaultConfig(targetDir, agentName));\n\n // --- state.md ---\n writeFileSync(\n join(targetDir, 'state.md'),\n `# Agent State\n\n## Mode\nidle\n\n## Goals\n\n## Active Workflows\n\n## Last Interaction\n${new Date().toISOString()}\n\n## Unfinished Business\n`\n );\n\n // --- memory/scratch.md ---\n writeFileSync(join(targetDir, 'memory', 'scratch.md'), '');\n\n // --- Copy default primitives from defaults/ directory ---\n copyDefaults(targetDir, vars);\n\n // --- README.md (the in-scaffold quickstart, the FIRST thing a non-coder reads) ---\n writeFileSync(\n join(targetDir, 'README.md'),\n `# ${agentName}\n\nYou just created an agent. The agent IS this folder — every file is part\nof its identity, behavior, knowledge, and memory.\n\n## Try these in order\n\n\\`\\`\\`bash\nharness run \"What can you do?\" # see what's loaded\nharness run \"Help me decide between two options: A or B\"\nharness run \"Plan a weekend project for me\" # watch it qualify before answering\n\\`\\`\\`\n\nUse it for a few days with varied prompts. Then:\n\n\\`\\`\\`bash\nharness journal # synthesize today's sessions and find patterns\nharness learn --install # promote learned patterns into instincts\n\\`\\`\\`\n\nThe agent gets measurably better the more you use it. Every interaction\nis journaled, patterns become instincts, and instincts change behavior\non the next run. **No retraining, no fine-tuning, no code.** You're\nediting markdown.\n\n## What's in this folder\n\n| File / dir | Owner | What it is |\n|---|---|---|\n| \\`CORE.md\\` | human | Identity. Who is this agent? Frozen. |\n| \\`SYSTEM.md\\` | human | Boot instructions. How does it operate? |\n| \\`config.yaml\\` | human | Model, runtime, MCP servers, budgets |\n| \\`state.md\\` | mixed | Live state: mode, goals, last interaction |\n| \\`rules/\\` | human | Hard boundaries the agent must respect |\n| \\`skills/\\` | mixed | Capabilities + how to think about using them |\n| \\`playbooks/\\` | mixed | Adaptive guidance for outcomes |\n| \\`instincts/\\` | agent | Reflexive behaviors learned from sessions |\n| \\`workflows/\\` | infra | Cron-driven automations |\n| \\`tools/\\` | extern | HTTP/API tool definitions |\n| \\`agents/\\` | extern | Sub-agent roster |\n| \\`memory/sessions/\\` | agent | Auto-captured interaction records |\n| \\`memory/journal/\\` | infra | Daily synthesized reflections |\n\nOpen any file and edit it. Save. Run \\`harness run \"...\"\\` again and the\nagent reads your change. That's the loop.\n\n## Going further\n\n\\`\\`\\`bash\nharness doctor # check scaffold health\nharness graph # see how primitives reference each other\nharness info # what's loaded in the context budget right now\nharness mcp discover # find MCP tools already installed on your machine\nharness mcp search <q> # browse the MCP registry for new tools\nharness install <url> # install a skill, agent, or rule from a URL\n\\`\\`\\`\n\nTools come from MCP servers — install one with \\`harness mcp install\\`.\n\n## When something feels off\n\n- \\`harness validate\\` — check the harness structure for errors\n- \\`harness doctor\\` — same, but auto-fix what it can\n- \\`harness contradictions\\` — check rules and instincts for conflicts\n- \\`harness dead-primitives\\` — find files you haven't used in a while\n\nThe agent journal in \\`memory/journal/\\` is the most interesting place\nto look — it's where the agent reflects on what you've been doing\ntogether. Read it once a week.\n`,\n );\n\n // --- .gitignore ---\n writeFileSync(\n join(targetDir, '.gitignore'),\n `memory/scratch.md\nmemory/context.jsonl\nmemory/context.md\nmemory/sessions/*\nmemory/journal/*\n!memory/sessions/.gitkeep\n!memory/journal/.gitkeep\n.env\n`\n );\n\n // Create .gitkeep files\n writeFileSync(join(targetDir, 'memory', 'sessions', '.gitkeep'), '');\n writeFileSync(join(targetDir, 'memory', 'journal', '.gitkeep'), '');\n}\n\n/**\n * Generate SYSTEM.md content from the actual directory structure of a harness.\n * Scans for primitives and reflects the real structure.\n */\nexport function generateSystemMd(harnessDir: string, agentName: string): string {\n const primitiveDirs = ['rules', 'instincts', 'skills', 'playbooks', 'workflows', 'tools', 'agents'];\n const sections: string[] = [];\n\n sections.push(`# System\\n`);\n sections.push(`You are ${agentName}. This file defines how you boot and operate.\\n`);\n\n // Boot sequence\n sections.push(`## Boot Sequence\n1. Load CORE.md — your identity (never changes)\n2. Load state.md — where you left off\n3. Load memory/scratch.md — current working memory\n4. Load indexes — scan all primitive directories\n5. Load relevant files based on current task\\n`);\n\n // Directory structure\n sections.push(`## Directory Structure\\n`);\n\n for (const dir of primitiveDirs) {\n const dirPath = join(harnessDir, dir);\n if (!existsSync(dirPath)) continue;\n\n const files = readdirSync(dirPath).filter((f) => f.endsWith('.md') && !f.startsWith('_'));\n if (files.length === 0) {\n sections.push(`- \\`${dir}/\\` — (empty)`);\n } else {\n sections.push(`- \\`${dir}/\\` — ${files.length} file(s): ${files.map((f) => f.replace('.md', '')).join(', ')}`);\n }\n }\n\n // Memory\n const sessionsDir = join(harnessDir, 'memory', 'sessions');\n const journalDir = join(harnessDir, 'memory', 'journal');\n const sessionCount = existsSync(sessionsDir)\n ? readdirSync(sessionsDir).filter((f) => f.endsWith('.md')).length\n : 0;\n const journalCount = existsSync(journalDir)\n ? readdirSync(journalDir).filter((f) => f.endsWith('.md')).length\n : 0;\n\n sections.push(`- \\`memory/sessions/\\` — ${sessionCount} session(s)`);\n sections.push(`- \\`memory/journal/\\` — ${journalCount} entry/entries`);\n sections.push('');\n\n // File ownership\n sections.push(`## File Ownership\n| Owner | Files | Can Modify |\n|-------|-------|------------|\n| Human | CORE.md, rules/*, config.yaml | Only human edits |\n| Agent | instincts/*, memory/sessions/*, state.md (goals) | During/after interactions |\n| Infrastructure | */_index.md, memory/journal/* | Auto-scripts only |\\n`);\n\n // Context loading strategy\n sections.push(`## Context Loading Strategy\n- L0 (~5 tokens): One-line summary — decides relevance\n- L1 (~50-100 tokens): Paragraph — enough to work with\n- L2 (full body): Complete content — loaded only when actively needed\n- Always load CORE + state + scratch first\n- Load primitives at the appropriate level based on token budget\n`);\n\n return sections.join('\\n');\n}\n\n/**\n * Generate a rich CORE.md using an LLM, given an agent name and purpose description.\n * Returns the generated markdown content, or throws on failure.\n */\nexport async function generateCoreMd(\n agentName: string,\n purpose: string,\n options: { provider?: string; modelId?: string; apiKey?: string },\n): Promise<string> {\n try {\n const { generate, getModel } = await import('../llm/provider.js');\n const { HarnessConfigSchema } = await import('../core/types.js');\n\n const config = HarnessConfigSchema.parse({\n agent: { name: agentName, version: '0.1.0' },\n model: {\n provider: options.provider ?? 'openrouter',\n id: options.modelId ?? 'anthropic/claude-sonnet-4',\n },\n });\n\n const model = getModel(config, options.apiKey);\n const result = await generate({\n model,\n system: `You are a technical writer creating an identity document for an AI agent.\nThe document defines who the agent is, what it does, its values, and its ethical boundaries.\nWrite in first person from the agent's perspective. Be specific and practical, not generic.\nOutput ONLY the markdown content, no code fences.`,\n prompt: `Create a CORE.md identity document for an AI agent with:\n- Name: ${agentName}\n- Purpose: ${purpose}\n\nThe document should have these sections:\n# ${agentName}\n\n## Purpose\n(Detailed purpose based on the description — be specific to what this agent does)\n\n## Values\n(5-7 values tailored to this agent's purpose — not generic platitudes)\n\n## Ethics\n(4-6 ethical boundaries specific to this agent's domain)\n\n## Capabilities\n(3-5 key capabilities this agent should have based on its purpose)\n\n## Boundaries\n(3-5 things this agent should NOT do or areas where it should escalate)`,\n maxOutputTokens: 2000,\n maxRetries: 1,\n timeoutMs: 30000,\n });\n\n return result.text.trim();\n } catch (err: unknown) {\n if (err instanceof Error) throw err;\n throw new Error(String(err));\n }\n}\n\n/**\n * List available templates.\n */\nexport function listTemplates(): string[] {\n const templatesDir = join(getPackageRoot(), 'templates');\n if (!existsSync(templatesDir)) return [];\n return readdirSync(templatesDir).filter((f) => {\n try {\n return readdirSync(join(templatesDir, f)).length > 0;\n } catch {\n return false;\n }\n });\n}\n"],"mappings":"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","names":[]}
|