@tonycasey/lisa 0.5.13

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 (48) hide show
  1. package/README.md +42 -0
  2. package/dist/cli.js +390 -0
  3. package/dist/lib/interfaces/IDockerClient.js +2 -0
  4. package/dist/lib/interfaces/IMcpClient.js +2 -0
  5. package/dist/lib/interfaces/IServices.js +2 -0
  6. package/dist/lib/interfaces/ITemplateCopier.js +2 -0
  7. package/dist/lib/mcp.js +35 -0
  8. package/dist/lib/services.js +57 -0
  9. package/dist/package.json +36 -0
  10. package/dist/templates/agents/.sample.env +12 -0
  11. package/dist/templates/agents/docs/STORAGE_SETUP.md +161 -0
  12. package/dist/templates/agents/skills/common/group-id.js +193 -0
  13. package/dist/templates/agents/skills/init-review/SKILL.md +119 -0
  14. package/dist/templates/agents/skills/init-review/scripts/ai-enrich.js +258 -0
  15. package/dist/templates/agents/skills/init-review/scripts/init-review.js +769 -0
  16. package/dist/templates/agents/skills/lisa/SKILL.md +92 -0
  17. package/dist/templates/agents/skills/lisa/cache/.gitkeep +0 -0
  18. package/dist/templates/agents/skills/lisa/scripts/storage.js +374 -0
  19. package/dist/templates/agents/skills/memory/SKILL.md +31 -0
  20. package/dist/templates/agents/skills/memory/scripts/memory.js +533 -0
  21. package/dist/templates/agents/skills/prompt/SKILL.md +19 -0
  22. package/dist/templates/agents/skills/prompt/scripts/prompt.js +184 -0
  23. package/dist/templates/agents/skills/tasks/SKILL.md +31 -0
  24. package/dist/templates/agents/skills/tasks/scripts/tasks.js +489 -0
  25. package/dist/templates/claude/config.js +40 -0
  26. package/dist/templates/claude/hooks/README.md +158 -0
  27. package/dist/templates/claude/hooks/common/complexity-rater.js +290 -0
  28. package/dist/templates/claude/hooks/common/context.js +263 -0
  29. package/dist/templates/claude/hooks/common/group-id.js +188 -0
  30. package/dist/templates/claude/hooks/common/mcp-client.js +131 -0
  31. package/dist/templates/claude/hooks/common/transcript-parser.js +256 -0
  32. package/dist/templates/claude/hooks/common/zep-client.js +175 -0
  33. package/dist/templates/claude/hooks/session-start.js +401 -0
  34. package/dist/templates/claude/hooks/session-stop-worker.js +341 -0
  35. package/dist/templates/claude/hooks/session-stop.js +122 -0
  36. package/dist/templates/claude/hooks/user-prompt-submit.js +256 -0
  37. package/dist/templates/claude/settings.json +46 -0
  38. package/dist/templates/docker/.env.lisa.example +17 -0
  39. package/dist/templates/docker/docker-compose.graphiti.yml +45 -0
  40. package/dist/templates/rules/shared/clean-architecture.md +333 -0
  41. package/dist/templates/rules/shared/code-quality-rules.md +469 -0
  42. package/dist/templates/rules/shared/git-rules.md +64 -0
  43. package/dist/templates/rules/shared/testing-principles.md +469 -0
  44. package/dist/templates/rules/typescript/coding-standards.md +751 -0
  45. package/dist/templates/rules/typescript/testing.md +629 -0
  46. package/dist/templates/rules/typescript/typescript-config-guide.md +465 -0
  47. package/package.json +64 -0
  48. package/scripts/postinstall.js +710 -0
