sverklo 0.28.2 → 0.29.0
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/README.md +6 -2
- package/dist/bin/sverklo.js +166 -4
- package/dist/bin/sverklo.js.map +1 -1
- package/dist/src/indexer/parser-tree-sitter.js +0 -1
- package/dist/src/indexer/parser-tree-sitter.js.map +1 -1
- package/dist/src/init-global.js +25 -24
- package/dist/src/init-global.js.map +1 -1
- package/dist/src/init.js +1 -0
- package/dist/src/init.js.map +1 -1
- package/dist/src/marketing/campaign-cycle.d.ts +13 -0
- package/dist/src/marketing/campaign-cycle.js +107 -0
- package/dist/src/marketing/campaign-cycle.js.map +1 -0
- package/dist/src/marketing/content-quality.d.ts +11 -0
- package/dist/src/marketing/content-quality.js +51 -0
- package/dist/src/marketing/content-quality.js.map +1 -0
- package/dist/src/marketing/content-seeding.d.ts +2 -0
- package/dist/src/marketing/content-seeding.js +105 -0
- package/dist/src/marketing/content-seeding.js.map +1 -0
- package/dist/src/marketing/decisions.d.ts +10 -0
- package/dist/src/marketing/decisions.js +142 -0
- package/dist/src/marketing/decisions.js.map +1 -0
- package/dist/src/marketing/index.d.ts +12 -0
- package/dist/src/marketing/index.js +13 -0
- package/dist/src/marketing/index.js.map +1 -0
- package/dist/src/marketing/models.d.ts +189 -0
- package/dist/src/marketing/models.js +5 -0
- package/dist/src/marketing/models.js.map +1 -0
- package/dist/src/marketing/opportunity-scout.d.ts +8 -0
- package/dist/src/marketing/opportunity-scout.js +73 -0
- package/dist/src/marketing/opportunity-scout.js.map +1 -0
- package/dist/src/marketing/profile-health.d.ts +2 -0
- package/dist/src/marketing/profile-health.js +96 -0
- package/dist/src/marketing/profile-health.js.map +1 -0
- package/dist/src/marketing/report.d.ts +4 -0
- package/dist/src/marketing/report.js +67 -0
- package/dist/src/marketing/report.js.map +1 -0
- package/dist/src/marketing/scoring.d.ts +5 -0
- package/dist/src/marketing/scoring.js +89 -0
- package/dist/src/marketing/scoring.js.map +1 -0
- package/dist/src/marketing/status.d.ts +3 -0
- package/dist/src/marketing/status.js +58 -0
- package/dist/src/marketing/status.js.map +1 -0
- package/dist/src/marketing/storage.d.ts +29 -0
- package/dist/src/marketing/storage.js +99 -0
- package/dist/src/marketing/storage.js.map +1 -0
- package/dist/src/marketing/test-fixtures.d.ts +7 -0
- package/dist/src/marketing/test-fixtures.js +31 -0
- package/dist/src/marketing/test-fixtures.js.map +1 -0
- package/dist/src/marketing/validation.d.ts +9 -0
- package/dist/src/marketing/validation.js +66 -0
- package/dist/src/marketing/validation.js.map +1 -0
- package/dist/src/prove.d.ts +6 -2
- package/dist/src/prove.js +119 -24
- package/dist/src/prove.js.map +1 -1
- package/dist/src/server/tools/review-diff.js +0 -1
- package/dist/src/server/tools/review-diff.js.map +1 -1
- package/dist/src/utils/logger.js +2 -0
- package/dist/src/utils/logger.js.map +1 -1
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -22,6 +22,10 @@ sverklo prove
|
|
|
22
22
|
|
|
23
23
|
`sverklo init` writes the MCP config for your agent, appends local instructions to `AGENTS.md` or `CLAUDE.md`, and runs `sverklo doctor` to verify the handshake. `sverklo prove` then shows central files, a real symbol with callers, and the exact prompt to paste into your agent. Your code stays on your machine.
|
|
24
24
|
|
|
25
|
+
Need something shareable? Run `sverklo prove --markdown` to print a GitHub/Discord-ready proof receipt from your repo, then [post it in the proof thread](https://github.com/sverklo/sverklo/discussions/79).
|
|
26
|
+
|
|
27
|
+
Need local launch planning for the Sverklo account? `sverklo marketing` runs a local-first Twitter/X agent-team workflow from operator-provided snapshots. It ranks opportunities, drafts seed-content queues, checks profile health, and records human decisions without posting, scraping, replying, liking, reposting, following, or changing the profile.
|
|
28
|
+
|
|
25
29
|
> *"The map is not the territory."* — Alfred Korzybski
|
|
26
30
|
>
|
|
27
31
|
> Training data is the map. Your codebase is the territory. **Sverklo gives the agent the territory.**
|
|
@@ -78,7 +82,7 @@ cd your-project && sverklo init
|
|
|
78
82
|
sverklo prove
|
|
79
83
|
```
|
|
80
84
|
|
|
81
|
-
That's it. `sverklo init` auto-detects your installed AI coding agent (Claude Code, Cursor, Windsurf, Zed), writes the right MCP config, appends instructions to `AGENTS.md` if present (otherwise `CLAUDE.md`), and runs `sverklo doctor` to verify the setup. `sverklo prove` shows the first useful repo-memory proof from your own codebase. Works on macOS, Linux, and Windows. **No API keys. No cloud. Telemetry off by default.**
|
|
85
|
+
That's it. `sverklo init` auto-detects your installed AI coding agent (Claude Code, Cursor, Windsurf, Zed), writes the right MCP config, appends instructions to `AGENTS.md` if present (otherwise `CLAUDE.md`), and runs `sverklo doctor` to verify the setup. `sverklo prove` shows the first useful repo-memory proof from your own codebase; `sverklo prove --markdown` makes that proof shareable in [the public proof thread](https://github.com/sverklo/sverklo/discussions/79). Works on macOS, Linux, and Windows. **No API keys. No cloud. Telemetry off by default.**
|
|
82
86
|
|
|
83
87
|
> The embedding model (`all-MiniLM-L6-v2` ONNX, ~86 MB) is downloaded from HuggingFace on first use into `~/.sverklo/models/` and cached forever — every subsequent run is fully offline.
|
|
84
88
|
|
|
@@ -452,7 +456,7 @@ cd your-project && sverklo init
|
|
|
452
456
|
sverklo prove
|
|
453
457
|
```
|
|
454
458
|
|
|
455
|
-
`sverklo init` auto-detects which AI coding agents you have (Claude Code, Cursor, Windsurf, Zed, Antigravity) and writes the right MCP config files. `sverklo prove` prints central files, a real caller graph, and a prompt to paste into your agent. Idempotent — safe to re-run. If sverklo doesn't appear in your agent after restart, run `sverklo doctor`.
|
|
459
|
+
`sverklo init` auto-detects which AI coding agents you have (Claude Code, Cursor, Windsurf, Zed, Antigravity) and writes the right MCP config files. `sverklo prove` prints central files, a real caller graph, and a prompt to paste into your agent. Add `--markdown` or `--receipt` for a shareable proof artifact, then post it in [the proof thread](https://github.com/sverklo/sverklo/discussions/79). Idempotent — safe to re-run. If sverklo doesn't appear in your agent after restart, run `sverklo doctor`.
|
|
456
460
|
|
|
457
461
|
**Per-agent config locations** (`sverklo init` writes these for you):
|
|
458
462
|
- Claude Code: `.mcp.json` at project root + appends to `CLAUDE.md` (or `AGENTS.md` if present)
|
package/dist/bin/sverklo.js
CHANGED
|
@@ -37,6 +37,38 @@ async function resolveProjectPath(flags) {
|
|
|
37
37
|
}
|
|
38
38
|
return target;
|
|
39
39
|
}
|
|
40
|
+
function parseProveArgs(rawArgs) {
|
|
41
|
+
let format = "text";
|
|
42
|
+
const pathArgs = [];
|
|
43
|
+
for (let i = 0; i < rawArgs.length; i++) {
|
|
44
|
+
const arg = rawArgs[i];
|
|
45
|
+
if (arg === "--markdown" || arg === "--receipt") {
|
|
46
|
+
format = "markdown";
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (arg === "--format") {
|
|
50
|
+
const value = rawArgs[i + 1];
|
|
51
|
+
if (value !== "text" && value !== "plain" && value !== "markdown") {
|
|
52
|
+
console.error("✗ --format expects text, plain, or markdown");
|
|
53
|
+
process.exit(2);
|
|
54
|
+
}
|
|
55
|
+
format = value === "markdown" ? "markdown" : "text";
|
|
56
|
+
i++;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (arg.startsWith("--format=")) {
|
|
60
|
+
const value = arg.slice("--format=".length);
|
|
61
|
+
if (value !== "text" && value !== "plain" && value !== "markdown") {
|
|
62
|
+
console.error("✗ --format expects text, plain, or markdown");
|
|
63
|
+
process.exit(2);
|
|
64
|
+
}
|
|
65
|
+
format = value === "markdown" ? "markdown" : "text";
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
pathArgs.push(arg);
|
|
69
|
+
}
|
|
70
|
+
return { format, pathArgs };
|
|
71
|
+
}
|
|
40
72
|
// Global --help / -h interceptor.
|
|
41
73
|
//
|
|
42
74
|
// Without this, `--help` falls through to whatever subcommand the user
|
|
@@ -52,7 +84,7 @@ if (command && command !== "--help" && command !== "-h") {
|
|
|
52
84
|
const HELP_BLURBS = {
|
|
53
85
|
init: "Set up sverklo in your project (.mcp.json + CLAUDE.md, auto-detects Claude Code/Cursor/Windsurf/Antigravity). With --global: one-time-per-machine setup — write SVERKLO_SNIPPET to ~/.claude/CLAUDE.md and ~/.codex/AGENTS.md, register the project, gitignore .sverklo/, import memories. Skips per-project boilerplate.",
|
|
54
86
|
doctor: "Diagnose MCP setup issues. Run after `init` to verify the agent can reach sverklo.",
|
|
55
|
-
prove: "Show a first-run repo-memory proof: central files, a real symbol with callers, and a paste-ready agent prompt.",
|
|
87
|
+
prove: "Show a first-run repo-memory proof: central files, a real symbol with callers, and a paste-ready agent prompt. Flags: --markdown, --receipt, --format text|markdown.",
|
|
56
88
|
audit: "Run codebase audit and emit a graded report. Flags: --format markdown|html|json|graph|arch|obsidian, --output PATH, --open, --badge, --publish.",
|
|
57
89
|
"audit-diff": "Incremental architectural quality gate. Audits `git diff` for new cycles + fan-in spikes. Flags: --against REF, --fan-in-threshold N, --format human|json, --show-existing, --verbose. Exits 1 on regression.",
|
|
58
90
|
review: "Risk-scored diff review (CI-friendly). Flags: --ref REF, --ci, --format markdown|json, --max-files N, --fail-on low|medium|high.",
|
|
@@ -70,6 +102,7 @@ if (command && command !== "--help" && command !== "-h") {
|
|
|
70
102
|
digest: "5-line summary of what changed in this project. Flags: --since 7d, --format markdown|plain.",
|
|
71
103
|
receipt: "Token-spend receipt for your recent Claude Code sessions. Shows where tokens went and projected yearly cost. Flags: --since 7d, --format plain|json.",
|
|
72
104
|
memory: "Manage the memory store. Subcommands: show, edit, import, export.",
|
|
105
|
+
marketing: "Run the local-first Sverklo Twitter agent team workflow. Subcommands: init, run-cycle, decide, status.",
|
|
73
106
|
grammars: "Manage tree-sitter grammars for the SVERKLO_PARSER=tree-sitter opt-in path. Subcommands: install.",
|
|
74
107
|
weights: "Inspect .sverklo.yaml weight rules. Subcommands: explain <path> — show which glob matched and the effective weight.",
|
|
75
108
|
"audit-prompt": "Print a ready-to-paste codebase-audit prompt (hybrid agent workflow).",
|
|
@@ -117,6 +150,132 @@ if (command === "--version" || command === "-v" || command === "-V") {
|
|
|
117
150
|
console.log("sverklo (version unknown)");
|
|
118
151
|
process.exit(0);
|
|
119
152
|
}
|
|
153
|
+
if (command === "marketing") {
|
|
154
|
+
const subcommand = args[1];
|
|
155
|
+
const flags = args.slice(2);
|
|
156
|
+
const flagVal = (name) => {
|
|
157
|
+
const idx = flags.indexOf(name);
|
|
158
|
+
if (idx !== -1 && flags[idx + 1])
|
|
159
|
+
return flags[idx + 1];
|
|
160
|
+
const prefixed = flags.find((f) => f.startsWith(`${name}=`));
|
|
161
|
+
return prefixed ? prefixed.slice(name.length + 1) : undefined;
|
|
162
|
+
};
|
|
163
|
+
const requireFlag = (name) => {
|
|
164
|
+
const value = flagVal(name);
|
|
165
|
+
if (!value) {
|
|
166
|
+
console.error(`✗ ${name} is required`);
|
|
167
|
+
process.exit(2);
|
|
168
|
+
}
|
|
169
|
+
return value;
|
|
170
|
+
};
|
|
171
|
+
const format = flagVal("--format") ?? "text";
|
|
172
|
+
if (format !== "text" && format !== "json") {
|
|
173
|
+
console.error(`✗ --format must be text or json, got "${format}"`);
|
|
174
|
+
process.exit(2);
|
|
175
|
+
}
|
|
176
|
+
const { appendOperatorDecision, applyOperatorDecision, assertEvidenceCatalog, assertProfileSnapshot, assertRecentPostsSnapshot, assertTrendSnapshot, buildStatusSummary, createOperatorDecision, initMarketingWorkspace, jsonFile, loadActiveCampaignCycle, loadCampaignCycle, loadMarketingWorkspace, marketingPaths, normalizeAccountHandle, recomputeCampaignReadiness, renderContentReport, renderOpportunityReport, renderProfileHealthReport, renderStatusText, resolveMarketingWorkspace, runCampaignCycle, saveCampaignCycle, saveMarketingWorkspace, writeReport, } = await import("../src/marketing/index.js");
|
|
177
|
+
const { existsSync } = await import("node:fs");
|
|
178
|
+
const { join } = await import("node:path");
|
|
179
|
+
const workspacePath = flagVal("--workspace");
|
|
180
|
+
const readOptional = (path) => {
|
|
181
|
+
return path && existsSync(path) ? jsonFile(path) : undefined;
|
|
182
|
+
};
|
|
183
|
+
if (!subcommand || subcommand === "--help" || subcommand === "-h") {
|
|
184
|
+
console.log(`\nsverklo marketing — local-first Twitter agent team workflow\n\n` +
|
|
185
|
+
`Usage:\n` +
|
|
186
|
+
` sverklo marketing init --account @sverklo [--workspace PATH]\n` +
|
|
187
|
+
` sverklo marketing run-cycle [--workspace PATH] [--trends PATH] [--profile PATH] [--recent-posts PATH] [--evidence PATH] [--format text|json]\n` +
|
|
188
|
+
` sverklo marketing decide --target-type TYPE --target-id ID --decision VALUE [--reason TEXT] [--future]\n` +
|
|
189
|
+
` sverklo marketing status [--workspace PATH] [--format text|json]\n\n` +
|
|
190
|
+
`No command posts to X/Twitter, scrapes X, sends DMs, likes, reposts, follows, unfollows, or mutates the profile.\n`);
|
|
191
|
+
process.exit(0);
|
|
192
|
+
}
|
|
193
|
+
try {
|
|
194
|
+
if (subcommand === "init") {
|
|
195
|
+
const account = normalizeAccountHandle(requireFlag("--account"));
|
|
196
|
+
const workspace = initMarketingWorkspace({ workspacePath, accountHandle: account });
|
|
197
|
+
console.log(`Initialized marketing workspace for ${workspace.account_handle} at ${resolveMarketingWorkspace(workspacePath)}`);
|
|
198
|
+
process.exit(0);
|
|
199
|
+
}
|
|
200
|
+
if (subcommand === "run-cycle") {
|
|
201
|
+
const workspace = loadMarketingWorkspace(workspacePath);
|
|
202
|
+
const root = resolveMarketingWorkspace(workspacePath);
|
|
203
|
+
const inputDir = marketingPaths(root).inputs;
|
|
204
|
+
const existing = loadActiveCampaignCycle(workspacePath, workspace);
|
|
205
|
+
const trends = readOptional(flagVal("--trends") ?? join(inputDir, "trend-snapshot.json"));
|
|
206
|
+
const profile = readOptional(flagVal("--profile") ?? join(inputDir, "profile-snapshot.json"));
|
|
207
|
+
const recentPosts = readOptional(flagVal("--recent-posts") ?? join(inputDir, "recent-posts.json"));
|
|
208
|
+
const evidence = readOptional(flagVal("--evidence") ?? join(inputDir, "evidence.json"));
|
|
209
|
+
if (trends)
|
|
210
|
+
assertTrendSnapshot(trends);
|
|
211
|
+
if (profile)
|
|
212
|
+
assertProfileSnapshot(profile);
|
|
213
|
+
if (recentPosts)
|
|
214
|
+
assertRecentPostsSnapshot(recentPosts);
|
|
215
|
+
if (evidence)
|
|
216
|
+
assertEvidenceCatalog(evidence);
|
|
217
|
+
if (!trends && !profile && !recentPosts && !evidence && !existing) {
|
|
218
|
+
throw new Error("no local marketing inputs found; provide --trends, --profile, --recent-posts, or --evidence");
|
|
219
|
+
}
|
|
220
|
+
const cycle = runCampaignCycle({
|
|
221
|
+
workspace,
|
|
222
|
+
existingCycle: existing,
|
|
223
|
+
trendSnapshot: trends,
|
|
224
|
+
profileSnapshot: profile,
|
|
225
|
+
recentPosts,
|
|
226
|
+
evidence,
|
|
227
|
+
cycleId: flagVal("--cycle"),
|
|
228
|
+
});
|
|
229
|
+
saveMarketingWorkspace(workspacePath, workspace);
|
|
230
|
+
saveCampaignCycle(workspacePath, cycle);
|
|
231
|
+
writeReport(workspacePath, cycle.cycle_id, "opportunities", renderOpportunityReport(cycle));
|
|
232
|
+
writeReport(workspacePath, cycle.cycle_id, "content", renderContentReport(cycle));
|
|
233
|
+
writeReport(workspacePath, cycle.cycle_id, "profile-health", renderProfileHealthReport(cycle));
|
|
234
|
+
const summary = buildStatusSummary(cycle);
|
|
235
|
+
if (format === "json")
|
|
236
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
237
|
+
else
|
|
238
|
+
process.stdout.write(renderStatusText(summary));
|
|
239
|
+
process.exit(0);
|
|
240
|
+
}
|
|
241
|
+
if (subcommand === "decide") {
|
|
242
|
+
const workspace = loadMarketingWorkspace(workspacePath);
|
|
243
|
+
if (!workspace.active_cycle_id)
|
|
244
|
+
throw new Error("no active marketing cycle");
|
|
245
|
+
const cycle = loadCampaignCycle(workspacePath, workspace.active_cycle_id);
|
|
246
|
+
const decision = createOperatorDecision({
|
|
247
|
+
targetType: requireFlag("--target-type"),
|
|
248
|
+
targetId: requireFlag("--target-id"),
|
|
249
|
+
decision: requireFlag("--decision"),
|
|
250
|
+
reason: flagVal("--reason"),
|
|
251
|
+
future: flags.includes("--future"),
|
|
252
|
+
});
|
|
253
|
+
applyOperatorDecision(workspace, cycle, decision);
|
|
254
|
+
recomputeCampaignReadiness(cycle);
|
|
255
|
+
saveMarketingWorkspace(workspacePath, workspace);
|
|
256
|
+
saveCampaignCycle(workspacePath, cycle);
|
|
257
|
+
appendOperatorDecision(workspacePath, decision);
|
|
258
|
+
console.log(`Recorded decision ${decision.decision_id}`);
|
|
259
|
+
process.exit(0);
|
|
260
|
+
}
|
|
261
|
+
if (subcommand === "status") {
|
|
262
|
+
const workspace = loadMarketingWorkspace(workspacePath);
|
|
263
|
+
const cycle = loadActiveCampaignCycle(workspacePath, workspace);
|
|
264
|
+
const summary = buildStatusSummary(cycle);
|
|
265
|
+
if (format === "json")
|
|
266
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
267
|
+
else
|
|
268
|
+
process.stdout.write(renderStatusText(summary));
|
|
269
|
+
process.exit(0);
|
|
270
|
+
}
|
|
271
|
+
console.error(`✗ unknown marketing subcommand: ${subcommand}`);
|
|
272
|
+
process.exit(2);
|
|
273
|
+
}
|
|
274
|
+
catch (err) {
|
|
275
|
+
console.error(`✗ ${err instanceof Error ? err.message : String(err)}`);
|
|
276
|
+
process.exit(2);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
120
279
|
if (command === "init") {
|
|
121
280
|
// Parse flags: --auto-capture, --mine-chats, --global
|
|
122
281
|
const flags = args.filter((a) => a.startsWith("--"));
|
|
@@ -163,10 +322,10 @@ if (command === "register") {
|
|
|
163
322
|
process.exit(0);
|
|
164
323
|
}
|
|
165
324
|
if (command === "prove") {
|
|
166
|
-
const
|
|
167
|
-
const projectPath = await resolveProjectPath(
|
|
325
|
+
const { format, pathArgs } = parseProveArgs(args.slice(1));
|
|
326
|
+
const projectPath = await resolveProjectPath(pathArgs);
|
|
168
327
|
const { runProve } = await import("../src/prove.js");
|
|
169
|
-
const report = await runProve(projectPath);
|
|
328
|
+
const report = await runProve(projectPath, { format });
|
|
170
329
|
process.stdout.write(report);
|
|
171
330
|
process.exit(0);
|
|
172
331
|
}
|
|
@@ -2589,6 +2748,7 @@ Usage:
|
|
|
2589
2748
|
sverklo init Set up sverklo in your project (.mcp.json + CLAUDE.md)
|
|
2590
2749
|
sverklo doctor Diagnose MCP setup issues
|
|
2591
2750
|
sverklo prove [path] Show central files, a real caller graph, and an agent prompt
|
|
2751
|
+
Use --markdown or --receipt for a shareable artifact.
|
|
2592
2752
|
sverklo reindex [path] Incremental rebuild of the index (changed files only)
|
|
2593
2753
|
Use --force to clear and rebuild from scratch.
|
|
2594
2754
|
Use --timing to see per-phase elapsed ms.
|
|
@@ -2613,6 +2773,7 @@ Memory + offline maintenance:
|
|
|
2613
2773
|
sverklo wiki Generate a markdown wiki from the indexed codebase
|
|
2614
2774
|
sverklo digest 5-line summary of what changed in this project (--since 7d)
|
|
2615
2775
|
sverklo memory export Export memories to markdown / Notion / JSON
|
|
2776
|
+
sverklo marketing Local Sverklo Twitter agent team workflow
|
|
2616
2777
|
sverklo grammars install Install tree-sitter grammars for the v0.17 opt-in parser
|
|
2617
2778
|
sverklo prune Decay stale memories + consolidate similar episodic ones
|
|
2618
2779
|
sverklo concept-index Label clusters with an LLM (requires Ollama)
|
|
@@ -2632,6 +2793,7 @@ Quick start (single project):
|
|
|
2632
2793
|
npm install -g sverklo
|
|
2633
2794
|
cd your-project && sverklo init
|
|
2634
2795
|
sverklo prove
|
|
2796
|
+
sverklo prove --markdown # shareable proof for GitHub, Discord, Reddit, etc.
|
|
2635
2797
|
claude # start coding — sverklo tools are preferred automatically
|
|
2636
2798
|
|
|
2637
2799
|
Quick start (multi-repo, global):
|