@ksm0709/context 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +168 -10
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -818,14 +818,17 @@ var DEFAULTS = {
818
818
  turnEndFile: "turn-end.md",
819
819
  knowledgeSources: ["AGENTS.md"],
820
820
  knowledgeDir: "docs",
821
- templateDir: ".opencode/context/templates"
821
+ templateDir: ".opencode/context/templates",
822
+ indexFilename: "INDEX.md",
823
+ maxDomainDepth: 2
822
824
  };
823
825
  var LIMITS = {
824
826
  maxPromptFileSize: 64 * 1024,
825
827
  maxIndexEntries: 100,
826
828
  maxTotalInjectionSize: 128 * 1024,
827
829
  maxScanDepth: 3,
828
- maxSummaryLength: 100
830
+ maxSummaryLength: 100,
831
+ maxIndexFileSize: 32 * 1024
829
832
  };
830
833
 
831
834
  // src/lib/config.ts
@@ -837,7 +840,10 @@ function getDefaultConfig() {
837
840
  },
838
841
  knowledge: {
839
842
  dir: DEFAULTS.knowledgeDir,
840
- sources: [...DEFAULTS.knowledgeSources]
843
+ sources: [...DEFAULTS.knowledgeSources],
844
+ mode: "auto",
845
+ indexFilename: DEFAULTS.indexFilename,
846
+ maxDomainDepth: DEFAULTS.maxDomainDepth
841
847
  }
842
848
  };
843
849
  }
@@ -850,7 +856,10 @@ function mergeWithDefaults(partial) {
850
856
  },
851
857
  knowledge: {
852
858
  dir: partial.knowledge?.dir ?? defaults.knowledge.dir,
853
- sources: partial.knowledge?.sources ?? defaults.knowledge.sources
859
+ sources: partial.knowledge?.sources ?? defaults.knowledge.sources,
860
+ mode: partial.knowledge?.mode ?? defaults.knowledge.mode,
861
+ indexFilename: partial.knowledge?.indexFilename ?? defaults.knowledge.indexFilename,
862
+ maxDomainDepth: partial.knowledge?.maxDomainDepth ?? defaults.knowledge.maxDomainDepth
854
863
  }
855
864
  };
856
865
  }
@@ -939,6 +948,131 @@ function formatKnowledgeIndex(entries) {
939
948
  return lines.join(`
940
949
  `);
941
950
  }
