@prover-coder-ai/context-doc 1.0.8 → 1.0.10

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.
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ import { Effect } from "effect";
3
+ import { buildSyncProgram, parseArgs } from "./syncKnowledge.js";
4
+ const program = buildSyncProgram(parseArgs());
5
+ Effect.runSync(program);
@@ -37,12 +37,16 @@ const resolveSourceDir = (cwd, override, metaRoot) => pipe(Effect.sync(() => {
37
37
  : path.join(metaRoot, ".codex");
38
38
  const localSource = path.join(cwd, ".codex");
39
39
  const homeSource = path.join(os.homedir(), ".codex");
40
+ const localKnowledge = path.join(cwd, ".knowledge", ".codex");
41
+ const homeKnowledge = path.join(os.homedir(), ".knowledge", ".codex");
40
42
  const candidates = [
41
43
  override,
42
44
  envSource,
43
45
  metaCandidate,
44
46
  localSource,
45
47
  homeSource,
48
+ localKnowledge,
49
+ homeKnowledge,
46
50
  ].filter((candidate) => candidate !== undefined);
47
51
  const existing = candidates.find((candidate) => fs.existsSync(candidate));
48
52
  return { existing, candidates };
@@ -92,6 +96,17 @@ const selectRelevantFiles = (files, locator) => Effect.reduce(files, [], (acc, f
92
96
  }
93
97
  return acc;
94
98
  })));
99
+ const resolveLocator = (options) => pipe(readRepositoryUrl(options.cwd, options.repositoryUrlOverride), Effect.map((repositoryUrl) => buildProjectLocator(repositoryUrl, options.cwd)), Effect.catchAll(() => Effect.gen(function* (__) {
100
+ yield* __(Console.log("Codex repository url missing; falling back to cwd-only match"));
101
+ return buildProjectLocator(options.cwd, options.cwd);
102
+ })));
103
+ const copyCodexFiles = (sourceDir, destinationDir, locator) => Effect.gen(function* (_) {
104
+ yield* _(ensureDirectory(destinationDir));
105
+ const allJsonlFiles = yield* _(collectJsonlFiles(sourceDir));
106
+ const relevantFiles = yield* _(selectRelevantFiles(allJsonlFiles, locator));
107
+ yield* _(Effect.forEach(relevantFiles, (filePath) => copyRelevantFile(sourceDir, destinationDir, filePath)));
108
+ yield* _(Console.log(`Codex: copied ${relevantFiles.length} files from ${sourceDir} to ${destinationDir}`));
109
+ });
95
110
  // CHANGE: Extract Codex dialog sync into dedicated module for clarity.
96
111
  // WHY: Separate Codex-specific shell effects from other sync flows.
97
112
  // QUOTE(ТЗ): "вынеси в отдельный файл"
