@itradingai/aiwiki 0.2.15 → 0.2.16
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/src/app.js +19 -4
- package/dist/src/lint.js +163 -23
- package/docs/AGENT_HANDOFF.md +22 -0
- package/docs/README.md +1 -0
- package/docs/USAGE.md +11 -1
- package/docs/development-log.md +97 -0
- package/package.json +1 -1
package/dist/src/app.js
CHANGED
|
@@ -6,7 +6,7 @@ import { fileURLToPath } from "node:url";
|
|
|
6
6
|
import { flagBool, flagString, parseArgs } from "./args.js";
|
|
7
7
|
import { buildContext } from "./context.js";
|
|
8
8
|
import { deriveFileTitle, ingestFile, ingestPayload } from "./ingest.js";
|
|
9
|
-
import { lintWorkspace, renderLintReport, writeLintReport } from "./lint.js";
|
|
9
|
+
import { filterLintReport, lintWorkspace, renderLintReport, renderLintSummary, writeLintReport } from "./lint.js";
|
|
10
10
|
import { CliError, writeLine } from "./output.js";
|
|
11
11
|
import { confirmInit, directorySummary, doctor, exists, initWorkspace, promptForSetup, promptForInitPath, readConfig, resolveWorkspace, setDefaultWorkspace, statusSummary } from "./workspace.js";
|
|
12
12
|
export async function runCli(argv, streams = { stdout: process.stdout, stderr: process.stderr }) {
|
|
@@ -159,10 +159,16 @@ export async function runCli(argv, streams = { stdout: process.stdout, stderr: p
|
|
|
159
159
|
}
|
|
160
160
|
if (command === "lint") {
|
|
161
161
|
const root = await resolveWorkspace(flagString(args, "path"));
|
|
162
|
-
const
|
|
163
|
-
const
|
|
162
|
+
const severity = parseLintSeverity(flagString(args, "severity"));
|
|
163
|
+
const report = filterLintReport(await lintWorkspace(root), severity);
|
|
164
|
+
if (flagBool(args, "json")) {
|
|
165
|
+
writeLine(streams.stdout, JSON.stringify(report, null, 2));
|
|
166
|
+
return 0;
|
|
167
|
+
}
|
|
168
|
+
const reportPath = flagBool(args, "no-write") ? undefined : await writeLintReport(root, report);
|
|
169
|
+
writeLine(streams.stdout, renderLintSummary(report, reportPath));
|
|
170
|
+
writeLine(streams.stdout, "");
|
|
164
171
|
writeLine(streams.stdout, renderLintReport(report));
|
|
165
|
-
writeLine(streams.stdout, `report: ${reportPath}`);
|
|
166
172
|
return 0;
|
|
167
173
|
}
|
|
168
174
|
if (command === "ingest-agent") {
|
|
@@ -256,6 +262,15 @@ function printHelp(stream) {
|
|
|
256
262
|
writeLine(stream, " aiwiki ingest-url <url> --content-file <file>");
|
|
257
263
|
writeLine(stream, " aiwiki agent check");
|
|
258
264
|
}
|
|
265
|
+
function parseLintSeverity(value) {
|
|
266
|
+
if (value === undefined) {
|
|
267
|
+
return undefined;
|
|
268
|
+
}
|
|
269
|
+
if (value === "error" || value === "warning" || value === "info") {
|
|
270
|
+
return value;
|
|
271
|
+
}
|
|
272
|
+
throw new CliError("lint --severity must be error, warning, or info");
|
|
273
|
+
}
|
|
259
274
|
async function discoverAgentTargets() {
|
|
260
275
|
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
261
276
|
const skillSource = path.join(packageRoot, "skill", "SKILL.md");
|
package/dist/src/lint.js
CHANGED
|
@@ -19,14 +19,17 @@ export async function lintWorkspace(rootPath, now = new Date().toISOString()) {
|
|
|
19
19
|
...await readNotes(root, "08-outputs/outlines")
|
|
20
20
|
];
|
|
21
21
|
const issues = [];
|
|
22
|
+
issues.push(...await systemFileIssues(root));
|
|
22
23
|
const wikiSourceCards = new Set(wikiEntries.map((note) => frontmatterString(note.frontmatter, "source_card")).filter(Boolean));
|
|
23
24
|
for (const card of sourceCards) {
|
|
24
25
|
if (!wikiSourceCards.has(card.path)) {
|
|
25
26
|
issues.push({
|
|
26
27
|
severity: "warning",
|
|
27
28
|
path: card.path,
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
category: "isolated_source_card",
|
|
30
|
+
action: "reingest",
|
|
31
|
+
message: "Source Card has no matching Wiki Entry.",
|
|
32
|
+
suggestion: `Reingest or create a matching 05-wiki/source-knowledge/${path.basename(card.path)} entry.`
|
|
30
33
|
});
|
|
31
34
|
}
|
|
32
35
|
}
|
|
@@ -35,26 +38,68 @@ export async function lintWorkspace(rootPath, now = new Date().toISOString()) {
|
|
|
35
38
|
const rawFile = frontmatterString(entry.frontmatter, "raw_file");
|
|
36
39
|
const mode = frontmatterString(entry.frontmatter, "generation_mode");
|
|
37
40
|
if (!sourceCard) {
|
|
38
|
-
issues.push({
|
|
41
|
+
issues.push({
|
|
42
|
+
severity: "warning",
|
|
43
|
+
path: entry.path,
|
|
44
|
+
category: "missing_source",
|
|
45
|
+
action: "reingest",
|
|
46
|
+
message: "Wiki Entry is missing source_card.",
|
|
47
|
+
suggestion: "Add the vault path of the source card."
|
|
48
|
+
});
|
|
39
49
|
}
|
|
40
50
|
if (!rawFile) {
|
|
41
|
-
issues.push({
|
|
51
|
+
issues.push({
|
|
52
|
+
severity: "warning",
|
|
53
|
+
path: entry.path,
|
|
54
|
+
category: "missing_source",
|
|
55
|
+
action: "reingest",
|
|
56
|
+
message: "Wiki Entry is missing raw_file.",
|
|
57
|
+
suggestion: "Add the vault path of the raw source file."
|
|
58
|
+
});
|
|
42
59
|
}
|
|
43
60
|
if (mode === "deterministic_fallback") {
|
|
44
|
-
issues.push({
|
|
61
|
+
issues.push({
|
|
62
|
+
severity: "info",
|
|
63
|
+
path: entry.path,
|
|
64
|
+
category: "stale_scaffold",
|
|
65
|
+
action: "enrich",
|
|
66
|
+
message: "Wiki Entry is a deterministic fallback and only contains source trace plus a content preview.",
|
|
67
|
+
suggestion: "Ask the host Agent to enrich it with analysis or a full wiki_entry."
|
|
68
|
+
});
|
|
45
69
|
const createdAt = Date.parse(frontmatterString(entry.frontmatter, "created_at") ?? "");
|
|
46
70
|
if (Number.isFinite(createdAt) && Date.parse(now) - createdAt > 7 * 24 * 60 * 60 * 1000) {
|
|
47
|
-
issues.push({
|
|
71
|
+
issues.push({
|
|
72
|
+
severity: "warning",
|
|
73
|
+
path: entry.path,
|
|
74
|
+
category: "stale_scaffold",
|
|
75
|
+
action: "enrich",
|
|
76
|
+
message: "Fallback Wiki Entry is older than 7 days.",
|
|
77
|
+
suggestion: "Reingest with a host Agent to generate an enriched Wiki Entry."
|
|
78
|
+
});
|
|
48
79
|
}
|
|
49
80
|
}
|
|
50
81
|
if (mode === "agent_enriched") {
|
|
51
|
-
const hasSummary =
|
|
52
|
-
const hasKeyPoints =
|
|
82
|
+
const hasSummary = /##\s+.+/.test(entry.body) || Boolean(frontmatterString(entry.frontmatter, "summary"));
|
|
83
|
+
const hasKeyPoints = /-\s+/.test(entry.body);
|
|
53
84
|
if (!hasSummary) {
|
|
54
|
-
issues.push({
|
|
85
|
+
issues.push({
|
|
86
|
+
severity: "warning",
|
|
87
|
+
path: entry.path,
|
|
88
|
+
category: "weak_entry",
|
|
89
|
+
action: "enrich",
|
|
90
|
+
message: "agent_enriched Wiki Entry is missing a summary.",
|
|
91
|
+
suggestion: "Ask the host Agent to provide analysis.summary."
|
|
92
|
+
});
|
|
55
93
|
}
|
|
56
94
|
if (!hasKeyPoints) {
|
|
57
|
-
issues.push({
|
|
95
|
+
issues.push({
|
|
96
|
+
severity: "warning",
|
|
97
|
+
path: entry.path,
|
|
98
|
+
category: "weak_entry",
|
|
99
|
+
action: "enrich",
|
|
100
|
+
message: "agent_enriched Wiki Entry is missing key points.",
|
|
101
|
+
suggestion: "Ask the host Agent to provide analysis.key_points."
|
|
102
|
+
});
|
|
58
103
|
}
|
|
59
104
|
}
|
|
60
105
|
if (frontmatterBoolean(entry.frontmatter, "grounding_needs_review") === true) {
|
|
@@ -62,15 +107,24 @@ export async function lintWorkspace(rootPath, now = new Date().toISOString()) {
|
|
|
62
107
|
issues.push({
|
|
63
108
|
severity: "warning",
|
|
64
109
|
path: entry.path,
|
|
65
|
-
|
|
66
|
-
|
|
110
|
+
category: "grounding_review",
|
|
111
|
+
action: "mark_reviewed",
|
|
112
|
+
message: `Wiki Entry needs grounding review${markers.length ? `: ${markers.join(", ")}` : "."}`,
|
|
113
|
+
suggestion: "Check whether source quotes are present in Raw. Heuristic coverage risks are not confirmed facts."
|
|
67
114
|
});
|
|
68
115
|
}
|
|
69
116
|
if (frontmatterBoolean(entry.frontmatter, "represents_user_view") === true && frontmatterString(entry.frontmatter, "source_role") !== "output") {
|
|
70
|
-
issues.push({
|
|
117
|
+
issues.push({
|
|
118
|
+
severity: "warning",
|
|
119
|
+
path: entry.path,
|
|
120
|
+
category: "metadata_boundary",
|
|
121
|
+
action: "mark_reviewed",
|
|
122
|
+
message: "Only output source_role entries should represent the user's view.",
|
|
123
|
+
suggestion: "Set represents_user_view to false, or change source_role to output when it is user-authored output."
|
|
124
|
+
});
|
|
71
125
|
}
|
|
72
126
|
}
|
|
73
|
-
issues.push(...duplicateIssues(sourceCards, "source_url", "
|
|
127
|
+
issues.push(...duplicateIssues(sourceCards, "source_url", "Duplicate URL"));
|
|
74
128
|
issues.push(...duplicateTitles(allNotes));
|
|
75
129
|
issues.push(...brokenLinkIssues(root, allNotes));
|
|
76
130
|
return {
|
|
@@ -84,6 +138,15 @@ export async function lintWorkspace(rootPath, now = new Date().toISOString()) {
|
|
|
84
138
|
issues
|
|
85
139
|
};
|
|
86
140
|
}
|
|
141
|
+
export function filterLintReport(report, severity) {
|
|
142
|
+
if (!severity) {
|
|
143
|
+
return report;
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
...report,
|
|
147
|
+
issues: report.issues.filter((issue) => issue.severity === severity)
|
|
148
|
+
};
|
|
149
|
+
}
|
|
87
150
|
export async function writeLintReport(rootPath, report) {
|
|
88
151
|
const root = path.resolve(rootPath);
|
|
89
152
|
const target = safeJoin(root, "dashboards", "Lint Report.md");
|
|
@@ -92,6 +155,8 @@ export async function writeLintReport(rootPath, report) {
|
|
|
92
155
|
return relativePath(root, target);
|
|
93
156
|
}
|
|
94
157
|
export function renderLintReport(report) {
|
|
158
|
+
const counts = severityCounts(report.issues);
|
|
159
|
+
const topIssue = report.issues[0];
|
|
95
160
|
return [
|
|
96
161
|
"# AIWiki Lint Report",
|
|
97
162
|
"",
|
|
@@ -103,17 +168,49 @@ export function renderLintReport(report) {
|
|
|
103
168
|
`- Source Cards: ${report.summary.source_cards}`,
|
|
104
169
|
`- Raw Files: ${report.summary.raw_files}`,
|
|
105
170
|
`- Runs: ${report.summary.runs}`,
|
|
171
|
+
`- Errors: ${counts.error}`,
|
|
172
|
+
`- Warnings: ${counts.warning}`,
|
|
173
|
+
`- Info: ${counts.info}`,
|
|
174
|
+
`- Top Issue: ${topIssue ? formatIssueLine(topIssue) : "none"}`,
|
|
106
175
|
"",
|
|
107
|
-
"##
|
|
176
|
+
"## Suggested Handling Order",
|
|
108
177
|
"",
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
178
|
+
"- Fix error issues first.",
|
|
179
|
+
"- Review warning issues next.",
|
|
180
|
+
"- Use info issues for enrichment and cleanup backlog.",
|
|
181
|
+
"",
|
|
182
|
+
...renderIssueGroup("Errors", report.issues.filter((issue) => issue.severity === "error")),
|
|
183
|
+
...renderIssueGroup("Warnings", report.issues.filter((issue) => issue.severity === "warning")),
|
|
184
|
+
...renderIssueGroup("Info", report.issues.filter((issue) => issue.severity === "info")),
|
|
114
185
|
""
|
|
115
186
|
].join("\n");
|
|
116
187
|
}
|
|
188
|
+
export function renderLintSummary(report, reportPath) {
|
|
189
|
+
const counts = severityCounts(report.issues);
|
|
190
|
+
const topIssue = report.issues[0];
|
|
191
|
+
return [
|
|
192
|
+
`lint_summary: errors=${counts.error} warnings=${counts.warning} info=${counts.info}`,
|
|
193
|
+
`top_issue: ${topIssue ? formatIssueLine(topIssue) : "none"}`,
|
|
194
|
+
...(reportPath ? [`report: ${reportPath}`] : [])
|
|
195
|
+
].join("\n");
|
|
196
|
+
}
|
|
197
|
+
async function systemFileIssues(root) {
|
|
198
|
+
const issues = [];
|
|
199
|
+
for (const systemFile of ["_system/purpose.md", "_system/index.md", "_system/log.md"]) {
|
|
200
|
+
if (await exists(path.join(root, systemFile))) {
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
issues.push({
|
|
204
|
+
severity: "error",
|
|
205
|
+
path: systemFile,
|
|
206
|
+
category: "workspace_structure",
|
|
207
|
+
action: "repair_structure",
|
|
208
|
+
message: `Required system file is missing: ${systemFile}`,
|
|
209
|
+
suggestion: `Run aiwiki setup --path "${root}" --yes`
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
return issues;
|
|
213
|
+
}
|
|
117
214
|
async function readNotes(root, dir) {
|
|
118
215
|
const absolute = path.join(root, dir);
|
|
119
216
|
if (!(await exists(absolute))) {
|
|
@@ -163,7 +260,13 @@ function duplicateIssues(notes, field, label) {
|
|
|
163
260
|
seen.set(value, [...(seen.get(value) ?? []), note.path]);
|
|
164
261
|
}
|
|
165
262
|
return Array.from(seen.entries()).flatMap(([value, paths]) => paths.length > 1
|
|
166
|
-
? [{
|
|
263
|
+
? [{
|
|
264
|
+
severity: "warning",
|
|
265
|
+
category: "duplicate",
|
|
266
|
+
action: "mark_reviewed",
|
|
267
|
+
message: `${label}: ${value}`,
|
|
268
|
+
suggestion: paths.join(", ")
|
|
269
|
+
}]
|
|
167
270
|
: []);
|
|
168
271
|
}
|
|
169
272
|
function duplicateTitles(notes) {
|
|
@@ -175,7 +278,13 @@ function duplicateTitles(notes) {
|
|
|
175
278
|
seen.set(note.title, [...(seen.get(note.title) ?? []), note.path]);
|
|
176
279
|
}
|
|
177
280
|
return Array.from(seen.entries()).flatMap(([title, paths]) => paths.length > 1
|
|
178
|
-
? [{
|
|
281
|
+
? [{
|
|
282
|
+
severity: "info",
|
|
283
|
+
category: "duplicate_title",
|
|
284
|
+
action: "archive",
|
|
285
|
+
message: `Duplicate title: ${title}`,
|
|
286
|
+
suggestion: paths.join(", ")
|
|
287
|
+
}]
|
|
179
288
|
: []);
|
|
180
289
|
}
|
|
181
290
|
function brokenLinkIssues(root, notes) {
|
|
@@ -185,12 +294,43 @@ function brokenLinkIssues(root, notes) {
|
|
|
185
294
|
for (const link of note.body.matchAll(/\[\[([^\]|]+)(?:\|[^\]]+)?\]\]/g)) {
|
|
186
295
|
const target = link[1].replace(/\\/g, "/").replace(/\.md$/i, "");
|
|
187
296
|
if (!existing.has(target) && !isRunLocalLink(target)) {
|
|
188
|
-
issues.push({
|
|
297
|
+
issues.push({
|
|
298
|
+
severity: "error",
|
|
299
|
+
path: note.path,
|
|
300
|
+
category: "broken_link",
|
|
301
|
+
action: "fix_link",
|
|
302
|
+
message: `Broken wikilink: ${target}`,
|
|
303
|
+
suggestion: "Check whether the target file exists or update the wikilink."
|
|
304
|
+
});
|
|
189
305
|
}
|
|
190
306
|
}
|
|
191
307
|
}
|
|
192
308
|
return issues;
|
|
193
309
|
}
|
|
310
|
+
function renderIssueGroup(title, issues) {
|
|
311
|
+
return [
|
|
312
|
+
`## ${title}`,
|
|
313
|
+
"",
|
|
314
|
+
...(issues.length ? issues.map((issue) => {
|
|
315
|
+
const suggestion = issue.suggestion ? `\n - Suggested Fix: ${issue.suggestion}` : "";
|
|
316
|
+
const action = issue.action ? `\n - Action: ${issue.action}` : "";
|
|
317
|
+
return `- ${formatIssueLine(issue)}${action}${suggestion}`;
|
|
318
|
+
}) : ["- none"]),
|
|
319
|
+
""
|
|
320
|
+
];
|
|
321
|
+
}
|
|
322
|
+
function formatIssueLine(issue) {
|
|
323
|
+
const suffix = issue.path ? ` (${issue.path})` : "";
|
|
324
|
+
const category = issue.category ? ` {${issue.category}}` : "";
|
|
325
|
+
return `[${issue.severity}]${category} ${issue.message}${suffix}`;
|
|
326
|
+
}
|
|
327
|
+
function severityCounts(issues) {
|
|
328
|
+
return {
|
|
329
|
+
error: issues.filter((issue) => issue.severity === "error").length,
|
|
330
|
+
warning: issues.filter((issue) => issue.severity === "warning").length,
|
|
331
|
+
info: issues.filter((issue) => issue.severity === "info").length
|
|
332
|
+
};
|
|
333
|
+
}
|
|
194
334
|
function isRunLocalLink(target) {
|
|
195
335
|
// Run-local notes are valid trace links but are not part of the long-term note set.
|
|
196
336
|
return target.startsWith("09-runs/");
|
package/docs/AGENT_HANDOFF.md
CHANGED
|
@@ -199,6 +199,28 @@ aiwiki query "<主题>"
|
|
|
199
199
|
aiwiki lint
|
|
200
200
|
```
|
|
201
201
|
|
|
202
|
+
需要机器读取时用:
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
aiwiki lint --json
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
只想看某一级别时用:
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
aiwiki lint --severity error
|
|
212
|
+
aiwiki lint --severity warning
|
|
213
|
+
aiwiki lint --severity info
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
只做临时检查、不改 dashboard 时用:
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
aiwiki lint --no-write
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Lint 输出会包含摘要、最高优先级问题、分级报告,以及建议动作。把 `error` 当作必须先修的结构问题,把 `warning` 当作需要处理或复核的维护问题,把 `info` 当作富集、归档或后续整理 backlog。
|
|
223
|
+
|
|
202
224
|
`context` 返回 JSON,注意其中的 `generation_mode`、`quality` 和 `warnings`。如果结果是 `deterministic_fallback` / `scaffold`,回复时要说明它只是可追溯脚手架,不是高质量知识提炼。
|
|
203
225
|
|
|
204
226
|
`context` 也可能返回 grounding 字段。回复用户时可以把 `grounding_needs_review: true` 解释为“这条资料需要复核证据或覆盖度”,不要说成“AIWiki 已确认漏掉重点”。
|
package/docs/README.md
CHANGED
package/docs/USAGE.md
CHANGED
|
@@ -318,13 +318,23 @@ aiwiki query "AI Agent"
|
|
|
318
318
|
aiwiki lint
|
|
319
319
|
```
|
|
320
320
|
|
|
321
|
+
常用工作台模式:
|
|
322
|
+
|
|
323
|
+
```bash
|
|
324
|
+
aiwiki lint --severity warning
|
|
325
|
+
aiwiki lint --json
|
|
326
|
+
aiwiki lint --no-write
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
`lint` 会先输出 `lint_summary`、`top_issue` 和报告路径,再按 Errors / Warnings / Info 分组展示问题。每个问题会尽量给出建议动作,例如 `enrich`、`fix_link`、`reingest`、`archive` 或 `mark_reviewed`。`--severity` 只查看指定级别,`--json` 给宿主 Agent 使用,`--no-write` 只在终端检查而不更新 `dashboards/Lint Report.md`。
|
|
330
|
+
|
|
321
331
|
查看下一步建议:
|
|
322
332
|
|
|
323
333
|
```bash
|
|
324
334
|
aiwiki next
|
|
325
335
|
```
|
|
326
336
|
|
|
327
|
-
|
|
337
|
+
默认情况下,`lint` 输出报告并写入 `dashboards/Lint Report.md`。
|
|
328
338
|
|
|
329
339
|
## 8. 高级调试
|
|
330
340
|
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# AIWiki Development Log
|
|
2
|
+
|
|
3
|
+
This log records queue-driven AIWiki development milestones that should remain visible to future maintainers, not only in automation chat history.
|
|
4
|
+
|
|
5
|
+
## 2026-06-05 - AIWIKI-004 lint workbench
|
|
6
|
+
|
|
7
|
+
Status: implemented, locally verified, pushed to GitHub, blocked on npm OTP before publication.
|
|
8
|
+
|
|
9
|
+
Version target: `@itradingai/aiwiki@0.2.16`
|
|
10
|
+
|
|
11
|
+
Commit: `932386c` (`Turn lint into an actionable maintenance workbench`)
|
|
12
|
+
|
|
13
|
+
### Goal
|
|
14
|
+
|
|
15
|
+
Turn `aiwiki lint` from a plain report writer into a practical structure-maintenance workbench for humans and host Agents.
|
|
16
|
+
|
|
17
|
+
The scoped acceptance criteria were:
|
|
18
|
+
|
|
19
|
+
- summarize lint output in the terminal with errors, warnings, info, top issue, and report path;
|
|
20
|
+
- group the markdown report by severity and provide a handling order;
|
|
21
|
+
- support `--severity error|warning|info`;
|
|
22
|
+
- support `--json` for machine-readable Agent use;
|
|
23
|
+
- support `--no-write` for temporary checks that do not update `dashboards/Lint Report.md`;
|
|
24
|
+
- add lightweight knowledge-gap signals where feasible;
|
|
25
|
+
- attach advisory review actions such as `enrich`, `fix_link`, `archive`, `reingest`, and `mark_reviewed`.
|
|
26
|
+
|
|
27
|
+
### Implemented
|
|
28
|
+
|
|
29
|
+
- `src/lint.ts`
|
|
30
|
+
- Added `LintSeverity` and advisory `LintAction`.
|
|
31
|
+
- Added issue `category` and `action` fields.
|
|
32
|
+
- Added system-file checks for `_system/purpose.md`, `_system/index.md`, and `_system/log.md`.
|
|
33
|
+
- Added signals for isolated Source Cards, stale deterministic fallback entries, grounding-review entries, metadata-boundary issues, duplicate URLs/titles, and broken wikilinks.
|
|
34
|
+
- Added severity filtering, terminal summary rendering, and severity-grouped report rendering.
|
|
35
|
+
|
|
36
|
+
- `src/app.ts`
|
|
37
|
+
- Added `aiwiki lint --severity error|warning|info`.
|
|
38
|
+
- Added `aiwiki lint --json`.
|
|
39
|
+
- Added `aiwiki lint --no-write`.
|
|
40
|
+
- Kept the default behavior of writing `dashboards/Lint Report.md`.
|
|
41
|
+
|
|
42
|
+
- `tests/cli.test.ts` and `tests/ingest.test.ts`
|
|
43
|
+
- Covered lint summary output, severity filtering, JSON output, no-write behavior, and updated lint issue text assertions.
|
|
44
|
+
|
|
45
|
+
- `docs/USAGE.md` and `docs/AGENT_HANDOFF.md`
|
|
46
|
+
- Documented human and Agent-facing lint modes.
|
|
47
|
+
|
|
48
|
+
### Verification
|
|
49
|
+
|
|
50
|
+
- `npm test`: passed, 53 tests.
|
|
51
|
+
- `npm run release:check`: passed, including 53 tests and release-check.
|
|
52
|
+
- `npm pack --dry-run`: passed for `@itradingai/aiwiki@0.2.16`.
|
|
53
|
+
- Clean export pack from `C:/tmp/aiwiki-004-publish`: passed, 31 files, shasum `945c70d3d4cf20c9550deaaf92036786b75e62cf`.
|
|
54
|
+
|
|
55
|
+
### Release State
|
|
56
|
+
|
|
57
|
+
GitHub push succeeded:
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
2e4b253..932386c main -> main
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
npm publication is blocked by a one-time password challenge:
|
|
64
|
+
|
|
65
|
+
```text
|
|
66
|
+
npm error code EOTP
|
|
67
|
+
npm error This operation requires a one-time password from your authenticator.
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Current registry version remains `0.2.15`, so remote smoke tests for `0.2.16` have not run yet.
|
|
71
|
+
|
|
72
|
+
### Resume Steps
|
|
73
|
+
|
|
74
|
+
From the clean publish directory:
|
|
75
|
+
|
|
76
|
+
```powershell
|
|
77
|
+
cd C:\tmp\aiwiki-004-publish
|
|
78
|
+
npm publish --access public --otp=<code>
|
|
79
|
+
npm view @itradingai/aiwiki version
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
After `npm view` returns `0.2.16`, run remote smoke tests for:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
aiwiki lint --path <tmp-vault>
|
|
86
|
+
aiwiki lint --severity warning --path <tmp-vault>
|
|
87
|
+
aiwiki lint --json --path <tmp-vault>
|
|
88
|
+
aiwiki lint --no-write --path <tmp-vault>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Then update the queue through `published`, `remote_verified`, and `done`.
|
|
92
|
+
|
|
93
|
+
### Notes For Future Changes
|
|
94
|
+
|
|
95
|
+
- Lint actions are advisory only. Do not make `archive`, `reingest`, `mark_reviewed`, or related actions mutate files without a separate explicit task.
|
|
96
|
+
- Keep lint local-file-only. Do not add crawling, vector search, RAG-over-wiki, RBAC, RSS, scheduled collection, or browser plugins under this queue item.
|
|
97
|
+
- The original working tree had unrelated `skill/SKILL.md` changes. Publication must use a clean commit export until that WIP is resolved.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@itradingai/aiwiki",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.16",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Agent-first AI knowledge base CLI for turning articles, links and notes into Obsidian-ready source cards, topics, outlines and reusable knowledge assets.",
|
|
6
6
|
"license": "MIT",
|