951
+ function countMdFiles(dir, indexFilename) {
952
+ try {
953
+ const items = readdirSync(dir);
954
+ return items.filter((item) => extname(item) === ".md" && item !== indexFilename && statSync(join2(dir, item)).isFile()).length;
955
+ } catch {
956
+ return 0;
957
+ }
958
+ }
959
+ function scanDomainsRecursive(baseDir, projectDir, indexFilename, currentDepth, maxDepth, results) {
960
+ if (currentDepth > maxDepth)
961
+ return;
962
+ try {
963
+ const items = readdirSync(baseDir);
964
+ for (const item of items) {
965
+ const fullPath = join2(baseDir, item);
966
+ try {
967
+ if (!statSync(fullPath).isDirectory())
968
+ continue;
969
+ const indexPath = join2(fullPath, indexFilename);
970
+ if (existsSync(indexPath) && statSync(indexPath).isFile()) {
971
+ const rawContent = readFileSync2(indexPath, "utf-8");
972
+ const indexContent = rawContent.slice(0, LIMITS.maxIndexFileSize);
973
+ results.push({
974
+ domain: item,
975
+ path: relative(projectDir, fullPath),
976
+ indexContent,
977
+ noteCount: countMdFiles(fullPath, indexFilename)
978
+ });
979
+ }
980
+ scanDomainsRecursive(fullPath, projectDir, indexFilename, currentDepth + 1, maxDepth, results);
981
+ } catch {}
982
+ }
983
+ } catch {}
984
+ }
985
+ function scanDomains(projectDir, knowledgeDir, indexFilename, maxDepth) {
986
+ const baseDir = join2(projectDir, knowledgeDir);
987
+ if (!existsSync(baseDir))
988
+ return [];
989
+ const results = [];
990
+ scanDomainsRecursive(baseDir, projectDir, indexFilename, 1, maxDepth, results);
991
+ return results;
992
+ }
993
+ function detectKnowledgeMode(projectDir, knowledgeDir, indexFilename, configMode) {
994
+ if (configMode !== "auto")
995
+ return configMode;
996
+ const domains = scanDomains(projectDir, knowledgeDir, indexFilename, 1);
997
+ return domains.length > 0 ? "domain" : "flat";
998
+ }
999
+ function formatDomainIndex(index) {
1000
+ const hasDomains = index.domains.length > 0;
1001
+ const hasFiles = index.individualFiles.length > 0;
1002
+ if (!hasDomains && !hasFiles)
1003
+ return "";
1004
+ const lines = ["## Available Knowledge", ""];
1005
+ if (hasDomains) {
1006
+ lines.push("### Domains", "");
1007
+ for (const domain of index.domains) {
1008
+ lines.push(`#### ${domain.path}/ (${domain.noteCount} notes)`, "");
1009
+ lines.push(domain.indexContent, "");
1010
+ }
1011
+ }
1012
+ if (hasFiles) {
1013
+ if (hasDomains) {
1014
+ lines.push("### Individual Files", "");
1015
+ }
1016
+ for (const file of index.individualFiles) {
1017
+ lines.push(`- ${file.filename}${file.summary ? ` \u2014 ${file.summary}` : ""}`);
1018
+ }
1019
+ }
1020
+ return lines.join(`
1021
+ `);
1022
+ }
1023
+ function collectRootFiles(projectDir, knowledgeDir, indexFilename) {
1024
+ const baseDir = join2(projectDir, knowledgeDir);
1025
+ if (!existsSync(baseDir))
1026
+ return [];
1027
+ const entries = [];
1028
+ try {
1029
+ const items = readdirSync(baseDir);
1030
+ for (const item of items) {
1031
+ const fullPath = join2(baseDir, item);
1032
+ try {
1033
+ const stat = statSync(fullPath);
1034
+ if (stat.isFile() && extname(item) === ".md" && item !== indexFilename) {
1035
+ entries.push({
1036
+ filename: relative(projectDir, fullPath),
1037
+ summary: extractSummary(fullPath)
1038
+ });
1039
+ }
1040
+ } catch {}
1041
+ }
1042
+ } catch {}
1043
+ return entries;
1044
+ }
1045
+ function buildKnowledgeIndexV2(projectDir, knowledgeConfig) {
1046
+ const dir = knowledgeConfig.dir ?? "docs";
1047
+ const indexFilename = knowledgeConfig.indexFilename ?? "INDEX.md";
1048
+ const maxDepth = knowledgeConfig.maxDomainDepth ?? 2;
1049
+ const configMode = knowledgeConfig.mode ?? "auto";
1050
+ const mode = detectKnowledgeMode(projectDir, dir, indexFilename, configMode);
1051
+ if (mode === "flat") {
1052
+ const allSources = [dir, ...knowledgeConfig.sources].filter(Boolean);
1053
+ const entries = buildKnowledgeIndex(projectDir, allSources);
1054
+ return { mode: "flat", domains: [], individualFiles: entries };
1055
+ }
1056
+ const domains = scanDomains(projectDir, dir, indexFilename, maxDepth);
1057
+ const rootFiles = collectRootFiles(projectDir, dir, indexFilename);
1058
+ const sourcesEntries = [];
1059
+ for (const source of knowledgeConfig.sources) {
1060
+ const fullPath = join2(projectDir, source);
1061
+ if (!existsSync(fullPath))
1062
+ continue;
1063
+ try {
1064
+ const stat = statSync(fullPath);
1065
+ if (stat.isFile() && extname(source) === ".md") {
1066
+ sourcesEntries.push({
1067
+ filename: source,
1068
+ summary: extractSummary(fullPath)
1069
+ });
1070
+ }
1071
+ } catch {}
1072
+ }
1073
+ const individualFiles = [...rootFiles, ...sourcesEntries];
1074
+ return { mode: "domain", domains, individualFiles };
1075
+ }
942
1076
 
