@ksm0709/context 0.0.18 → 0.0.19

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/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // @bun
2
2
  // src/index.ts
3
- import { join as join4 } from "path";
3
+ import { isAbsolute, join as join5 } from "path";
4
4
 
5
5
  // node_modules/jsonc-parser/lib/esm/impl/scanner.js
6
6
  function createScanner(text, ignoreTrivia = false) {
@@ -808,18 +808,19 @@ var ParseErrorCode;
808
808
 
809
809
  // src/lib/config.ts
810
810
  import { readFileSync } from "fs";
811
- import { join } from "path";
811
+ import { join as join2 } from "path";
812
812
 
813
813
  // src/constants.ts
814
814
  var DEFAULTS = {
815
- configPath: ".opencode/context/config.jsonc",
816
- promptDir: ".opencode/context/prompts",
815
+ configPath: ".context/config.jsonc",
816
+ promptDir: ".context/prompts",
817
817
  turnStartFile: "turn-start.md",
818
818
  turnEndFile: "turn-end.md",
819
819
  knowledgeSources: ["AGENTS.md"],
820
- templateDir: ".opencode/context/templates",
820
+ templateDir: ".context/templates",
821
821
  indexFilename: "INDEX.md",
822
- maxDomainDepth: 2
822
+ maxDomainDepth: 2,
823
+ knowledgeDir: "docs"
823
824
  };
824
825
  var LIMITS = {
825
826
  maxPromptFileSize: 64 * 1024,
@@ -830,12 +831,27 @@ var LIMITS = {
830
831
  maxIndexFileSize: 32 * 1024
831
832
  };
832
833
 
834
+ // src/lib/context-dir.ts
835
+ import { existsSync } from "fs";
836
+ import { join } from "path";
837
+ function resolveContextDir(projectDir) {
838
+ const nextContextDir = ".context";
839
+ if (existsSync(join(projectDir, nextContextDir))) {
840
+ return nextContextDir;
841
+ }
842
+ const legacyContextDir = ".opencode/context";
843
+ if (existsSync(join(projectDir, legacyContextDir))) {
844
+ return legacyContextDir;
845
+ }
846
+ return nextContextDir;
847
+ }
848
+
833
849
  // src/lib/config.ts
834
850
  function getDefaultConfig() {
835
851
  return {
836
852
  prompts: {
837
- turnStart: join(DEFAULTS.promptDir, DEFAULTS.turnStartFile),
838
- turnEnd: join(DEFAULTS.promptDir, DEFAULTS.turnEndFile)
853
+ turnStart: join2(DEFAULTS.promptDir, DEFAULTS.turnStartFile),
854
+ turnEnd: join2(DEFAULTS.promptDir, DEFAULTS.turnEndFile)
839
855
  },
840
856
  knowledge: {
841
857
  dir: "docs",
@@ -863,7 +879,7 @@ function mergeWithDefaults(partial) {
863
879
  };
864
880
  }
865
881
  function loadConfig(projectDir) {
866
- const configPath = join(projectDir, DEFAULTS.configPath);
882
+ const configPath = join2(projectDir, resolveContextDir(projectDir), "config.jsonc");
867
883
  try {
868
884
  const raw = readFileSync(configPath, "utf-8");
869
885
  const parsed = parse2(raw);
@@ -876,8 +892,8 @@ function loadConfig(projectDir) {
876
892
  }
877
893
 
878
894
  // src/lib/knowledge-index.ts
879
- import { readdirSync, readFileSync as readFileSync2, statSync, existsSync } from "fs";
880
- import { join as join2, relative, extname } from "path";
895
+ import { readdirSync, readFileSync as readFileSync2, statSync, existsSync as existsSync2 } from "fs";
896
+ import { join as join3, relative, extname } from "path";
881
897
  function extractSummary(filePath) {
882
898
  try {
883
899
  const content = readFileSync2(filePath, "utf-8");
@@ -900,7 +916,7 @@ function scanDir(dir, projectDir, depth, entries) {
900
916
  for (const item of items) {
901
917
  if (entries.length >= LIMITS.maxIndexEntries)
902
918
  break;
903
- const fullPath = join2(dir, item);
919
+ const fullPath = join3(dir, item);
904
920
  try {
905
921
  const stat = statSync(fullPath);
906
922
  if (stat.isDirectory()) {
@@ -920,8 +936,8 @@ function buildKnowledgeIndex(projectDir, sources) {
920
936
  for (const source of sources) {
921
937
  if (entries.length >= LIMITS.maxIndexEntries)
922
938
  break;
923
- const fullPath = join2(projectDir, source);
924
- if (!existsSync(fullPath))
939
+ const fullPath = join3(projectDir, source);
940
+ if (!existsSync2(fullPath))
925
941
  continue;
926
942
  try {
927
943
  const stat = statSync(fullPath);
@@ -950,7 +966,7 @@ function formatKnowledgeIndex(entries) {
950
966
  function countMdFiles(dir, indexFilename) {
951
967
  try {
952
968
  const items = readdirSync(dir);
953
- return items.filter((item) => extname(item) === ".md" && item !== indexFilename && statSync(join2(dir, item)).isFile()).length;
969
+ return items.filter((item) => extname(item) === ".md" && item !== indexFilename && statSync(join3(dir, item)).isFile()).length;
954
970
  } catch {
955
971
  return 0;
956
972
  }
@@ -961,12 +977,12 @@ function scanDomainsRecursive(baseDir, projectDir, indexFilename, currentDepth,
961
977
  try {
962
978
  const items = readdirSync(baseDir);
963
979
  for (const item of items) {
964
- const fullPath = join2(baseDir, item);
980
+ const fullPath = join3(baseDir, item);
965
981
  try {
966
982
  if (!statSync(fullPath).isDirectory())
967
983
  continue;
968
- const indexPath = join2(fullPath, indexFilename);
969
- if (existsSync(indexPath) && statSync(indexPath).isFile()) {
984
+ const indexPath = join3(fullPath, indexFilename);
985
+ if (existsSync2(indexPath) && statSync(indexPath).isFile()) {
970
986
  const rawContent = readFileSync2(indexPath, "utf-8");
971
987
  const indexContent = rawContent.slice(0, LIMITS.maxIndexFileSize);
972
988
  results.push({
@@ -982,8 +998,8 @@ function scanDomainsRecursive(baseDir, projectDir, indexFilename, currentDepth,
982
998
  } catch {}
983
999
  }
984
1000
  function scanDomains(projectDir, knowledgeDir, indexFilename, maxDepth) {
985
- const baseDir = join2(projectDir, knowledgeDir);
986
- if (!existsSync(baseDir))
1001
+ const baseDir = join3(projectDir, knowledgeDir);
1002
+ if (!existsSync2(baseDir))
987
1003
  return [];
988
1004
  const results = [];
989
1005
  scanDomainsRecursive(baseDir, projectDir, indexFilename, 1, maxDepth, results);
@@ -1020,14 +1036,14 @@ function formatDomainIndex(index) {
1020
1036
  `);
1021
1037
  }
1022
1038
  function collectRootFiles(projectDir, knowledgeDir, indexFilename) {
1023
- const baseDir = join2(projectDir, knowledgeDir);
1024
- if (!existsSync(baseDir))
1039
+ const baseDir = join3(projectDir, knowledgeDir);
1040
+ if (!existsSync2(baseDir))
1025
1041
  return [];
1026
1042
  const entries = [];
1027
1043
  try {
1028
1044
  const items = readdirSync(baseDir);
1029
1045
  for (const item of items) {
1030
- const fullPath = join2(baseDir, item);
1046
+ const fullPath = join3(baseDir, item);
1031
1047
  try {
1032
1048
  const stat = statSync(fullPath);
1033
1049
  if (stat.isFile() && extname(item) === ".md" && item !== indexFilename) {
@@ -1056,8 +1072,8 @@ function buildKnowledgeIndexV2(projectDir, knowledgeConfig) {
1056
1072
  const rootFiles = collectRootFiles(projectDir, dir, indexFilename);
1057
1073
  const sourcesEntries = [];
1058
1074
  for (const source of knowledgeConfig.sources) {
1059
- const fullPath = join2(projectDir, source);
1060
- if (!existsSync(fullPath))
1075
+ const fullPath = join3(projectDir, source);
1076
+ if (!existsSync2(fullPath))
1061
1077
  continue;
1062
1078
  try {
1063
1079
  const stat = statSync(fullPath);
@@ -1086,14 +1102,18 @@ function readPromptFile(filePath) {
1086
1102
  return "";
1087
1103
  }
1088
1104
  }
1105
+ function resolvePromptVariables(content, vars) {
1106
+ const normalized = (vars.knowledgeDir || "docs").replace(/\\/g, "/").replace(/\/+$/, "");
1107
+ return content.replaceAll("{{knowledgeDir}}", normalized);
1108
+ }
1089
1109
 
1090
1110
  // src/lib/scaffold.ts
1091
- import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync4, writeFileSync } from "fs";
1092
- import { join as join3 } from "path";
1111
+ import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync4, writeFileSync } from "fs";
1112
+ import { join as join4 } from "path";
1093
1113
  // package.json
1094
1114
  var package_default = {
1095
1115
  name: "@ksm0709/context",
1096
- version: "0.0.18",
1116
+ version: "0.0.19",
1097
1117
  author: {
1098
1118
  name: "TaehoKang",
1099
1119
  email: "ksm07091@gmail.com"
@@ -1108,6 +1128,11 @@ var package_default = {
1108
1128
  import: "./dist/index.js",
1109
1129
  types: "./dist/index.d.ts",
1110
1130
  default: "./dist/index.js"
1131
+ },
1132
+ "./omx": {
1133
+ import: "./dist/omx/index.mjs",
1134
+ types: "./dist/omx/index.d.ts",
1135
+ default: "./dist/omx/index.mjs"
1111
1136
  }
1112
1137
  },
1113
1138
  repository: {
@@ -1118,10 +1143,10 @@ var package_default = {
1118
1143
  access: "public"
1119
1144
  },
1120
1145
  scripts: {
1121
- build: "bun build ./src/index.ts --outdir dist --target bun && bun build ./src/cli/index.ts --outdir dist/cli --target bun",
1146
+ build: "bun build ./src/index.ts --outdir dist --target bun && bun build ./src/cli/index.ts --outdir dist/cli --target bun && bun build ./src/omx/index.ts --outdir dist/omx --target node --format esm --external jsonc-parser && mv dist/omx/index.js dist/omx/index.mjs",
1122
1147
  test: "vitest run",
1123
1148
  lint: "eslint src --ext .ts",
1124
- prepublishOnly: "bun build ./src/index.ts --outdir dist --target bun && bun build ./src/cli/index.ts --outdir dist/cli --target bun"
1149
+ prepublishOnly: "bun build ./src/index.ts --outdir dist --target bun && bun build ./src/cli/index.ts --outdir dist/cli --target bun && bun build ./src/omx/index.ts --outdir dist/omx --target node --format esm --external jsonc-parser && mv dist/omx/index.js dist/omx/index.mjs"
1125
1150
  },
1126
1151
  files: [
1127
1152
  "dist"
@@ -1130,7 +1155,6 @@ var package_default = {
1130
1155
  "@opencode-ai/plugin": ">=1.0.0"
1131
1156
  },
1132
1157
  dependencies: {
1133
- "@ksm0709/context": "^0.0.17",
1134
1158
  "jsonc-parser": "^3.0.0"
1135
1159
  },
1136
1160
  devDependencies: {
@@ -1156,8 +1180,8 @@ var DEFAULT_CONFIG = `{
1156
1180
  // Context Plugin Configuration
1157
1181
  // See: https://github.com/ksm0709/context
1158
1182
  "prompts": {
1159
- "turnStart": ".opencode/context/prompts/turn-start.md",
1160
- "turnEnd": ".opencode/context/prompts/turn-end.md"
1183
+ "turnStart": "prompts/turn-start.md",
1184
+ "turnEnd": "prompts/turn-end.md"
1161
1185
  },
1162
1186
  "knowledge": {
1163
1187
  "dir": "docs",
@@ -1215,21 +1239,21 @@ var DEFAULT_TURN_END = `## \uC791\uC5C5 \uB9C8\uBB34\uB9AC
1215
1239
 
1216
1240
  | \uC0C1\uD669 | \uD15C\uD50C\uB9BF | \uD30C\uC77C\uBA85 \uD328\uD134 |
1217
1241
  | ------------------------------- | --------------------------------------------------- | --------------------------- |
1218
- | \uC544\uD0A4\uD14D\uCC98/\uAE30\uC220 \uC2A4\uD0DD \uC911\uB300 \uACB0\uC815 | [ADR](.opencode/context/templates/adr.md) | \`adr-NNN-\uC81C\uBAA9.md\` |
1219
- | \uBC18\uBCF5 \uC0AC\uC6A9\uD560 \uCF54\uB4DC \uD328\uD134 \uBC1C\uACAC | [Pattern](.opencode/context/templates/pattern.md) | \`pattern-\uC81C\uBAA9.md\` |
1220
- | \uBE44\uC790\uBA85\uD55C \uBC84\uADF8 \uD574\uACB0 | [Bug](.opencode/context/templates/bug.md) | \`bug-\uC81C\uBAA9.md\` |
1221
- | \uC678\uBD80 API/\uB77C\uC774\uBE0C\uB7EC\uB9AC \uC608\uC0C1\uC678 \uB3D9\uC791 | [Gotcha](.opencode/context/templates/gotcha.md) | \`gotcha-\uB77C\uC774\uBE0C\uB7EC\uB9AC-\uC81C\uBAA9.md\` |
1222
- | \uC791\uC740 \uAE30\uC220\uC801 \uC120\uD0DD | [Decision](.opencode/context/templates/decision.md) | \`decision-\uC81C\uBAA9.md\` |
1223
- | \uBAA8\uB4C8/\uD504\uB85C\uC81D\uD2B8 \uAC1C\uC694 \uD544\uC694 | [Context](.opencode/context/templates/context.md) | \`context-\uC81C\uBAA9.md\` |
1224
- | \uBC18\uBCF5 \uAC00\uB2A5\uD55C \uD504\uB85C\uC138\uC2A4 \uC815\uB9BD | [Runbook](.opencode/context/templates/runbook.md) | \`runbook-\uC81C\uBAA9.md\` |
1225
- | \uC2E4\uD5D8/\uB514\uBC84\uAE45 \uC911 \uD559\uC2B5 | [Insight](.opencode/context/templates/insight.md) | \`insight-\uC81C\uBAA9.md\` |
1242
+ | \uC544\uD0A4\uD14D\uCC98/\uAE30\uC220 \uC2A4\uD0DD \uC911\uB300 \uACB0\uC815 | [ADR](.context/templates/adr.md) | \`adr-NNN-\uC81C\uBAA9.md\` |
1243
+ | \uBC18\uBCF5 \uC0AC\uC6A9\uD560 \uCF54\uB4DC \uD328\uD134 \uBC1C\uACAC | [Pattern](.context/templates/pattern.md) | \`pattern-\uC81C\uBAA9.md\` |
1244
+ | \uBE44\uC790\uBA85\uD55C \uBC84\uADF8 \uD574\uACB0 | [Bug](.context/templates/bug.md) | \`bug-\uC81C\uBAA9.md\` |
1245
+ | \uC678\uBD80 API/\uB77C\uC774\uBE0C\uB7EC\uB9AC \uC608\uC0C1\uC678 \uB3D9\uC791 | [Gotcha](.context/templates/gotcha.md) | \`gotcha-\uB77C\uC774\uBE0C\uB7EC\uB9AC-\uC81C\uBAA9.md\` |
1246
+ | \uC791\uC740 \uAE30\uC220\uC801 \uC120\uD0DD | [Decision](.context/templates/decision.md) | \`decision-\uC81C\uBAA9.md\` |
1247
+ | \uBAA8\uB4C8/\uD504\uB85C\uC81D\uD2B8 \uAC1C\uC694 \uD544\uC694 | [Context](.context/templates/context.md) | \`context-\uC81C\uBAA9.md\` |
1248
+ | \uBC18\uBCF5 \uAC00\uB2A5\uD55C \uD504\uB85C\uC138\uC2A4 \uC815\uB9BD | [Runbook](.context/templates/runbook.md) | \`runbook-\uC81C\uBAA9.md\` |
1249
+ | \uC2E4\uD5D8/\uB514\uBC84\uAE45 \uC911 \uD559\uC2B5 | [Insight](.context/templates/insight.md) | \`insight-\uC81C\uBAA9.md\` |
1226
1250
 
1227
1251
  \uD574\uB2F9 \uC0AC\uD56D\uC774 \uC5C6\uC73C\uBA74 \uC774 \uB2E8\uACC4\uB294 \uAC74\uB108\uB6F0\uC138\uC694.
1228
1252
 
1229
1253
  - \uAD00\uB828 \uD15C\uD50C\uB9BF \uD30C\uC77C\uC744 \uC77D\uACE0 \uADF8 \uAD6C\uC870\uC5D0 \uB9DE\uCDB0 \uB0B4\uC6A9\uC744 \uC815\uB9AC\uD558\uC138\uC694
1230
1254
  - \uB178\uD2B8 \uCCAB \uC904\uC740 \uBA85\uD655\uD55C \uC81C\uBAA9(\`# Title\`)\uC73C\uB85C \uC2DC\uC791\uD558\uC138\uC694
1231
1255
  - \uD575\uC2EC \uB0B4\uC6A9\uC744 \uC790\uAE30 \uC5B8\uC5B4\uB85C \uAC04\uACB0\uD558\uAC8C \uC11C\uC220\uD558\uACE0, \uAD00\uB828 \uB178\uD2B8\uB294 \`[[relative/path/file.md]]\` \uD615\uD0DC\uB85C \uC5F0\uACB0\uD558\uC138\uC694
1232
- - knowledge \uB514\uB809\uD1A0\uB9AC(\uAE30\uBCF8: \`docs/\`) \uB610\uB294 \uC801\uC808\uD55C \uB3C4\uBA54\uC778 \uD3F4\uB354\uC5D0 \uC800\uC7A5\uD558\uACE0, \uD544\uC694\uD55C \uACBD\uC6B0 \uAE30\uC874 INDEX.md\uB098 \uAD00\uB828 \uB178\uD2B8\uB97C \uD568\uAED8 \uAC31\uC2E0\uD558\uC138\uC694
1256
+ - knowledge \uB514\uB809\uD1A0\uB9AC(\`{{knowledgeDir}}/\`) \uB610\uB294 \uC801\uC808\uD55C \uB3C4\uBA54\uC778 \uD3F4\uB354\uC5D0 \uC800\uC7A5\uD558\uACE0, \uD544\uC694\uD55C \uACBD\uC6B0 \uAE30\uC874 INDEX.md\uB098 \uAD00\uB828 \uB178\uD2B8\uB97C \uD568\uAED8 \uAC31\uC2E0\uD558\uC138\uC694
1233
1257
 
1234
1258
  \uAE30\uC874 \uC124\uCE58\uC758 \uC0AC\uC6A9\uC790 \uD504\uB86C\uD504\uD2B8 \uD30C\uC77C\uC740 \uC790\uB3D9\uC73C\uB85C \uBC14\uB00C\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC0C8 \uAE30\uBCF8 \uD504\uB86C\uD504\uD2B8\uAC00 \uD544\uC694\uD558\uBA74 \`context update prompt\`\uB85C \uBA85\uC2DC\uC801\uC73C\uB85C \uC0C8\uB85C\uACE0\uCE68\uD558\uC138\uC694.
1235
1259
  `;
@@ -1451,20 +1475,20 @@ var TEMPLATE_FILES = {
1451
1475
  "index.md": DEFAULT_INDEX_TEMPLATE
1452
1476
  };
1453
1477
  function scaffoldIfNeeded(projectDir) {
1454
- const contextDir = join3(projectDir, ".opencode", "context");
1455
- if (existsSync2(contextDir)) {
1478
+ const contextDir = join4(projectDir, resolveContextDir(projectDir));
1479
+ if (existsSync3(contextDir)) {
1456
1480
  return false;
1457
1481
  }
1458
1482
  try {
1459
- const promptsDir = join3(contextDir, "prompts");
1483
+ const promptsDir = join4(contextDir, "prompts");
1460
1484
  mkdirSync(promptsDir, { recursive: true });
1461
- const templatesDir = join3(contextDir, "templates");
1485
+ const templatesDir = join4(contextDir, "templates");
1462
1486
  mkdirSync(templatesDir, { recursive: true });
1463
- writeFileSync(join3(contextDir, "config.jsonc"), DEFAULT_CONFIG, "utf-8");
1464
- writeFileSync(join3(promptsDir, DEFAULTS.turnStartFile), DEFAULT_TURN_START, "utf-8");
1465
- writeFileSync(join3(promptsDir, DEFAULTS.turnEndFile), DEFAULT_TURN_END, "utf-8");
1487
+ writeFileSync(join4(contextDir, "config.jsonc"), DEFAULT_CONFIG, "utf-8");
1488
+ writeFileSync(join4(promptsDir, DEFAULTS.turnStartFile), DEFAULT_TURN_START, "utf-8");
1489
+ writeFileSync(join4(promptsDir, DEFAULTS.turnEndFile), DEFAULT_TURN_END, "utf-8");
1466
1490
  for (const [filename, content] of Object.entries(TEMPLATE_FILES)) {
1467
- writeFileSync(join3(templatesDir, filename), content, "utf-8");
1491
+ writeFileSync(join4(templatesDir, filename), content, "utf-8");
1468
1492
  }
1469
1493
  writeVersion(contextDir, PLUGIN_VERSION);
1470
1494
  return true;
@@ -1474,25 +1498,25 @@ function scaffoldIfNeeded(projectDir) {
1474
1498
  }
1475
1499
  function getStoredVersion(projectDir) {
1476
1500
  try {
1477
- return readFileSync4(join3(projectDir, ".opencode", "context", ".version"), "utf-8").trim();
1501
+ return readFileSync4(join4(projectDir, resolveContextDir(projectDir), ".version"), "utf-8").trim();
1478
1502
  } catch {
1479
1503
  return null;
1480
1504
  }
1481
1505
  }
1482
1506
  function writeVersion(contextDir, version) {
1483
- writeFileSync(join3(contextDir, ".version"), version, "utf-8");
1507
+ writeFileSync(join4(contextDir, ".version"), version, "utf-8");
1484
1508
  }
1485
1509
  function autoUpdateTemplates(projectDir) {
1486
- const contextDir = join3(projectDir, ".opencode", "context");
1487
- if (!existsSync2(contextDir))
1510
+ const contextDir = join4(projectDir, resolveContextDir(projectDir));
1511
+ if (!existsSync3(contextDir))
1488
1512
  return [];
1489
1513
  const stored = getStoredVersion(projectDir);
1490
1514
  if (stored === PLUGIN_VERSION)
1491
1515
  return [];
1492
- mkdirSync(join3(contextDir, "templates"), { recursive: true });
1516
+ mkdirSync(join4(contextDir, "templates"), { recursive: true });
1493
1517
  const updated = [];
1494
1518
  for (const [filename, content] of Object.entries(TEMPLATE_FILES)) {
1495
- const filePath = join3(contextDir, "templates", filename);
1519
+ const filePath = join4(contextDir, "templates", filename);
1496
1520
  try {
1497
1521
  const existing = readFileSync4(filePath, "utf-8");
1498
1522
  if (existing === content)
@@ -1506,14 +1530,23 @@ function autoUpdateTemplates(projectDir) {
1506
1530
  }
1507
1531
 
1508
1532
  // src/index.ts
1533
+ function resolvePromptPath(directory, contextDir, promptPath) {
1534
+ if (isAbsolute(promptPath))
1535
+ return promptPath;
1536
+ if (promptPath.startsWith(".context/") || promptPath.startsWith(".opencode/")) {
1537
+ return join5(directory, promptPath);
1538
+ }
1539
+ return join5(directory, contextDir, promptPath);
1540
+ }
1509
1541
  var plugin = async ({ directory, client }) => {
1510
1542
  const scaffolded = scaffoldIfNeeded(directory);
1543
+ const contextDir = resolveContextDir(directory);
1511
1544
  if (scaffolded) {
1512
1545
  await client.app.log({
1513
1546
  body: {
1514
1547
  service: "context",
1515
1548
  level: "info",
1516
- message: "Scaffold created at .opencode/context/"
1549
+ message: `Scaffold created at ${contextDir}/`
1517
1550
  }
1518
1551
  });
1519
1552
  } else {
@@ -1536,8 +1569,10 @@ var plugin = async ({ directory, client }) => {
1536
1569
  const lastUserMsg = output.messages.filter((m) => m.info.role === "user").at(-1);
1537
1570
  if (!lastUserMsg)
1538
1571
  return;
1539
- const turnStartPath = join4(directory, config.prompts.turnStart ?? join4(DEFAULTS.promptDir, DEFAULTS.turnStartFile));
1540
- const turnStart = readPromptFile(turnStartPath) ?? "";
1572
+ const promptVars = { knowledgeDir: config.knowledge.dir ?? "docs" };
1573
+ const turnStartPath = resolvePromptPath(directory, contextDir, config.prompts.turnStart ?? join5(DEFAULTS.promptDir, DEFAULTS.turnStartFile));
1574
+ const turnStartRaw = readPromptFile(turnStartPath) ?? "";
1575
+ const turnStart = resolvePromptVariables(turnStartRaw, promptVars);
1541
1576
  const knowledgeIndex = buildKnowledgeIndexV2(directory, config.knowledge);
1542
1577
  const indexContent = knowledgeIndex.mode === "flat" ? formatKnowledgeIndex(knowledgeIndex.individualFiles) : formatDomainIndex(knowledgeIndex);
1543
1578
  const combinedContent = [turnStart, indexContent].filter(Boolean).join(`
@@ -1552,10 +1587,11 @@ var plugin = async ({ directory, client }) => {
1552
1587
  text: combinedContent
1553
1588
  });
1554
1589
  }
1555
- const turnEndPath = join4(directory, config.prompts.turnEnd ?? join4(DEFAULTS.promptDir, DEFAULTS.turnEndFile));
1556
- const turnEnd = readPromptFile(turnEndPath);
1557
- if (!turnEnd)
1590
+ const turnEndPath = resolvePromptPath(directory, contextDir, config.prompts.turnEnd ?? join5(DEFAULTS.promptDir, DEFAULTS.turnEndFile));
1591
+ const turnEndRaw = readPromptFile(turnEndPath);
1592
+ if (!turnEndRaw)
1558
1593
  return;
1594
+ const turnEnd = resolvePromptVariables(turnEndRaw, promptVars);
1559
1595
  const msgId = `context-turn-end-${Date.now()}`;
1560
1596
  output.messages.push({
1561
1597
  info: {