@ksm0709/context 0.1.0-next.1 → 0.2.0-next.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/cli/index.js +44 -21
- package/dist/index.js +62 -26
- package/dist/omc/session-start-hook.js +64 -8
- package/dist/omx/index.mjs +106 -48
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
// @bun
|
|
3
3
|
|
|
4
4
|
// src/cli/commands/update.ts
|
|
5
|
-
import { resolve as resolve3, join as
|
|
5
|
+
import { resolve as resolve3, join as join9 } from "path";
|
|
6
6
|
import { existsSync as existsSync9 } from "fs";
|
|
7
|
-
import { homedir as
|
|
7
|
+
import { homedir as homedir5 } from "os";
|
|
8
8
|
|
|
9
9
|
// src/lib/scaffold.ts
|
|
10
10
|
import { existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
@@ -27,7 +27,7 @@ function resolveContextDir(projectDir) {
|
|
|
27
27
|
// package.json
|
|
28
28
|
var package_default = {
|
|
29
29
|
name: "@ksm0709/context",
|
|
30
|
-
version: "0.
|
|
30
|
+
version: "0.2.0-next.1",
|
|
31
31
|
author: {
|
|
32
32
|
name: "TaehoKang",
|
|
33
33
|
email: "ksm07091@gmail.com"
|
|
@@ -451,7 +451,7 @@ function writeVersion(contextDir, version) {
|
|
|
451
451
|
}
|
|
452
452
|
|
|
453
453
|
// src/cli/commands/install.ts
|
|
454
|
-
import { join as
|
|
454
|
+
import { join as join8, resolve as resolve2, dirname as dirname5 } from "path";
|
|
455
455
|
import { existsSync as existsSync8, mkdirSync as mkdirSync5, copyFileSync } from "fs";
|
|
456
456
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
457
457
|
import { createRequire as createRequire2 } from "module";
|
|
@@ -611,6 +611,23 @@ function injectIntoAgentsMd(agentsMdPath, content) {
|
|
|
611
611
|
writeFileAtomically(agentsMdPath, nextContent);
|
|
612
612
|
}
|
|
613
613
|
|
|
614
|
+
// src/shared/global-instructions.ts
|
|
615
|
+
import { homedir as homedir2 } from "os";
|
|
616
|
+
import { join as join5 } from "path";
|
|
617
|
+
function getGlobalInstructionPath(tool) {
|
|
618
|
+
const home = homedir2();
|
|
619
|
+
switch (tool) {
|
|
620
|
+
case "claude":
|
|
621
|
+
return join5(home, ".claude", "CLAUDE.md");
|
|
622
|
+
case "codex":
|
|
623
|
+
return join5(home, ".codex", "instructions.md");
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
function injectIntoGlobalInstructions(tool, content) {
|
|
627
|
+
const path = getGlobalInstructionPath(tool);
|
|
628
|
+
injectIntoAgentsMd(path, content);
|
|
629
|
+
}
|
|
630
|
+
|
|
614
631
|
// src/shared/knowledge-context.ts
|
|
615
632
|
var STATIC_KNOWLEDGE_CONTEXT = `## Knowledge Context
|
|
616
633
|
|
|
@@ -653,10 +670,10 @@ var STATIC_KNOWLEDGE_CONTEXT = `## Knowledge Context
|
|
|
653
670
|
|
|
654
671
|
// src/shared/codex-settings.ts
|
|
655
672
|
import { existsSync as existsSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
656
|
-
import { homedir as
|
|
657
|
-
import { isAbsolute, join as
|
|
673
|
+
import { homedir as homedir3 } from "os";
|
|
674
|
+
import { isAbsolute, join as join6 } from "path";
|
|
658
675
|
var STALE_MOCK_MCP_SERVER_NAME = "mock-mcp";
|
|
659
|
-
var codexConfigPath =
|
|
676
|
+
var codexConfigPath = join6(homedir3(), ".codex", "config.toml");
|
|
660
677
|
function findMcpServerBlockRange(lines, serverName) {
|
|
661
678
|
const header = `[mcp_servers.${serverName}]`;
|
|
662
679
|
const start = lines.findIndex((line) => line.trim() === header);
|
|
@@ -706,8 +723,8 @@ function pruneStaleMockMcpServer() {
|
|
|
706
723
|
|
|
707
724
|
// src/shared/claude-settings.ts
|
|
708
725
|
import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync5, renameSync as renameSync2, mkdirSync as mkdirSync4 } from "fs";
|
|
709
|
-
import { dirname as dirname4, join as
|
|
710
|
-
import { homedir as
|
|
726
|
+
import { dirname as dirname4, join as join7 } from "path";
|
|
727
|
+
import { homedir as homedir4 } from "os";
|
|
711
728
|
|
|
712
729
|
// node_modules/jsonc-parser/lib/esm/impl/scanner.js
|
|
713
730
|
function createScanner(text, ignoreTrivia = false) {
|
|
@@ -2035,7 +2052,7 @@ function applyEdits(text, edits) {
|
|
|
2035
2052
|
// src/shared/claude-settings.ts
|
|
2036
2053
|
var CONTEXT_MCP_SERVER_NAME = "context-mcp";
|
|
2037
2054
|
var LEGACY_CONTEXT_MCP_SERVER_NAME = "context_mcp";
|
|
2038
|
-
var settingsPath =
|
|
2055
|
+
var settingsPath = join7(homedir4(), ".claude", "settings.json");
|
|
2039
2056
|
function readClaudeSettings() {
|
|
2040
2057
|
if (!existsSync7(settingsPath)) {
|
|
2041
2058
|
return {};
|
|
@@ -2145,7 +2162,7 @@ function resolveOmxSource() {
|
|
|
2145
2162
|
try {
|
|
2146
2163
|
const cliDir = dirname5(fileURLToPath2(import.meta.url));
|
|
2147
2164
|
const pkgRoot = resolve2(cliDir, "..", "..");
|
|
2148
|
-
const source =
|
|
2165
|
+
const source = join8(pkgRoot, "dist", "omx", "index.mjs");
|
|
2149
2166
|
if (existsSync8(source))
|
|
2150
2167
|
return source;
|
|
2151
2168
|
} catch {}
|
|
@@ -2163,9 +2180,9 @@ function installOmx(projectDir, sourcePath) {
|
|
|
2163
2180
|
process.exit(1);
|
|
2164
2181
|
return;
|
|
2165
2182
|
}
|
|
2166
|
-
const targetDir =
|
|
2183
|
+
const targetDir = join8(projectDir, ".omx", "hooks");
|
|
2167
2184
|
mkdirSync5(targetDir, { recursive: true });
|
|
2168
|
-
copyFileSync(sourcePath,
|
|
2185
|
+
copyFileSync(sourcePath, join8(targetDir, "context.mjs"));
|
|
2169
2186
|
process.stdout.write(`Installed context plugin to .omx/hooks/context.mjs
|
|
2170
2187
|
`);
|
|
2171
2188
|
if (ensureMcpRegistered()) {
|
|
@@ -2176,16 +2193,19 @@ function installOmx(projectDir, sourcePath) {
|
|
|
2176
2193
|
process.stdout.write(`Removed stale mock-mcp from ~/.codex/config.toml because its target file is missing
|
|
2177
2194
|
`);
|
|
2178
2195
|
}
|
|
2196
|
+
injectIntoGlobalInstructions("codex", STATIC_KNOWLEDGE_CONTEXT);
|
|
2197
|
+
process.stdout.write(`Injected knowledge context into ~/.codex/instructions.md
|
|
2198
|
+
`);
|
|
2179
2199
|
}
|
|
2180
2200
|
function installOmc(projectDir) {
|
|
2181
2201
|
scaffoldIfNeeded(projectDir);
|
|
2182
|
-
injectIntoAgentsMd(
|
|
2202
|
+
injectIntoAgentsMd(join8(projectDir, "AGENTS.md"), STATIC_KNOWLEDGE_CONTEXT);
|
|
2183
2203
|
let bunPath = "bun";
|
|
2184
2204
|
try {
|
|
2185
2205
|
bunPath = execSync2("which bun", { encoding: "utf-8" }).trim();
|
|
2186
2206
|
} catch {}
|
|
2187
2207
|
const mcpPath = resolveMcpPath();
|
|
2188
|
-
const hookBasePath =
|
|
2208
|
+
const hookBasePath = join8(dirname5(mcpPath), "omc") + "/";
|
|
2189
2209
|
removeMcpServer("context_mcp");
|
|
2190
2210
|
removeMcpServer("context-mcp");
|
|
2191
2211
|
try {
|
|
@@ -2223,6 +2243,9 @@ function installOmc(projectDir) {
|
|
|
2223
2243
|
}
|
|
2224
2244
|
]
|
|
2225
2245
|
});
|
|
2246
|
+
injectIntoGlobalInstructions("claude", STATIC_KNOWLEDGE_CONTEXT);
|
|
2247
|
+
process.stdout.write(`Injected knowledge context into ~/.claude/CLAUDE.md
|
|
2248
|
+
`);
|
|
2226
2249
|
process.stdout.write(`Successfully installed context (omc) plugin.
|
|
2227
2250
|
`);
|
|
2228
2251
|
}
|
|
@@ -2287,7 +2310,7 @@ function runUpdate(args) {
|
|
|
2287
2310
|
}
|
|
2288
2311
|
}
|
|
2289
2312
|
function isOmxInstalled(projectDir) {
|
|
2290
|
-
return existsSync9(
|
|
2313
|
+
return existsSync9(join9(projectDir, ".omx", "hooks", "context.mjs"));
|
|
2291
2314
|
}
|
|
2292
2315
|
function isOmcInstalled() {
|
|
2293
2316
|
try {
|
|
@@ -2360,7 +2383,7 @@ function detectPackageManager() {
|
|
|
2360
2383
|
}
|
|
2361
2384
|
function detectGlobalInstalls() {
|
|
2362
2385
|
const installs = [];
|
|
2363
|
-
const bunGlobalBin =
|
|
2386
|
+
const bunGlobalBin = join9(homedir5(), ".bun", "bin", "context");
|
|
2364
2387
|
if (existsSync9(bunGlobalBin)) {
|
|
2365
2388
|
installs.push({ pm: "bun", label: "bun global", installCmd: ["bun", "install", "-g"] });
|
|
2366
2389
|
}
|
|
@@ -2414,7 +2437,7 @@ function runUpdatePlugin(version) {
|
|
|
2414
2437
|
}
|
|
2415
2438
|
|
|
2416
2439
|
// src/cli/commands/migrate.ts
|
|
2417
|
-
import { resolve as resolve4, join as
|
|
2440
|
+
import { resolve as resolve4, join as join10 } from "path";
|
|
2418
2441
|
import { existsSync as existsSync10, cpSync, rmSync, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "fs";
|
|
2419
2442
|
var LEGACY_CONTEXT_DIR = ".opencode/context";
|
|
2420
2443
|
var NEW_CONTEXT_DIR = ".context";
|
|
@@ -2422,8 +2445,8 @@ function runMigrate(args) {
|
|
|
2422
2445
|
const keepFlag = args.includes("--keep");
|
|
2423
2446
|
const pathArg = args.find((a) => !a.startsWith("--"));
|
|
2424
2447
|
const projectDir = resolve4(pathArg ?? process.cwd());
|
|
2425
|
-
const legacyDir =
|
|
2426
|
-
const newDir =
|
|
2448
|
+
const legacyDir = join10(projectDir, LEGACY_CONTEXT_DIR);
|
|
2449
|
+
const newDir = join10(projectDir, NEW_CONTEXT_DIR);
|
|
2427
2450
|
if (!existsSync10(legacyDir)) {
|
|
2428
2451
|
process.stdout.write(`Nothing to migrate.
|
|
2429
2452
|
`);
|
|
@@ -2444,7 +2467,7 @@ function runMigrate(args) {
|
|
|
2444
2467
|
`);
|
|
2445
2468
|
}
|
|
2446
2469
|
function updateConfigPaths(contextDir) {
|
|
2447
|
-
const configPath =
|
|
2470
|
+
const configPath = join10(contextDir, "config.jsonc");
|
|
2448
2471
|
if (!existsSync10(configPath))
|
|
2449
2472
|
return;
|
|
2450
2473
|
try {
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// src/index.ts
|
|
3
|
-
import { existsSync as
|
|
4
|
-
import { join as
|
|
3
|
+
import { existsSync as existsSync4, readFileSync as readFileSync2, statSync, unlinkSync } from "fs";
|
|
4
|
+
import { join as join4, dirname as dirname2 } from "path";
|
|
5
5
|
import { fileURLToPath } from "url";
|
|
6
6
|
|
|
7
7
|
// src/lib/context-dir.ts
|
|
@@ -19,13 +19,48 @@ function resolveContextDir(projectDir) {
|
|
|
19
19
|
return nextContextDir;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
// src/lib/project-root.ts
|
|
23
|
+
import { existsSync as existsSync2 } from "fs";
|
|
24
|
+
import { join as join2, dirname, resolve } from "path";
|
|
25
|
+
import { homedir } from "os";
|
|
26
|
+
function findGitRoot(startDir) {
|
|
27
|
+
let current = resolve(startDir);
|
|
28
|
+
while (true) {
|
|
29
|
+
if (existsSync2(join2(current, ".git"))) {
|
|
30
|
+
return current;
|
|
31
|
+
}
|
|
32
|
+
const parent = dirname(current);
|
|
33
|
+
if (parent === current) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
current = parent;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function resolveProjectPaths(startDir) {
|
|
40
|
+
const gitRoot = findGitRoot(startDir);
|
|
41
|
+
if (gitRoot) {
|
|
42
|
+
return {
|
|
43
|
+
contextParent: gitRoot,
|
|
44
|
+
agentsMdPath: join2(gitRoot, "AGENTS.md"),
|
|
45
|
+
claudeMdPath: join2(gitRoot, "CLAUDE.md")
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const home = homedir();
|
|
49
|
+
const contextDir = join2(home, ".context");
|
|
50
|
+
return {
|
|
51
|
+
contextParent: home,
|
|
52
|
+
agentsMdPath: join2(contextDir, "AGENTS.md"),
|
|
53
|
+
claudeMdPath: join2(contextDir, "CLAUDE.md")
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
22
57
|
// src/lib/scaffold.ts
|
|
23
|
-
import { existsSync as
|
|
24
|
-
import { join as
|
|
58
|
+
import { existsSync as existsSync3, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
59
|
+
import { join as join3 } from "path";
|
|
25
60
|
// package.json
|
|
26
61
|
var package_default = {
|
|
27
62
|
name: "@ksm0709/context",
|
|
28
|
-
version: "0.
|
|
63
|
+
version: "0.2.0-next.1",
|
|
29
64
|
author: {
|
|
30
65
|
name: "TaehoKang",
|
|
31
66
|
email: "ksm07091@gmail.com"
|
|
@@ -397,21 +432,21 @@ var TEMPLATE_FILES = {
|
|
|
397
432
|
"work-complete.txt": DEFAULT_WORK_COMPLETE_TEMPLATE
|
|
398
433
|
};
|
|
399
434
|
function scaffoldIfNeeded(projectDir) {
|
|
400
|
-
const contextDir =
|
|
401
|
-
if (
|
|
435
|
+
const contextDir = join3(projectDir, resolveContextDir(projectDir));
|
|
436
|
+
if (existsSync3(contextDir)) {
|
|
402
437
|
return false;
|
|
403
438
|
}
|
|
404
439
|
try {
|
|
405
|
-
const templatesDir =
|
|
440
|
+
const templatesDir = join3(contextDir, "templates");
|
|
406
441
|
mkdirSync(templatesDir, { recursive: true });
|
|
407
|
-
const guidesDir =
|
|
442
|
+
const guidesDir = join3(contextDir, "guides");
|
|
408
443
|
mkdirSync(guidesDir, { recursive: true });
|
|
409
|
-
writeFileSync(
|
|
444
|
+
writeFileSync(join3(contextDir, "config.jsonc"), DEFAULT_CONFIG, "utf-8");
|
|
410
445
|
for (const [filename, content] of Object.entries(TEMPLATE_FILES)) {
|
|
411
|
-
writeFileSync(
|
|
446
|
+
writeFileSync(join3(templatesDir, filename), content, "utf-8");
|
|
412
447
|
}
|
|
413
448
|
for (const [filename, content] of Object.entries(GUIDE_FILES)) {
|
|
414
|
-
writeFileSync(
|
|
449
|
+
writeFileSync(join3(guidesDir, filename), content, "utf-8");
|
|
415
450
|
}
|
|
416
451
|
writeVersion(contextDir, PLUGIN_VERSION);
|
|
417
452
|
return true;
|
|
@@ -421,30 +456,30 @@ function scaffoldIfNeeded(projectDir) {
|
|
|
421
456
|
}
|
|
422
457
|
function getStoredVersion(projectDir) {
|
|
423
458
|
try {
|
|
424
|
-
return readFileSync(
|
|
459
|
+
return readFileSync(join3(projectDir, resolveContextDir(projectDir), ".version"), "utf-8").trim();
|
|
425
460
|
} catch {
|
|
426
461
|
return null;
|
|
427
462
|
}
|
|
428
463
|
}
|
|
429
464
|
function writeVersion(contextDir, version) {
|
|
430
|
-
writeFileSync(
|
|
465
|
+
writeFileSync(join3(contextDir, ".version"), version, "utf-8");
|
|
431
466
|
}
|
|
432
467
|
function autoUpdateTemplates(projectDir) {
|
|
433
|
-
const contextDir =
|
|
434
|
-
if (!
|
|
468
|
+
const contextDir = join3(projectDir, resolveContextDir(projectDir));
|
|
469
|
+
if (!existsSync3(contextDir))
|
|
435
470
|
return [];
|
|
436
471
|
const stored = getStoredVersion(projectDir);
|
|
437
472
|
if (stored === PLUGIN_VERSION)
|
|
438
473
|
return [];
|
|
439
|
-
mkdirSync(
|
|
440
|
-
mkdirSync(
|
|
474
|
+
mkdirSync(join3(contextDir, "templates"), { recursive: true });
|
|
475
|
+
mkdirSync(join3(contextDir, "guides"), { recursive: true });
|
|
441
476
|
const filesToUpdate = {
|
|
442
477
|
...Object.fromEntries(Object.entries(TEMPLATE_FILES).map(([f, c]) => [`templates/${f}`, c])),
|
|
443
478
|
...Object.fromEntries(Object.entries(GUIDE_FILES).map(([f, c]) => [`guides/${f}`, c]))
|
|
444
479
|
};
|
|
445
480
|
const updated = [];
|
|
446
481
|
for (const [path, content] of Object.entries(filesToUpdate)) {
|
|
447
|
-
const filePath =
|
|
482
|
+
const filePath = join3(contextDir, path);
|
|
448
483
|
try {
|
|
449
484
|
const existing = readFileSync(filePath, "utf-8");
|
|
450
485
|
if (existing === content)
|
|
@@ -479,10 +514,11 @@ var LIMITS = {
|
|
|
479
514
|
|
|
480
515
|
// src/index.ts
|
|
481
516
|
var __filename2 = fileURLToPath(import.meta.url);
|
|
482
|
-
var __dirname2 =
|
|
517
|
+
var __dirname2 = dirname2(__filename2);
|
|
483
518
|
var plugin = async ({ directory, client }) => {
|
|
484
|
-
const
|
|
485
|
-
const
|
|
519
|
+
const { contextParent: projectRoot } = resolveProjectPaths(directory);
|
|
520
|
+
const scaffolded = scaffoldIfNeeded(projectRoot);
|
|
521
|
+
const contextDir = resolveContextDir(projectRoot);
|
|
486
522
|
if (scaffolded) {
|
|
487
523
|
await client.app.log({
|
|
488
524
|
body: {
|
|
@@ -492,7 +528,7 @@ var plugin = async ({ directory, client }) => {
|
|
|
492
528
|
}
|
|
493
529
|
});
|
|
494
530
|
} else {
|
|
495
|
-
const autoUpdated = autoUpdateTemplates(
|
|
531
|
+
const autoUpdated = autoUpdateTemplates(projectRoot);
|
|
496
532
|
if (autoUpdated.length > 0) {
|
|
497
533
|
await client.app.log({
|
|
498
534
|
body: {
|
|
@@ -508,7 +544,7 @@ var plugin = async ({ directory, client }) => {
|
|
|
508
544
|
config.mcp = config.mcp || {};
|
|
509
545
|
config.mcp["context-mcp"] = {
|
|
510
546
|
type: "local",
|
|
511
|
-
command: ["bun",
|
|
547
|
+
command: ["bun", join4(__dirname2, "mcp.js")]
|
|
512
548
|
};
|
|
513
549
|
},
|
|
514
550
|
"experimental.chat.messages.transform": async (_input, output) => {
|
|
@@ -523,8 +559,8 @@ var plugin = async ({ directory, client }) => {
|
|
|
523
559
|
if (isTurnEndMessage) {
|
|
524
560
|
return;
|
|
525
561
|
}
|
|
526
|
-
const signalPath =
|
|
527
|
-
if (
|
|
562
|
+
const signalPath = join4(projectRoot, DEFAULTS.workCompleteFile);
|
|
563
|
+
if (existsSync4(signalPath)) {
|
|
528
564
|
const content = readFileSync2(signalPath, "utf-8");
|
|
529
565
|
const match = content.match(/^session_id=(.*)$/m);
|
|
530
566
|
const fileSessionId = match ? match[1].trim() : undefined;
|
|
@@ -20,7 +20,7 @@ function resolveContextDir(projectDir) {
|
|
|
20
20
|
// package.json
|
|
21
21
|
var package_default = {
|
|
22
22
|
name: "@ksm0709/context",
|
|
23
|
-
version: "0.
|
|
23
|
+
version: "0.2.0-next.1",
|
|
24
24
|
author: {
|
|
25
25
|
name: "TaehoKang",
|
|
26
26
|
email: "ksm07091@gmail.com"
|
|
@@ -418,9 +418,44 @@ function writeVersion(contextDir, version) {
|
|
|
418
418
|
writeFileSync(join2(contextDir, ".version"), version, "utf-8");
|
|
419
419
|
}
|
|
420
420
|
|
|
421
|
+
// src/lib/project-root.ts
|
|
422
|
+
import { existsSync as existsSync3 } from "fs";
|
|
423
|
+
import { join as join3, dirname, resolve } from "path";
|
|
424
|
+
import { homedir } from "os";
|
|
425
|
+
function findGitRoot(startDir) {
|
|
426
|
+
let current = resolve(startDir);
|
|
427
|
+
while (true) {
|
|
428
|
+
if (existsSync3(join3(current, ".git"))) {
|
|
429
|
+
return current;
|
|
430
|
+
}
|
|
431
|
+
const parent = dirname(current);
|
|
432
|
+
if (parent === current) {
|
|
433
|
+
return null;
|
|
434
|
+
}
|
|
435
|
+
current = parent;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
function resolveProjectPaths(startDir) {
|
|
439
|
+
const gitRoot = findGitRoot(startDir);
|
|
440
|
+
if (gitRoot) {
|
|
441
|
+
return {
|
|
442
|
+
contextParent: gitRoot,
|
|
443
|
+
agentsMdPath: join3(gitRoot, "AGENTS.md"),
|
|
444
|
+
claudeMdPath: join3(gitRoot, "CLAUDE.md")
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
const home = homedir();
|
|
448
|
+
const contextDir = join3(home, ".context");
|
|
449
|
+
return {
|
|
450
|
+
contextParent: home,
|
|
451
|
+
agentsMdPath: join3(contextDir, "AGENTS.md"),
|
|
452
|
+
claudeMdPath: join3(contextDir, "CLAUDE.md")
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
|
|
421
456
|
// src/shared/agents-md.ts
|
|
422
|
-
import { existsSync as
|
|
423
|
-
import { dirname } from "path";
|
|
457
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync, writeFileSync as writeFileSync2 } from "fs";
|
|
458
|
+
import { dirname as dirname2 } from "path";
|
|
424
459
|
var START_MARKER = "<!-- context:start -->";
|
|
425
460
|
var END_MARKER = "<!-- context:end -->";
|
|
426
461
|
function renderMarkerBlock(content, trailingNewline) {
|
|
@@ -461,8 +496,8 @@ function writeFileAtomically(filePath, content) {
|
|
|
461
496
|
renameSync(tempPath, filePath);
|
|
462
497
|
}
|
|
463
498
|
function injectIntoAgentsMd(agentsMdPath, content) {
|
|
464
|
-
mkdirSync2(
|
|
465
|
-
if (!
|
|
499
|
+
mkdirSync2(dirname2(agentsMdPath), { recursive: true });
|
|
500
|
+
if (!existsSync4(agentsMdPath)) {
|
|
466
501
|
writeFileAtomically(agentsMdPath, renderMarkerBlock(content, true));
|
|
467
502
|
return;
|
|
468
503
|
}
|
|
@@ -471,6 +506,23 @@ function injectIntoAgentsMd(agentsMdPath, content) {
|
|
|
471
506
|
writeFileAtomically(agentsMdPath, nextContent);
|
|
472
507
|
}
|
|
473
508
|
|
|
509
|
+
// src/shared/global-instructions.ts
|
|
510
|
+
import { homedir as homedir2 } from "os";
|
|
511
|
+
import { join as join4 } from "path";
|
|
512
|
+
function getGlobalInstructionPath(tool) {
|
|
513
|
+
const home = homedir2();
|
|
514
|
+
switch (tool) {
|
|
515
|
+
case "claude":
|
|
516
|
+
return join4(home, ".claude", "CLAUDE.md");
|
|
517
|
+
case "codex":
|
|
518
|
+
return join4(home, ".codex", "instructions.md");
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
function injectIntoGlobalInstructions(tool, content) {
|
|
522
|
+
const path = getGlobalInstructionPath(tool);
|
|
523
|
+
injectIntoAgentsMd(path, content);
|
|
524
|
+
}
|
|
525
|
+
|
|
474
526
|
// src/shared/knowledge-context.ts
|
|
475
527
|
var STATIC_KNOWLEDGE_CONTEXT = `## Knowledge Context
|
|
476
528
|
|
|
@@ -512,7 +564,11 @@ var STATIC_KNOWLEDGE_CONTEXT = `## Knowledge Context
|
|
|
512
564
|
- \uD544\uC694\uD55C \uC778\uC790: daily_note_update_proof, knowledge_note_proof, quality_check_output, checkpoint_commit_hashes, scope_review_notes`;
|
|
513
565
|
|
|
514
566
|
// src/omc/session-start-hook.ts
|
|
515
|
-
import { join as join3 } from "path";
|
|
516
567
|
var projectDir = process.env.CLAUDE_PROJECT_DIR ?? process.cwd();
|
|
517
|
-
|
|
518
|
-
|
|
568
|
+
var paths = resolveProjectPaths(projectDir);
|
|
569
|
+
scaffoldIfNeeded(paths.contextParent);
|
|
570
|
+
injectIntoAgentsMd(paths.agentsMdPath, STATIC_KNOWLEDGE_CONTEXT);
|
|
571
|
+
injectIntoAgentsMd(paths.claudeMdPath, STATIC_KNOWLEDGE_CONTEXT);
|
|
572
|
+
if (!findGitRoot(projectDir)) {
|
|
573
|
+
injectIntoGlobalInstructions("claude", STATIC_KNOWLEDGE_CONTEXT);
|
|
574
|
+
}
|
package/dist/omx/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/omx/index.ts
|
|
2
|
-
import { existsSync as
|
|
3
|
-
import { join as
|
|
2
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6, unlinkSync } from "node:fs";
|
|
3
|
+
import { join as join9 } from "node:path";
|
|
4
4
|
|
|
5
5
|
// src/constants.ts
|
|
6
6
|
var DEFAULTS = {
|
|
@@ -99,13 +99,48 @@ function loadConfig(projectDir) {
|
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
// src/lib/project-root.ts
|
|
103
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
104
|
+
import { join as join3, dirname, resolve } from "node:path";
|
|
105
|
+
import { homedir } from "node:os";
|
|
106
|
+
function findGitRoot(startDir) {
|
|
107
|
+
let current = resolve(startDir);
|
|
108
|
+
while (true) {
|
|
109
|
+
if (existsSync2(join3(current, ".git"))) {
|
|
110
|
+
return current;
|
|
111
|
+
}
|
|
112
|
+
const parent = dirname(current);
|
|
113
|
+
if (parent === current) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
current = parent;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function resolveProjectPaths(startDir) {
|
|
120
|
+
const gitRoot = findGitRoot(startDir);
|
|
121
|
+
if (gitRoot) {
|
|
122
|
+
return {
|
|
123
|
+
contextParent: gitRoot,
|
|
124
|
+
agentsMdPath: join3(gitRoot, "AGENTS.md"),
|
|
125
|
+
claudeMdPath: join3(gitRoot, "CLAUDE.md")
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
const home = homedir();
|
|
129
|
+
const contextDir = join3(home, ".context");
|
|
130
|
+
return {
|
|
131
|
+
contextParent: home,
|
|
132
|
+
agentsMdPath: join3(contextDir, "AGENTS.md"),
|
|
133
|
+
claudeMdPath: join3(contextDir, "CLAUDE.md")
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
102
137
|
// src/lib/scaffold.ts
|
|
103
|
-
import { existsSync as
|
|
104
|
-
import { join as
|
|
138
|
+
import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "node:fs";
|
|
139
|
+
import { join as join4 } from "node:path";
|
|
105
140
|
// package.json
|
|
106
141
|
var package_default = {
|
|
107
142
|
name: "@ksm0709/context",
|
|
108
|
-
version: "0.
|
|
143
|
+
version: "0.2.0-next.1",
|
|
109
144
|
author: {
|
|
110
145
|
name: "TaehoKang",
|
|
111
146
|
email: "ksm07091@gmail.com"
|
|
@@ -477,21 +512,21 @@ var TEMPLATE_FILES = {
|
|
|
477
512
|
"work-complete.txt": DEFAULT_WORK_COMPLETE_TEMPLATE
|
|
478
513
|
};
|
|
479
514
|
function scaffoldIfNeeded(projectDir) {
|
|
480
|
-
const contextDir =
|
|
481
|
-
if (
|
|
515
|
+
const contextDir = join4(projectDir, resolveContextDir(projectDir));
|
|
516
|
+
if (existsSync3(contextDir)) {
|
|
482
517
|
return false;
|
|
483
518
|
}
|
|
484
519
|
try {
|
|
485
|
-
const templatesDir =
|
|
520
|
+
const templatesDir = join4(contextDir, "templates");
|
|
486
521
|
mkdirSync(templatesDir, { recursive: true });
|
|
487
|
-
const guidesDir =
|
|
522
|
+
const guidesDir = join4(contextDir, "guides");
|
|
488
523
|
mkdirSync(guidesDir, { recursive: true });
|
|
489
|
-
writeFileSync(
|
|
524
|
+
writeFileSync(join4(contextDir, "config.jsonc"), DEFAULT_CONFIG, "utf-8");
|
|
490
525
|
for (const [filename, content] of Object.entries(TEMPLATE_FILES)) {
|
|
491
|
-
writeFileSync(
|
|
526
|
+
writeFileSync(join4(templatesDir, filename), content, "utf-8");
|
|
492
527
|
}
|
|
493
528
|
for (const [filename, content] of Object.entries(GUIDE_FILES)) {
|
|
494
|
-
writeFileSync(
|
|
529
|
+
writeFileSync(join4(guidesDir, filename), content, "utf-8");
|
|
495
530
|
}
|
|
496
531
|
writeVersion(contextDir, PLUGIN_VERSION);
|
|
497
532
|
return true;
|
|
@@ -500,12 +535,12 @@ function scaffoldIfNeeded(projectDir) {
|
|
|
500
535
|
}
|
|
501
536
|
}
|
|
502
537
|
function writeVersion(contextDir, version) {
|
|
503
|
-
writeFileSync(
|
|
538
|
+
writeFileSync(join4(contextDir, ".version"), version, "utf-8");
|
|
504
539
|
}
|
|
505
540
|
|
|
506
541
|
// src/shared/agents-md.ts
|
|
507
|
-
import { existsSync as
|
|
508
|
-
import { dirname } from "node:path";
|
|
542
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync3, renameSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
543
|
+
import { dirname as dirname2 } from "node:path";
|
|
509
544
|
var START_MARKER = "<!-- context:start -->";
|
|
510
545
|
var END_MARKER = "<!-- context:end -->";
|
|
511
546
|
function renderMarkerBlock(content, trailingNewline) {
|
|
@@ -546,8 +581,8 @@ function writeFileAtomically(filePath, content) {
|
|
|
546
581
|
renameSync(tempPath, filePath);
|
|
547
582
|
}
|
|
548
583
|
function injectIntoAgentsMd(agentsMdPath, content) {
|
|
549
|
-
mkdirSync2(
|
|
550
|
-
if (!
|
|
584
|
+
mkdirSync2(dirname2(agentsMdPath), { recursive: true });
|
|
585
|
+
if (!existsSync4(agentsMdPath)) {
|
|
551
586
|
writeFileAtomically(agentsMdPath, renderMarkerBlock(content, true));
|
|
552
587
|
return;
|
|
553
588
|
}
|
|
@@ -557,11 +592,11 @@ function injectIntoAgentsMd(agentsMdPath, content) {
|
|
|
557
592
|
}
|
|
558
593
|
|
|
559
594
|
// src/shared/codex-settings.ts
|
|
560
|
-
import { existsSync as
|
|
561
|
-
import { homedir } from "node:os";
|
|
562
|
-
import { isAbsolute, join as
|
|
595
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
|
|
596
|
+
import { homedir as homedir2 } from "node:os";
|
|
597
|
+
import { isAbsolute, join as join5 } from "node:path";
|
|
563
598
|
var STALE_MOCK_MCP_SERVER_NAME = "mock-mcp";
|
|
564
|
-
var codexConfigPath =
|
|
599
|
+
var codexConfigPath = join5(homedir2(), ".codex", "config.toml");
|
|
565
600
|
function findMcpServerBlockRange(lines, serverName) {
|
|
566
601
|
const header = `[mcp_servers.${serverName}]`;
|
|
567
602
|
const start = lines.findIndex((line) => line.trim() === header);
|
|
@@ -588,7 +623,7 @@ function resolveFirstArgPath(blockLines) {
|
|
|
588
623
|
return null;
|
|
589
624
|
}
|
|
590
625
|
function pruneStaleMockMcpServer() {
|
|
591
|
-
if (!
|
|
626
|
+
if (!existsSync5(codexConfigPath)) {
|
|
592
627
|
return false;
|
|
593
628
|
}
|
|
594
629
|
const content = readFileSync4(codexConfigPath, "utf8");
|
|
@@ -600,7 +635,7 @@ function pruneStaleMockMcpServer() {
|
|
|
600
635
|
}
|
|
601
636
|
const blockLines = lines.slice(blockRange.start, blockRange.end);
|
|
602
637
|
const firstArgPath = resolveFirstArgPath(blockLines);
|
|
603
|
-
if (!firstArgPath || !isAbsolute(firstArgPath) ||
|
|
638
|
+
if (!firstArgPath || !isAbsolute(firstArgPath) || existsSync5(firstArgPath)) {
|
|
604
639
|
return false;
|
|
605
640
|
}
|
|
606
641
|
const nextLines = [...lines.slice(0, blockRange.start), ...lines.slice(blockRange.end)];
|
|
@@ -609,6 +644,23 @@ function pruneStaleMockMcpServer() {
|
|
|
609
644
|
return true;
|
|
610
645
|
}
|
|
611
646
|
|
|
647
|
+
// src/shared/global-instructions.ts
|
|
648
|
+
import { homedir as homedir3 } from "node:os";
|
|
649
|
+
import { join as join6 } from "node:path";
|
|
650
|
+
function getGlobalInstructionPath(tool) {
|
|
651
|
+
const home = homedir3();
|
|
652
|
+
switch (tool) {
|
|
653
|
+
case "claude":
|
|
654
|
+
return join6(home, ".claude", "CLAUDE.md");
|
|
655
|
+
case "codex":
|
|
656
|
+
return join6(home, ".codex", "instructions.md");
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
function injectIntoGlobalInstructions(tool, content) {
|
|
660
|
+
const path = getGlobalInstructionPath(tool);
|
|
661
|
+
injectIntoAgentsMd(path, content);
|
|
662
|
+
}
|
|
663
|
+
|
|
612
664
|
// src/shared/knowledge-context.ts
|
|
613
665
|
var STATIC_KNOWLEDGE_CONTEXT = `## Knowledge Context
|
|
614
666
|
|
|
@@ -650,32 +702,32 @@ var STATIC_KNOWLEDGE_CONTEXT = `## Knowledge Context
|
|
|
650
702
|
- 필요한 인자: daily_note_update_proof, knowledge_note_proof, quality_check_output, checkpoint_commit_hashes, scope_review_notes`;
|
|
651
703
|
|
|
652
704
|
// src/omx/registry.ts
|
|
653
|
-
import { join as
|
|
654
|
-
import { existsSync as
|
|
705
|
+
import { join as join8, dirname as dirname4 } from "node:path";
|
|
706
|
+
import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3 } from "node:fs";
|
|
655
707
|
import { execSync } from "node:child_process";
|
|
656
|
-
import { homedir as
|
|
708
|
+
import { homedir as homedir4 } from "node:os";
|
|
657
709
|
|
|
658
710
|
// src/shared/mcp-path.ts
|
|
659
711
|
import { fileURLToPath } from "node:url";
|
|
660
|
-
import { dirname as
|
|
661
|
-
import { existsSync as
|
|
712
|
+
import { dirname as dirname3, join as join7, resolve as resolve2 } from "node:path";
|
|
713
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
662
714
|
import { createRequire } from "node:module";
|
|
663
715
|
function resolveMcpPath() {
|
|
664
716
|
try {
|
|
665
717
|
const req = createRequire(import.meta.url);
|
|
666
718
|
const pkgJsonPath = req.resolve("@ksm0709/context/package.json");
|
|
667
|
-
const pkgRoot =
|
|
668
|
-
const distMcp =
|
|
669
|
-
if (
|
|
719
|
+
const pkgRoot = dirname3(pkgJsonPath);
|
|
720
|
+
const distMcp = join7(pkgRoot, "dist", "mcp.js");
|
|
721
|
+
if (existsSync6(distMcp))
|
|
670
722
|
return distMcp;
|
|
671
723
|
} catch {}
|
|
672
724
|
const currentFile = fileURLToPath(import.meta.url);
|
|
673
|
-
const currentDir =
|
|
674
|
-
const distMcpPath =
|
|
675
|
-
if (
|
|
725
|
+
const currentDir = dirname3(currentFile);
|
|
726
|
+
const distMcpPath = resolve2(currentDir, "..", "mcp.js");
|
|
727
|
+
if (existsSync6(distMcpPath))
|
|
676
728
|
return distMcpPath;
|
|
677
|
-
const srcMcpPath =
|
|
678
|
-
if (
|
|
729
|
+
const srcMcpPath = resolve2(currentDir, "..", "mcp.ts");
|
|
730
|
+
if (existsSync6(srcMcpPath))
|
|
679
731
|
return srcMcpPath;
|
|
680
732
|
return distMcpPath;
|
|
681
733
|
}
|
|
@@ -690,21 +742,21 @@ function resolveBunPath() {
|
|
|
690
742
|
}
|
|
691
743
|
function getRegistryPaths() {
|
|
692
744
|
return [
|
|
693
|
-
|
|
694
|
-
|
|
745
|
+
join8(homedir4(), ".omx", "mcp-registry.json"),
|
|
746
|
+
join8(homedir4(), ".omc", "mcp-registry.json")
|
|
695
747
|
];
|
|
696
748
|
}
|
|
697
749
|
function ensureMcpRegistered(sdkLog) {
|
|
698
750
|
const registryPaths = getRegistryPaths();
|
|
699
751
|
let targetPath = registryPaths[0];
|
|
700
752
|
for (const p of registryPaths) {
|
|
701
|
-
if (
|
|
753
|
+
if (existsSync7(p)) {
|
|
702
754
|
targetPath = p;
|
|
703
755
|
break;
|
|
704
756
|
}
|
|
705
757
|
}
|
|
706
758
|
let registry = {};
|
|
707
|
-
if (
|
|
759
|
+
if (existsSync7(targetPath)) {
|
|
708
760
|
try {
|
|
709
761
|
const content = readFileSync5(targetPath, "utf-8");
|
|
710
762
|
registry = JSON.parse(content);
|
|
@@ -734,7 +786,7 @@ function ensureMcpRegistered(sdkLog) {
|
|
|
734
786
|
}
|
|
735
787
|
if (changed) {
|
|
736
788
|
try {
|
|
737
|
-
mkdirSync3(
|
|
789
|
+
mkdirSync3(dirname4(targetPath), { recursive: true });
|
|
738
790
|
writeFileSync4(targetPath, JSON.stringify(registry, null, 2), "utf-8");
|
|
739
791
|
if (sdkLog) {
|
|
740
792
|
sdkLog(`[INFO] Registered context-mcp in ${targetPath}`);
|
|
@@ -766,7 +818,7 @@ function runTmux(args) {
|
|
|
766
818
|
return { ok: true };
|
|
767
819
|
}
|
|
768
820
|
function sleep(ms) {
|
|
769
|
-
return new Promise((
|
|
821
|
+
return new Promise((resolve3) => globalThis.setTimeout(resolve3, ms));
|
|
770
822
|
}
|
|
771
823
|
async function sendTmuxSubmitSequence(target, attempts = 3) {
|
|
772
824
|
const totalAttempts = Math.max(1, Math.floor(attempts));
|
|
@@ -834,11 +886,16 @@ async function logWarn(sdk, message, meta = {}) {
|
|
|
834
886
|
}
|
|
835
887
|
async function onSessionStart(event, sdk) {
|
|
836
888
|
const projectDir = resolveProjectDir(event);
|
|
889
|
+
const paths = resolveProjectPaths(projectDir);
|
|
837
890
|
if (pruneStaleMockMcpServer()) {
|
|
838
891
|
await sdk.log.info("Removed stale mock-mcp from ~/.codex/config.toml because its target file is missing.");
|
|
839
892
|
}
|
|
840
|
-
scaffoldIfNeeded(
|
|
841
|
-
injectIntoAgentsMd(
|
|
893
|
+
scaffoldIfNeeded(paths.contextParent);
|
|
894
|
+
injectIntoAgentsMd(paths.agentsMdPath, STATIC_KNOWLEDGE_CONTEXT);
|
|
895
|
+
injectIntoAgentsMd(paths.claudeMdPath, STATIC_KNOWLEDGE_CONTEXT);
|
|
896
|
+
if (!findGitRoot(projectDir)) {
|
|
897
|
+
injectIntoGlobalInstructions("codex", STATIC_KNOWLEDGE_CONTEXT);
|
|
898
|
+
}
|
|
842
899
|
await sdk.log.info(`Injected context into AGENTS.md for ${projectDir}`);
|
|
843
900
|
const wasRegistered = ensureMcpRegistered(sdk.log.info);
|
|
844
901
|
if (wasRegistered) {
|
|
@@ -856,7 +913,8 @@ async function onSessionStart(event, sdk) {
|
|
|
856
913
|
}
|
|
857
914
|
async function onTurnComplete(event, sdk) {
|
|
858
915
|
const projectDir = resolveProjectDir(event);
|
|
859
|
-
const
|
|
916
|
+
const paths = resolveProjectPaths(projectDir);
|
|
917
|
+
const config = loadConfig(paths.contextParent);
|
|
860
918
|
const strategy = config.omx?.turnEnd?.strategy ?? "off";
|
|
861
919
|
if (strategy !== "turn-complete-sendkeys") {
|
|
862
920
|
return;
|
|
@@ -878,8 +936,8 @@ async function onTurnComplete(event, sdk) {
|
|
|
878
936
|
}
|
|
879
937
|
const followupScopeKey = resolveFollowupScopeKey(event);
|
|
880
938
|
let pendingFollowupScopes = typeof sdk.state?.read === "function" ? await sdk.state.read(TURN_END_PENDING_SKIP_KEY, {}) ?? {} : {};
|
|
881
|
-
const workCompleteFile =
|
|
882
|
-
if (
|
|
939
|
+
const workCompleteFile = join9(paths.contextParent, DEFAULTS.workCompleteFile);
|
|
940
|
+
if (existsSync8(workCompleteFile)) {
|
|
883
941
|
const content = readFileSync6(workCompleteFile, "utf-8");
|
|
884
942
|
const { sessionId: fileSessionId, turnId: fileTurnId } = parseWorkComplete(content);
|
|
885
943
|
const currentScopeId = event.session_id ?? event.thread_id ?? "";
|
|
@@ -946,7 +1004,7 @@ async function onTurnComplete(event, sdk) {
|
|
|
946
1004
|
${turnEnd}
|
|
947
1005
|
</system-reminder>`;
|
|
948
1006
|
const sessionName = typeof event.context?.session_name === "string" && event.context.session_name.trim().length > 0 ? event.context.session_name.trim() : undefined;
|
|
949
|
-
await new Promise((
|
|
1007
|
+
await new Promise((resolve3) => globalThis.setTimeout(resolve3, 500));
|
|
950
1008
|
if (typeof sdk.tmux?.sendKeys === "function") {}
|
|
951
1009
|
const result = await sdk.tmux.sendKeys({
|
|
952
1010
|
sessionName,
|