943
1077
  // src/lib/prompt-reader.ts
944
1078
  import { readFileSync as readFileSync3 } from "fs";
@@ -983,9 +1117,16 @@ var DEFAULT_TURN_START = `## Knowledge Context
983
1117
  ### \uC791\uC5C5 \uC804 \uD544\uC218
984
1118
 
985
1119
  - \uC544\uB798 **Available Knowledge** \uBAA9\uB85D\uC5D0\uC11C \uD604\uC7AC \uC791\uC5C5\uACFC \uAD00\uB828\uB41C \uBB38\uC11C\uB97C **\uBA3C\uC800** \uC77D\uC73C\uC138\uC694
1120
+ - \uB3C4\uBA54\uC778 \uD3F4\uB354 \uAD6C\uC870\uAC00 \uC788\uB2E4\uBA74 INDEX.md\uC758 \uC694\uC57D\uC744 \uCC38\uACE0\uD558\uC5EC \uD544\uC694\uD55C \uB178\uD2B8\uB9CC \uC120\uD0DD\uC801\uC73C\uB85C \uC77D\uC73C\uC138\uC694
986
1121
  - \uBB38\uC11C \uB0B4 [[\uB9C1\uD06C]]\uB97C \uB530\uB77C\uAC00\uBA70 \uAD00\uB828 \uB178\uD2B8\uB97C \uD0D0\uC0C9\uD558\uC138\uC694 -- \uB9C1\uD06C\uB97C \uB193\uCE58\uBA74 \uC911\uC694\uD55C \uB9E5\uB77D\uC744 \uC783\uC2B5\uB2C8\uB2E4
987
1122
  - \uC9C0\uC2DD \uD30C\uC77C\uC5D0 \uAE30\uB85D\uB41C \uC544\uD0A4\uD14D\uCC98 \uACB0\uC815, \uD328\uD134, \uC81C\uC57D\uC0AC\uD56D\uC744 \uBC18\uB4DC\uC2DC \uB530\uB974\uC138\uC694
988
1123
 
1124
+ ### \uAC1C\uBC1C \uC6D0\uCE59
1125
+
1126
+ - **TDD** (Test-Driven Development): \uD14C\uC2A4\uD2B8\uB97C \uBA3C\uC800 \uC791\uC131\uD558\uACE0(RED), \uAD6C\uD604\uD558\uC5EC \uD1B5\uACFC\uC2DC\uD0A8 \uB4A4(GREEN), \uB9AC\uD329\uD1A0\uB9C1\uD558\uC138\uC694
1127
+ - **DDD** (Domain-Driven Design): \uB3C4\uBA54\uC778 \uAC1C\uB150\uC744 \uCF54\uB4DC \uAD6C\uC870\uC5D0 \uBC18\uC601\uD558\uC138\uC694. \uD0C0\uC785\uACFC \uBAA8\uB4C8\uC740 \uBE44\uC988\uB2C8\uC2A4 \uB3C4\uBA54\uC778\uC744 \uAE30\uC900\uC73C\uB85C \uBD84\uB9AC\uD558\uC138\uC694
1128
+ - **\uD14C\uC2A4\uD2B8 \uCEE4\uBC84\uB9AC\uC9C0**: \uC0C8\uB85C \uC791\uC131\uD558\uAC70\uB098 \uBCC0\uACBD\uD55C \uCF54\uB4DC\uB294 \uD14C\uC2A4\uD2B8 \uCEE4\uBC84\uB9AC\uC9C0 80% \uC774\uC0C1\uC744 \uBAA9\uD45C\uB85C \uD558\uC138\uC694. \uAD6C\uD604 \uC804\uC5D0 \uD14C\uC2A4\uD2B8\uBD80\uD130 \uC791\uC131\uD558\uBA74 \uC790\uC5F0\uC2A4\uB7FD\uAC8C \uB2EC\uC131\uB429\uB2C8\uB2E4
1129
+
989
1130
  ### \uC6B0\uC120\uC21C\uC704
990
1131
 
991
1132
  - AGENTS.md\uC758 \uC9C0\uC2DC\uC0AC\uD56D\uC774 \uD56D\uC0C1 \uCD5C\uC6B0\uC120
@@ -999,8 +1140,10 @@ var DEFAULT_TURN_END = `## \uC791\uC5C5 \uB9C8\uBB34\uB9AC \uCCB4\uD06C\uB9AC\uC
999
1140
  ### \uD004\uB9AC\uD2F0 \uBCF4\uC7A5
