@aigne/doc-smith 0.1.3 → 0.2.0

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.
@@ -1,67 +1,14 @@
1
1
  import { access, readFile } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { glob } from "glob";
4
-
5
- // Default file patterns for inclusion and exclusion
6
- const DEFAULT_INCLUDE_PATTERNS = [
7
- "*.py",
8
- "*.js",
9
- "*.jsx",
10
- "*.ts",
11
- "*.tsx",
12
- "*.go",
13
- "*.java",
14
- "*.pyi",
15
- "*.pyx",
16
- "*.c",
17
- "*.cc",
18
- "*.cpp",
19
- "*.h",
20
- "*.md",
21
- "*.rst",
22
- "*.json",
23
- "*Dockerfile",
24
- "*Makefile",
25
- "*.yaml",
26
- "*.yml",
27
- ];
28
-
29
- const DEFAULT_EXCLUDE_PATTERNS = [
30
- "aigne-docs/**",
31
- "doc-smith/**",
32
- "assets/**",
33
- "data/**",
34
- "images/**",
35
- "public/**",
36
- "static/**",
37
- "**/vendor/**",
38
- "temp/**",
39
- "**/*docs/**",
40
- "**/*doc/**",
41
- "**/*venv/**",
42
- "*.venv/**",
43
- "*test*",
44
- "**/*test/**",
45
- "**/*tests/**",
46
- "**/*examples/**",
47
- "**/playgrounds/**",
48
- "v1/**",
49
- "**/dist/**",
50
- "**/*build/**",
51
- "**/*experimental/**",
52
- "**/*deprecated/**",
53
- "**/*misc/**",
54
- "**/*legacy/**",
55
- ".git/**",
56
- ".github/**",
57
- ".next/**",
58
- ".vscode/**",
59
- "**/*obj/**",
60
- "**/*bin/**",
61
- "**/*node_modules/**",
62
- "*.log",
63
- "**/*test.*",
64
- ];
4
+ import {
5
+ getCurrentGitHead,
6
+ getModifiedFilesBetweenCommits,
7
+ } from "../utils/utils.mjs";
8
+ import {
9
+ DEFAULT_INCLUDE_PATTERNS,
10
+ DEFAULT_EXCLUDE_PATTERNS,
11
+ } from "../utils/constants.mjs";
65
12
 
