sverklo 0.28.3 → 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.
Files changed (52) hide show
  1. package/README.md +5 -3
  2. package/dist/bin/sverklo.js +128 -0
  3. package/dist/bin/sverklo.js.map +1 -1
  4. package/dist/src/indexer/parser-tree-sitter.js +0 -1
  5. package/dist/src/indexer/parser-tree-sitter.js.map +1 -1
  6. package/dist/src/init-global.js +25 -24
  7. package/dist/src/init-global.js.map +1 -1
  8. package/dist/src/marketing/campaign-cycle.d.ts +13 -0
  9. package/dist/src/marketing/campaign-cycle.js +107 -0
  10. package/dist/src/marketing/campaign-cycle.js.map +1 -0
  11. package/dist/src/marketing/content-quality.d.ts +11 -0
  12. package/dist/src/marketing/content-quality.js +51 -0
  13. package/dist/src/marketing/content-quality.js.map +1 -0
  14. package/dist/src/marketing/content-seeding.d.ts +2 -0
  15. package/dist/src/marketing/content-seeding.js +105 -0
  16. package/dist/src/marketing/content-seeding.js.map +1 -0
  17. package/dist/src/marketing/decisions.d.ts +10 -0
  18. package/dist/src/marketing/decisions.js +142 -0
  19. package/dist/src/marketing/decisions.js.map +1 -0
  20. package/dist/src/marketing/index.d.ts +12 -0
  21. package/dist/src/marketing/index.js +13 -0
  22. package/dist/src/marketing/index.js.map +1 -0
  23. package/dist/src/marketing/models.d.ts +189 -0
  24. package/dist/src/marketing/models.js +5 -0
  25. package/dist/src/marketing/models.js.map +1 -0
  26. package/dist/src/marketing/opportunity-scout.d.ts +8 -0
  27. package/dist/src/marketing/opportunity-scout.js +73 -0
  28. package/dist/src/marketing/opportunity-scout.js.map +1 -0
  29. package/dist/src/marketing/profile-health.d.ts +2 -0
  30. package/dist/src/marketing/profile-health.js +96 -0
  31. package/dist/src/marketing/profile-health.js.map +1 -0
  32. package/dist/src/marketing/report.d.ts +4 -0
  33. package/dist/src/marketing/report.js +67 -0
  34. package/dist/src/marketing/report.js.map +1 -0
  35. package/dist/src/marketing/scoring.d.ts +5 -0
  36. package/dist/src/marketing/scoring.js +89 -0
  37. package/dist/src/marketing/scoring.js.map +1 -0
  38. package/dist/src/marketing/status.d.ts +3 -0
  39. package/dist/src/marketing/status.js +58 -0
  40. package/dist/src/marketing/status.js.map +1 -0
  41. package/dist/src/marketing/storage.d.ts +29 -0
  42. package/dist/src/marketing/storage.js +99 -0
  43. package/dist/src/marketing/storage.js.map +1 -0
  44. package/dist/src/marketing/test-fixtures.d.ts +7 -0
  45. package/dist/src/marketing/test-fixtures.js +31 -0
  46. package/dist/src/marketing/test-fixtures.js.map +1 -0
  47. package/dist/src/marketing/validation.d.ts +9 -0
  48. package/dist/src/marketing/validation.js +66 -0
  49. package/dist/src/marketing/validation.js.map +1 -0
  50. package/dist/src/server/tools/review-diff.js +0 -1
  51. package/dist/src/server/tools/review-diff.js.map +1 -1
  52. package/package.json +3 -1
package/README.md CHANGED
@@ -22,7 +22,9 @@ 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.
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.
26
28
 
27
29
  > *"The map is not the territory."* — Alfred Korzybski
28
30
  >
@@ -80,7 +82,7 @@ cd your-project && sverklo init
80
82
  sverklo prove
81
83
  ```
82
84
 
83
- 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. 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.**
84
86
 
85
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.
86
88
 
@@ -454,7 +456,7 @@ cd your-project && sverklo init
454
456
  sverklo prove
455
457
  ```
456
458
 
457
- `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. 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`.
458
460
 
459
461
  **Per-agent config locations** (`sverklo init` writes these for you):
460
462
  - Claude Code: `.mcp.json` at project root + appends to `CLAUDE.md` (or `AGENTS.md` if present)
@@ -102,6 +102,7 @@ if (command && command !== "--help" && command !== "-h") {
102
102
  digest: "5-line summary of what changed in this project. Flags: --since 7d, --format markdown|plain.",
103
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.",
104
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.",
105
106
  grammars: "Manage tree-sitter grammars for the SVERKLO_PARSER=tree-sitter opt-in path. Subcommands: install.",
106
107
  weights: "Inspect .sverklo.yaml weight rules. Subcommands: explain <path> — show which glob matched and the effective weight.",
107
108
  "audit-prompt": "Print a ready-to-paste codebase-audit prompt (hybrid agent workflow).",
@@ -149,6 +150,132 @@ if (command === "--version" || command === "-v" || command === "-V") {
149
150
  console.log("sverklo (version unknown)");
150
151
  process.exit(0);
151
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
+ }
152
279
  if (command === "init") {
153
280
  // Parse flags: --auto-capture, --mine-chats, --global
154
281
  const flags = args.filter((a) => a.startsWith("--"));
@@ -2646,6 +2773,7 @@ Memory + offline maintenance:
2646
2773
  sverklo wiki Generate a markdown wiki from the indexed codebase
2647
2774
  sverklo digest 5-line summary of what changed in this project (--since 7d)
2648
2775
  sverklo memory export Export memories to markdown / Notion / JSON
2776
+ sverklo marketing Local Sverklo Twitter agent team workflow
2649
2777
  sverklo grammars install Install tree-sitter grammars for the v0.17 opt-in parser
2650
2778
  sverklo prune Decay stale memories + consolidate similar episodic ones
2651
2779
  sverklo concept-index Label clusters with an LLM (requires Ollama)