@tricknowtech/context 0.1.0 → 0.1.1
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/{chunk-DEH5MUFT.js → chunk-BWATZKYM.js} +86 -4
- package/dist/cli.cjs +93 -5
- package/dist/cli.js +10 -2
- package/dist/index.cjs +47 -4
- package/dist/index.js +1 -1
- package/package.json +3 -3
|
@@ -228,12 +228,41 @@ var PROJECT_CONTEXT_GLOBS = [
|
|
|
228
228
|
".cursorrules",
|
|
229
229
|
".github/copilot-instructions.md",
|
|
230
230
|
".claude/settings.json",
|
|
231
|
+
// `.local.json` variants are gitignored by default, so nothing else carries
|
|
232
|
+
// them — which makes them exactly the kind of file this tool exists for.
|
|
233
|
+
".claude/settings.local.json",
|
|
231
234
|
".claude/memory/",
|
|
232
235
|
".claude/plans/",
|
|
233
236
|
".claude/commands/",
|
|
234
237
|
".claude/agents/",
|
|
235
238
|
".claude/skills/"
|
|
236
239
|
];
|
|
240
|
+
function planStem(fileName) {
|
|
241
|
+
return fileName.replace(/\.md$/, "").replace(/-agent-[0-9a-f]+$/i, "");
|
|
242
|
+
}
|
|
243
|
+
function collectPlans(plansDir, projectRoot, exclude) {
|
|
244
|
+
const all = walk(plansDir, { exclude });
|
|
245
|
+
if (all.length === 0) return [];
|
|
246
|
+
const projectName = path3.basename(projectRoot);
|
|
247
|
+
const related = /* @__PURE__ */ new Set();
|
|
248
|
+
const stems = /* @__PURE__ */ new Set();
|
|
249
|
+
for (const abs of all) {
|
|
250
|
+
let text = "";
|
|
251
|
+
try {
|
|
252
|
+
text = fs3.readFileSync(abs, "utf8");
|
|
253
|
+
} catch {
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
if (text.includes(projectRoot) || text.includes(projectName)) {
|
|
257
|
+
related.add(abs);
|
|
258
|
+
stems.add(planStem(path3.basename(abs)));
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
for (const abs of all) {
|
|
262
|
+
if (stems.has(planStem(path3.basename(abs)))) related.add(abs);
|
|
263
|
+
}
|
|
264
|
+
return [...related];
|
|
265
|
+
}
|
|
237
266
|
function push(out, sourcePath, storePath, tier, sourceRoot, ctx) {
|
|
238
267
|
let size = 0;
|
|
239
268
|
try {
|
|
@@ -268,10 +297,24 @@ function collect(projectRoot, cfg, tiers) {
|
|
|
268
297
|
}
|
|
269
298
|
push(files, abs, `project/${rel}`, "core", "project", ctx);
|
|
270
299
|
}
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
300
|
+
const projectsDir = path3.join(userClaude, "projects");
|
|
301
|
+
let projectKeys = [];
|
|
302
|
+
try {
|
|
303
|
+
projectKeys = fs3.readdirSync(projectsDir, { withFileTypes: true }).filter((d) => d.isDirectory() && (d.name === key || d.name.startsWith(key + "-"))).map((d) => d.name);
|
|
304
|
+
} catch {
|
|
305
|
+
projectKeys = [];
|
|
306
|
+
}
|
|
307
|
+
for (const pk of projectKeys) {
|
|
308
|
+
const memoryDir = path3.join(projectsDir, pk, "memory");
|
|
309
|
+
for (const abs of walk(memoryDir, { exclude })) {
|
|
310
|
+
const rel = toPosix(path3.relative(memoryDir, abs));
|
|
311
|
+
const storePath = pk === key ? `memory/${rel}` : `memory-sub/${pk.slice(key.length + 1)}/${rel}`;
|
|
312
|
+
push(files, abs, storePath, "core", "user", ctx);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
for (const abs of collectPlans(path3.join(userClaude, "plans"), projectRoot, exclude)) {
|
|
316
|
+
const rel = toPosix(path3.relative(path3.join(userClaude, "plans"), abs));
|
|
317
|
+
push(files, abs, `plans/${rel}`, "core", "user", ctx);
|
|
275
318
|
}
|
|
276
319
|
const skillsDir = path3.join(userClaude, "skills");
|
|
277
320
|
for (const abs of walk(skillsDir, { exclude })) {
|
|
@@ -307,6 +350,44 @@ function collect(projectRoot, cfg, tiers) {
|
|
|
307
350
|
}
|
|
308
351
|
return { files, skippedTracked, ctx };
|
|
309
352
|
}
|
|
353
|
+
function describeExcluded(projectRoot, tiers) {
|
|
354
|
+
const userClaude = userClaudeDir();
|
|
355
|
+
const key = cwdKey(projectRoot);
|
|
356
|
+
const out = [];
|
|
357
|
+
const measure = (dir, filter) => {
|
|
358
|
+
let files = 0;
|
|
359
|
+
let bytes = 0;
|
|
360
|
+
for (const abs of walk(dir, { exclude: [] })) {
|
|
361
|
+
if (filter && !filter(abs)) continue;
|
|
362
|
+
files++;
|
|
363
|
+
try {
|
|
364
|
+
bytes += fs3.statSync(abs).size;
|
|
365
|
+
} catch {
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return { files, bytes };
|
|
369
|
+
};
|
|
370
|
+
if (!tiers.includes("transcripts")) {
|
|
371
|
+
const projDir = path3.join(userClaude, "projects", key);
|
|
372
|
+
const m = measure(projDir, (p) => !p.includes(`${path3.sep}memory${path3.sep}`));
|
|
373
|
+
if (m.files > 0) {
|
|
374
|
+
out.push({
|
|
375
|
+
label: "session transcripts",
|
|
376
|
+
...m,
|
|
377
|
+
reason: "cloud-only \u2014 append-only logs this large would permanently bloat the repo"
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
for (const [dir, label, reason] of [
|
|
382
|
+
["uploads", "pasted files/images", "session-scoped binaries; regenerate rather than sync"],
|
|
383
|
+
["file-history", "edit-undo snapshots", "transient local undo state, not portable context"],
|
|
384
|
+
["tasks", "task outputs", "session-scoped tool output"]
|
|
385
|
+
]) {
|
|
386
|
+
const m = measure(path3.join(userClaude, dir));
|
|
387
|
+
if (m.files > 0) out.push({ label, ...m, reason });
|
|
388
|
+
}
|
|
389
|
+
return out.filter((g) => g.bytes > 0);
|
|
390
|
+
}
|
|
310
391
|
function summarize(files) {
|
|
311
392
|
const empty = { count: 0, bytes: 0 };
|
|
312
393
|
const out = {
|
|
@@ -606,6 +687,7 @@ export {
|
|
|
606
687
|
loadConfig,
|
|
607
688
|
saveConfig,
|
|
608
689
|
collect,
|
|
690
|
+
describeExcluded,
|
|
609
691
|
summarize,
|
|
610
692
|
SLASH_COMMAND_PATH,
|
|
611
693
|
SLASH_COMMAND_BODY,
|
package/dist/cli.cjs
CHANGED
|
@@ -273,12 +273,41 @@ var PROJECT_CONTEXT_GLOBS = [
|
|
|
273
273
|
".cursorrules",
|
|
274
274
|
".github/copilot-instructions.md",
|
|
275
275
|
".claude/settings.json",
|
|
276
|
+
// `.local.json` variants are gitignored by default, so nothing else carries
|
|
277
|
+
// them — which makes them exactly the kind of file this tool exists for.
|
|
278
|
+
".claude/settings.local.json",
|
|
276
279
|
".claude/memory/",
|
|
277
280
|
".claude/plans/",
|
|
278
281
|
".claude/commands/",
|
|
279
282
|
".claude/agents/",
|
|
280
283
|
".claude/skills/"
|
|
281
284
|
];
|
|
285
|
+
function planStem(fileName) {
|
|
286
|
+
return fileName.replace(/\.md$/, "").replace(/-agent-[0-9a-f]+$/i, "");
|
|
287
|
+
}
|
|
288
|
+
function collectPlans(plansDir, projectRoot, exclude) {
|
|
289
|
+
const all = walk(plansDir, { exclude });
|
|
290
|
+
if (all.length === 0) return [];
|
|
291
|
+
const projectName = import_node_path3.default.basename(projectRoot);
|
|
292
|
+
const related = /* @__PURE__ */ new Set();
|
|
293
|
+
const stems = /* @__PURE__ */ new Set();
|
|
294
|
+
for (const abs of all) {
|
|
295
|
+
let text = "";
|
|
296
|
+
try {
|
|
297
|
+
text = import_node_fs3.default.readFileSync(abs, "utf8");
|
|
298
|
+
} catch {
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
if (text.includes(projectRoot) || text.includes(projectName)) {
|
|
302
|
+
related.add(abs);
|
|
303
|
+
stems.add(planStem(import_node_path3.default.basename(abs)));
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
for (const abs of all) {
|
|
307
|
+
if (stems.has(planStem(import_node_path3.default.basename(abs)))) related.add(abs);
|
|
308
|
+
}
|
|
309
|
+
return [...related];
|
|
310
|
+
}
|
|
282
311
|
function push(out2, sourcePath, storePath, tier, sourceRoot, ctx) {
|
|
283
312
|
let size = 0;
|
|
284
313
|
try {
|
|
@@ -313,10 +342,24 @@ function collect(projectRoot, cfg, tiers) {
|
|
|
313
342
|
}
|
|
314
343
|
push(files, abs, `project/${rel}`, "core", "project", ctx);
|
|
315
344
|
}
|
|
316
|
-
const
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
345
|
+
const projectsDir = import_node_path3.default.join(userClaude, "projects");
|
|
346
|
+
let projectKeys = [];
|
|
347
|
+
try {
|
|
348
|
+
projectKeys = import_node_fs3.default.readdirSync(projectsDir, { withFileTypes: true }).filter((d) => d.isDirectory() && (d.name === key || d.name.startsWith(key + "-"))).map((d) => d.name);
|
|
349
|
+
} catch {
|
|
350
|
+
projectKeys = [];
|
|
351
|
+
}
|
|
352
|
+
for (const pk of projectKeys) {
|
|
353
|
+
const memoryDir = import_node_path3.default.join(projectsDir, pk, "memory");
|
|
354
|
+
for (const abs of walk(memoryDir, { exclude })) {
|
|
355
|
+
const rel = toPosix(import_node_path3.default.relative(memoryDir, abs));
|
|
356
|
+
const storePath = pk === key ? `memory/${rel}` : `memory-sub/${pk.slice(key.length + 1)}/${rel}`;
|
|
357
|
+
push(files, abs, storePath, "core", "user", ctx);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
for (const abs of collectPlans(import_node_path3.default.join(userClaude, "plans"), projectRoot, exclude)) {
|
|
361
|
+
const rel = toPosix(import_node_path3.default.relative(import_node_path3.default.join(userClaude, "plans"), abs));
|
|
362
|
+
push(files, abs, `plans/${rel}`, "core", "user", ctx);
|
|
320
363
|
}
|
|
321
364
|
const skillsDir = import_node_path3.default.join(userClaude, "skills");
|
|
322
365
|
for (const abs of walk(skillsDir, { exclude })) {
|
|
@@ -352,6 +395,44 @@ function collect(projectRoot, cfg, tiers) {
|
|
|
352
395
|
}
|
|
353
396
|
return { files, skippedTracked, ctx };
|
|
354
397
|
}
|
|
398
|
+
function describeExcluded(projectRoot, tiers) {
|
|
399
|
+
const userClaude = userClaudeDir();
|
|
400
|
+
const key = cwdKey(projectRoot);
|
|
401
|
+
const out2 = [];
|
|
402
|
+
const measure = (dir, filter) => {
|
|
403
|
+
let files = 0;
|
|
404
|
+
let bytes = 0;
|
|
405
|
+
for (const abs of walk(dir, { exclude: [] })) {
|
|
406
|
+
if (filter && !filter(abs)) continue;
|
|
407
|
+
files++;
|
|
408
|
+
try {
|
|
409
|
+
bytes += import_node_fs3.default.statSync(abs).size;
|
|
410
|
+
} catch {
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return { files, bytes };
|
|
414
|
+
};
|
|
415
|
+
if (!tiers.includes("transcripts")) {
|
|
416
|
+
const projDir = import_node_path3.default.join(userClaude, "projects", key);
|
|
417
|
+
const m = measure(projDir, (p) => !p.includes(`${import_node_path3.default.sep}memory${import_node_path3.default.sep}`));
|
|
418
|
+
if (m.files > 0) {
|
|
419
|
+
out2.push({
|
|
420
|
+
label: "session transcripts",
|
|
421
|
+
...m,
|
|
422
|
+
reason: "cloud-only \u2014 append-only logs this large would permanently bloat the repo"
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
for (const [dir, label, reason] of [
|
|
427
|
+
["uploads", "pasted files/images", "session-scoped binaries; regenerate rather than sync"],
|
|
428
|
+
["file-history", "edit-undo snapshots", "transient local undo state, not portable context"],
|
|
429
|
+
["tasks", "task outputs", "session-scoped tool output"]
|
|
430
|
+
]) {
|
|
431
|
+
const m = measure(import_node_path3.default.join(userClaude, dir));
|
|
432
|
+
if (m.files > 0) out2.push({ label, ...m, reason });
|
|
433
|
+
}
|
|
434
|
+
return out2.filter((g) => g.bytes > 0);
|
|
435
|
+
}
|
|
355
436
|
function summarize(files) {
|
|
356
437
|
const empty = { count: 0, bytes: 0 };
|
|
357
438
|
const out2 = {
|
|
@@ -735,6 +816,13 @@ function cmdPush(opts = {}) {
|
|
|
735
816
|
if (skippedTracked.length > 0) {
|
|
736
817
|
lines.push("", `${skippedTracked.length} project files skipped \u2014 git already tracks them.`);
|
|
737
818
|
}
|
|
819
|
+
const excluded = describeExcluded(root, tiers);
|
|
820
|
+
if (excluded.length > 0) {
|
|
821
|
+
lines.push("", "Not included (by design):");
|
|
822
|
+
for (const g of excluded) {
|
|
823
|
+
lines.push(` ${g.label.padEnd(22)} ${formatBytes(g.bytes).padStart(9)} ${g.reason}`);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
738
826
|
if (!opts.dryRun) {
|
|
739
827
|
lines.push("", "Commit .contextsync/ to carry this context with the repo.");
|
|
740
828
|
}
|
|
@@ -854,7 +942,7 @@ function parseArgs(argv) {
|
|
|
854
942
|
function run(argv) {
|
|
855
943
|
const { command, flags } = parseArgs(argv);
|
|
856
944
|
if (flags.has("h") || flags.has("help")) return { code: 0, lines: [USAGE] };
|
|
857
|
-
if (flags.has("v") || flags.has("version")) return { code: 0, lines: ["0.1.
|
|
945
|
+
if (flags.has("v") || flags.has("version")) return { code: 0, lines: ["0.1.1"] };
|
|
858
946
|
switch (command) {
|
|
859
947
|
case "init":
|
|
860
948
|
return cmdInit({ artifacts: flags.has("artifacts"), force: flags.has("force") });
|
package/dist/cli.js
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
configPath,
|
|
8
8
|
cwdKey,
|
|
9
9
|
defaultConfig,
|
|
10
|
+
describeExcluded,
|
|
10
11
|
ensureGitignoreEntries,
|
|
11
12
|
findProjectRoot,
|
|
12
13
|
formatBytes,
|
|
@@ -19,7 +20,7 @@ import {
|
|
|
19
20
|
storeDir,
|
|
20
21
|
summarize,
|
|
21
22
|
userClaudeDir
|
|
22
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-BWATZKYM.js";
|
|
23
24
|
|
|
24
25
|
// src/commands.ts
|
|
25
26
|
import fs from "fs";
|
|
@@ -129,6 +130,13 @@ function cmdPush(opts = {}) {
|
|
|
129
130
|
if (skippedTracked.length > 0) {
|
|
130
131
|
lines.push("", `${skippedTracked.length} project files skipped \u2014 git already tracks them.`);
|
|
131
132
|
}
|
|
133
|
+
const excluded = describeExcluded(root, tiers);
|
|
134
|
+
if (excluded.length > 0) {
|
|
135
|
+
lines.push("", "Not included (by design):");
|
|
136
|
+
for (const g of excluded) {
|
|
137
|
+
lines.push(` ${g.label.padEnd(22)} ${formatBytes(g.bytes).padStart(9)} ${g.reason}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
132
140
|
if (!opts.dryRun) {
|
|
133
141
|
lines.push("", "Commit .contextsync/ to carry this context with the repo.");
|
|
134
142
|
}
|
|
@@ -248,7 +256,7 @@ function parseArgs(argv) {
|
|
|
248
256
|
function run(argv) {
|
|
249
257
|
const { command, flags } = parseArgs(argv);
|
|
250
258
|
if (flags.has("h") || flags.has("help")) return { code: 0, lines: [USAGE] };
|
|
251
|
-
if (flags.has("v") || flags.has("version")) return { code: 0, lines: ["0.1.
|
|
259
|
+
if (flags.has("v") || flags.has("version")) return { code: 0, lines: ["0.1.1"] };
|
|
252
260
|
switch (command) {
|
|
253
261
|
case "init":
|
|
254
262
|
return cmdInit({ artifacts: flags.has("artifacts"), force: flags.has("force") });
|
package/dist/index.cjs
CHANGED
|
@@ -299,12 +299,41 @@ var PROJECT_CONTEXT_GLOBS = [
|
|
|
299
299
|
".cursorrules",
|
|
300
300
|
".github/copilot-instructions.md",
|
|
301
301
|
".claude/settings.json",
|
|
302
|
+
// `.local.json` variants are gitignored by default, so nothing else carries
|
|
303
|
+
// them — which makes them exactly the kind of file this tool exists for.
|
|
304
|
+
".claude/settings.local.json",
|
|
302
305
|
".claude/memory/",
|
|
303
306
|
".claude/plans/",
|
|
304
307
|
".claude/commands/",
|
|
305
308
|
".claude/agents/",
|
|
306
309
|
".claude/skills/"
|
|
307
310
|
];
|
|
311
|
+
function planStem(fileName) {
|
|
312
|
+
return fileName.replace(/\.md$/, "").replace(/-agent-[0-9a-f]+$/i, "");
|
|
313
|
+
}
|
|
314
|
+
function collectPlans(plansDir, projectRoot, exclude) {
|
|
315
|
+
const all = walk(plansDir, { exclude });
|
|
316
|
+
if (all.length === 0) return [];
|
|
317
|
+
const projectName = import_node_path3.default.basename(projectRoot);
|
|
318
|
+
const related = /* @__PURE__ */ new Set();
|
|
319
|
+
const stems = /* @__PURE__ */ new Set();
|
|
320
|
+
for (const abs of all) {
|
|
321
|
+
let text = "";
|
|
322
|
+
try {
|
|
323
|
+
text = import_node_fs3.default.readFileSync(abs, "utf8");
|
|
324
|
+
} catch {
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
if (text.includes(projectRoot) || text.includes(projectName)) {
|
|
328
|
+
related.add(abs);
|
|
329
|
+
stems.add(planStem(import_node_path3.default.basename(abs)));
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
for (const abs of all) {
|
|
333
|
+
if (stems.has(planStem(import_node_path3.default.basename(abs)))) related.add(abs);
|
|
334
|
+
}
|
|
335
|
+
return [...related];
|
|
336
|
+
}
|
|
308
337
|
function push(out, sourcePath, storePath, tier, sourceRoot, ctx) {
|
|
309
338
|
let size = 0;
|
|
310
339
|
try {
|
|
@@ -339,10 +368,24 @@ function collect(projectRoot, cfg, tiers) {
|
|
|
339
368
|
}
|
|
340
369
|
push(files, abs, `project/${rel}`, "core", "project", ctx);
|
|
341
370
|
}
|
|
342
|
-
const
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
371
|
+
const projectsDir = import_node_path3.default.join(userClaude, "projects");
|
|
372
|
+
let projectKeys = [];
|
|
373
|
+
try {
|
|
374
|
+
projectKeys = import_node_fs3.default.readdirSync(projectsDir, { withFileTypes: true }).filter((d) => d.isDirectory() && (d.name === key || d.name.startsWith(key + "-"))).map((d) => d.name);
|
|
375
|
+
} catch {
|
|
376
|
+
projectKeys = [];
|
|
377
|
+
}
|
|
378
|
+
for (const pk of projectKeys) {
|
|
379
|
+
const memoryDir = import_node_path3.default.join(projectsDir, pk, "memory");
|
|
380
|
+
for (const abs of walk(memoryDir, { exclude })) {
|
|
381
|
+
const rel = toPosix(import_node_path3.default.relative(memoryDir, abs));
|
|
382
|
+
const storePath = pk === key ? `memory/${rel}` : `memory-sub/${pk.slice(key.length + 1)}/${rel}`;
|
|
383
|
+
push(files, abs, storePath, "core", "user", ctx);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
for (const abs of collectPlans(import_node_path3.default.join(userClaude, "plans"), projectRoot, exclude)) {
|
|
387
|
+
const rel = toPosix(import_node_path3.default.relative(import_node_path3.default.join(userClaude, "plans"), abs));
|
|
388
|
+
push(files, abs, `plans/${rel}`, "core", "user", ctx);
|
|
346
389
|
}
|
|
347
390
|
const skillsDir = import_node_path3.default.join(userClaude, "skills");
|
|
348
391
|
for (const abs of walk(skillsDir, { exclude })) {
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tricknowtech/context",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Carry a project's LLM context — memory, skills, instructions and session handoff — between machines. Local-first, commit it to your repo.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"bin": {
|
|
17
|
-
"ctx": "
|
|
18
|
-
"tricknowtech-context": "
|
|
17
|
+
"ctx": "dist/cli.js",
|
|
18
|
+
"tricknowtech-context": "dist/cli.js"
|
|
19
19
|
},
|
|
20
20
|
"files": [
|
|
21
21
|
"dist"
|