66
13
  /**
67
14
  * Load .gitignore patterns from a directory
@@ -158,6 +105,7 @@ export default async function loadSources({
158
105
  "doc-path": docPath,
159
106
  boardId,
160
107
  useDefaultPatterns = true,
108
+ lastGitHead,
161
109
  } = {}) {
162
110
  let files = Array.isArray(sources) ? [...sources] : [];
163
111
 
@@ -224,9 +172,11 @@ export default async function loadSources({
224
172
  const sourceFiles = await Promise.all(
225
173
  files.map(async (file) => {
226
174
  const content = await readFile(file, "utf8");
227
- allSources += `// sourceId: ${file}\n${content}\n`;
175
+ // Convert absolute path to relative path from project root
176
+ const relativePath = path.relative(process.cwd(), file);
177
+ allSources += `// sourceId: ${relativePath}\n${content}\n`;
228
178
  return {
229
- sourceId: file,
179
+ sourceId: relativePath,
230
180
  content,
231
181
  };
232
182
  })
@@ -280,12 +230,34 @@ export default async function loadSources({
280
230
  }
281
231
  }
282
232
 
233
+ // Get git change detection data
234
+ let modifiedFiles = [];
235
+ let currentGitHead = null;
236
+
237
+ if (lastGitHead) {
238
+ try {
239
+ currentGitHead = getCurrentGitHead();
240
+ if (currentGitHead && currentGitHead !== lastGitHead) {
241
+ modifiedFiles = getModifiedFilesBetweenCommits(
242
+ lastGitHead,
243
+ currentGitHead
244
+ );
245
+ console.log(
246
+ `Detected ${modifiedFiles.length} modified files since last generation`
247
+ );
248
+ }
249
+ } catch (error) {
250
+ console.warn("Failed to detect git changes:", error.message);
251
+ }
252
+ }
253
+
283
254
  return {
284
255
  datasourcesList: sourceFiles,
285
256
  datasources: allSources,
286
257
  content,
287
258
  originalStructurePlan,
288
259
  files,
260
+ modifiedFiles,
289
261
  };
290
262
  }
291
263
 
@@ -324,6 +296,10 @@ loadSources.input_schema = {
324
296
  type: "string",
325
297
  description: "The board ID for boardId-flattenedPath format matching",
326
298
  },
299
+ lastGitHead: {
300
+ type: "string",
301
+ description: "The git HEAD from last generation for change detection",
302
+ },
327
303
  },
328
304
  required: [],
329
305
  };
@@ -349,5 +325,10 @@ loadSources.output_schema = {
349
325
  items: { type: "string" },
350
326
  description: "Array of file paths that were loaded",
351
327
  },
328
+ modifiedFiles: {
329
+ type: "array",
330
+ items: { type: "string" },
331
+ description: "Array of modified files since last generation",
332
+ },
352
333
  },
353
334
  };
@@ -9,8 +9,10 @@ import { homedir } from "node:os";
9
9
  import { parse, stringify } from "yaml";
10
10
  import { execSync } from "node:child_process";
11
11
  import { basename } from "node:path";
12
+ import { loadConfigFromFile, saveValueToConfig } from "../utils/utils.mjs";
12
13
 
13
14
  const WELLKNOWN_SERVICE_PATH_PREFIX = "/.well-known/service";
15
+ const DEFAULT_APP_URL = "https://docsmith.aigne.io";
14
16
 
15
17
  /**
16
18
  * Get project name from git repository or current directory
@@ -116,51 +118,50 @@ async function getAccessToken(appUrl) {
116
118
  return accessToken;
117
119
  }
118
120
 
119
- /**
120
- * Save boardId to config.yaml file if it was auto-created
121
- * @param {string} boardId - The original boardId (may be empty)
122
- * @param {string} newBoardId - The boardId returned from publishDocsFn
123
- */
124
- async function saveBoardIdToInput(boardId, newBoardId) {
125
- // Only save if boardId was auto-created
126
- if (!boardId && newBoardId) {
127
- try {
128
- const docSmithDir = join(process.cwd(), "doc-smith");
129
- if (!existsSync(docSmithDir)) {
130
- mkdirSync(docSmithDir, { recursive: true });
131
- }
132
-
133
- const inputFilePath = join(docSmithDir, "config.yaml");
134
- let fileContent = "";
135
-
136
- // Read existing file content if it exists
137
- if (existsSync(inputFilePath)) {
138
- fileContent = await readFile(inputFilePath, "utf8");
139
- }
140
-
141
- // Check if boardId already exists in the file
142
- const boardIdRegex = /^boardId:\s*.*$/m;
143
- const newBoardIdLine = `boardId: ${newBoardId}`;
144
-
145
- if (boardIdRegex.test(fileContent)) {
146
- // Replace existing boardId line
147
- fileContent = fileContent.replace(boardIdRegex, newBoardIdLine);
148
- } else {
149
- // Add boardId to the end of file
150
- if (fileContent && !fileContent.endsWith("\n")) {
151
- fileContent += "\n";
152
- }
153
- fileContent += newBoardIdLine + "\n";
154
- }
121
+ export default async function publishDocs(
122
+ { docsDir, appUrl, boardId },
123
+ options
124
+ ) {
125
+ // Check if appUrl is default and not saved in config
126
+ const config = await loadConfigFromFile();
127
+ const isDefaultAppUrl = appUrl === DEFAULT_APP_URL;
128
+ const hasAppUrlInConfig = config && config.appUrl;
129
+
130
+ if (isDefaultAppUrl && !hasAppUrlInConfig) {
131
+ console.log("\n=== Document Publishing Platform Selection ===");
132
+ console.log(
133
+ "Please select the platform where you want to publish your documents:"
134
+ );
155
135
 
156
- await writeFile(inputFilePath, fileContent);
157
- } catch (error) {
158
- console.warn("Failed to save board ID to config.yaml:", error.message);
136
+ const choice = await options.prompts.select({
137
+ message: "Select publishing platform:",
138
+ choices: [
139
+ {
140
+ name: "Use official platform (docsmith.aigne.io) - Documents will be publicly accessible, suitable for open source projects",
141
+ value: "default",
142
+ },
143
+ {
144
+ name: "Use private platform - Deploy your own Discuss Kit instance, suitable for internal documentation",
145
+ value: "custom",
146
+ },
147
+ ],
148
+ });
149
+
150
+ if (choice === "custom") {
151
+ appUrl = await options.prompts.input({
152
+ message: "Please enter your Discuss Kit platform URL:",
153
+ validate: (input) => {
154
+ try {
155
+ new URL(input);
156
+ return true;
157
+ } catch {
158
+ return "Please enter a valid URL";
159
+ }
160
+ },
161
+ });
159
162
  }
160
163
  }
161
- }
162
164
 
163
- export default async function publishDocs({ docsDir, appUrl, boardId }) {
164
165
  const accessToken = await getAccessToken(appUrl);
165
166
 
166
167
  process.env.DOC_ROOT_DIR = docsDir;
@@ -179,8 +180,16 @@ export default async function publishDocs({ docsDir, appUrl, boardId }) {
179
180
  autoCreateBoard: !boardId,
180
181
  });
181
182
 
182
- // Save boardId to config.yaml if it was auto-created
183
- await saveBoardIdToInput(boardId, newBoardId);
183
+ // Save values to config.yaml if publish was successful
184
+ if (success) {
185
+ // Save appUrl to config
186
+ await saveValueToConfig("appUrl", appUrl);
187
+
188
+ // Save boardId to config if it was auto-created
189
+ if (!boardId && newBoardId) {
190
+ await saveValueToConfig("boardId", newBoardId);
191
+ }
192
+ }
184
193
 
185
194
  return {
186
195
  publishResult: {
@@ -199,9 +208,7 @@ publishDocs.input_schema = {
199
208
  appUrl: {
200
209
  type: "string",
201
210
  description: "The url of the app",
202
- default:
203
- // "https://bbqawfllzdt3pahkdsrsone6p3wpxcwp62vlabtawfu.did.abtnet.io",
204
- "https://www.staging.arcblock.io",
211
+ default: DEFAULT_APP_URL,
205
212
  },
206
213
  boardId: {
207
214
  type: "string",
@@ -1,5 +1,6 @@
1
1
  import { writeFile, readdir, unlink } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
+ import { getCurrentGitHead, saveGitHeadToConfig } from "../utils/utils.mjs";
3
4
 
4
5
  /**
5
6
  * @param {Object} params
@@ -16,6 +17,14 @@ export default async function saveDocs({
16
17
  }) {
17
18
  const results = [];
18
19
 
20
+ // Save current git HEAD to config.yaml for change detection
21
+ try {
22
+ const gitHead = getCurrentGitHead();
23
+ await saveGitHeadToConfig(gitHead);
24
+ } catch (err) {
25
+ console.warn("Failed to save git HEAD:", err.message);
26
+ }
27
+
19
28
  // Generate _sidebar.md
20
29
  try {
21
30
  const sidebar = generateSidebar(structurePlan);
@@ -5,6 +5,9 @@ alias:
5
5
  - p
6
6
  description: Publish the documentation to Discuss Kit
7
7
  skills:
8
+ - url: ./input-generator.mjs
9
+ default_input:
10
+ skipIfExists: true
8
11
  - load-config.mjs
9
12
  - publish-docs.mjs
10
13
  input_schema:
@@ -1,14 +1,28 @@
1
+ import { normalizePath, toRelativePath } from "../utils/utils.mjs";
2
+
1
3
  export default function transformDetailDatasources({
2
4
  sourceIds,
3
5
  datasourcesList,
4
6
  }) {
5
- // Build a map for fast lookup
7
+ // Build a map for fast lookup, with path normalization for compatibility
6
8
  const dsMap = Object.fromEntries(
7
- (datasourcesList || []).map((ds) => [ds.sourceId, ds.content])
9
+ (datasourcesList || []).map((ds) => {
10
+ const normalizedSourceId = normalizePath(ds.sourceId);
11
+ return [normalizedSourceId, ds.content];
12
+ })
8
13
  );
9
- // Collect formatted contents in order
14
+
15
+ // Collect formatted contents in order, with path normalization
10
16
  const contents = (sourceIds || [])
11
- .filter((id) => dsMap[id])
12
- .map((id) => `// sourceId: ${id}\n${dsMap[id]}\n`);
17
+ .filter((id) => {
18
+ const normalizedId = normalizePath(id);
19
+ return dsMap[normalizedId];
20
+ })
21
+ .map((id) => {
22
+ const normalizedId = normalizePath(id);
23
+ const relativeId = toRelativePath(id);
24
+ return `// sourceId: ${relativeId}\n${dsMap[normalizedId]}\n`;
25
+ });
26
+
13
27
  return { detailDataSources: contents.join("") };
14
28
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aigne/doc-smith",
3
- "version": "0.1.3",
3
+ "version": "0.2.0",
4
4
  "description": "",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -12,12 +12,12 @@
12
12
  "author": "Arcblock <blocklet@arcblock.io> https://github.com/blocklet",
13
13
  "license": "MIT",
14
14
  "dependencies": {
15
- "@aigne/anthropic": "^0.10.4",
16
- "@aigne/cli": "^1.29.0",
17
- "@aigne/core": "^1.41.0",
18
- "@aigne/gemini": "^0.8.8",
19
- "@aigne/openai": "^0.10.8",
20
- "@aigne/publish-docs": "^0.5.1",
15
+ "@aigne/anthropic": "^0.10.6",
16
+ "@aigne/cli": "^1.30.1",
17
+ "@aigne/core": "^1.43.0",
18
+ "@aigne/gemini": "^0.8.10",
19
+ "@aigne/openai": "^0.10.10",
20
+ "@aigne/publish-docs": "^0.5.2",
21
21
  "glob": "^11.0.3",
22
22
  "open": "^10.2.0",
23
23
  "ufo": "^1.6.1",
@@ -17,7 +17,7 @@
17
17
  ```
18
18
  {{ feedback }}
19
19
 
20
- 根据最新的 Data Sources 按需要更新节点的 sourceIds ,更新至状态。
20
+ 根据最新的 Data Sources 按需要更新节点的 sourceIds
21
21
  ```
22
22
  </context>
23
23
 
@@ -30,7 +30,7 @@
30
30
  <structure_plan_feedback>
31
31
  {{ feedback }}
32
32
 
33
- 根据最新的 Data Sources 按需要更新节点的 sourceIds ,更新至状态。
33
+ 根据最新的 Data Sources 按需要更新节点的 sourceIds
34
34
  </structure_plan_feedback>
35
35
 
36
36
  <review_structure_plan>
@@ -0,0 +1,60 @@
1
+ // Default file patterns for inclusion and exclusion
2
+ export const DEFAULT_INCLUDE_PATTERNS = [
3
+ "*.py",
4
+ "*.js",
5
+ "*.jsx",
6
+ "*.ts",
7
+ "*.tsx",
8
+ "*.go",
9
+ "*.java",
10
+ "*.pyi",
11
+ "*.pyx",
12
+ "*.c",
13
+ "*.cc",
14
+ "*.cpp",
15
+ "*.h",
16
+ "*.md",
17
+ "*.rst",
18
+ "*.json",
19
+ "*Dockerfile",
20
+ "*Makefile",
21
+ "*.yaml",
22
+ "*.yml",
23
+ ];
24
+
25
+ export const DEFAULT_EXCLUDE_PATTERNS = [
26
+ "aigne-docs/**",
27
+ "doc-smith/**",
28
+ "assets/**",
29
+ "data/**",
30
+ "images/**",
31
+ "public/**",
32
+ "static/**",
33
+ "**/vendor/**",
34
+ "temp/**",
35
+ "**/*docs/**",
36
+ "**/*doc/**",
37
+ "**/*venv/**",
38
+ "*.venv/**",
39
+ "*test*",
40
+ "**/*test/**",
41
+ "**/*tests/**",
42
+ "**/*examples/**",
43
+ "**/playgrounds/**",
44
+ "v1/**",
45
+ "**/dist/**",
46
+ "**/*build/**",
47
+ "**/*experimental/**",
48
+ "**/*deprecated/**",
49
+ "**/*misc/**",
50
+ "**/*legacy/**",
51
+ ".git/**",
52
+ ".github/**",
53
+ ".next/**",
54
+ ".vscode/**",
55
+ "**/*obj/**",
56
+ "**/*bin/**",
57
+ "**/*node_modules/**",
58
+ "*.log",
59
+ "**/*test.*",
60
+ ];