1000
1141
 
1001
1142
  - [ ] \uBCC0\uACBD\uD55C \uCF54\uB4DC\uC5D0 \uB300\uD574 lint \uC2E4\uD589
1002
- - [ ] \uD0C0\uC785 \uC5D0\uB7EC \uD655\uC778
1143
+ - [ ] \uBCC0\uACBD\uD55C \uCF54\uB4DC\uC5D0 \uB300\uD574 formatter \uC2E4\uD589 (lint\uC640 \uBCC4\uAC1C)
1003
1144
  - [ ] \uAE30\uC874 \uD14C\uC2A4\uD2B8 \uD1B5\uACFC \uD655\uC778
1145
+ - [ ] \uBCC0\uACBD \uBC94\uC704 \uD655\uC778: \uC694\uCCAD\uACFC \uBB34\uAD00\uD55C \uD30C\uC77C\uC744 \uAC74\uB4DC\uB9AC\uC9C0 \uC54A\uC558\uB294\uAC00?
1146
+ - [ ] \uC0C8\uB85C \uC791\uC131\uD558\uAC70\uB098 \uBCC0\uACBD\uD55C \uCF54\uB4DC\uC758 \uD14C\uC2A4\uD2B8 \uCEE4\uBC84\uB9AC\uC9C0 80% \uC774\uC0C1 \uB2EC\uC131
1004
1147
 
1005
1148
  ### \uC9C0\uC2DD \uC815\uB9AC (Zettelkasten)
1006
1149
 
@@ -1020,13 +1163,14 @@ var DEFAULT_TURN_END = `## \uC791\uC5C5 \uB9C8\uBB34\uB9AC \uCCB4\uD06C\uB9AC\uC
1020
1163
  - [ ] \uC704 \uC0C1\uD669\uC5D0 \uD574\uB2F9\uD558\uB294 \uBC1C\uACAC\uC774 \uC788\uC5C8\uB2E4\uBA74 \uB178\uD2B8\uB97C \uC791\uC131\uD588\uB294\uAC00?
1021
1164
  - [ ] \uAD00\uB828 \uAE30\uC874 \uB178\uD2B8\uC5D0 [[\uB9C1\uD06C]]\uB97C \uCD94\uAC00\uD588\uB294\uAC00?
1022
1165
  - [ ] \uAE30\uC874 \uB178\uD2B8\uC758 \uB0B4\uC6A9\uC774 \uBCC0\uACBD\uC0AC\uD56D\uACFC \uBD88\uC77C\uCE58\uD558\uBA74 \uC5C5\uB370\uC774\uD2B8\uD588\uB294\uAC00?
1166
+ - [ ] \uB178\uD2B8\uB97C \uB3C4\uBA54\uC778 \uD3F4\uB354\uC5D0 \uC800\uC7A5\uD588\uB2E4\uBA74 \uD574\uB2F9 INDEX.md\uC5D0 \uCD94\uAC00\uD588\uB294\uAC00?
1023
1167
 
1024
1168
  #### \uB178\uD2B8 \uC791\uC131 \uADDC\uCE59
1025
1169
 
1026
1170
  - \uCCAB \uC904: \uBA85\uD655\uD55C \uC81C\uBAA9 (\`# Title\`)
1027
1171
  - \uD575\uC2EC \uB0B4\uC6A9\uC744 \uC790\uC2E0\uC758 \uC5B8\uC5B4\uB85C \uAC04\uACB0\uD558\uAC8C \uC11C\uC220
1028
1172
  - \uAD00\uB828 \uB178\uD2B8\uB97C \`[[relative/path/file.md]]\` \uD615\uD0DC\uC758 wikilink\uB85C \uC5F0\uACB0
1029
- - knowledge \uB514\uB809\uD1A0\uB9AC (\uAE30\uBCF8: \`docs/\`)\uC5D0 \uC800\uC7A5
1173
+ - knowledge \uB514\uB809\uD1A0\uB9AC (\uAE30\uBCF8: \`docs/\`)\uC5D0 \uC800\uC7A5. \uB3C4\uBA54\uC778 \uD3F4\uB354\uAC00 \uC788\uB2E4\uBA74 \uC801\uC808\uD55C \uB3C4\uBA54\uC778\uC5D0 \uC800\uC7A5
1030
1174
  `;