@@ -103,13 +118,12 @@ const selectRelevantFiles = (files, locator) => Effect.reduce(files, [], (acc, f
103
118
  // INVARIANT: ∀f ∈ copiedFiles: linesMatchProject(f, locator)
104
119
  // COMPLEXITY: O(n) time / O(n) space, n = |files|
105
120
  export const syncCodex = (options) => Effect.gen(function* (_) {
106
- const repositoryUrl = yield* _(readRepositoryUrl(options.cwd, options.repositoryUrlOverride));
121
+ const locator = yield* _(resolveLocator(options));
107
122
  const sourceDir = yield* _(resolveSourceDir(options.cwd, options.sourceDir, options.metaRoot));
108
123
  const destinationDir = options.destinationDir ?? path.join(options.cwd, ".knowledge", ".codex");
109
- yield* _(ensureDirectory(destinationDir));
110
- const locator = buildProjectLocator(repositoryUrl, options.cwd);
111
- const allJsonlFiles = yield* _(collectJsonlFiles(sourceDir));
112
- const relevantFiles = yield* _(selectRelevantFiles(allJsonlFiles, locator));
113
- yield* _(Effect.forEach(relevantFiles, (filePath) => copyRelevantFile(sourceDir, destinationDir, filePath)));
114
- yield* _(Console.log(`Synced ${relevantFiles.length} dialog files into .knowledge/.codex from ${sourceDir}`));
124
+ if (path.resolve(sourceDir) === path.resolve(destinationDir)) {
125
+ yield* _(Console.log("Codex source equals destination; skipping copy to avoid duplicates"));
126
+ return;
127
+ }
128
+ yield* _(copyCodexFiles(sourceDir, destinationDir, locator));
115
129
  }).pipe(Effect.catchAll((error) => Console.log(`Codex source not found; skipped syncing Codex dialog files (${error.reason})`)));
@@ -34,18 +34,33 @@ const resolveQwenSourceDir = (cwd, override, metaRoot) => Effect.gen(function* (
34
34
  : metaRoot.endsWith(".qwen")
35
35
  ? metaRoot
36
36
  : path.join(metaRoot, ".qwen");
37
+ const metaKnowledge = path.join(metaRoot ?? "", ".knowledge", ".qwen");
37
38
  const homeBase = path.join(os.homedir(), ".qwen");
39
+ const homeKnowledge = path.join(os.homedir(), ".knowledge", ".qwen");
38
40
  const candidates = [
39
41
  override,
40
42
  envSource,
41
43
  baseFromMeta ? path.join(baseFromMeta, "tmp", hash) : undefined,
42
44
  path.join(cwd, ".qwen", "tmp", hash),
45
+ path.join(cwd, ".knowledge", ".qwen", "tmp", hash),
46
+ metaKnowledge ? path.join(metaKnowledge, "tmp", hash) : undefined,
43
47
  path.join(homeBase, "tmp", hash),
48
+ path.join(homeKnowledge, "tmp", hash),
44
49
  ].filter((candidate) => candidate !== undefined);
45
50
  const found = candidates.find((candidate) => fs.existsSync(candidate));
46
51
  if (found === undefined) {
47
- return yield* _(Effect.fail(syncError(".qwen", `Qwen source directory is missing; checked: ${candidates.join(", ")}`)));
52
+ return yield* _(Effect.fail(syncError(".qwen", `Qwen source directory is missing for hash ${hash}`)));
48
53
  }
49
54
  return found;
50
55
  });
51
- export const syncQwen = (options) => pipe(resolveQwenSourceDir(options.cwd, options.qwenSourceDir, options.metaRoot), Effect.tap((qwenSource) => Console.log(`Qwen source resolved: ${qwenSource}`)), Effect.flatMap((qwenSource) => pipe(ensureDirectory(path.join(options.cwd, ".knowledge", ".qwen")), Effect.flatMap(() => copyDirectoryJsonOnly(qwenSource, path.join(options.cwd, ".knowledge", ".qwen"))), Effect.flatMap((copiedCount) => Console.log(`Synced ${copiedCount} Qwen dialog files into .knowledge/.qwen`)))), Effect.catchAll((error) => Console.log(`Qwen source not found; skipped syncing Qwen dialog files (${error.reason})`)));
56
+ export const syncQwen = (options) => pipe(resolveQwenSourceDir(options.cwd, options.qwenSourceDir, options.metaRoot), Effect.flatMap((qwenSource) => Effect.gen(function* (_) {
57
+ const destination = path.join(options.cwd, ".knowledge", ".qwen");
58
+ if (path.resolve(qwenSource) === path.resolve(destination)) {
59
+ yield* _(Console.log("Qwen source equals destination; skipping copy to avoid duplicates"));
60
+ return;
61
+ }
62
+ yield* _(ensureDirectory(destination));
63
+ const qwenRoot = path.dirname(path.dirname(qwenSource));
64
+ const copiedCount = yield* _(copyDirectoryJsonOnly(qwenSource, destination));
65
+ yield* _(Console.log(`Qwen: copied ${copiedCount} files from ${qwenRoot} to ${destination}`));
66
+ })), Effect.catchAll((error) => Console.log(`Qwen source not found; skipped syncing Qwen dialog files (${error.reason})`)));
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import { pathToFileURL } from "node:url";
3
2
  import { Effect } from "effect";
4
3
  import { syncCodex } from "./codexSync.js";
5
4
  import { syncQwen } from "./qwenSync.js";
@@ -8,14 +7,7 @@ export const buildSyncProgram = (options) => Effect.gen(function* (_) {
8
7
  yield* _(syncCodex(options));
9
8
  yield* _(syncQwen(options));
10
9
  });
11
- const isMainModule = () => {
12
- const entry = process.argv[1];
13
- if (entry === undefined) {
14
- return false;
15
- }
16
- return import.meta.url === pathToFileURL(entry).href;
17
- };
18
- const parseArgs = () => {
10
+ export const parseArgs = () => {
19
11
  const argv = process.argv.slice(2);
20
12
  let result = { cwd: process.cwd() };
21
13
  const mapping = {
@@ -42,7 +34,3 @@ const parseArgs = () => {
42
34
  }
43
35
  return result;
44
36
  };
45
- if (isMainModule()) {
46
- const program = buildSyncProgram(parseArgs());
47
- Effect.runSync(program);
48
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prover-coder-ai/context-doc",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -8,11 +8,11 @@
8
8
  "build": "tsc -p tsconfig.build.json",
9
9
  "lint": "npx --no-install @ton-ai-core/vibecode-linter src/",
10
10
  "test": "npx --no-install @ton-ai-core/vibecode-linter tests/ && vitest run --passWithNoTests",
11
- "sync:knowledge": "tsx src/shell/syncKnowledge.ts",
11
+ "sync:knowledge": "npm run build && PKG=prover-coder-ai-context-doc-$(node -p \"require('./package.json').version\").tgz && rm -f \"$PKG\" && npm pack >/dev/null && npx -y -p \"./$PKG\" context-doc",
12
12
  "release": "npm run build && npm run lint && npm version patch && npm publish --access public"
13
13
  },
14
14
  "bin": {
15
- "context-doc": "dist/shell/syncKnowledge.js"
15
+ "context-doc": "dist/shell/cli.js"
16
16
  },
17
17
  "repository": {
18
18
  "type": "git",
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import { Effect } from "effect";
3
+ import { buildSyncProgram, parseArgs } from "./syncKnowledge.js";
4
+
5
+ const program = buildSyncProgram(parseArgs());
6
+
7
+ Effect.runSync(program);
@@ -57,12 +57,17 @@ const resolveSourceDir = (
57
57
  : path.join(metaRoot, ".codex");
58
58
  const localSource = path.join(cwd, ".codex");
59
59
  const homeSource = path.join(os.homedir(), ".codex");
60
+ const localKnowledge = path.join(cwd, ".knowledge", ".codex");
61
+ const homeKnowledge = path.join(os.homedir(), ".knowledge", ".codex");
62
+
60
63
  const candidates = [
61
64
  override,
62
65
  envSource,
63
66
  metaCandidate,
64
67
  localSource,
65
68
  homeSource,
69
+ localKnowledge,
70
+ homeKnowledge,
66
71
  ].filter((candidate): candidate is string => candidate !== undefined);
67
72
 
68
73
  const existing = candidates.find((candidate) => fs.existsSync(candidate));
@@ -150,6 +155,47 @@ const selectRelevantFiles = (
150
155
  ),
151
156
  );
152
157
 
158
+ const resolveLocator = (
159
+ options: SyncOptions,
160
+ ): Effect.Effect<ProjectLocator, SyncError> =>
161
+ pipe(
162
+ readRepositoryUrl(options.cwd, options.repositoryUrlOverride),
163
+ Effect.map((repositoryUrl) =>
164
+ buildProjectLocator(repositoryUrl, options.cwd),
165
+ ),
166
+ Effect.catchAll(() =>
167
+ Effect.gen(function* (__) {
168
+ yield* __(
169
+ Console.log(
170
+ "Codex repository url missing; falling back to cwd-only match",
171
+ ),
172
+ );
173
+ return buildProjectLocator(options.cwd, options.cwd);
174
+ }),
175
+ ),
176
+ );
177
+
178
+ const copyCodexFiles = (
179
+ sourceDir: string,
180
+ destinationDir: string,
181
+ locator: ProjectLocator,
182
+ ): Effect.Effect<void, SyncError> =>
183
+ Effect.gen(function* (_) {
184
+ yield* _(ensureDirectory(destinationDir));
185
+ const allJsonlFiles = yield* _(collectJsonlFiles(sourceDir));
186
+ const relevantFiles = yield* _(selectRelevantFiles(allJsonlFiles, locator));
187
+ yield* _(
188
+ Effect.forEach(relevantFiles, (filePath) =>
189
+ copyRelevantFile(sourceDir, destinationDir, filePath),
190
+ ),
191
+ );
192
+ yield* _(
193
+ Console.log(
194
+ `Codex: copied ${relevantFiles.length} files from ${sourceDir} to ${destinationDir}`,
195
+ ),
196
+ );
197
+ });
198
+
153
199
  // CHANGE: Extract Codex dialog sync into dedicated module for clarity.
154
200
  // WHY: Separate Codex-specific shell effects from other sync flows.
155
201
  // QUOTE(ТЗ): "вынеси в отдельный файл"
@@ -164,32 +210,23 @@ export const syncCodex = (
164
210
  options: SyncOptions,
165
211
  ): Effect.Effect<void, SyncError> =>
166
212
  Effect.gen(function* (_) {
167
- const repositoryUrl = yield* _(
168
- readRepositoryUrl(options.cwd, options.repositoryUrlOverride),
169
- );
213
+ const locator = yield* _(resolveLocator(options));
170
214
  const sourceDir = yield* _(
171
215
  resolveSourceDir(options.cwd, options.sourceDir, options.metaRoot),
172
216
  );
173
217
  const destinationDir =
174
218
  options.destinationDir ?? path.join(options.cwd, ".knowledge", ".codex");
175
219
 
176
- yield* _(ensureDirectory(destinationDir));
177
-
178
- const locator = buildProjectLocator(repositoryUrl, options.cwd);
179
- const allJsonlFiles = yield* _(collectJsonlFiles(sourceDir));
180
- const relevantFiles = yield* _(selectRelevantFiles(allJsonlFiles, locator));
181
-
182
- yield* _(
183
- Effect.forEach(relevantFiles, (filePath) =>
184
- copyRelevantFile(sourceDir, destinationDir, filePath),
185
- ),
186
- );
220
+ if (path.resolve(sourceDir) === path.resolve(destinationDir)) {
221
+ yield* _(
222
+ Console.log(
223
+ "Codex source equals destination; skipping copy to avoid duplicates",
224
+ ),
225
+ );
226
+ return;
227
+ }
187
228
 
188
- yield* _(
189
- Console.log(
190
- `Synced ${relevantFiles.length} dialog files into .knowledge/.codex from ${sourceDir}`,
191
- ),
192
- );
229
+ yield* _(copyCodexFiles(sourceDir, destinationDir, locator));
193
230
  }).pipe(
194
231
  Effect.catchAll((error) =>
195
232
  Console.log(
@@ -49,14 +49,19 @@ const resolveQwenSourceDir = (
49
49
  : metaRoot.endsWith(".qwen")
50
50
  ? metaRoot
51
51
  : path.join(metaRoot, ".qwen");
52
+ const metaKnowledge = path.join(metaRoot ?? "", ".knowledge", ".qwen");
52
53
  const homeBase = path.join(os.homedir(), ".qwen");
54
+ const homeKnowledge = path.join(os.homedir(), ".knowledge", ".qwen");
53
55
 
54
56
  const candidates = [
55
57
  override,
56
58
  envSource,
57
59
  baseFromMeta ? path.join(baseFromMeta, "tmp", hash) : undefined,
58
60
  path.join(cwd, ".qwen", "tmp", hash),
61
+ path.join(cwd, ".knowledge", ".qwen", "tmp", hash),
62
+ metaKnowledge ? path.join(metaKnowledge, "tmp", hash) : undefined,
59
63
  path.join(homeBase, "tmp", hash),
64
+ path.join(homeKnowledge, "tmp", hash),
60
65
  ].filter((candidate): candidate is string => candidate !== undefined);
61
66
 
62
67
  const found = candidates.find((candidate) => fs.existsSync(candidate));
@@ -66,7 +71,7 @@ const resolveQwenSourceDir = (
66
71
  Effect.fail(
67
72
  syncError(
68
73
  ".qwen",
69
- `Qwen source directory is missing; checked: ${candidates.join(", ")}`,
74
+ `Qwen source directory is missing for hash ${hash}`,
70
75
  ),
71
76
  ),
72
77
  );
@@ -80,24 +85,29 @@ export const syncQwen = (
80
85
  ): Effect.Effect<void, SyncError> =>
81
86
  pipe(
82
87
  resolveQwenSourceDir(options.cwd, options.qwenSourceDir, options.metaRoot),
83
- Effect.tap((qwenSource) =>
84
- Console.log(`Qwen source resolved: ${qwenSource}`),
85
- ),
86
88
  Effect.flatMap((qwenSource) =>
87
- pipe(
88
- ensureDirectory(path.join(options.cwd, ".knowledge", ".qwen")),
89
- Effect.flatMap(() =>
90
- copyDirectoryJsonOnly(
91
- qwenSource,
92
- path.join(options.cwd, ".knowledge", ".qwen"),
93
- ),
94
- ),
95
- Effect.flatMap((copiedCount) =>
89
+ Effect.gen(function* (_) {
90
+ const destination = path.join(options.cwd, ".knowledge", ".qwen");
91
+ if (path.resolve(qwenSource) === path.resolve(destination)) {
92
+ yield* _(
93
+ Console.log(
94
+ "Qwen source equals destination; skipping copy to avoid duplicates",
95
+ ),
96
+ );
97
+ return;
98
+ }
99
+
100
+ yield* _(ensureDirectory(destination));
101
+ const qwenRoot = path.dirname(path.dirname(qwenSource));
102
+ const copiedCount = yield* _(
103
+ copyDirectoryJsonOnly(qwenSource, destination),
104
+ );
105
+ yield* _(
96
106
  Console.log(
97
- `Synced ${copiedCount} Qwen dialog files into .knowledge/.qwen`,
107
+ `Qwen: copied ${copiedCount} files from ${qwenRoot} to ${destination}`,
98
108
  ),
99
- ),
100
- ),
109
+ );
110
+ }),
101
111
  ),
102
112
  Effect.catchAll((error) =>
103
113
  Console.log(
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import { pathToFileURL } from "node:url";
3
2
  import { Effect } from "effect";
4
3
  import { syncCodex } from "./codexSync.js";
5
4
  import { syncQwen } from "./qwenSync.js";
@@ -14,17 +13,7 @@ export const buildSyncProgram = (
14
13
  yield* _(syncQwen(options));
15
14
  });
16
15
 
17
- const isMainModule = (): boolean => {
18
- const entry = process.argv[1];
19
-
20
- if (entry === undefined) {
21
- return false;
22
- }
23
-
24
- return import.meta.url === pathToFileURL(entry).href;
25
- };
26
-
27
- const parseArgs = (): SyncOptions => {
16
+ export const parseArgs = (): SyncOptions => {
28
17
  const argv = process.argv.slice(2);
29
18
  let result: SyncOptions = { cwd: process.cwd() };
30
19
 
@@ -55,9 +44,3 @@ const parseArgs = (): SyncOptions => {
55
44
 
56
45
  return result;
57
46
  };
58
-
59
- if (isMainModule()) {
60
- const program = buildSyncProgram(parseArgs());
61
-
62
- Effect.runSync(program);
63
- }