@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 CHANGED
@@ -2,9 +2,9 @@
2
2
  // @bun
3
3
 
4
4
  // src/cli/commands/update.ts
5
- import { resolve as resolve3, join as join8 } from "path";
5
+ import { resolve as resolve3, join as join9 } from "path";
6
6
  import { existsSync as existsSync9 } from "fs";
7
- import { homedir as homedir4 } from "os";
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.1.0-next.1",
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 join7, resolve as resolve2, dirname as dirname5 } from "path";
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 homedir2 } from "os";
657
- import { isAbsolute, join as join5 } from "path";
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 = join5(homedir2(), ".codex", "config.toml");
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 join6 } from "path";
710
- import { homedir as homedir3 } from "os";
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 = join6(homedir3(), ".claude", "settings.json");
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 = join7(pkgRoot, "dist", "omx", "index.mjs");
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 = join7(projectDir, ".omx", "hooks");
2183
+ const targetDir = join8(projectDir, ".omx", "hooks");
2167
2184
  mkdirSync5(targetDir, { recursive: true });
2168
- copyFileSync(sourcePath, join7(targetDir, "context.mjs"));
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(join7(projectDir, "AGENTS.md"), STATIC_KNOWLEDGE_CONTEXT);
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 = join7(dirname5(mcpPath), "omc") + "/";
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(join8(projectDir, ".omx", "hooks", "context.mjs"));
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 = join8(homedir4(), ".bun", "bin", "context");
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 join9 } from "path";
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 = join9(projectDir, LEGACY_CONTEXT_DIR);
2426
- const newDir = join9(projectDir, NEW_CONTEXT_DIR);
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 = join9(contextDir, "config.jsonc");
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 existsSync3, readFileSync as readFileSync2, statSync, unlinkSync } from "fs";
4
- import { join as join3, dirname } from "path";
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 existsSync2, mkdirSync, readFileSync, writeFileSync } from "fs";
24
- import { join as join2 } from "path";
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.1.0-next.1",
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 = join2(projectDir, resolveContextDir(projectDir));
401
- if (existsSync2(contextDir)) {
435
+ const contextDir = join3(projectDir, resolveContextDir(projectDir));
436
+ if (existsSync3(contextDir)) {
402
437
  return false;
403
438
  }
404
439
  try {
405
- const templatesDir = join2(contextDir, "templates");
440
+ const templatesDir = join3(contextDir, "templates");
406
441
  mkdirSync(templatesDir, { recursive: true });
407
- const guidesDir = join2(contextDir, "guides");
442
+ const guidesDir = join3(contextDir, "guides");
408
443
  mkdirSync(guidesDir, { recursive: true });
409
- writeFileSync(join2(contextDir, "config.jsonc"), DEFAULT_CONFIG, "utf-8");
444
+ writeFileSync(join3(contextDir, "config.jsonc"), DEFAULT_CONFIG, "utf-8");
410
445
  for (const [filename, content] of Object.entries(TEMPLATE_FILES)) {
411
- writeFileSync(join2(templatesDir, filename), content, "utf-8");
446
+ writeFileSync(join3(templatesDir, filename), content, "utf-8");
412
447
  }
413
448
  for (const [filename, content] of Object.entries(GUIDE_FILES)) {
414
- writeFileSync(join2(guidesDir, filename), content, "utf-8");
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(join2(projectDir, resolveContextDir(projectDir), ".version"), "utf-8").trim();
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(join2(contextDir, ".version"), version, "utf-8");
465
+ writeFileSync(join3(contextDir, ".version"), version, "utf-8");
431
466
  }
432
467
  function autoUpdateTemplates(projectDir) {
433
- const contextDir = join2(projectDir, resolveContextDir(projectDir));
434
- if (!existsSync2(contextDir))
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(join2(contextDir, "templates"), { recursive: true });
440
- mkdirSync(join2(contextDir, "guides"), { recursive: true });
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 = join2(contextDir, path);
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 = dirname(__filename2);
517
+ var __dirname2 = dirname2(__filename2);
483
518
  var plugin = async ({ directory, client }) => {
484
- const scaffolded = scaffoldIfNeeded(directory);
485
- const contextDir = resolveContextDir(directory);
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(directory);
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", join3(__dirname2, "mcp.js")]
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 = join3(directory, DEFAULTS.workCompleteFile);
527
- if (existsSync3(signalPath)) {
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.1.0-next.1",
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 existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync, writeFileSync as writeFileSync2 } from "fs";
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(dirname(agentsMdPath), { recursive: true });
465
- if (!existsSync3(agentsMdPath)) {
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
- scaffoldIfNeeded(projectDir);
518
- injectIntoAgentsMd(join3(projectDir, "AGENTS.md"), STATIC_KNOWLEDGE_CONTEXT);
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
+ }
@@ -1,6 +1,6 @@
1
1
  // src/omx/index.ts
2
- import { existsSync as existsSync7, readFileSync as readFileSync6, unlinkSync } from "node:fs";
3
- import { join as join7 } from "node:path";
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 existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "node:fs";
104
- import { join as join3 } from "node:path";
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.1.0-next.1",
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 = join3(projectDir, resolveContextDir(projectDir));
481
- if (existsSync2(contextDir)) {
515
+ const contextDir = join4(projectDir, resolveContextDir(projectDir));
516
+ if (existsSync3(contextDir)) {
482
517
  return false;
483
518
  }
484
519
  try {
485
- const templatesDir = join3(contextDir, "templates");
520
+ const templatesDir = join4(contextDir, "templates");
486
521
  mkdirSync(templatesDir, { recursive: true });
487
- const guidesDir = join3(contextDir, "guides");
522
+ const guidesDir = join4(contextDir, "guides");
488
523
  mkdirSync(guidesDir, { recursive: true });
489
- writeFileSync(join3(contextDir, "config.jsonc"), DEFAULT_CONFIG, "utf-8");
524
+ writeFileSync(join4(contextDir, "config.jsonc"), DEFAULT_CONFIG, "utf-8");
490
525
  for (const [filename, content] of Object.entries(TEMPLATE_FILES)) {
491
- writeFileSync(join3(templatesDir, filename), content, "utf-8");
526
+ writeFileSync(join4(templatesDir, filename), content, "utf-8");
492
527
  }
493
528
  for (const [filename, content] of Object.entries(GUIDE_FILES)) {
494
- writeFileSync(join3(guidesDir, filename), content, "utf-8");
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(join3(contextDir, ".version"), version, "utf-8");
538
+ writeFileSync(join4(contextDir, ".version"), version, "utf-8");
504
539
  }
505
540
 
506
541
  // src/shared/agents-md.ts
507
- import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, renameSync, writeFileSync as writeFileSync2 } from "node:fs";
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(dirname(agentsMdPath), { recursive: true });
550
- if (!existsSync3(agentsMdPath)) {
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 existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
561
- import { homedir } from "node:os";
562
- import { isAbsolute, join as join4 } from "node:path";
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 = join4(homedir(), ".codex", "config.toml");
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 (!existsSync4(codexConfigPath)) {
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) || existsSync4(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 join6, dirname as dirname3 } from "node:path";
654
- import { existsSync as existsSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3 } from "node:fs";
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 homedir2 } from "node:os";
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 dirname2, join as join5, resolve } from "node:path";
661
- import { existsSync as existsSync5 } from "node:fs";
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 = dirname2(pkgJsonPath);
668
- const distMcp = join5(pkgRoot, "dist", "mcp.js");
669
- if (existsSync5(distMcp))
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 = dirname2(currentFile);
674
- const distMcpPath = resolve(currentDir, "..", "mcp.js");
675
- if (existsSync5(distMcpPath))
725
+ const currentDir = dirname3(currentFile);
726
+ const distMcpPath = resolve2(currentDir, "..", "mcp.js");
727
+ if (existsSync6(distMcpPath))
676
728
  return distMcpPath;
677
- const srcMcpPath = resolve(currentDir, "..", "mcp.ts");
678
- if (existsSync5(srcMcpPath))
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
- join6(homedir2(), ".omx", "mcp-registry.json"),
694
- join6(homedir2(), ".omc", "mcp-registry.json")
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 (existsSync6(p)) {
753
+ if (existsSync7(p)) {
702
754
  targetPath = p;
703
755
  break;
704
756
  }
705
757
  }
706
758
  let registry = {};
707
- if (existsSync6(targetPath)) {
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(dirname3(targetPath), { recursive: true });
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((resolve2) => globalThis.setTimeout(resolve2, ms));
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(projectDir);
841
- injectIntoAgentsMd(join7(projectDir, "AGENTS.md"), STATIC_KNOWLEDGE_CONTEXT);
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 config = loadConfig(projectDir);
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 = join7(projectDir, DEFAULTS.workCompleteFile);
882
- if (existsSync7(workCompleteFile)) {
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((resolve2) => globalThis.setTimeout(resolve2, 500));
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,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ksm0709/context",
3
- "version": "0.1.0-next.1",
3
+ "version": "0.2.0-next.1",
4
4
  "author": {
5
5
  "name": "TaehoKang",
6
6
  "email": "ksm07091@gmail.com"