1031
1175
  var DEFAULT_ADR_TEMPLATE = `# ADR-NNN: [\uC81C\uBAA9]
1032
1176
 
@@ -1220,6 +1364,20 @@ var DEFAULT_INSIGHT_TEMPLATE = `# Insight: [\uBC1C\uACAC \uC81C\uBAA9]
1220
1364
 
1221
1365
  - [[\uAD00\uB828-insight.md]] / [[\uC601\uD5A5\uBC1B\uB294-\uD328\uD134.md]] / [[\uAD00\uB828-ADR.md]]
1222
1366
  `;
1367
+ var DEFAULT_INDEX_TEMPLATE = `# [Domain] Domain
1368
+
1369
+ Overview: [1-2 sentence description of this domain]
1370
+
1371
+ ## Notes
1372
+
1373
+ | File | Summary | Read When... |
1374
+ |------|---------|--------------|
1375
+ | [[example.md]] | Example summary | Working on X |
1376
+
1377
+ ## Related Domains
1378
+
1379
+ - [[../other-domain/INDEX.md]] -- Description
1380
+ `;
1223
1381
  var TEMPLATE_FILES = {
1224
1382
  "adr.md": DEFAULT_ADR_TEMPLATE,
1225
1383
  "pattern.md": DEFAULT_PATTERN_TEMPLATE,
@@ -1228,7 +1386,8 @@ var TEMPLATE_FILES = {
1228
1386
  "decision.md": DEFAULT_DECISION_TEMPLATE,
1229
1387
  "context.md": DEFAULT_CONTEXT_TEMPLATE,
1230
1388
  "runbook.md": DEFAULT_RUNBOOK_TEMPLATE,
1231
- "insight.md": DEFAULT_INSIGHT_TEMPLATE
1389
+ "insight.md": DEFAULT_INSIGHT_TEMPLATE,
1390
+ "index.md": DEFAULT_INDEX_TEMPLATE
1232
1391
  };
1233
1392
  function scaffoldIfNeeded(projectDir) {
1234
1393
  const contextDir = join3(projectDir, ".opencode", "context");
@@ -1318,9 +1477,8 @@ ${lines}` }];
1318
1477
  return;
1319
1478
  const turnStartPath = join4(directory, config.prompts.turnStart ?? join4(DEFAULTS.promptDir, DEFAULTS.turnStartFile));
1320
1479
  const turnStart = readPromptFile(turnStartPath);
1321
- const knowledgeSources = [config.knowledge.dir, ...config.knowledge.sources].filter((s) => Boolean(s));
1322
- const entries = buildKnowledgeIndex(directory, knowledgeSources);
1323
- const indexContent = formatKnowledgeIndex(entries);
1480
+ const knowledgeIndex = buildKnowledgeIndexV2(directory, config.knowledge);
1481
+ const indexContent = knowledgeIndex.mode === "flat" ? formatKnowledgeIndex(knowledgeIndex.individualFiles) : formatDomainIndex(knowledgeIndex);
1324
1482
  const combinedContent = [turnStart, indexContent].filter(Boolean).join(`
1325
1483
 
1326
1484
  `);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ksm0709/context",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "Intent tools for Bun",
5
5
  "author": {
6
6
  "name": "TaehoKang",