mulch-cli 0.4.3 → 0.6.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.
- package/README.md +24 -4
- package/package.json +11 -16
- package/src/api.ts +310 -0
- package/src/cli.ts +54 -0
- package/src/commands/add.ts +61 -0
- package/src/commands/compact.ts +924 -0
- package/src/commands/delete.ts +103 -0
- package/src/commands/diff.ts +209 -0
- package/src/commands/doctor.ts +586 -0
- package/src/commands/edit.ts +253 -0
- package/src/commands/init.ts +33 -0
- package/src/commands/learn.ts +170 -0
- package/src/commands/onboard.ts +362 -0
- package/src/commands/prime.ts +327 -0
- package/src/commands/prune.ts +128 -0
- package/src/commands/query.ts +177 -0
- package/src/commands/ready.ts +194 -0
- package/src/commands/record.ts +959 -0
- package/src/commands/search.ts +234 -0
- package/src/commands/setup.ts +823 -0
- package/src/commands/status.ts +83 -0
- package/src/commands/sync.ts +224 -0
- package/src/commands/update.ts +112 -0
- package/src/commands/validate.ts +107 -0
- package/src/index.ts +50 -0
- package/src/schemas/config.ts +31 -0
- package/src/schemas/index.ts +18 -0
- package/src/schemas/record-schema.ts +177 -0
- package/src/schemas/record.ts +83 -0
- package/src/utils/bm25.ts +243 -0
- package/src/utils/budget.ts +157 -0
- package/src/utils/config.ts +117 -0
- package/src/utils/expertise.ts +379 -0
- package/src/utils/format.ts +767 -0
- package/src/utils/git.ts +89 -0
- package/src/utils/index.ts +54 -0
- package/src/utils/json-output.ts +13 -0
- package/src/utils/lock.ts +82 -0
- package/src/utils/markers.ts +51 -0
- package/src/utils/scoring.ts +101 -0
- package/src/utils/version.ts +46 -0
- package/dist/cli.d.ts +0 -3
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -50
- package/dist/cli.js.map +0 -1
- package/dist/commands/add.d.ts +0 -3
- package/dist/commands/add.d.ts.map +0 -1
- package/dist/commands/add.js +0 -47
- package/dist/commands/add.js.map +0 -1
- package/dist/commands/compact.d.ts +0 -5
- package/dist/commands/compact.d.ts.map +0 -1
- package/dist/commands/compact.js +0 -709
- package/dist/commands/compact.js.map +0 -1
- package/dist/commands/delete.d.ts +0 -3
- package/dist/commands/delete.d.ts.map +0 -1
- package/dist/commands/delete.js +0 -82
- package/dist/commands/delete.js.map +0 -1
- package/dist/commands/diff.d.ts +0 -11
- package/dist/commands/diff.d.ts.map +0 -1
- package/dist/commands/diff.js +0 -170
- package/dist/commands/diff.js.map +0 -1
- package/dist/commands/doctor.d.ts +0 -3
- package/dist/commands/doctor.d.ts.map +0 -1
- package/dist/commands/doctor.js +0 -391
- package/dist/commands/doctor.js.map +0 -1
- package/dist/commands/edit.d.ts +0 -3
- package/dist/commands/edit.d.ts.map +0 -1
- package/dist/commands/edit.js +0 -210
- package/dist/commands/edit.js.map +0 -1
- package/dist/commands/init.d.ts +0 -3
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js +0 -30
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/learn.d.ts +0 -12
- package/dist/commands/learn.d.ts.map +0 -1
- package/dist/commands/learn.js +0 -130
- package/dist/commands/learn.js.map +0 -1
- package/dist/commands/onboard.d.ts +0 -10
- package/dist/commands/onboard.d.ts.map +0 -1
- package/dist/commands/onboard.js +0 -286
- package/dist/commands/onboard.js.map +0 -1
- package/dist/commands/prime.d.ts +0 -3
- package/dist/commands/prime.d.ts.map +0 -1
- package/dist/commands/prime.js +0 -242
- package/dist/commands/prime.js.map +0 -1
- package/dist/commands/prune.d.ts +0 -8
- package/dist/commands/prune.d.ts.map +0 -1
- package/dist/commands/prune.js +0 -90
- package/dist/commands/prune.js.map +0 -1
- package/dist/commands/query.d.ts +0 -3
- package/dist/commands/query.d.ts.map +0 -1
- package/dist/commands/query.js +0 -118
- package/dist/commands/query.js.map +0 -1
- package/dist/commands/ready.d.ts +0 -3
- package/dist/commands/ready.d.ts.map +0 -1
- package/dist/commands/ready.js +0 -160
- package/dist/commands/ready.js.map +0 -1
- package/dist/commands/record.d.ts +0 -13
- package/dist/commands/record.d.ts.map +0 -1
- package/dist/commands/record.js +0 -688
- package/dist/commands/record.js.map +0 -1
- package/dist/commands/search.d.ts +0 -3
- package/dist/commands/search.d.ts.map +0 -1
- package/dist/commands/search.js +0 -163
- package/dist/commands/search.js.map +0 -1
- package/dist/commands/setup.d.ts +0 -29
- package/dist/commands/setup.d.ts.map +0 -1
- package/dist/commands/setup.js +0 -548
- package/dist/commands/setup.js.map +0 -1
- package/dist/commands/status.d.ts +0 -3
- package/dist/commands/status.d.ts.map +0 -1
- package/dist/commands/status.js +0 -61
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/sync.d.ts +0 -3
- package/dist/commands/sync.d.ts.map +0 -1
- package/dist/commands/sync.js +0 -176
- package/dist/commands/sync.js.map +0 -1
- package/dist/commands/update.d.ts +0 -3
- package/dist/commands/update.d.ts.map +0 -1
- package/dist/commands/update.js +0 -72
- package/dist/commands/update.js.map +0 -1
- package/dist/commands/validate.d.ts +0 -3
- package/dist/commands/validate.d.ts.map +0 -1
- package/dist/commands/validate.js +0 -86
- package/dist/commands/validate.js.map +0 -1
- package/dist/index.d.ts +0 -7
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -8
- package/dist/index.js.map +0 -1
- package/dist/schemas/config.d.ts +0 -17
- package/dist/schemas/config.d.ts.map +0 -1
- package/dist/schemas/config.js +0 -16
- package/dist/schemas/config.js.map +0 -1
- package/dist/schemas/index.d.ts +0 -5
- package/dist/schemas/index.d.ts.map +0 -1
- package/dist/schemas/index.js +0 -3
- package/dist/schemas/index.js.map +0 -1
- package/dist/schemas/record-schema.d.ts +0 -379
- package/dist/schemas/record-schema.d.ts.map +0 -1
- package/dist/schemas/record-schema.js +0 -148
- package/dist/schemas/record-schema.js.map +0 -1
- package/dist/schemas/record.d.ts +0 -60
- package/dist/schemas/record.d.ts.map +0 -1
- package/dist/schemas/record.js +0 -2
- package/dist/schemas/record.js.map +0 -1
- package/dist/utils/bm25.d.ts +0 -39
- package/dist/utils/bm25.d.ts.map +0 -1
- package/dist/utils/bm25.js +0 -171
- package/dist/utils/bm25.js.map +0 -1
- package/dist/utils/budget.d.ts +0 -35
- package/dist/utils/budget.d.ts.map +0 -1
- package/dist/utils/budget.js +0 -114
- package/dist/utils/budget.js.map +0 -1
- package/dist/utils/config.d.ts +0 -12
- package/dist/utils/config.d.ts.map +0 -1
- package/dist/utils/config.js +0 -89
- package/dist/utils/config.js.map +0 -1
- package/dist/utils/expertise.d.ts +0 -57
- package/dist/utils/expertise.d.ts.map +0 -1
- package/dist/utils/expertise.js +0 -264
- package/dist/utils/expertise.js.map +0 -1
- package/dist/utils/format.d.ts +0 -31
- package/dist/utils/format.d.ts.map +0 -1
- package/dist/utils/format.js +0 -556
- package/dist/utils/format.js.map +0 -1
- package/dist/utils/git.d.ts +0 -6
- package/dist/utils/git.d.ts.map +0 -1
- package/dist/utils/git.js +0 -81
- package/dist/utils/git.js.map +0 -1
- package/dist/utils/index.d.ts +0 -8
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js +0 -8
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/json-output.d.ts +0 -8
- package/dist/utils/json-output.d.ts.map +0 -1
- package/dist/utils/json-output.js +0 -7
- package/dist/utils/json-output.js.map +0 -1
- package/dist/utils/lock.d.ts +0 -6
- package/dist/utils/lock.d.ts.map +0 -1
- package/dist/utils/lock.js +0 -70
- package/dist/utils/lock.js.map +0 -1
- package/dist/utils/markers.d.ts +0 -22
- package/dist/utils/markers.d.ts.map +0 -1
- package/dist/utils/markers.js +0 -42
- package/dist/utils/markers.js.map +0 -1
- package/dist/utils/scoring.d.ts +0 -73
- package/dist/utils/scoring.d.ts.map +0 -1
- package/dist/utils/scoring.js +0 -80
- package/dist/utils/scoring.js.map +0 -1
- package/dist/utils/version.d.ts +0 -15
- package/dist/utils/version.d.ts.map +0 -1
- package/dist/utils/version.js +0 -48
- package/dist/utils/version.js.map +0 -1
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { type Command, Option } from "commander";
|
|
2
|
+
import { getExpertisePath, readConfig } from "../utils/config.ts";
|
|
3
|
+
import {
|
|
4
|
+
filterByClassification,
|
|
5
|
+
filterByFile,
|
|
6
|
+
filterByType,
|
|
7
|
+
getFileModTime,
|
|
8
|
+
readExpertiseFile,
|
|
9
|
+
} from "../utils/expertise.ts";
|
|
10
|
+
import { searchRecords } from "../utils/expertise.ts";
|
|
11
|
+
import { formatDomainExpertise } from "../utils/format.ts";
|
|
12
|
+
import { outputJson, outputJsonError } from "../utils/json-output.ts";
|
|
13
|
+
import {
|
|
14
|
+
type ScoredRecord,
|
|
15
|
+
sortByConfirmationScore,
|
|
16
|
+
} from "../utils/scoring.ts";
|
|
17
|
+
|
|
18
|
+
export function registerSearchCommand(program: Command): void {
|
|
19
|
+
program
|
|
20
|
+
.command("search")
|
|
21
|
+
.argument("[query]", "search string (case-insensitive substring match)")
|
|
22
|
+
.description("Search expertise records across domains")
|
|
23
|
+
.option("--domain <domain>", "limit search to a specific domain")
|
|
24
|
+
.addOption(
|
|
25
|
+
new Option("--type <type>", "filter by record type").choices([
|
|
26
|
+
"convention",
|
|
27
|
+
"pattern",
|
|
28
|
+
"failure",
|
|
29
|
+
"decision",
|
|
30
|
+
"reference",
|
|
31
|
+
"guide",
|
|
32
|
+
]),
|
|
33
|
+
)
|
|
34
|
+
.option("--tag <tag>", "filter by tag")
|
|
35
|
+
.addOption(
|
|
36
|
+
new Option(
|
|
37
|
+
"--classification <classification>",
|
|
38
|
+
"filter by classification",
|
|
39
|
+
).choices(["foundational", "tactical", "observational"]),
|
|
40
|
+
)
|
|
41
|
+
.option("--file <file>", "filter by associated file path (substring match)")
|
|
42
|
+
.addOption(
|
|
43
|
+
new Option(
|
|
44
|
+
"--outcome-status <status>",
|
|
45
|
+
"filter by outcome status",
|
|
46
|
+
).choices(["success", "failure", "partial"]),
|
|
47
|
+
)
|
|
48
|
+
.option(
|
|
49
|
+
"--sort-by-score",
|
|
50
|
+
"sort results by confirmation-frequency score (highest first)",
|
|
51
|
+
)
|
|
52
|
+
.action(
|
|
53
|
+
async (
|
|
54
|
+
query: string | undefined,
|
|
55
|
+
options: {
|
|
56
|
+
domain?: string;
|
|
57
|
+
type?: string;
|
|
58
|
+
tag?: string;
|
|
59
|
+
classification?: string;
|
|
60
|
+
file?: string;
|
|
61
|
+
outcomeStatus?: string;
|
|
62
|
+
sortByScore?: boolean;
|
|
63
|
+
},
|
|
64
|
+
) => {
|
|
65
|
+
const jsonMode = program.opts().json === true;
|
|
66
|
+
try {
|
|
67
|
+
if (
|
|
68
|
+
!query &&
|
|
69
|
+
!options.type &&
|
|
70
|
+
!options.domain &&
|
|
71
|
+
!options.tag &&
|
|
72
|
+
!options.classification &&
|
|
73
|
+
!options.file &&
|
|
74
|
+
!options.outcomeStatus
|
|
75
|
+
) {
|
|
76
|
+
if (jsonMode) {
|
|
77
|
+
outputJsonError(
|
|
78
|
+
"search",
|
|
79
|
+
"Provide a search query or use --type, --domain, --tag, --classification, --file, or --outcome-status to filter.",
|
|
80
|
+
);
|
|
81
|
+
} else {
|
|
82
|
+
console.error(
|
|
83
|
+
"Error: Provide a search query or use --type, --domain, --tag, --classification, --file, or --outcome-status to filter.",
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
process.exitCode = 1;
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const config = await readConfig();
|
|
91
|
+
|
|
92
|
+
let domainsToSearch: string[];
|
|
93
|
+
|
|
94
|
+
if (options.domain) {
|
|
95
|
+
if (!config.domains.includes(options.domain)) {
|
|
96
|
+
if (jsonMode) {
|
|
97
|
+
outputJsonError(
|
|
98
|
+
"search",
|
|
99
|
+
`Domain "${options.domain}" not found in config. Available domains: ${config.domains.join(", ")}`,
|
|
100
|
+
);
|
|
101
|
+
} else {
|
|
102
|
+
console.error(
|
|
103
|
+
`Error: Domain "${options.domain}" not found in config. Available domains: ${config.domains.join(", ")}`,
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
process.exitCode = 1;
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
domainsToSearch = [options.domain];
|
|
110
|
+
} else {
|
|
111
|
+
domainsToSearch = config.domains;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
let totalMatches = 0;
|
|
115
|
+
|
|
116
|
+
if (jsonMode) {
|
|
117
|
+
const result: Array<{ domain: string; matches: unknown[] }> = [];
|
|
118
|
+
for (const domain of domainsToSearch) {
|
|
119
|
+
const filePath = getExpertisePath(domain);
|
|
120
|
+
let records = await readExpertiseFile(filePath);
|
|
121
|
+
if (options.type) {
|
|
122
|
+
records = filterByType(records, options.type);
|
|
123
|
+
}
|
|
124
|
+
if (options.tag) {
|
|
125
|
+
const tagLower = options.tag.toLowerCase();
|
|
126
|
+
records = records.filter((r) =>
|
|
127
|
+
r.tags?.some((t) => t.toLowerCase() === tagLower),
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
if (options.classification) {
|
|
131
|
+
records = filterByClassification(
|
|
132
|
+
records,
|
|
133
|
+
options.classification,
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
if (options.file) {
|
|
137
|
+
records = filterByFile(records, options.file);
|
|
138
|
+
}
|
|
139
|
+
if (options.outcomeStatus) {
|
|
140
|
+
records = records.filter((r) =>
|
|
141
|
+
r.outcomes?.some((o) => o.status === options.outcomeStatus),
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
let matches = query ? searchRecords(records, query) : records;
|
|
145
|
+
if (options.sortByScore) {
|
|
146
|
+
matches = sortByConfirmationScore(matches as ScoredRecord[]);
|
|
147
|
+
}
|
|
148
|
+
if (matches.length > 0) {
|
|
149
|
+
totalMatches += matches.length;
|
|
150
|
+
result.push({ domain, matches });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
outputJson({
|
|
154
|
+
success: true,
|
|
155
|
+
command: "search",
|
|
156
|
+
query: query ?? null,
|
|
157
|
+
total: totalMatches,
|
|
158
|
+
domains: result,
|
|
159
|
+
});
|
|
160
|
+
} else {
|
|
161
|
+
const sections: string[] = [];
|
|
162
|
+
for (const domain of domainsToSearch) {
|
|
163
|
+
const filePath = getExpertisePath(domain);
|
|
164
|
+
let records = await readExpertiseFile(filePath);
|
|
165
|
+
const lastUpdated = await getFileModTime(filePath);
|
|
166
|
+
if (options.type) {
|
|
167
|
+
records = filterByType(records, options.type);
|
|
168
|
+
}
|
|
169
|
+
if (options.tag) {
|
|
170
|
+
const tagLower = options.tag.toLowerCase();
|
|
171
|
+
records = records.filter((r) =>
|
|
172
|
+
r.tags?.some((t) => t.toLowerCase() === tagLower),
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
if (options.classification) {
|
|
176
|
+
records = filterByClassification(
|
|
177
|
+
records,
|
|
178
|
+
options.classification,
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
if (options.file) {
|
|
182
|
+
records = filterByFile(records, options.file);
|
|
183
|
+
}
|
|
184
|
+
if (options.outcomeStatus) {
|
|
185
|
+
records = records.filter((r) =>
|
|
186
|
+
r.outcomes?.some((o) => o.status === options.outcomeStatus),
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
let matches = query ? searchRecords(records, query) : records;
|
|
190
|
+
if (options.sortByScore) {
|
|
191
|
+
matches = sortByConfirmationScore(matches as ScoredRecord[]);
|
|
192
|
+
}
|
|
193
|
+
if (matches.length > 0) {
|
|
194
|
+
totalMatches += matches.length;
|
|
195
|
+
sections.push(
|
|
196
|
+
formatDomainExpertise(domain, matches, lastUpdated),
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const label = query ? `matching "${query}"` : "matching filters";
|
|
202
|
+
if (sections.length === 0) {
|
|
203
|
+
console.log(`No records ${label} found.`);
|
|
204
|
+
} else {
|
|
205
|
+
console.log(sections.join("\n\n"));
|
|
206
|
+
console.log(
|
|
207
|
+
`\n${totalMatches} match${totalMatches === 1 ? "" : "es"} found.`,
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
} catch (err) {
|
|
212
|
+
if ((err as NodeJS.ErrnoException).code === "ENOENT") {
|
|
213
|
+
if (jsonMode) {
|
|
214
|
+
outputJsonError(
|
|
215
|
+
"search",
|
|
216
|
+
"No .mulch/ directory found. Run `mulch init` first.",
|
|
217
|
+
);
|
|
218
|
+
} else {
|
|
219
|
+
console.error(
|
|
220
|
+
"Error: No .mulch/ directory found. Run `mulch init` first.",
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
} else {
|
|
224
|
+
if (jsonMode) {
|
|
225
|
+
outputJsonError("search", (err as Error).message);
|
|
226
|
+
} else {
|
|
227
|
+
console.error(`Error: ${(err as Error).message}`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
process.exitCode = 1;
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
);
|
|
234
|
+
}
|