@goondocks/myco 0.1.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/.claude-plugin/marketplace.json +22 -0
- package/.claude-plugin/plugin.json +18 -0
- package/CONTRIBUTING.md +143 -0
- package/LICENSE +21 -0
- package/README.md +74 -0
- package/commands/init.md +231 -0
- package/commands/setup-llm.md +89 -0
- package/commands/status.md +112 -0
- package/dist/src/agents/adapter.d.ts +76 -0
- package/dist/src/agents/adapter.d.ts.map +1 -0
- package/dist/src/agents/adapter.js +124 -0
- package/dist/src/agents/adapter.js.map +1 -0
- package/dist/src/agents/claude-code.d.ts +3 -0
- package/dist/src/agents/claude-code.d.ts.map +1 -0
- package/dist/src/agents/claude-code.js +22 -0
- package/dist/src/agents/claude-code.js.map +1 -0
- package/dist/src/agents/cursor.d.ts +3 -0
- package/dist/src/agents/cursor.d.ts.map +1 -0
- package/dist/src/agents/cursor.js +154 -0
- package/dist/src/agents/cursor.js.map +1 -0
- package/dist/src/agents/index.d.ts +6 -0
- package/dist/src/agents/index.d.ts.map +1 -0
- package/dist/src/agents/index.js +5 -0
- package/dist/src/agents/index.js.map +1 -0
- package/dist/src/agents/registry.d.ts +34 -0
- package/dist/src/agents/registry.d.ts.map +1 -0
- package/dist/src/agents/registry.js +95 -0
- package/dist/src/agents/registry.js.map +1 -0
- package/dist/src/artifacts/candidates.d.ts +20 -0
- package/dist/src/artifacts/candidates.d.ts.map +1 -0
- package/dist/src/artifacts/candidates.js +84 -0
- package/dist/src/artifacts/candidates.js.map +1 -0
- package/dist/src/artifacts/slugify.d.ts +2 -0
- package/dist/src/artifacts/slugify.d.ts.map +1 -0
- package/dist/src/artifacts/slugify.js +22 -0
- package/dist/src/artifacts/slugify.js.map +1 -0
- package/dist/src/capture/artifact-watcher.d.ts +19 -0
- package/dist/src/capture/artifact-watcher.d.ts.map +1 -0
- package/dist/src/capture/artifact-watcher.js +37 -0
- package/dist/src/capture/artifact-watcher.js.map +1 -0
- package/dist/src/capture/buffer.d.ts +20 -0
- package/dist/src/capture/buffer.d.ts.map +1 -0
- package/dist/src/capture/buffer.js +55 -0
- package/dist/src/capture/buffer.js.map +1 -0
- package/dist/src/capture/plan-detector.d.ts +15 -0
- package/dist/src/capture/plan-detector.d.ts.map +1 -0
- package/dist/src/capture/plan-detector.js +34 -0
- package/dist/src/capture/plan-detector.js.map +1 -0
- package/dist/src/capture/processor.d.ts +2 -0
- package/dist/src/capture/processor.d.ts.map +1 -0
- package/dist/src/capture/processor.js +3 -0
- package/dist/src/capture/processor.js.map +1 -0
- package/dist/src/capture/prompts/classify.md +28 -0
- package/dist/src/capture/prompts/debugging.md +91 -0
- package/dist/src/capture/prompts/exploration.md +88 -0
- package/dist/src/capture/prompts/extraction.md +93 -0
- package/dist/src/capture/prompts/implementation.md +90 -0
- package/dist/src/capture/prompts/prompts/classify.md +28 -0
- package/dist/src/capture/prompts/prompts/debugging.md +91 -0
- package/dist/src/capture/prompts/prompts/exploration.md +88 -0
- package/dist/src/capture/prompts/prompts/extraction.md +93 -0
- package/dist/src/capture/prompts/prompts/implementation.md +90 -0
- package/dist/src/capture/prompts/prompts/schema.yaml +97 -0
- package/dist/src/capture/prompts/prompts/session-summary.md +65 -0
- package/dist/src/capture/prompts/prompts/session-title.md +46 -0
- package/dist/src/capture/prompts/schema.yaml +97 -0
- package/dist/src/capture/prompts/session-summary.md +65 -0
- package/dist/src/capture/prompts/session-title.md +46 -0
- package/dist/src/capture/prompts.d.ts +77 -0
- package/dist/src/capture/prompts.d.ts.map +1 -0
- package/dist/src/capture/prompts.js +255 -0
- package/dist/src/capture/prompts.js.map +1 -0
- package/dist/src/capture/transcript-miner.d.ts +31 -0
- package/dist/src/capture/transcript-miner.d.ts.map +1 -0
- package/dist/src/capture/transcript-miner.js +61 -0
- package/dist/src/capture/transcript-miner.js.map +1 -0
- package/dist/src/cli.d.ts +3 -0
- package/dist/src/cli.d.ts.map +1 -0
- package/dist/src/cli.js +584 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/config/loader.d.ts +4 -0
- package/dist/src/config/loader.d.ts.map +1 -0
- package/dist/src/config/loader.js +32 -0
- package/dist/src/config/loader.js.map +1 -0
- package/dist/src/config/schema.d.ts +83 -0
- package/dist/src/config/schema.d.ts.map +1 -0
- package/dist/src/config/schema.js +55 -0
- package/dist/src/config/schema.js.map +1 -0
- package/dist/src/constants.d.ts +73 -0
- package/dist/src/constants.d.ts.map +1 -0
- package/dist/src/constants.js +86 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/context/injector.d.ts +18 -0
- package/dist/src/context/injector.d.ts.map +1 -0
- package/dist/src/context/injector.js +71 -0
- package/dist/src/context/injector.js.map +1 -0
- package/dist/src/context/relevance.d.ts +13 -0
- package/dist/src/context/relevance.d.ts.map +1 -0
- package/dist/src/context/relevance.js +44 -0
- package/dist/src/context/relevance.js.map +1 -0
- package/dist/src/daemon/batch.d.ts +22 -0
- package/dist/src/daemon/batch.d.ts.map +1 -0
- package/dist/src/daemon/batch.js +38 -0
- package/dist/src/daemon/batch.js.map +1 -0
- package/dist/src/daemon/lifecycle.d.ts +27 -0
- package/dist/src/daemon/lifecycle.d.ts.map +1 -0
- package/dist/src/daemon/lifecycle.js +50 -0
- package/dist/src/daemon/lifecycle.js.map +1 -0
- package/dist/src/daemon/lineage.d.ts +42 -0
- package/dist/src/daemon/lineage.d.ts.map +1 -0
- package/dist/src/daemon/lineage.js +116 -0
- package/dist/src/daemon/lineage.js.map +1 -0
- package/dist/src/daemon/logger.d.ts +33 -0
- package/dist/src/daemon/logger.d.ts.map +1 -0
- package/dist/src/daemon/logger.js +88 -0
- package/dist/src/daemon/logger.js.map +1 -0
- package/dist/src/daemon/main.d.ts +2 -0
- package/dist/src/daemon/main.d.ts.map +1 -0
- package/dist/src/daemon/main.js +738 -0
- package/dist/src/daemon/main.js.map +1 -0
- package/dist/src/daemon/processor.d.ts +44 -0
- package/dist/src/daemon/processor.d.ts.map +1 -0
- package/dist/src/daemon/processor.js +142 -0
- package/dist/src/daemon/processor.js.map +1 -0
- package/dist/src/daemon/server.d.ts +24 -0
- package/dist/src/daemon/server.d.ts.map +1 -0
- package/dist/src/daemon/server.js +117 -0
- package/dist/src/daemon/server.js.map +1 -0
- package/dist/src/daemon/watcher.d.ts +29 -0
- package/dist/src/daemon/watcher.d.ts.map +1 -0
- package/dist/src/daemon/watcher.js +67 -0
- package/dist/src/daemon/watcher.js.map +1 -0
- package/dist/src/hooks/client.d.ts +20 -0
- package/dist/src/hooks/client.d.ts.map +1 -0
- package/dist/src/hooks/client.js +111 -0
- package/dist/src/hooks/client.js.map +1 -0
- package/dist/src/hooks/post-tool-use.d.ts +2 -0
- package/dist/src/hooks/post-tool-use.d.ts.map +1 -0
- package/dist/src/hooks/post-tool-use.js +40 -0
- package/dist/src/hooks/post-tool-use.js.map +1 -0
- package/dist/src/hooks/read-stdin.d.ts +2 -0
- package/dist/src/hooks/read-stdin.d.ts.map +1 -0
- package/dist/src/hooks/read-stdin.js +10 -0
- package/dist/src/hooks/read-stdin.js.map +1 -0
- package/dist/src/hooks/session-end.d.ts +2 -0
- package/dist/src/hooks/session-end.d.ts.map +1 -0
- package/dist/src/hooks/session-end.js +23 -0
- package/dist/src/hooks/session-end.js.map +1 -0
- package/dist/src/hooks/session-start.d.ts +2 -0
- package/dist/src/hooks/session-start.d.ts.map +1 -0
- package/dist/src/hooks/session-start.js +49 -0
- package/dist/src/hooks/session-start.js.map +1 -0
- package/dist/src/hooks/stop.d.ts +2 -0
- package/dist/src/hooks/stop.d.ts.map +1 -0
- package/dist/src/hooks/stop.js +34 -0
- package/dist/src/hooks/stop.js.map +1 -0
- package/dist/src/hooks/user-prompt-submit.d.ts +2 -0
- package/dist/src/hooks/user-prompt-submit.d.ts.map +1 -0
- package/dist/src/hooks/user-prompt-submit.js +46 -0
- package/dist/src/hooks/user-prompt-submit.js.map +1 -0
- package/dist/src/index/fts.d.ts +16 -0
- package/dist/src/index/fts.d.ts.map +1 -0
- package/dist/src/index/fts.js +53 -0
- package/dist/src/index/fts.js.map +1 -0
- package/dist/src/index/rebuild.d.ts +4 -0
- package/dist/src/index/rebuild.d.ts.map +1 -0
- package/dist/src/index/rebuild.js +40 -0
- package/dist/src/index/rebuild.js.map +1 -0
- package/dist/src/index/sqlite.d.ts +33 -0
- package/dist/src/index/sqlite.d.ts.map +1 -0
- package/dist/src/index/sqlite.js +99 -0
- package/dist/src/index/sqlite.js.map +1 -0
- package/dist/src/index/vectors.d.ts +24 -0
- package/dist/src/index/vectors.d.ts.map +1 -0
- package/dist/src/index/vectors.js +97 -0
- package/dist/src/index/vectors.js.map +1 -0
- package/dist/src/intelligence/anthropic.d.ts +17 -0
- package/dist/src/intelligence/anthropic.d.ts.map +1 -0
- package/dist/src/intelligence/anthropic.js +36 -0
- package/dist/src/intelligence/anthropic.js.map +1 -0
- package/dist/src/intelligence/embeddings.d.ts +3 -0
- package/dist/src/intelligence/embeddings.d.ts.map +1 -0
- package/dist/src/intelligence/embeddings.js +15 -0
- package/dist/src/intelligence/embeddings.js.map +1 -0
- package/dist/src/intelligence/haiku.d.ts +17 -0
- package/dist/src/intelligence/haiku.d.ts.map +1 -0
- package/dist/src/intelligence/haiku.js +35 -0
- package/dist/src/intelligence/haiku.js.map +1 -0
- package/dist/src/intelligence/llm.d.ts +33 -0
- package/dist/src/intelligence/llm.d.ts.map +1 -0
- package/dist/src/intelligence/llm.js +26 -0
- package/dist/src/intelligence/llm.js.map +1 -0
- package/dist/src/intelligence/lm-studio.d.ts +20 -0
- package/dist/src/intelligence/lm-studio.d.ts.map +1 -0
- package/dist/src/intelligence/lm-studio.js +59 -0
- package/dist/src/intelligence/lm-studio.js.map +1 -0
- package/dist/src/intelligence/ollama.d.ts +22 -0
- package/dist/src/intelligence/ollama.d.ts.map +1 -0
- package/dist/src/intelligence/ollama.js +64 -0
- package/dist/src/intelligence/ollama.js.map +1 -0
- package/dist/src/intelligence/response.d.ts +29 -0
- package/dist/src/intelligence/response.d.ts.map +1 -0
- package/dist/src/intelligence/response.js +71 -0
- package/dist/src/intelligence/response.js.map +1 -0
- package/dist/src/intelligence/service.d.ts +18 -0
- package/dist/src/intelligence/service.d.ts.map +1 -0
- package/dist/src/intelligence/service.js +66 -0
- package/dist/src/intelligence/service.js.map +1 -0
- package/dist/src/logs/format.d.ts +6 -0
- package/dist/src/logs/format.d.ts.map +1 -0
- package/dist/src/logs/format.js +46 -0
- package/dist/src/logs/format.js.map +1 -0
- package/dist/src/logs/reader.d.ts +28 -0
- package/dist/src/logs/reader.d.ts.map +1 -0
- package/dist/src/logs/reader.js +106 -0
- package/dist/src/logs/reader.js.map +1 -0
- package/dist/src/mcp/server.d.ts +16 -0
- package/dist/src/mcp/server.d.ts.map +1 -0
- package/dist/src/mcp/server.js +305 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/dist/src/mcp/tools/consolidate.d.ts +15 -0
- package/dist/src/mcp/tools/consolidate.d.ts.map +1 -0
- package/dist/src/mcp/tools/consolidate.js +49 -0
- package/dist/src/mcp/tools/consolidate.js.map +1 -0
- package/dist/src/mcp/tools/graph.d.ts +30 -0
- package/dist/src/mcp/tools/graph.d.ts.map +1 -0
- package/dist/src/mcp/tools/graph.js +106 -0
- package/dist/src/mcp/tools/graph.js.map +1 -0
- package/dist/src/mcp/tools/logs.d.ts +3 -0
- package/dist/src/mcp/tools/logs.d.ts.map +1 -0
- package/dist/src/mcp/tools/logs.js +7 -0
- package/dist/src/mcp/tools/logs.js.map +1 -0
- package/dist/src/mcp/tools/plans.d.ts +23 -0
- package/dist/src/mcp/tools/plans.d.ts.map +1 -0
- package/dist/src/mcp/tools/plans.js +63 -0
- package/dist/src/mcp/tools/plans.js.map +1 -0
- package/dist/src/mcp/tools/recall.d.ts +30 -0
- package/dist/src/mcp/tools/recall.d.ts.map +1 -0
- package/dist/src/mcp/tools/recall.js +34 -0
- package/dist/src/mcp/tools/recall.js.map +1 -0
- package/dist/src/mcp/tools/remember.d.ts +15 -0
- package/dist/src/mcp/tools/remember.d.ts.map +1 -0
- package/dist/src/mcp/tools/remember.js +18 -0
- package/dist/src/mcp/tools/remember.js.map +1 -0
- package/dist/src/mcp/tools/search.d.ts +19 -0
- package/dist/src/mcp/tools/search.d.ts.map +1 -0
- package/dist/src/mcp/tools/search.js +59 -0
- package/dist/src/mcp/tools/search.js.map +1 -0
- package/dist/src/mcp/tools/sessions.d.ts +21 -0
- package/dist/src/mcp/tools/sessions.d.ts.map +1 -0
- package/dist/src/mcp/tools/sessions.js +36 -0
- package/dist/src/mcp/tools/sessions.js.map +1 -0
- package/dist/src/mcp/tools/supersede.d.ts +14 -0
- package/dist/src/mcp/tools/supersede.d.ts.map +1 -0
- package/dist/src/mcp/tools/supersede.js +30 -0
- package/dist/src/mcp/tools/supersede.js.map +1 -0
- package/dist/src/mcp/tools/team.d.ts +16 -0
- package/dist/src/mcp/tools/team.d.ts.map +1 -0
- package/dist/src/mcp/tools/team.js +32 -0
- package/dist/src/mcp/tools/team.js.map +1 -0
- package/dist/src/obsidian/formatter.d.ts +80 -0
- package/dist/src/obsidian/formatter.d.ts.map +1 -0
- package/dist/src/obsidian/formatter.js +227 -0
- package/dist/src/obsidian/formatter.js.map +1 -0
- package/dist/src/prompts/classification.md +42 -0
- package/dist/src/prompts/extraction.md +45 -0
- package/dist/src/prompts/index.d.ts +13 -0
- package/dist/src/prompts/index.d.ts.map +1 -0
- package/dist/src/prompts/index.js +75 -0
- package/dist/src/prompts/index.js.map +1 -0
- package/dist/src/prompts/session-similarity.md +24 -0
- package/dist/src/prompts/summary.md +9 -0
- package/dist/src/prompts/title.md +8 -0
- package/dist/src/vault/frontmatter.d.ts +6 -0
- package/dist/src/vault/frontmatter.d.ts.map +1 -0
- package/dist/src/vault/frontmatter.js +10 -0
- package/dist/src/vault/frontmatter.js.map +1 -0
- package/dist/src/vault/observations.d.ts +10 -0
- package/dist/src/vault/observations.d.ts.map +1 -0
- package/dist/src/vault/observations.js +33 -0
- package/dist/src/vault/observations.js.map +1 -0
- package/dist/src/vault/reader.d.ts +10 -0
- package/dist/src/vault/reader.d.ts.map +1 -0
- package/dist/src/vault/reader.js +48 -0
- package/dist/src/vault/reader.js.map +1 -0
- package/dist/src/vault/resolve.d.ts +18 -0
- package/dist/src/vault/resolve.d.ts.map +1 -0
- package/dist/src/vault/resolve.js +51 -0
- package/dist/src/vault/resolve.js.map +1 -0
- package/dist/src/vault/session-id.d.ts +16 -0
- package/dist/src/vault/session-id.d.ts.map +1 -0
- package/dist/src/vault/session-id.js +29 -0
- package/dist/src/vault/session-id.js.map +1 -0
- package/dist/src/vault/types.d.ts +88 -0
- package/dist/src/vault/types.d.ts.map +1 -0
- package/dist/src/vault/types.js +94 -0
- package/dist/src/vault/types.js.map +1 -0
- package/dist/src/vault/writer.d.ts +66 -0
- package/dist/src/vault/writer.d.ts.map +1 -0
- package/dist/src/vault/writer.js +217 -0
- package/dist/src/vault/writer.js.map +1 -0
- package/hooks/hooks.json +60 -0
- package/package.json +52 -0
- package/skills/myco/SKILL.md +206 -0
- package/skills/myco/references/wisdom.md +61 -0
- package/skills/rules/SKILL.md +185 -0
- package/skills/rules/references/rules-bad-example.md +106 -0
- package/skills/rules/references/rules-good-example.md +90 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { claudeCodeAdapter } from './claude-code.js';
|
|
2
|
+
import { cursorAdapter } from './cursor.js';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
/**
|
|
5
|
+
* All known agent adapters, ordered by priority.
|
|
6
|
+
* When searching for a transcript, adapters are tried in order.
|
|
7
|
+
* Add new adapters here as agent support grows.
|
|
8
|
+
*/
|
|
9
|
+
const ALL_ADAPTERS = [
|
|
10
|
+
claudeCodeAdapter,
|
|
11
|
+
cursorAdapter,
|
|
12
|
+
];
|
|
13
|
+
export class AgentRegistry {
|
|
14
|
+
adapters;
|
|
15
|
+
constructor(additionalAdapters = []) {
|
|
16
|
+
this.adapters = [...ALL_ADAPTERS, ...additionalAdapters];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Find and parse transcript turns for a session.
|
|
20
|
+
* Tries each adapter in priority order. Returns the first match.
|
|
21
|
+
*/
|
|
22
|
+
getTranscriptTurns(sessionId) {
|
|
23
|
+
for (const adapter of this.adapters) {
|
|
24
|
+
const filePath = adapter.findTranscript(sessionId);
|
|
25
|
+
if (!filePath)
|
|
26
|
+
continue;
|
|
27
|
+
try {
|
|
28
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
29
|
+
const turns = adapter.parseTurns(content);
|
|
30
|
+
if (turns.length > 0) {
|
|
31
|
+
return { turns, source: adapter.name };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Adapter found a path but read/parse failed — try next
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
/** List all registered adapter names */
|
|
41
|
+
get adapterNames() {
|
|
42
|
+
return this.adapters.map((a) => a.name);
|
|
43
|
+
}
|
|
44
|
+
/** Get a specific adapter by name */
|
|
45
|
+
getAdapter(name) {
|
|
46
|
+
return this.adapters.find((a) => a.name === name);
|
|
47
|
+
}
|
|
48
|
+
/** Detect which agent is currently active based on environment variables */
|
|
49
|
+
detectActiveAgent() {
|
|
50
|
+
for (const adapter of this.adapters) {
|
|
51
|
+
if (process.env[adapter.pluginRootEnvVar]) {
|
|
52
|
+
return adapter;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Parse turns from a known transcript file path (provided by hook).
|
|
59
|
+
* Tries each adapter's parseTurns until one produces results.
|
|
60
|
+
* Skips directory scanning entirely — the path is already known.
|
|
61
|
+
*/
|
|
62
|
+
parseTurnsFromPath(filePath) {
|
|
63
|
+
try {
|
|
64
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
65
|
+
// Try the active agent's parser first, then fall back to others
|
|
66
|
+
const active = this.detectActiveAgent();
|
|
67
|
+
const orderedAdapters = active
|
|
68
|
+
? [active, ...this.adapters.filter((a) => a !== active)]
|
|
69
|
+
: this.adapters;
|
|
70
|
+
for (const adapter of orderedAdapters) {
|
|
71
|
+
const turns = adapter.parseTurns(content);
|
|
72
|
+
if (turns.length > 0) {
|
|
73
|
+
return { turns, source: `${adapter.name}:direct` };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// File unreadable — caller will fall back to directory scanning
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Resolve the plugin root directory from the active agent's environment variable.
|
|
84
|
+
* Returns undefined if no agent env var is set (e.g., running from CLI directly).
|
|
85
|
+
*/
|
|
86
|
+
resolvePluginRoot() {
|
|
87
|
+
for (const adapter of this.adapters) {
|
|
88
|
+
const value = process.env[adapter.pluginRootEnvVar];
|
|
89
|
+
if (value)
|
|
90
|
+
return value;
|
|
91
|
+
}
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/agents/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface ArtifactCandidate {
|
|
2
|
+
path: string;
|
|
3
|
+
content: string;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Returns true if a relative path belongs to plugin/agent infrastructure
|
|
7
|
+
* that should never be captured as a project artifact.
|
|
8
|
+
*/
|
|
9
|
+
export declare function isExcludedPath(relativePath: string): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Filters a set of written/edited file paths by extension, gitignore,
|
|
12
|
+
* and infrastructure exclusions, then reads final content from disk.
|
|
13
|
+
*
|
|
14
|
+
* Uses execFileSync (not exec) for git check-ignore — arguments are passed
|
|
15
|
+
* as an array, so no shell injection risk.
|
|
16
|
+
*/
|
|
17
|
+
export declare function collectArtifactCandidates(filePaths: Set<string>, config: {
|
|
18
|
+
artifact_extensions: string[];
|
|
19
|
+
}, projectRoot: string): ArtifactCandidate[];
|
|
20
|
+
//# sourceMappingURL=candidates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"candidates.d.ts","sourceRoot":"","sources":["../../../src/artifacts/candidates.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAyBD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAM5D;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,EACtB,MAAM,EAAE;IAAE,mBAAmB,EAAE,MAAM,EAAE,CAAA;CAAE,EACzC,WAAW,EAAE,MAAM,GAClB,iBAAiB,EAAE,CAgCrB"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
/** Filenames (case-insensitive) that are agent/plugin infrastructure, not project artifacts. */
|
|
5
|
+
const EXCLUDED_FILENAMES = new Set([
|
|
6
|
+
'claude.md',
|
|
7
|
+
'agents.md',
|
|
8
|
+
'gemini.md',
|
|
9
|
+
'readme.md',
|
|
10
|
+
'contributing.md',
|
|
11
|
+
'changelog.md',
|
|
12
|
+
'license.md',
|
|
13
|
+
'pull_request_template.md',
|
|
14
|
+
]);
|
|
15
|
+
/** Directory prefixes (relative to project root) that contain plugin/agent components or repo infrastructure. */
|
|
16
|
+
const EXCLUDED_PREFIXES = [
|
|
17
|
+
'commands/',
|
|
18
|
+
'skills/',
|
|
19
|
+
'hooks/',
|
|
20
|
+
'.claude-plugin/',
|
|
21
|
+
'.cursor-plugin/',
|
|
22
|
+
'.claude/',
|
|
23
|
+
'.github/',
|
|
24
|
+
];
|
|
25
|
+
/**
|
|
26
|
+
* Returns true if a relative path belongs to plugin/agent infrastructure
|
|
27
|
+
* that should never be captured as a project artifact.
|
|
28
|
+
*/
|
|
29
|
+
export function isExcludedPath(relativePath) {
|
|
30
|
+
const basename = path.basename(relativePath).toLowerCase();
|
|
31
|
+
if (EXCLUDED_FILENAMES.has(basename))
|
|
32
|
+
return true;
|
|
33
|
+
const normalized = relativePath.replace(/\\/g, '/');
|
|
34
|
+
return EXCLUDED_PREFIXES.some((prefix) => normalized.startsWith(prefix));
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Filters a set of written/edited file paths by extension, gitignore,
|
|
38
|
+
* and infrastructure exclusions, then reads final content from disk.
|
|
39
|
+
*
|
|
40
|
+
* Uses execFileSync (not exec) for git check-ignore — arguments are passed
|
|
41
|
+
* as an array, so no shell injection risk.
|
|
42
|
+
*/
|
|
43
|
+
export function collectArtifactCandidates(filePaths, config, projectRoot) {
|
|
44
|
+
if (filePaths.size === 0)
|
|
45
|
+
return [];
|
|
46
|
+
// Filter by extension first (cheap)
|
|
47
|
+
const extFiltered = [...filePaths].filter((absPath) => config.artifact_extensions.includes(path.extname(absPath)));
|
|
48
|
+
if (extFiltered.length === 0)
|
|
49
|
+
return [];
|
|
50
|
+
// Batch git check-ignore: one subprocess instead of N
|
|
51
|
+
const ignoredSet = getGitIgnored(extFiltered, projectRoot);
|
|
52
|
+
const candidates = [];
|
|
53
|
+
for (const absPath of extFiltered) {
|
|
54
|
+
if (ignoredSet.has(absPath))
|
|
55
|
+
continue;
|
|
56
|
+
try {
|
|
57
|
+
const content = fs.readFileSync(absPath, 'utf-8');
|
|
58
|
+
const relativePath = path.relative(projectRoot, absPath);
|
|
59
|
+
// Skip plugin/agent infrastructure files
|
|
60
|
+
if (isExcludedPath(relativePath))
|
|
61
|
+
continue;
|
|
62
|
+
candidates.push({ path: relativePath, content });
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
// File was deleted between event capture and now — skip
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return candidates;
|
|
69
|
+
}
|
|
70
|
+
function getGitIgnored(filePaths, cwd) {
|
|
71
|
+
try {
|
|
72
|
+
const result = execFileSync('git', ['check-ignore', ...filePaths], {
|
|
73
|
+
cwd,
|
|
74
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
75
|
+
encoding: 'utf-8',
|
|
76
|
+
});
|
|
77
|
+
return new Set(result.trim().split('\n').filter(Boolean));
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// exit 1 = none are ignored (or git not available)
|
|
81
|
+
return new Set();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=candidates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"candidates.js","sourceRoot":"","sources":["../../../src/artifacts/candidates.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slugify.d.ts","sourceRoot":"","sources":["../../../src/artifacts/slugify.ts"],"names":[],"mappings":"AAIA,wBAAgB,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAoBxD"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { MAX_SLUG_LENGTH } from '../constants.js';
|
|
4
|
+
export function slugifyPath(relativePath) {
|
|
5
|
+
const ext = path.extname(relativePath);
|
|
6
|
+
const withoutExt = ext ? relativePath.slice(0, -ext.length) : relativePath;
|
|
7
|
+
let slug = withoutExt
|
|
8
|
+
.replace(/[/\\]/g, '-')
|
|
9
|
+
.toLowerCase()
|
|
10
|
+
.replace(/\s+/g, '-')
|
|
11
|
+
.replace(/[^a-z0-9-]/g, '');
|
|
12
|
+
if (slug.length > MAX_SLUG_LENGTH) {
|
|
13
|
+
const hash = crypto
|
|
14
|
+
.createHash('sha256')
|
|
15
|
+
.update(relativePath)
|
|
16
|
+
.digest('hex')
|
|
17
|
+
.slice(0, 6);
|
|
18
|
+
slug = slug.slice(0, MAX_SLUG_LENGTH) + '-' + hash;
|
|
19
|
+
}
|
|
20
|
+
return slug;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=slugify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slugify.js","sourceRoot":"","sources":["../../../src/artifacts/slugify.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElD,MAAM,UAAU,WAAW,CAAC,YAAoB;IAC9C,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IACvC,MAAM,UAAU,GAAG,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;IAE3E,IAAI,IAAI,GAAG,UAAU;SAClB,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC;SACtB,WAAW,EAAE;SACb,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;IAE9B,IAAI,IAAI,CAAC,MAAM,GAAG,eAAe,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,MAAM;aAChB,UAAU,CAAC,QAAQ,CAAC;aACpB,MAAM,CAAC,YAAY,CAAC;aACpB,MAAM,CAAC,KAAK,CAAC;aACb,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACf,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC;IACrD,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface ArtifactEvent {
|
|
2
|
+
type: 'add' | 'change';
|
|
3
|
+
path: string;
|
|
4
|
+
absolutePath: string;
|
|
5
|
+
}
|
|
6
|
+
type ArtifactHandler = (event: ArtifactEvent) => void;
|
|
7
|
+
export declare class ArtifactWatcher {
|
|
8
|
+
private projectRoot;
|
|
9
|
+
private watchPaths;
|
|
10
|
+
private watcher;
|
|
11
|
+
private handlers;
|
|
12
|
+
constructor(projectRoot: string, watchPaths: string[]);
|
|
13
|
+
onArtifact(handler: ArtifactHandler): void;
|
|
14
|
+
start(): void;
|
|
15
|
+
stop(): void;
|
|
16
|
+
private emit;
|
|
17
|
+
}
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=artifact-watcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-watcher.d.ts","sourceRoot":"","sources":["../../../src/capture/artifact-watcher.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,KAAK,GAAG,QAAQ,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,KAAK,eAAe,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;AAEtD,qBAAa,eAAe;IAKxB,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,UAAU;IALpB,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,QAAQ,CAAyB;gBAG/B,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAAE;IAG9B,UAAU,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI;IAI1C,KAAK,IAAI,IAAI;IAeb,IAAI,IAAI,IAAI;IAKZ,OAAO,CAAC,IAAI;CAOb"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { watch } from 'chokidar';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
export class ArtifactWatcher {
|
|
4
|
+
projectRoot;
|
|
5
|
+
watchPaths;
|
|
6
|
+
watcher = null;
|
|
7
|
+
handlers = [];
|
|
8
|
+
constructor(projectRoot, watchPaths) {
|
|
9
|
+
this.projectRoot = projectRoot;
|
|
10
|
+
this.watchPaths = watchPaths;
|
|
11
|
+
}
|
|
12
|
+
onArtifact(handler) {
|
|
13
|
+
this.handlers.push(handler);
|
|
14
|
+
}
|
|
15
|
+
start() {
|
|
16
|
+
const absolutePaths = this.watchPaths.map((p) => path.resolve(this.projectRoot, p));
|
|
17
|
+
this.watcher = watch(absolutePaths, {
|
|
18
|
+
ignoreInitial: true,
|
|
19
|
+
persistent: false,
|
|
20
|
+
depth: 3,
|
|
21
|
+
});
|
|
22
|
+
this.watcher.on('add', (filePath) => this.emit('add', filePath));
|
|
23
|
+
this.watcher.on('change', (filePath) => this.emit('change', filePath));
|
|
24
|
+
}
|
|
25
|
+
stop() {
|
|
26
|
+
this.watcher?.close();
|
|
27
|
+
this.watcher = null;
|
|
28
|
+
}
|
|
29
|
+
emit(type, absolutePath) {
|
|
30
|
+
const relativePath = path.relative(this.projectRoot, absolutePath);
|
|
31
|
+
const event = { type, path: relativePath, absolutePath };
|
|
32
|
+
for (const handler of this.handlers) {
|
|
33
|
+
handler(event);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=artifact-watcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-watcher.js","sourceRoot":"","sources":["../../../src/capture/artifact-watcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAEjC,OAAO,IAAI,MAAM,WAAW,CAAC;AAU7B,MAAM,OAAO,eAAe;IAKhB;IACA;IALF,OAAO,GAAqB,IAAI,CAAC;IACjC,QAAQ,GAAsB,EAAE,CAAC;IAEzC,YACU,WAAmB,EACnB,UAAoB;QADpB,gBAAW,GAAX,WAAW,CAAQ;QACnB,eAAU,GAAV,UAAU,CAAU;IAC3B,CAAC;IAEJ,UAAU,CAAC,OAAwB;QACjC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAED,KAAK;QACH,MAAM,aAAa,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAC9C,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAClC,CAAC;QAEF,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,aAAa,EAAE;YAClC,aAAa,EAAE,IAAI;YACnB,UAAU,EAAE,KAAK;YACjB,KAAK,EAAE,CAAC;SACT,CAAC,CAAC;QAEH,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC;QACjE,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;IACzE,CAAC;IAED,IAAI;QACF,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACtB,CAAC;IAEO,IAAI,CAAC,IAAsB,EAAE,YAAoB;QACvD,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;QACnE,MAAM,KAAK,GAAkB,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,YAAY,EAAE,CAAC;QACxE,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACpC,OAAO,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
interface BufferOptions {
|
|
2
|
+
maxEvents?: number;
|
|
3
|
+
}
|
|
4
|
+
export declare class EventBuffer {
|
|
5
|
+
private bufferDir;
|
|
6
|
+
private sessionId;
|
|
7
|
+
private filePath;
|
|
8
|
+
private maxEvents;
|
|
9
|
+
private eventCount;
|
|
10
|
+
constructor(bufferDir: string, sessionId: string, options?: BufferOptions);
|
|
11
|
+
append(event: Record<string, unknown>): void;
|
|
12
|
+
readAll(): Array<Record<string, unknown>>;
|
|
13
|
+
count(): number;
|
|
14
|
+
exists(): boolean;
|
|
15
|
+
delete(): void;
|
|
16
|
+
isOverflow(): boolean;
|
|
17
|
+
getFilePath(): string;
|
|
18
|
+
}
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=buffer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buffer.d.ts","sourceRoot":"","sources":["../../../src/capture/buffer.ts"],"names":[],"mappings":"AAGA,UAAU,aAAa;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,WAAW;IAMpB,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,SAAS;IANnB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAK;gBAGb,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACzB,OAAO,GAAE,aAAkB;IAW7B,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAY5C,OAAO,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAOzC,KAAK,IAAI,MAAM;IAIf,MAAM,IAAI,OAAO;IAIjB,MAAM,IAAI,IAAI;IAOd,UAAU,IAAI,OAAO;IAIrB,WAAW,IAAI,MAAM;CAGtB"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
export class EventBuffer {
|
|
4
|
+
bufferDir;
|
|
5
|
+
sessionId;
|
|
6
|
+
filePath;
|
|
7
|
+
maxEvents;
|
|
8
|
+
eventCount = 0;
|
|
9
|
+
constructor(bufferDir, sessionId, options = {}) {
|
|
10
|
+
this.bufferDir = bufferDir;
|
|
11
|
+
this.sessionId = sessionId;
|
|
12
|
+
this.filePath = path.join(bufferDir, `${sessionId}.jsonl`);
|
|
13
|
+
this.maxEvents = options.maxEvents ?? 500;
|
|
14
|
+
if (fs.existsSync(this.filePath)) {
|
|
15
|
+
const content = fs.readFileSync(this.filePath, 'utf-8').trim();
|
|
16
|
+
this.eventCount = content ? content.split('\n').length : 0;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
append(event) {
|
|
20
|
+
fs.mkdirSync(this.bufferDir, { recursive: true });
|
|
21
|
+
const line = JSON.stringify({
|
|
22
|
+
...event,
|
|
23
|
+
timestamp: event.timestamp ?? new Date().toISOString(),
|
|
24
|
+
});
|
|
25
|
+
fs.appendFileSync(this.filePath, line + '\n');
|
|
26
|
+
this.eventCount++;
|
|
27
|
+
}
|
|
28
|
+
readAll() {
|
|
29
|
+
if (!fs.existsSync(this.filePath))
|
|
30
|
+
return [];
|
|
31
|
+
const content = fs.readFileSync(this.filePath, 'utf-8').trim();
|
|
32
|
+
if (!content)
|
|
33
|
+
return [];
|
|
34
|
+
return content.split('\n').map((line) => JSON.parse(line));
|
|
35
|
+
}
|
|
36
|
+
count() {
|
|
37
|
+
return this.eventCount;
|
|
38
|
+
}
|
|
39
|
+
exists() {
|
|
40
|
+
return fs.existsSync(this.filePath);
|
|
41
|
+
}
|
|
42
|
+
delete() {
|
|
43
|
+
if (fs.existsSync(this.filePath)) {
|
|
44
|
+
fs.unlinkSync(this.filePath);
|
|
45
|
+
}
|
|
46
|
+
this.eventCount = 0;
|
|
47
|
+
}
|
|
48
|
+
isOverflow() {
|
|
49
|
+
return this.eventCount > this.maxEvents;
|
|
50
|
+
}
|
|
51
|
+
getFilePath() {
|
|
52
|
+
return this.filePath;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=buffer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buffer.js","sourceRoot":"","sources":["../../../src/capture/buffer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAM7B,MAAM,OAAO,WAAW;IAMZ;IACA;IANF,QAAQ,CAAS;IACjB,SAAS,CAAS;IAClB,UAAU,GAAG,CAAC,CAAC;IAEvB,YACU,SAAiB,EACjB,SAAiB,EACzB,UAAyB,EAAE;QAFnB,cAAS,GAAT,SAAS,CAAQ;QACjB,cAAS,GAAT,SAAS,CAAQ;QAGzB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,SAAS,QAAQ,CAAC,CAAC;QAC3D,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,GAAG,CAAC;QAE1C,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YACjC,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;YAC/D,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;IAED,MAAM,CAAC,KAA8B;QACnC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAElD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;YAC1B,GAAG,KAAK;YACR,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACvD,CAAC,CAAC;QAEH,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,GAAG,IAAI,CAAC,CAAC;QAC9C,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;IAED,OAAO;QACL,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC;YAAE,OAAO,EAAE,CAAC;QAC7C,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QAC/D,IAAI,CAAC,OAAO;YAAE,OAAO,EAAE,CAAC;QACxB,OAAO,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED,KAAK;QACH,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,MAAM;QACJ,OAAO,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACtC,CAAC;IAED,MAAM;QACJ,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YACjC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC/B,CAAC;QACD,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;IACtB,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC;IAC1C,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;CACF"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface PlanSignal {
|
|
2
|
+
source: 'hook' | 'artifact' | 'content' | 'transcript';
|
|
3
|
+
confidence: 'high' | 'medium' | 'low';
|
|
4
|
+
detail: string;
|
|
5
|
+
}
|
|
6
|
+
interface DetectionInput {
|
|
7
|
+
hookEvents?: Array<Record<string, unknown>>;
|
|
8
|
+
newFiles?: string[];
|
|
9
|
+
sessionContent?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare class PlanDetector {
|
|
12
|
+
detect(input: DetectionInput): PlanSignal[];
|
|
13
|
+
}
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=plan-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-detector.d.ts","sourceRoot":"","sources":["../../../src/capture/plan-detector.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,GAAG,YAAY,CAAC;IACvD,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACtC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,cAAc;IACtB,UAAU,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5C,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAQD,qBAAa,YAAY;IACvB,MAAM,CAAC,KAAK,EAAE,cAAc,GAAG,UAAU,EAAE;CA6B5C"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const PLAN_DIRECTORIES = [
|
|
2
|
+
'docs/superpowers/specs/',
|
|
3
|
+
'.claude/plans/',
|
|
4
|
+
'.cursor/plans/',
|
|
5
|
+
];
|
|
6
|
+
export class PlanDetector {
|
|
7
|
+
detect(input) {
|
|
8
|
+
const signals = [];
|
|
9
|
+
if (input.hookEvents) {
|
|
10
|
+
for (const event of input.hookEvents) {
|
|
11
|
+
if (event.type === 'EnterPlanMode' || event.type === 'ExitPlanMode') {
|
|
12
|
+
signals.push({
|
|
13
|
+
source: 'hook',
|
|
14
|
+
confidence: 'high',
|
|
15
|
+
detail: `Plan mode ${event.type === 'EnterPlanMode' ? 'entered' : 'exited'}`,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
if (input.newFiles) {
|
|
21
|
+
for (const file of input.newFiles) {
|
|
22
|
+
if (PLAN_DIRECTORIES.some((dir) => file.startsWith(dir))) {
|
|
23
|
+
signals.push({
|
|
24
|
+
source: 'artifact',
|
|
25
|
+
confidence: 'medium',
|
|
26
|
+
detail: `New file in plan directory: ${file}`,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return signals;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=plan-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-detector.js","sourceRoot":"","sources":["../../../src/capture/plan-detector.ts"],"names":[],"mappings":"AAYA,MAAM,gBAAgB,GAAG;IACvB,yBAAyB;IACzB,gBAAgB;IAChB,gBAAgB;CACjB,CAAC;AAEF,MAAM,OAAO,YAAY;IACvB,MAAM,CAAC,KAAqB;QAC1B,MAAM,OAAO,GAAiB,EAAE,CAAC;QAEjC,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;YACrB,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;gBACrC,IAAI,KAAK,CAAC,IAAI,KAAK,eAAe,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;oBACpE,OAAO,CAAC,IAAI,CAAC;wBACX,MAAM,EAAE,MAAM;wBACd,UAAU,EAAE,MAAM;wBAClB,MAAM,EAAE,aAAa,KAAK,CAAC,IAAI,KAAK,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE;qBAC7E,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YACnB,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;gBAClC,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;oBACzD,OAAO,CAAC,IAAI,CAAC;wBACX,MAAM,EAAE,UAAU;wBAClB,UAAU,EAAE,QAAQ;wBACpB,MAAM,EAAE,+BAA+B,IAAI,EAAE;qBAC9C,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"processor.d.ts","sourceRoot":"","sources":["../../../src/capture/processor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,KAAK,WAAW,EAAE,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"processor.js","sourceRoot":"","sources":["../../../src/capture/processor.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,OAAO,EAAE,eAAe,EAA0C,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: classify
|
|
3
|
+
description: Classify activity type for a single user request
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Classify the type of work done in response to a single user request.
|
|
7
|
+
|
|
8
|
+
## Activity Summary
|
|
9
|
+
|
|
10
|
+
- Duration: {{session_duration}} minutes
|
|
11
|
+
- Tools used: {{tool_summary}}
|
|
12
|
+
- Files read: {{files_read_count}}
|
|
13
|
+
- Files modified: {{files_modified_count}}
|
|
14
|
+
- Files created: {{files_created_count}}
|
|
15
|
+
- Errors encountered: {{has_errors}}
|
|
16
|
+
|
|
17
|
+
## Activity Log
|
|
18
|
+
|
|
19
|
+
{{activities}}
|
|
20
|
+
|
|
21
|
+
## Classification Types
|
|
22
|
+
|
|
23
|
+
{{classification_types}}
|
|
24
|
+
|
|
25
|
+
## Task
|
|
26
|
+
|
|
27
|
+
Based on the activities above, determine what the agent was primarily doing.
|
|
28
|
+
Respond with ONLY the classification word (e.g., exploration, debugging, implementation, refactoring), nothing else.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: debugging
|
|
3
|
+
description: For debugging sessions with errors
|
|
4
|
+
activity_filter: Read,Edit,Bash
|
|
5
|
+
min_activities: 2
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You are analyzing a debugging session to capture the root cause and fix.
|
|
9
|
+
|
|
10
|
+
## Context
|
|
11
|
+
|
|
12
|
+
The developer was debugging an issue.
|
|
13
|
+
|
|
14
|
+
Duration: {{session_duration}} minutes
|
|
15
|
+
Files investigated: {{files_read}}
|
|
16
|
+
Files modified: {{files_modified}}
|
|
17
|
+
Errors: {{errors}}
|
|
18
|
+
|
|
19
|
+
### Debugging Activity
|
|
20
|
+
|
|
21
|
+
{{activities}}
|
|
22
|
+
|
|
23
|
+
## Observation Types
|
|
24
|
+
|
|
25
|
+
{{observation_types}}
|
|
26
|
+
|
|
27
|
+
## Importance Levels
|
|
28
|
+
|
|
29
|
+
Rate each observation's importance based on its value for future sessions:
|
|
30
|
+
|
|
31
|
+
- **high**: Non-obvious insight that would cause bugs, confusion, or wasted time if forgotten. Cannot be easily rediscovered from code alone.
|
|
32
|
+
- **medium**: Useful context that saves time but could be rediscovered with investigation.
|
|
33
|
+
- **low**: Nice-to-know information that is easily found from code or already documented elsewhere. Skip if already captured in project docs.
|
|
34
|
+
|
|
35
|
+
Prefer fewer high-quality observations over many low-importance ones.
|
|
36
|
+
|
|
37
|
+
## Task
|
|
38
|
+
|
|
39
|
+
Extract the debugging journey: what was the symptom, what was investigated, what was the root cause, and how was it fixed.
|
|
40
|
+
|
|
41
|
+
Focus on:
|
|
42
|
+
- The initial error or symptom
|
|
43
|
+
- Wrong assumptions or dead ends
|
|
44
|
+
- The actual root cause
|
|
45
|
+
- The fix and why it works
|
|
46
|
+
- How to avoid this in the future
|
|
47
|
+
|
|
48
|
+
Prefer **bug_fix** and **gotcha** types for debugging sessions.
|
|
49
|
+
|
|
50
|
+
## Examples
|
|
51
|
+
|
|
52
|
+
**Good observation** (specific root cause and fix — extract this):
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"type": "bug_fix",
|
|
56
|
+
"observation": "SQLite LIMIT clause was string-interpolated, allowing SQL injection. Fix: use parameterized query with LIMIT ? and push value to params array.",
|
|
57
|
+
"context": "src/index/sqlite.ts",
|
|
58
|
+
"importance": "high"
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Bad observation** (too vague — skip this):
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"type": "bug_fix",
|
|
66
|
+
"observation": "Fixed a database error",
|
|
67
|
+
"context": "src/index",
|
|
68
|
+
"importance": "medium"
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Output Format
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"observations": [
|
|
77
|
+
{
|
|
78
|
+
"type": "{{type_names}}",
|
|
79
|
+
"observation": "Root cause and fix description",
|
|
80
|
+
"context": "File where bug was",
|
|
81
|
+
"importance": "high|medium|low"
|
|
82
|
+
}
|
|
83
|
+
],
|
|
84
|
+
"summary": "Brief description of bug and fix"
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Guidelines:
|
|
89
|
+
- Extract at most 5 observations per session. Prefer fewer, higher-quality observations over many low-value ones.
|
|
90
|
+
|
|
91
|
+
Respond ONLY with valid JSON.
|