@@ -0,0 +1,184 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Prompt Capture Skill
5
+ *
6
+ * Stores user prompts as episodes in Graphiti MCP.
7
+ * Graphiti's LLM automatically classifies entities as:
8
+ * - KeyDecision: Major decisions about approach/strategy
9
+ * - DirectionChange: Changes in strategy or pivots
10
+ * - ArchitecturalChoice: Technical/architectural decisions
11
+ * - Preference: User preferences and style choices
12
+ * - Requirement: Specific needs that must be fulfilled
13
+ *
14
+ * The classification happens server-side based on entity_types in config.yaml
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ const crypto = require('crypto');
18
+ const path = require('path');
19
+ const fs = require('fs');
20
+ const os = require('os');
21
+ // ============================================================================
22
+ // Group ID Utilities (inline to avoid import complexity in deployed skills)
23
+ // ============================================================================
24
+ const MAX_GROUP_ID_LENGTH = 128;
25
+ function normalizePathToGroupId(absolutePath) {
26
+ let normalized = absolutePath
27
+ .toLowerCase()
28
+ .replace(/^\//, '')
29
+ .replace(/\//g, '-')
30
+ .replace(/\./g, '_'); // Graphiti requires alphanumeric, dashes, underscores only
31
+ if (normalized.length > MAX_GROUP_ID_LENGTH) {
32
+ normalized = normalized.slice(-MAX_GROUP_ID_LENGTH);
33
+ }
34
+ return normalized;
35
+ }
36
+ function getCurrentGroupId(cwd = process.cwd()) {
37
+ return normalizePathToGroupId(cwd);
38
+ }
39
+ const args = process.argv.slice(2);
40
+ function popFlag(name, fallback) {
41
+ const idx = args.indexOf(name);
42
+ if (idx === -1)
43
+ return fallback;
44
+ const val = args[idx + 1];
45
+ args.splice(idx, 2);
46
+ if (typeof fallback === 'boolean')
47
+ return true;
48
+ return val ?? fallback;
49
+ }
50
+ function hasFlag(name) {
51
+ const idx = args.indexOf(name);
52
+ if (idx === -1)
53
+ return false;
54
+ args.splice(idx, 1);
55
+ return true;
56
+ }
57
+ // Read from .agents/skills/.env (2 levels up from prompt/scripts/)
58
+ const envPath = path.join(__dirname, '..', '..', '.env');
59
+ const env = {};
60
+ try {
61
+ const raw = fs.readFileSync(envPath, 'utf8');
62
+ raw.split(/\r?\n/).forEach((line) => {
63
+ if (!line || line.startsWith('#'))
64
+ return;
65
+ const idx = line.indexOf('=');
66
+ if (idx === -1)
67
+ return;
68
+ env[line.slice(0, idx).trim()] = line.slice(idx + 1).trim();
69
+ });
70
+ }
71
+ catch (_) {
72
+ /* optional */
73
+ }
74
+ const endpoint = popFlag('--endpoint', env.GRAPHITI_ENDPOINT || process.env.GRAPHITI_ENDPOINT || 'http://localhost:8010/mcp/');
75
+ // Group ID: explicit --group > env > folder-based (current directory)
76
+ const explicitGroup = popFlag('--group', false);
77
+ const groupId = explicitGroup || env.GRAPHITI_GROUP_ID || process.env.GRAPHITI_GROUP_ID || getCurrentGroupId();
78
+ const force = hasFlag('--force') || popFlag('--force', false);
79
+ function parseArgs() {
80
+ const out = { role: 'user', source: 'user-prompt' };
81
+ for (let i = 0; i < args.length; i++) {
82
+ if (args[i] === '--text' || args[i] === '-t')
83
+ out.text = args[++i];
84
+ if (args[i] === '--role' || args[i] === '-r')
85
+ out.role = args[++i];
86
+ if (args[i] === '--source' || args[i] === '-s')
87
+ out.source = args[++i];
88
+ // Legacy support for --kind (now ignored - Graphiti classifies automatically)
89
+ if (args[i] === '--kind' || args[i] === '-k')
90
+ i++; // skip value
91
+ }
92
+ return out;
93
+ }
94
+ function fingerprint(text) {
95
+ return crypto.createHash('sha1').update(text.trim()).digest('hex').slice(0, 16);
96
+ }
97
+ async function initialize() {
98
+ const body = {
99
+ jsonrpc: '2.0',
100
+ id: 'init',
101
+ method: 'initialize',
102
+ params: {
103
+ protocolVersion: '2024-11-05',
104
+ capabilities: { experimental: {}, prompts: { listChanged: false }, resources: { subscribe: false, listChanged: false }, tools: { listChanged: false } },
105
+ clientInfo: { name: 'prompt-skill', version: '0.1.0' },
106
+ },
107
+ };
108
+ const resp = await fetch(endpoint, {
109
+ method: 'POST',
110
+ headers: { 'Content-Type': 'application/json', Accept: 'application/json, text/event-stream' },
111
+ body: JSON.stringify(body),
112
+ });
113
+ if (!resp.ok)
114
+ throw new Error(`initialize failed: ${resp.status}`);
115
+ const sid = resp.headers.get('mcp-session-id');
116
+ if (!sid)
117
+ throw new Error('missing mcp-session-id');
118
+ return sid;
119
+ }
120
+ async function rpcCall(method, params, sessionId) {
121
+ const payload = method === 'initialize' || method === 'ping' || method.startsWith('tools/')
122
+ ? { jsonrpc: '2.0', id: '1', method, params }
123
+ : { jsonrpc: '2.0', id: '1', method: 'tools/call', params: { name: method, arguments: params } };
124
+ const resp = await fetch(endpoint, {
125
+ method: 'POST',
126
+ headers: { 'Content-Type': 'application/json', 'MCP-SESSION-ID': sessionId, Accept: 'application/json, text/event-stream' },
127
+ body: JSON.stringify(payload),
128
+ });
129
+ let text = await resp.text();
130
+ if (text.startsWith('event:')) {
131
+ const dataLine = text.split('\n').find((l) => l.startsWith('data:'));
132
+ if (dataLine)
133
+ text = dataLine.slice(5).trim();
134
+ }
135
+ const data = JSON.parse(text);
136
+ if (!resp.ok || data.error)
137
+ throw new Error(data?.error?.message || `HTTP ${resp.status}`);
138
+ return data.result?.structuredContent?.result || data.result || data;
139
+ }
140
+ async function addPrompt() {
141
+ const { text, role = 'user', source = 'user-prompt' } = parseArgs();
142
+ if (!text)
143
+ throw new Error('prompt requires --text');
144
+ const fp = fingerprint(text);
145
+ const fpTag = `fingerprint:${fp}`;
146
+ const sid = await initialize();
147
+ if (!force) {
148
+ try {
149
+ const searchParams = { query: fp, tags: [fpTag], max_nodes: 1, group_ids: [groupId] };
150
+ const existing = await rpcCall('search_nodes', searchParams, sid);
151
+ const nodes = existing?.result?.nodes || existing?.nodes || [];
152
+ if (nodes.length) {
153
+ console.log('Duplicate prompt; skipping (use --force to override).');
154
+ return { status: 'skipped', reason: 'duplicate' };
155
+ }
156
+ }
157
+ catch (_) {
158
+ // ignore dedupe errors
159
+ }
160
+ }
161
+ // Let Graphiti's LLM classify the content automatically based on entity_types config
162
+ // We just provide the raw text - classification happens server-side
163
+ const params = {
164
+ name: text.substring(0, 100),
165
+ episode_body: text, // Pass raw text for better LLM classification
166
+ source: source, // Track where this came from
167
+ group_id: groupId,
168
+ tags: [fpTag, `role:${role}`, `source:${source}`],
169
+ };
170
+ await rpcCall('add_memory', params, sid);
171
+ return { status: 'ok', action: 'add', group: groupId, role, source };
172
+ }
173
+ async function main() {
174
+ try {
175
+ const result = await addPrompt();
176
+ console.log(JSON.stringify(result, null, 2));
177
+ }
178
+ catch (err) {
179
+ const message = err instanceof Error ? err.message : String(err);
180
+ console.error(message);
181
+ process.exit(1);
182
+ }
183
+ }
184
+ main();
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: tasks
3
+ description: "Create, load, or summarize tasks via Graphiti MCP; triggers on 'tasks', 'list tasks', 'add task', usable by any model (Claude, Gemini)."
4
+ ---
5
+
6
+ ## Purpose
7
+ Model-neutral helper to add/list tasks in Graphiti MCP so any agent can keep a shared task board.
8
+
9
+ ## Triggers
10
+ Use when the user says: "add a task", "list tasks", "load tasks", "task status".
11
+
12
+ ## How to use
13
+ 1) List: `scripts/tasks.js list --cache [--group <id>] [--limit 20]`
14
+ 2) Add: `scripts/tasks.js add "<task text>" [--status todo|doing|done] [--tag foo] [--group <id>] --cache`
15
+ 3) Defaults: reads ${GRAPHITI_ENDPOINT} / ${GRAPHITI_GROUP_ID} from `.agents/.env` (written by init); see root `AGENTS.md` for canonical defaults.
16
+ 4) Cache fallback: writes/reads `cache/tasks.log` when `--cache` is passed, returning last cached result on MCP failure.
17
+ 5) Keep prompts model-neutral; models only orchestrate script calls and summarize JSON output.
18
+
19
+ ## I/O contract (examples)
20
+ - List: `{ status: "ok", action: "list", tasks: [...] }`
21
+ - Add: `{ status: "ok", action: "add", task: { text, status, group } }`
22
+ - Fallback: `{ status: "fallback", error, fallback: <cached object> }`
23
+
24
+ ## Cross-model checklist
25
+ - Claude: concise instructions; avoid role tokens; keep outputs small.
26
+ - Gemini: explicit commands and minimal formatting.
27
+
28
+ ## Notes
29
+ - Node.js script expects fetch (Node ≥18). Use `node --experimental-fetch` on older runtimes.
30
+ - Tasks are stored via Graphiti MCP `add_task`/`list_tasks` (tool names referenced in script). Adjust if server differs.
31
+ - Folder `.agents/skills/tasks/` keeps this decoupled from model-specific bindings.