nex-level-code 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/dist/commands/doctor.d.ts +3 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +164 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/install.d.ts +3 -0
- package/dist/commands/install.d.ts.map +1 -0
- package/dist/commands/install.js +31 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/mcp.d.ts +3 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +56 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +142 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/uninstall.d.ts +3 -0
- package/dist/commands/uninstall.d.ts.map +1 -0
- package/dist/commands/uninstall.js +114 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/commands/update.d.ts +3 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +26 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/server.d.ts +12 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +270 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/registry/tools.d.ts +64 -0
- package/dist/registry/tools.d.ts.map +1 -0
- package/dist/registry/tools.js +212 -0
- package/dist/registry/tools.js.map +1 -0
- package/dist/services/install.d.ts +36 -0
- package/dist/services/install.d.ts.map +1 -0
- package/dist/services/install.js +371 -0
- package/dist/services/install.js.map +1 -0
- package/package.json +57 -0
- package/templates/hooks/dev-logger.js +252 -0
- package/templates/hooks/memory-check.js +64 -0
- package/templates/hooks/session-start.js +115 -0
- package/templates/rules/claude.md +27 -0
- package/templates/rules/cursor.md +27 -0
- package/templates/starters/MEMORY.md +23 -0
- package/templates/starters/session-handoff.md +19 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// NLC Development Logger — Installed by Nex Level Code (NLC)
|
|
3
|
+
// Fires on stop: reads latest exchange, asks a small LLM if a task was completed,
|
|
4
|
+
// logs to memory/YYYY-MM-DD.md.
|
|
5
|
+
// DO NOT EDIT — managed by NLC. Run `nlc update` to get latest version.
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
|
|
10
|
+
// --- API Key Resolution ---
|
|
11
|
+
function resolveApiKey() {
|
|
12
|
+
if (process.env.ANTHROPIC_API_KEY) return process.env.ANTHROPIC_API_KEY;
|
|
13
|
+
|
|
14
|
+
const home = process.env.USERPROFILE || process.env.HOME || '';
|
|
15
|
+
|
|
16
|
+
// Check common config locations
|
|
17
|
+
const candidates = [
|
|
18
|
+
path.join(home, '.memory-mcp', 'config.json'),
|
|
19
|
+
path.join(home, '.nlc', 'config.json'),
|
|
20
|
+
];
|
|
21
|
+
for (const p of candidates) {
|
|
22
|
+
if (fs.existsSync(p)) {
|
|
23
|
+
try {
|
|
24
|
+
const cfg = JSON.parse(fs.readFileSync(p, 'utf-8'));
|
|
25
|
+
if (cfg.apiKey) return cfg.apiKey;
|
|
26
|
+
} catch {}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Check file-based key storage
|
|
31
|
+
const keyFiles = [
|
|
32
|
+
path.join(home, '.config', 'anthropic', 'api_key'),
|
|
33
|
+
path.join(home, '.anthropic', 'api_key'),
|
|
34
|
+
];
|
|
35
|
+
for (const p of keyFiles) {
|
|
36
|
+
if (fs.existsSync(p)) return fs.readFileSync(p, 'utf-8').trim();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// --- LLM Call ---
|
|
43
|
+
async function callSmallModel(prompt, maxTokens = 256) {
|
|
44
|
+
const key = resolveApiKey();
|
|
45
|
+
if (!key) return null;
|
|
46
|
+
|
|
47
|
+
const response = await fetch('https://api.anthropic.com/v1/messages', {
|
|
48
|
+
method: 'POST',
|
|
49
|
+
headers: {
|
|
50
|
+
'Content-Type': 'application/json',
|
|
51
|
+
'x-api-key': key,
|
|
52
|
+
'anthropic-version': '2023-06-01',
|
|
53
|
+
},
|
|
54
|
+
body: JSON.stringify({
|
|
55
|
+
model: 'claude-haiku-4-5-20251001',
|
|
56
|
+
max_tokens: maxTokens,
|
|
57
|
+
messages: [{ role: 'user', content: prompt }],
|
|
58
|
+
}),
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
if (!response.ok) return null;
|
|
62
|
+
const data = await response.json();
|
|
63
|
+
return data.content?.[0]?.text || null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// --- Transcript Parsing ---
|
|
67
|
+
function getLatestExchange(transcriptPath, cursorLine) {
|
|
68
|
+
if (!fs.existsSync(transcriptPath)) return null;
|
|
69
|
+
|
|
70
|
+
const content = fs.readFileSync(transcriptPath, 'utf-8');
|
|
71
|
+
const lines = content.split('\n').filter(l => l.trim());
|
|
72
|
+
const newLines = lines.slice(cursorLine);
|
|
73
|
+
|
|
74
|
+
if (newLines.length === 0) return { text: '', hasToolUse: false, totalLines: lines.length };
|
|
75
|
+
|
|
76
|
+
const parts = [];
|
|
77
|
+
let hasToolUse = false;
|
|
78
|
+
|
|
79
|
+
for (const line of newLines) {
|
|
80
|
+
try {
|
|
81
|
+
const entry = JSON.parse(line);
|
|
82
|
+
if (entry.type === 'assistant') {
|
|
83
|
+
const msgContent = entry.message?.content;
|
|
84
|
+
if (typeof msgContent === 'string') {
|
|
85
|
+
parts.push(msgContent);
|
|
86
|
+
} else if (Array.isArray(msgContent)) {
|
|
87
|
+
for (const block of msgContent) {
|
|
88
|
+
if (block.type === 'text' && block.text) {
|
|
89
|
+
parts.push(block.text);
|
|
90
|
+
} else if (block.type === 'tool_use') {
|
|
91
|
+
hasToolUse = true;
|
|
92
|
+
const name = block.name || 'unknown';
|
|
93
|
+
const input = block.input || {};
|
|
94
|
+
if (name === 'Write' || name === 'Edit') {
|
|
95
|
+
parts.push(`[${name}: ${input.file_path || 'unknown file'}]`);
|
|
96
|
+
} else if (name === 'Bash') {
|
|
97
|
+
parts.push(`[Bash: ${(input.command || '').slice(0, 300)}]`);
|
|
98
|
+
} else {
|
|
99
|
+
parts.push(`[${name}: ${input.file_path || input.pattern || ''}]`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
} else if (entry.type === 'user') {
|
|
105
|
+
const msgContent = entry.message?.content;
|
|
106
|
+
const text = typeof msgContent === 'string'
|
|
107
|
+
? msgContent
|
|
108
|
+
: Array.isArray(msgContent)
|
|
109
|
+
? msgContent.filter(b => b.type === 'text').map(b => b.text).join(' ')
|
|
110
|
+
: '';
|
|
111
|
+
if (text) parts.push(`USER: ${text.slice(0, 500)}`);
|
|
112
|
+
}
|
|
113
|
+
} catch {}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return { text: parts.join('\n'), hasToolUse, totalLines: lines.length };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// --- Cursor (per-session progress tracking) ---
|
|
120
|
+
function getCursorPath(cwd) {
|
|
121
|
+
return path.join(cwd, '.memory', 'dev-cursor.json');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function getCursor(cwd, sessionId) {
|
|
125
|
+
const p = getCursorPath(cwd);
|
|
126
|
+
if (!fs.existsSync(p)) return 0;
|
|
127
|
+
try {
|
|
128
|
+
const data = JSON.parse(fs.readFileSync(p, 'utf-8'));
|
|
129
|
+
return data[sessionId] || 0;
|
|
130
|
+
} catch { return 0; }
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function setCursor(cwd, sessionId, line) {
|
|
134
|
+
const p = getCursorPath(cwd);
|
|
135
|
+
const dir = path.dirname(p);
|
|
136
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
137
|
+
|
|
138
|
+
let data = {};
|
|
139
|
+
if (fs.existsSync(p)) {
|
|
140
|
+
try { data = JSON.parse(fs.readFileSync(p, 'utf-8')); } catch {}
|
|
141
|
+
}
|
|
142
|
+
data[sessionId] = line;
|
|
143
|
+
fs.writeFileSync(p, JSON.stringify(data, null, 2));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// --- Memory Directory ---
|
|
147
|
+
function cwdToProjectKey(cwd) {
|
|
148
|
+
return cwd
|
|
149
|
+
.replace(/\\/g, '-')
|
|
150
|
+
.replace(/\//g, '-')
|
|
151
|
+
.replace(/:/g, '-')
|
|
152
|
+
.replace(/_/g, '-')
|
|
153
|
+
.replace(/^([a-z])/, (m) => m.toUpperCase());
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function getMemoryDir(cwd) {
|
|
157
|
+
const home = process.env.USERPROFILE || process.env.HOME || '';
|
|
158
|
+
const key = cwdToProjectKey(cwd);
|
|
159
|
+
const lowerKey = key.replace(/^([A-Z])/, (m) => m.toLowerCase());
|
|
160
|
+
|
|
161
|
+
const candidates = [
|
|
162
|
+
path.join(home, '.claude', 'projects', lowerKey, 'memory'),
|
|
163
|
+
path.join(home, '.claude', 'projects', key, 'memory'),
|
|
164
|
+
path.join(home, '.nlc', 'projects', lowerKey),
|
|
165
|
+
path.join(home, '.nlc', 'projects', key),
|
|
166
|
+
];
|
|
167
|
+
|
|
168
|
+
for (const p of candidates) {
|
|
169
|
+
if (fs.existsSync(p)) return p;
|
|
170
|
+
}
|
|
171
|
+
return path.join(home, '.nlc', 'projects', lowerKey);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// --- Development Extraction Prompt ---
|
|
175
|
+
function buildDevPrompt(exchange) {
|
|
176
|
+
return `You are a development logger. Analyze the following exchange between a user and an AI coding assistant. Determine if a meaningful task was COMPLETED (not just started or discussed).
|
|
177
|
+
|
|
178
|
+
A "development" is: a feature implemented, bug fixed, config changed, infrastructure deployed, file created/modified with purpose, tool/dependency installed, test written, document created, or script/automation built.
|
|
179
|
+
|
|
180
|
+
NOT a development: reading files, asking questions, explaining without acting, work in progress, minor acknowledgments, or planning without implementing.
|
|
181
|
+
|
|
182
|
+
If a development was completed, respond with ONLY 1-2 concise lines summarizing what was accomplished. Consolidate related steps. Start each line with an action verb. Be specific — include names, paths, or URLs where relevant.
|
|
183
|
+
|
|
184
|
+
If no development was completed, respond with exactly: NONE
|
|
185
|
+
|
|
186
|
+
--- EXCHANGE ---
|
|
187
|
+
${exchange.slice(0, 6000)}`;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// --- Date/Time ---
|
|
191
|
+
function getDateStr() { return new Date().toISOString().split('T')[0]; }
|
|
192
|
+
function getTimeStr() { return new Date().toTimeString().slice(0, 5); }
|
|
193
|
+
|
|
194
|
+
// --- Main ---
|
|
195
|
+
async function main() {
|
|
196
|
+
try {
|
|
197
|
+
let input = '';
|
|
198
|
+
await new Promise((resolve) => {
|
|
199
|
+
process.stdin.setEncoding('utf-8');
|
|
200
|
+
process.stdin.on('data', (chunk) => input += chunk);
|
|
201
|
+
process.stdin.on('end', resolve);
|
|
202
|
+
setTimeout(resolve, 2000);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
if (!input.trim()) return;
|
|
206
|
+
const hookData = JSON.parse(input);
|
|
207
|
+
const { session_id, transcript_path, cwd } = hookData;
|
|
208
|
+
if (!transcript_path || !cwd || !session_id) return;
|
|
209
|
+
|
|
210
|
+
const cursor = getCursor(cwd, session_id);
|
|
211
|
+
const result = getLatestExchange(transcript_path, cursor);
|
|
212
|
+
if (!result) return;
|
|
213
|
+
|
|
214
|
+
setCursor(cwd, session_id, result.totalLines);
|
|
215
|
+
|
|
216
|
+
// Pre-filter: skip trivially short responses with no tool usage
|
|
217
|
+
if (!result.hasToolUse && result.text.length < 100) return;
|
|
218
|
+
|
|
219
|
+
const prompt = buildDevPrompt(result.text);
|
|
220
|
+
const response = await callSmallModel(prompt);
|
|
221
|
+
if (!response || response.trim() === 'NONE' || response.trim().startsWith('NONE')) return;
|
|
222
|
+
|
|
223
|
+
// Log to memory directory
|
|
224
|
+
const memoryDir = getMemoryDir(cwd);
|
|
225
|
+
if (!fs.existsSync(memoryDir)) fs.mkdirSync(memoryDir, { recursive: true });
|
|
226
|
+
|
|
227
|
+
const dateStr = getDateStr();
|
|
228
|
+
const timeStr = getTimeStr();
|
|
229
|
+
const logFile = path.join(memoryDir, `${dateStr}.md`);
|
|
230
|
+
|
|
231
|
+
let existing = '';
|
|
232
|
+
if (fs.existsSync(logFile)) {
|
|
233
|
+
existing = fs.readFileSync(logFile, 'utf-8');
|
|
234
|
+
} else {
|
|
235
|
+
existing = `# Developments — ${dateStr}\n\n`;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const devLines = response.trim().split('\n')
|
|
239
|
+
.map(l => l.trim())
|
|
240
|
+
.filter(l => l && l !== 'NONE');
|
|
241
|
+
|
|
242
|
+
if (devLines.length === 0) return;
|
|
243
|
+
|
|
244
|
+
const entries = devLines.map(line => `- **${timeStr}** — ${line}`).join('\n');
|
|
245
|
+
fs.writeFileSync(logFile, existing + entries + '\n');
|
|
246
|
+
|
|
247
|
+
} catch {
|
|
248
|
+
// Silent failure — never disrupt the agent's work
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
main();
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// NLC Memory Check Hook — Installed by Nex Level Code (NLC)
|
|
2
|
+
// Fires on user prompt: warns if session-handoff.md is stale (>1 hour).
|
|
3
|
+
// DO NOT EDIT — managed by NLC. Run `nlc update` to get latest version.
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
|
|
8
|
+
function getHome() {
|
|
9
|
+
return process.env.USERPROFILE || process.env.HOME || '';
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function cwdToProjectKey(cwd) {
|
|
13
|
+
return cwd
|
|
14
|
+
.replace(/\\/g, '-')
|
|
15
|
+
.replace(/\//g, '-')
|
|
16
|
+
.replace(/:/g, '-')
|
|
17
|
+
.replace(/_/g, '-')
|
|
18
|
+
.replace(/^([a-z])/, (m) => m.toUpperCase());
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function findHandoff(cwd) {
|
|
22
|
+
const home = getHome();
|
|
23
|
+
const key = cwdToProjectKey(cwd);
|
|
24
|
+
const lowerKey = key.replace(/^([A-Z])/, (m) => m.toLowerCase());
|
|
25
|
+
|
|
26
|
+
const candidates = [
|
|
27
|
+
path.join(home, '.claude', 'projects', lowerKey, 'memory', 'session-handoff.md'),
|
|
28
|
+
path.join(home, '.claude', 'projects', key, 'memory', 'session-handoff.md'),
|
|
29
|
+
path.join(home, '.nlc', 'projects', lowerKey, 'session-handoff.md'),
|
|
30
|
+
path.join(home, '.nlc', 'projects', key, 'session-handoff.md'),
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
for (const p of candidates) {
|
|
34
|
+
if (fs.existsSync(p)) return p;
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let input = '';
|
|
40
|
+
process.stdin.setEncoding('utf8');
|
|
41
|
+
process.stdin.on('data', (chunk) => { input += chunk; });
|
|
42
|
+
process.stdin.on('end', () => {
|
|
43
|
+
try {
|
|
44
|
+
const hookData = JSON.parse(input);
|
|
45
|
+
const cwd = hookData.cwd || hookData.session_cwd || process.cwd();
|
|
46
|
+
const handoffPath = findHandoff(cwd);
|
|
47
|
+
|
|
48
|
+
if (!handoffPath) process.exit(0);
|
|
49
|
+
|
|
50
|
+
const stats = fs.statSync(handoffPath);
|
|
51
|
+
const ageMs = Date.now() - stats.mtimeMs;
|
|
52
|
+
const ageHours = ageMs / (1000 * 60 * 60);
|
|
53
|
+
|
|
54
|
+
if (ageHours > 1) {
|
|
55
|
+
const hours = Math.floor(ageHours);
|
|
56
|
+
console.log(
|
|
57
|
+
`[NLC MEMORY] session-handoff.md was last updated ${hours} hour${hours !== 1 ? 's' : ''} ago. ` +
|
|
58
|
+
`Update it with current session progress. Also update MEMORY.md if setup state has changed.`
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
} catch (e) {
|
|
62
|
+
process.exit(0);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// NLC Session Start Hook — Installed by Nex Level Code (NLC)
|
|
2
|
+
// Fires on session start: injects memory protocol + recent development logs.
|
|
3
|
+
// DO NOT EDIT — managed by NLC. Run `nlc update` to get latest version.
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
|
|
8
|
+
// --- NLC Config (set during install) ---
|
|
9
|
+
const NLC_TOOL = '{{TOOL_ID}}'; // e.g., 'claude', 'cursor'
|
|
10
|
+
|
|
11
|
+
// --- Path Resolution ---
|
|
12
|
+
function getHome() {
|
|
13
|
+
return process.env.USERPROFILE || process.env.HOME || '';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function cwdToProjectKey(cwd) {
|
|
17
|
+
return cwd
|
|
18
|
+
.replace(/\\/g, '-')
|
|
19
|
+
.replace(/\//g, '-')
|
|
20
|
+
.replace(/:/g, '-')
|
|
21
|
+
.replace(/_/g, '-')
|
|
22
|
+
.replace(/^([a-z])/, (m) => m.toUpperCase());
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getMemoryDir(cwd) {
|
|
26
|
+
const home = getHome();
|
|
27
|
+
const key = cwdToProjectKey(cwd);
|
|
28
|
+
const lowerKey = key.replace(/^([A-Z])/, (m) => m.toLowerCase());
|
|
29
|
+
|
|
30
|
+
// Try multiple paths (tools use different directory structures)
|
|
31
|
+
const candidates = [
|
|
32
|
+
path.join(home, '.claude', 'projects', lowerKey, 'memory'),
|
|
33
|
+
path.join(home, '.claude', 'projects', key, 'memory'),
|
|
34
|
+
path.join(home, '.nlc', 'projects', lowerKey),
|
|
35
|
+
path.join(home, '.nlc', 'projects', key),
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
for (const p of candidates) {
|
|
39
|
+
if (fs.existsSync(p)) return p;
|
|
40
|
+
}
|
|
41
|
+
// Default: NLC's own directory
|
|
42
|
+
return path.join(home, '.nlc', 'projects', lowerKey);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function findHandoff(cwd) {
|
|
46
|
+
const memoryDir = getMemoryDir(cwd);
|
|
47
|
+
const handoffPath = path.join(memoryDir, 'session-handoff.md');
|
|
48
|
+
if (fs.existsSync(handoffPath)) return handoffPath;
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function getDateStr(daysAgo = 0) {
|
|
53
|
+
const d = new Date();
|
|
54
|
+
d.setDate(d.getDate() - daysAgo);
|
|
55
|
+
return d.toISOString().split('T')[0];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function readDevLog(cwd, dateStr) {
|
|
59
|
+
const memoryDir = getMemoryDir(cwd);
|
|
60
|
+
const logPath = path.join(memoryDir, `${dateStr}.md`);
|
|
61
|
+
if (!fs.existsSync(logPath)) return null;
|
|
62
|
+
try {
|
|
63
|
+
const content = fs.readFileSync(logPath, 'utf-8').trim();
|
|
64
|
+
if (content.split('\n').length <= 2) return null;
|
|
65
|
+
return content;
|
|
66
|
+
} catch { return null; }
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// --- Main ---
|
|
70
|
+
let input = '';
|
|
71
|
+
process.stdin.setEncoding('utf8');
|
|
72
|
+
process.stdin.on('data', (chunk) => { input += chunk; });
|
|
73
|
+
process.stdin.on('end', () => {
|
|
74
|
+
try {
|
|
75
|
+
const hookData = JSON.parse(input);
|
|
76
|
+
const cwd = hookData.cwd || hookData.session_cwd || process.cwd();
|
|
77
|
+
|
|
78
|
+
const parts = [];
|
|
79
|
+
|
|
80
|
+
// Memory Protocol Reminder
|
|
81
|
+
const handoffPath = findHandoff(cwd);
|
|
82
|
+
if (handoffPath) {
|
|
83
|
+
const stats = fs.statSync(handoffPath);
|
|
84
|
+
const ageHours = (Date.now() - stats.mtimeMs) / (1000 * 60 * 60);
|
|
85
|
+
const staleNote = ageHours > 2
|
|
86
|
+
? ` WARNING: It was last updated ${Math.floor(ageHours)} hours ago and may be stale.`
|
|
87
|
+
: '';
|
|
88
|
+
|
|
89
|
+
parts.push(
|
|
90
|
+
`[NLC MEMORY PROTOCOL] This project uses session-handoff.md for cross-session context.${staleNote} ` +
|
|
91
|
+
`You MUST update session-handoff.md and MEMORY.md incrementally as you complete tasks — ` +
|
|
92
|
+
`do NOT wait until the end of the session. Context can be lost at any time.`
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Recent Development Logs
|
|
97
|
+
const today = getDateStr(0);
|
|
98
|
+
const yesterday = getDateStr(1);
|
|
99
|
+
const todayLog = readDevLog(cwd, today);
|
|
100
|
+
const yesterdayLog = readDevLog(cwd, yesterday);
|
|
101
|
+
|
|
102
|
+
if (yesterdayLog || todayLog) {
|
|
103
|
+
parts.push('');
|
|
104
|
+
parts.push('[NLC RECENT DEVELOPMENTS] Auto-logged task completions:');
|
|
105
|
+
if (yesterdayLog) { parts.push(''); parts.push(yesterdayLog); }
|
|
106
|
+
if (todayLog) { parts.push(''); parts.push(todayLog); }
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (parts.length > 0) {
|
|
110
|
+
console.log(parts.join('\n'));
|
|
111
|
+
}
|
|
112
|
+
} catch (e) {
|
|
113
|
+
process.exit(0);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Agent Rules — Installed by Nex Level Code (NLC)
|
|
2
|
+
|
|
3
|
+
## Memory Protocol (Non-Negotiable)
|
|
4
|
+
1. **Read session-handoff.md at the start of every session** — it contains cross-session context
|
|
5
|
+
2. **Update session-handoff.md incrementally as you work** — do NOT wait until the end
|
|
6
|
+
3. **Update MEMORY.md when setup state changes** — new tools, configs, environment changes
|
|
7
|
+
4. **Never lose context** — previous sessions have lost all context by failing to write to memory. This is the #1 problem NLC solves.
|
|
8
|
+
|
|
9
|
+
## Behavioral Rules
|
|
10
|
+
1. **Never ask for permission to READ anything** — files, URLs, documentation. Just read it.
|
|
11
|
+
2. **ALWAYS ask the user before EDIT or WRITE** — confirm in conversation before modifying files
|
|
12
|
+
3. **Log every user decision** — when the user makes a decision, note it in session-handoff.md
|
|
13
|
+
4. **End responses with a helpful question** — keep the conversation moving forward
|
|
14
|
+
|
|
15
|
+
## Workflow
|
|
16
|
+
- Follow the PREVC method for non-trivial tasks:
|
|
17
|
+
- **P**lanning → **R**eview → **E**xecution → **V**alidation → **C**onfirmation
|
|
18
|
+
- QUICK (bug fix): E → V
|
|
19
|
+
- SMALL (simple feature): P → E → V
|
|
20
|
+
- MEDIUM (standard feature): P → R → E → V
|
|
21
|
+
- LARGE (complex system): P → R → E → V → C
|
|
22
|
+
|
|
23
|
+
## Communication Style
|
|
24
|
+
- Be concise and direct
|
|
25
|
+
- Use plain language — avoid jargon unless the user uses it first
|
|
26
|
+
- When presenting options, clearly distinguish proper solutions from workarounds
|
|
27
|
+
- Never make confident assertions about things you're uncertain about
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Agent Rules — Installed by Nex Level Code (NLC)
|
|
2
|
+
|
|
3
|
+
## Memory Protocol (Non-Negotiable)
|
|
4
|
+
1. Read session-handoff.md at the start of every session — it contains cross-session context
|
|
5
|
+
2. Update session-handoff.md incrementally as you work — do NOT wait until the end
|
|
6
|
+
3. Update MEMORY.md when setup state changes — new tools, configs, environment changes
|
|
7
|
+
4. Never lose context — previous sessions have lost all context by failing to write to memory
|
|
8
|
+
|
|
9
|
+
## Behavioral Rules
|
|
10
|
+
1. Never ask for permission to READ anything — files, URLs, documentation. Just read it.
|
|
11
|
+
2. ALWAYS ask the user before EDIT or WRITE — confirm in conversation before modifying files
|
|
12
|
+
3. Log every user decision — when the user makes a decision, note it in session-handoff.md
|
|
13
|
+
4. End responses with a helpful question — keep the conversation moving forward
|
|
14
|
+
|
|
15
|
+
## Workflow
|
|
16
|
+
- Follow the PREVC method for non-trivial tasks:
|
|
17
|
+
- Planning → Review → Execution → Validation → Confirmation
|
|
18
|
+
- QUICK (bug fix): E → V
|
|
19
|
+
- SMALL (simple feature): P → E → V
|
|
20
|
+
- MEDIUM (standard feature): P → R → E → V
|
|
21
|
+
- LARGE (complex system): P → R → E → V → C
|
|
22
|
+
|
|
23
|
+
## Communication Style
|
|
24
|
+
- Be concise and direct
|
|
25
|
+
- Use plain language — avoid jargon unless the user uses it first
|
|
26
|
+
- When presenting options, clearly distinguish proper solutions from workarounds
|
|
27
|
+
- Never make confident assertions about things you're uncertain about
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Project Memory
|
|
2
|
+
|
|
3
|
+
> Managed by Nex Level Code (NLC). This file persists across sessions.
|
|
4
|
+
> Keep it concise — lines after 200 will be truncated in context.
|
|
5
|
+
|
|
6
|
+
## Project Overview
|
|
7
|
+
<!-- What is this project? Tech stack? Main directories? -->
|
|
8
|
+
|
|
9
|
+
## Key Documents
|
|
10
|
+
<!-- Important files the agent should read before making changes. -->
|
|
11
|
+
|
|
12
|
+
## User Requirements
|
|
13
|
+
<!-- Non-negotiable rules the user has established. -->
|
|
14
|
+
|
|
15
|
+
## User Preferences
|
|
16
|
+
<!-- How the user likes to work. Communication style. Tool preferences. -->
|
|
17
|
+
|
|
18
|
+
## Current Setup State
|
|
19
|
+
<!-- What's installed, configured, and running. Update as things change. -->
|
|
20
|
+
|
|
21
|
+
## Session Protocol
|
|
22
|
+
- **START**: Read `session-handoff.md` first
|
|
23
|
+
- **END**: Update `session-handoff.md` with what was done + what's next
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Session Handoff
|
|
2
|
+
|
|
3
|
+
> Updated by: [agent] | Last updated: [date]
|
|
4
|
+
> This file is your cross-session memory. Update it as you work — don't wait until the end.
|
|
5
|
+
|
|
6
|
+
## What's Working
|
|
7
|
+
<!-- List things that are confirmed working. Remove items that break. -->
|
|
8
|
+
|
|
9
|
+
## Known Issues
|
|
10
|
+
<!-- Active bugs, blockers, or things that need fixing. Remove when resolved. -->
|
|
11
|
+
|
|
12
|
+
## Key Decisions
|
|
13
|
+
<!-- Important decisions made by the user. Include reasoning. -->
|
|
14
|
+
|
|
15
|
+
## Current Focus
|
|
16
|
+
<!-- What the user is working on right now. What's next. -->
|
|
17
|
+
|
|
18
|
+
## Environment
|
|
19
|
+
<!-- OS, tools, versions, paths — anything the next session needs to know. -->
|