@shrkcrft/cli 0.1.0-alpha.7 → 0.1.0-alpha.9
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 +1 -1
- package/dist/commands/boundaries.command.d.ts.map +1 -1
- package/dist/commands/boundaries.command.js +12 -0
- package/dist/commands/check.command.d.ts.map +1 -1
- package/dist/commands/check.command.js +30 -20
- package/dist/commands/command-catalog.d.ts.map +1 -1
- package/dist/commands/command-catalog.js +14 -1
- package/dist/commands/doctor.command.d.ts.map +1 -1
- package/dist/commands/doctor.command.js +7 -8
- package/dist/commands/help.command.d.ts.map +1 -1
- package/dist/commands/help.command.js +8 -6
- package/dist/commands/init.command.d.ts.map +1 -1
- package/dist/commands/init.command.js +13 -37
- package/dist/commands/mcp.command.d.ts.map +1 -1
- package/dist/commands/mcp.command.js +131 -2
- package/dist/commands/onboard.command.d.ts.map +1 -1
- package/dist/commands/onboard.command.js +15 -3
- package/dist/commands/packs-new.d.ts.map +1 -1
- package/dist/commands/packs-new.js +10 -3
- package/dist/commands/packs.command.d.ts.map +1 -1
- package/dist/commands/packs.command.js +17 -3
- package/dist/commands/review.command.d.ts.map +1 -1
- package/dist/commands/review.command.js +28 -2
- package/dist/init/init-templates.d.ts.map +1 -1
- package/dist/init/init-templates.js +113 -133
- package/dist/main.d.ts +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +35 -13
- package/dist/output/failure-hints.d.ts +9 -1
- package/dist/output/failure-hints.d.ts.map +1 -1
- package/dist/output/failure-hints.js +8 -2
- package/dist/output/watch-loop.d.ts +1 -9
- package/dist/output/watch-loop.d.ts.map +1 -1
- package/dist/output/watch-loop.js +3 -13
- package/dist/schemas/json-schemas.d.ts +36 -36
- package/dist/schemas/json-schemas.js +36 -36
- package/dist/surface/about.d.ts.map +1 -1
- package/dist/surface/about.js +15 -37
- package/dist/surface/no-args-landing.d.ts.map +1 -1
- package/dist/surface/no-args-landing.js +13 -9
- package/dist/surface/surface-config-writer.d.ts.map +1 -1
- package/dist/surface/surface-config-writer.js +11 -23
- package/package.json +25 -26
- package/dist/init/paths-advisory.d.ts +0 -20
- package/dist/init/paths-advisory.d.ts.map +0 -1
- package/dist/init/paths-advisory.js +0 -88
|
@@ -1,10 +1,18 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
1
9
|
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
2
10
|
import * as nodePath from 'node:path';
|
|
11
|
+
import { pathToFileURL } from 'node:url';
|
|
3
12
|
import { buildPackDoctorReport, buildPackSignatureStatusReport, checkPackSymbolCompat, explainPackSignatureStatus, inspectSharkcraft, mergePackReleaseChecks, runPackReleaseCheck, runPackReleaseChecksForReport, } from '@shrkcrft/inspector';
|
|
4
13
|
import { PACK_SECRET_ENV, signPackManifest, validatePackManifest, verifyPackManifest, } from '@shrkcrft/plugin-api';
|
|
5
14
|
import { flagBool, flagString, resolveCwd, } from "../command-registry.js";
|
|
6
15
|
import { asJson, header, kv } from "../output/format-output.js";
|
|
7
|
-
import { importModuleViaLoader } from '@shrkcrft/core';
|
|
8
16
|
function statusLabel(valid) {
|
|
9
17
|
return valid ? 'OK ' : 'INVALID';
|
|
10
18
|
}
|
|
@@ -545,7 +553,7 @@ async function loadManifestFromPath(manifestPath) {
|
|
|
545
553
|
if (manifestPath.endsWith('.json')) {
|
|
546
554
|
return JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
547
555
|
}
|
|
548
|
-
const mod = (await
|
|
556
|
+
const mod = (await import(__rewriteRelativeImportExtension(pathToFileURL(manifestPath).href)));
|
|
549
557
|
return (mod.default ?? mod);
|
|
550
558
|
}
|
|
551
559
|
export const packsSignCommand = {
|
|
@@ -765,11 +773,17 @@ export const packsCompatCommand = {
|
|
|
765
773
|
: nodePath.resolve(cwd, consumerRootRaw)
|
|
766
774
|
: null;
|
|
767
775
|
const distAware = flagBool(args, 'dist-aware');
|
|
776
|
+
const fastMode = flagBool(args, 'fast');
|
|
768
777
|
// Run a release-check first; surfaces helper-missing diagnostics.
|
|
769
778
|
const release = await runPackReleaseCheck(abs);
|
|
770
779
|
const helperMissing = release.findings.filter((f) => f.code === 'contribution-helper-missing');
|
|
771
780
|
// Symbol-level diff against the consumer's installed plugin-api.
|
|
772
|
-
const symbol = checkPackSymbolCompat({
|
|
781
|
+
const symbol = checkPackSymbolCompat({
|
|
782
|
+
packPath: abs,
|
|
783
|
+
consumerRoot,
|
|
784
|
+
distAware,
|
|
785
|
+
mode: fastMode ? 'fast' : 'ts',
|
|
786
|
+
});
|
|
773
787
|
const passed = helperMissing.length === 0 && symbol.compatible;
|
|
774
788
|
if (flagBool(args, 'json')) {
|
|
775
789
|
process.stdout.write(asJson({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"review.command.d.ts","sourceRoot":"","sources":["../../src/commands/review.command.ts"],"names":[],"mappings":"AAgBA,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AA6GhC,eAAO,MAAM,aAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"review.command.d.ts","sourceRoot":"","sources":["../../src/commands/review.command.ts"],"names":[],"mappings":"AAgBA,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AA6GhC,eAAO,MAAM,aAAa,EAAE,eA8F3B,CAAC"}
|
|
@@ -95,8 +95,21 @@ export const reviewCommand = {
|
|
|
95
95
|
if (args.positional[0] === 'packet') {
|
|
96
96
|
return runPacket(args);
|
|
97
97
|
}
|
|
98
|
-
const
|
|
98
|
+
const cwd = resolveCwd(args);
|
|
99
|
+
const inspection = await inspectSharkcraft({ cwd });
|
|
99
100
|
const since = flagString(args, 'since');
|
|
101
|
+
if (since) {
|
|
102
|
+
const { verifyGitRef } = await import('@shrkcrft/inspector');
|
|
103
|
+
const verify = verifyGitRef(cwd, since);
|
|
104
|
+
if (!verify.valid) {
|
|
105
|
+
process.stderr.write(`error: --since ref "${since}" does not resolve to a commit in this repository.\n` +
|
|
106
|
+
(verify.suggestions && verify.suggestions.length > 0
|
|
107
|
+
? `\nDid you mean:\n${verify.suggestions.map((s) => ` --since ${s}`).join('\n')}\n`
|
|
108
|
+
: '') +
|
|
109
|
+
'\nUse `git branch -a` to list available refs.\n');
|
|
110
|
+
return 2;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
100
113
|
const files = flagList(args, 'files');
|
|
101
114
|
const packet = buildReviewPacket(inspection, {
|
|
102
115
|
...(since ? { since } : {}),
|
|
@@ -295,8 +308,21 @@ function isReviewPacketV3Shape(v) {
|
|
|
295
308
|
return v.schema === REVIEW_PACKET_V3_SCHEMA;
|
|
296
309
|
}
|
|
297
310
|
async function runPacket(args) {
|
|
298
|
-
const
|
|
311
|
+
const cwd = resolveCwd(args);
|
|
312
|
+
const inspection = await inspectSharkcraft({ cwd });
|
|
299
313
|
const since = flagString(args, 'since');
|
|
314
|
+
if (since) {
|
|
315
|
+
const { verifyGitRef } = await import('@shrkcrft/inspector');
|
|
316
|
+
const verify = verifyGitRef(cwd, since);
|
|
317
|
+
if (!verify.valid) {
|
|
318
|
+
process.stderr.write(`error: --since ref "${since}" does not resolve to a commit in this repository.\n` +
|
|
319
|
+
(verify.suggestions && verify.suggestions.length > 0
|
|
320
|
+
? `\nDid you mean:\n${verify.suggestions.map((s) => ` --since ${s}`).join('\n')}\n`
|
|
321
|
+
: '') +
|
|
322
|
+
'\nUse `git branch -a` to list available refs.\n');
|
|
323
|
+
return 2;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
300
326
|
const files = flagList(args, 'files');
|
|
301
327
|
const v2 = flagBool(args, 'v2');
|
|
302
328
|
const baselineFile = flagString(args, 'quality-baseline');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init-templates.d.ts","sourceRoot":"","sources":["../../src/init/init-templates.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB;
|
|
1
|
+
{"version":3,"file":"init-templates.d.ts","sourceRoot":"","sources":["../../src/init/init-templates.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,UAAU,EAAE,SAAS,SAAS,EA4Z1C,CAAC"}
|
|
@@ -1,18 +1,9 @@
|
|
|
1
|
-
// Self-contained scaffolding for `shrk init --legacy`. Every generated
|
|
2
|
-
// `sharkcraft/*.ts` file must work in a brand-new downstream repo where
|
|
3
|
-
// no `@shrkcrft/*` packages are installed beyond the CLI itself. The
|
|
4
|
-
// loaders (knowledge / templates / pipelines / path-conventions) are
|
|
5
|
-
// shape-agnostic — they accept any object with the required string
|
|
6
|
-
// fields — so each emitted file declares its own minimal helpers +
|
|
7
|
-
// enum-like constants inline.
|
|
8
1
|
export const INIT_FILES = [
|
|
9
2
|
{
|
|
10
3
|
relativePath: 'sharkcraft.config.ts',
|
|
11
|
-
content:
|
|
12
|
-
// @shrkcrft/* import required. The config loader validates this object
|
|
13
|
-
// by shape (zod), so the literal works without a helper call.
|
|
4
|
+
content: `import { defineSharkCraftConfig } from '@shrkcrft/config';
|
|
14
5
|
|
|
15
|
-
export default {
|
|
6
|
+
export default defineSharkCraftConfig({
|
|
16
7
|
projectName: 'my-project',
|
|
17
8
|
description: 'A SharkCraft-powered repository.',
|
|
18
9
|
knowledgeFiles: ['knowledge.ts'],
|
|
@@ -22,36 +13,12 @@ export default {
|
|
|
22
13
|
docsFiles: ['docs/overview.md', 'docs/architecture.md', 'docs/quick-start.md'],
|
|
23
14
|
defaultMaxTokens: 4000,
|
|
24
15
|
defaultScope: ['typescript'],
|
|
25
|
-
};
|
|
16
|
+
});
|
|
26
17
|
`,
|
|
27
18
|
},
|
|
28
19
|
{
|
|
29
20
|
relativePath: 'knowledge.ts',
|
|
30
|
-
content:
|
|
31
|
-
// The knowledge loader is shape-agnostic; it accepts any object whose
|
|
32
|
-
// \`id\`, \`title\`, and \`content\` are strings.
|
|
33
|
-
|
|
34
|
-
const KnowledgePriority = {
|
|
35
|
-
Critical: 'critical',
|
|
36
|
-
High: 'high',
|
|
37
|
-
Medium: 'medium',
|
|
38
|
-
Low: 'low',
|
|
39
|
-
} as const;
|
|
40
|
-
|
|
41
|
-
const KnowledgeType = {
|
|
42
|
-
Rule: 'rule',
|
|
43
|
-
Path: 'path',
|
|
44
|
-
Template: 'template',
|
|
45
|
-
Architecture: 'architecture',
|
|
46
|
-
Technical: 'technical',
|
|
47
|
-
Convention: 'convention',
|
|
48
|
-
Workflow: 'workflow',
|
|
49
|
-
Warning: 'warning',
|
|
50
|
-
} as const;
|
|
51
|
-
|
|
52
|
-
function defineKnowledgeEntry<T>(entry: T): T {
|
|
53
|
-
return entry;
|
|
54
|
-
}
|
|
21
|
+
content: `import { defineKnowledgeEntry, KnowledgeType, KnowledgePriority } from '@shrkcrft/knowledge';
|
|
55
22
|
|
|
56
23
|
export const projectOverview = defineKnowledgeEntry({
|
|
57
24
|
id: 'project.overview',
|
|
@@ -100,20 +67,8 @@ export default [projectOverview, aiAgentBriefing, generationSafety];
|
|
|
100
67
|
},
|
|
101
68
|
{
|
|
102
69
|
relativePath: 'rules.ts',
|
|
103
|
-
content:
|
|
104
|
-
|
|
105
|
-
const KnowledgePriority = {
|
|
106
|
-
Critical: 'critical',
|
|
107
|
-
High: 'high',
|
|
108
|
-
Medium: 'medium',
|
|
109
|
-
Low: 'low',
|
|
110
|
-
} as const;
|
|
111
|
-
|
|
112
|
-
const KnowledgeType = { Rule: 'rule' } as const;
|
|
113
|
-
|
|
114
|
-
function defineRule<T>(rule: T): T {
|
|
115
|
-
return { ...rule, type: KnowledgeType.Rule } as T;
|
|
116
|
-
}
|
|
70
|
+
content: `import { defineRule } from '@shrkcrft/rules';
|
|
71
|
+
import { KnowledgePriority } from '@shrkcrft/knowledge';
|
|
117
72
|
|
|
118
73
|
export const tsNamingClasses = defineRule({
|
|
119
74
|
id: 'typescript.naming.classes',
|
|
@@ -187,15 +142,81 @@ export default [
|
|
|
187
142
|
},
|
|
188
143
|
{
|
|
189
144
|
relativePath: 'paths.ts',
|
|
190
|
-
content:
|
|
145
|
+
content: `import { definePathConvention } from '@shrkcrft/paths';
|
|
146
|
+
import { KnowledgePriority } from '@shrkcrft/knowledge';
|
|
147
|
+
|
|
148
|
+
export const appSrc = definePathConvention({
|
|
149
|
+
id: 'app.src',
|
|
150
|
+
title: 'Application source root',
|
|
151
|
+
path: 'src',
|
|
152
|
+
description: 'All application source lives here.',
|
|
153
|
+
priority: KnowledgePriority.Critical,
|
|
154
|
+
scope: ['typescript'],
|
|
155
|
+
tags: ['source-path', 'root'],
|
|
156
|
+
appliesWhen: ['generate-code'],
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
export const services = definePathConvention({
|
|
160
|
+
id: 'app.services',
|
|
161
|
+
title: 'Application services',
|
|
162
|
+
path: 'src/services',
|
|
163
|
+
description: 'Application services live here.',
|
|
164
|
+
priority: KnowledgePriority.High,
|
|
165
|
+
scope: ['typescript', 'backend'],
|
|
166
|
+
tags: ['service', 'source-path'],
|
|
167
|
+
appliesWhen: ['generate-service', 'create-business-logic'],
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
export const utils = definePathConvention({
|
|
171
|
+
id: 'app.utils',
|
|
172
|
+
title: 'Utilities',
|
|
173
|
+
path: 'src/utils',
|
|
174
|
+
description: 'Pure functions, no side effects.',
|
|
175
|
+
priority: KnowledgePriority.Medium,
|
|
176
|
+
scope: ['typescript'],
|
|
177
|
+
tags: ['util', 'source-path'],
|
|
178
|
+
appliesWhen: ['generate-utility'],
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
export const features = definePathConvention({
|
|
182
|
+
id: 'app.features',
|
|
183
|
+
title: 'Feature folders',
|
|
184
|
+
path: 'src/features',
|
|
185
|
+
description: 'Vertical feature slices. Use this for end-to-end features.',
|
|
186
|
+
priority: KnowledgePriority.Medium,
|
|
187
|
+
scope: ['typescript'],
|
|
188
|
+
tags: ['feature', 'source-path'],
|
|
189
|
+
appliesWhen: ['generate-feature'],
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
export const tests = definePathConvention({
|
|
193
|
+
id: 'app.tests',
|
|
194
|
+
title: 'Test files',
|
|
195
|
+
path: 'tests',
|
|
196
|
+
description: 'Test files (or co-located *.spec.ts next to the unit under test).',
|
|
197
|
+
priority: KnowledgePriority.Medium,
|
|
198
|
+
scope: ['typescript', 'testing'],
|
|
199
|
+
tags: ['test', 'source-path'],
|
|
200
|
+
appliesWhen: ['generate-test'],
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
export const docs = definePathConvention({
|
|
204
|
+
id: 'app.docs',
|
|
205
|
+
title: 'Documentation',
|
|
206
|
+
path: 'docs',
|
|
207
|
+
description: 'Long-form human-readable docs (optional).',
|
|
208
|
+
priority: KnowledgePriority.Low,
|
|
209
|
+
scope: ['typescript'],
|
|
210
|
+
tags: ['docs'],
|
|
211
|
+
appliesWhen: ['add-docs'],
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
export default [appSrc, services, utils, features, tests, docs];
|
|
215
|
+
`,
|
|
191
216
|
},
|
|
192
217
|
{
|
|
193
218
|
relativePath: 'templates.ts',
|
|
194
|
-
content:
|
|
195
|
-
|
|
196
|
-
function defineTemplate<T>(template: T): T {
|
|
197
|
-
return template;
|
|
198
|
-
}
|
|
219
|
+
content: `import { defineTemplate } from '@shrkcrft/templates';
|
|
199
220
|
|
|
200
221
|
export const tsService = defineTemplate({
|
|
201
222
|
id: 'typescript.service',
|
|
@@ -208,8 +229,8 @@ export const tsService = defineTemplate({
|
|
|
208
229
|
{ name: 'name', required: true, description: 'kebab-case file name (e.g. user-profile)' },
|
|
209
230
|
{ name: 'className', required: true, description: 'PascalCase class name (e.g. UserProfileService)' },
|
|
210
231
|
],
|
|
211
|
-
targetPath: ({ name }
|
|
212
|
-
content: ({ className }
|
|
232
|
+
targetPath: ({ name }) => \`src/services/\${name}.service.ts\`,
|
|
233
|
+
content: ({ className }) => \`export class \${className} {
|
|
213
234
|
constructor() {}
|
|
214
235
|
|
|
215
236
|
init(): void {
|
|
@@ -232,14 +253,42 @@ export const tsUtility = defineTemplate({
|
|
|
232
253
|
{ name: 'name', required: true, description: 'kebab-case file name' },
|
|
233
254
|
{ name: 'camel', required: true, description: 'camelCase function name' },
|
|
234
255
|
],
|
|
235
|
-
targetPath: ({ name }
|
|
236
|
-
content: ({ camel }
|
|
256
|
+
targetPath: ({ name }) => \`src/utils/\${name}.ts\`,
|
|
257
|
+
content: ({ camel }) => \`export function \${camel}(input: unknown): unknown {
|
|
237
258
|
return input;
|
|
238
259
|
}
|
|
239
260
|
\`,
|
|
240
261
|
postGenerationNotes: ['Keep utilities pure. No side effects, no shared mutable state.'],
|
|
241
262
|
});
|
|
242
263
|
|
|
264
|
+
export const tsFeatureFolder = defineTemplate({
|
|
265
|
+
id: 'typescript.feature',
|
|
266
|
+
name: 'TypeScript Feature folder',
|
|
267
|
+
description: 'Creates a vertical feature slice (index + service + types).',
|
|
268
|
+
tags: ['typescript', 'feature'],
|
|
269
|
+
scope: ['typescript'],
|
|
270
|
+
appliesWhen: ['generate-feature'],
|
|
271
|
+
variables: [
|
|
272
|
+
{ name: 'name', required: true },
|
|
273
|
+
{ name: 'pascal', required: true },
|
|
274
|
+
],
|
|
275
|
+
files: ({ name, pascal }) => [
|
|
276
|
+
{
|
|
277
|
+
targetPath: \`src/features/\${name}/index.ts\`,
|
|
278
|
+
content: \`export * from './\${name}.service.ts';\nexport * from './\${name}.types.ts';\n\`,
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
targetPath: \`src/features/\${name}/\${name}.service.ts\`,
|
|
282
|
+
content: \`import type { I\${pascal}Config } from './\${name}.types.ts';\n\nexport class \${pascal}Service {\n constructor(private readonly config: I\${pascal}Config) {}\n}\n\`,
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
targetPath: \`src/features/\${name}/\${name}.types.ts\`,
|
|
286
|
+
content: \`export interface I\${pascal}Config {\n enabled: boolean;\n}\n\`,
|
|
287
|
+
},
|
|
288
|
+
],
|
|
289
|
+
postGenerationNotes: ['Add tests under tests/<feature> or co-located *.spec.ts.'],
|
|
290
|
+
});
|
|
291
|
+
|
|
243
292
|
export const tsTest = defineTemplate({
|
|
244
293
|
id: 'typescript.test',
|
|
245
294
|
name: 'TypeScript Test File',
|
|
@@ -251,18 +300,11 @@ export const tsTest = defineTemplate({
|
|
|
251
300
|
{ name: 'name', required: true },
|
|
252
301
|
{ name: 'pascal', required: true },
|
|
253
302
|
],
|
|
254
|
-
targetPath: ({ name }
|
|
255
|
-
content: ({ pascal }
|
|
256
|
-
|
|
257
|
-
describe('\${pascal}', () => {
|
|
258
|
-
test('placeholder', () => {
|
|
259
|
-
expect(true).toBe(true);
|
|
260
|
-
});
|
|
261
|
-
});
|
|
262
|
-
\`,
|
|
303
|
+
targetPath: ({ name }) => \`tests/\${name}.spec.ts\`,
|
|
304
|
+
content: ({ pascal }) => \`import { describe, expect, test } from 'bun:test';\n\ndescribe('\${pascal}', () => {\n test('placeholder', () => {\n expect(true).toBe(true);\n });\n});\n\`,
|
|
263
305
|
});
|
|
264
306
|
|
|
265
|
-
export default [tsService, tsUtility, tsTest];
|
|
307
|
+
export default [tsService, tsUtility, tsFeatureFolder, tsTest];
|
|
266
308
|
`,
|
|
267
309
|
},
|
|
268
310
|
{
|
|
@@ -369,65 +411,3 @@ Lower-priority work for SharkCraft-powered knowledge in this repo.
|
|
|
369
411
|
`,
|
|
370
412
|
},
|
|
371
413
|
];
|
|
372
|
-
function PATHS_PLACEHOLDER_CONTENT() {
|
|
373
|
-
// The legacy seed ships generic path examples. The modern preset path
|
|
374
|
-
// (`shrk init --preset <id>`) is workspace-aware. To avoid emitting
|
|
375
|
-
// broken defaults like `src/services/` in repos that don't have them,
|
|
376
|
-
// the legacy seed now ships *commented* examples plus an `// TODO:`
|
|
377
|
-
// marker the human is expected to fill in. The runner-instructions in
|
|
378
|
-
// docs/onboarding.md describe how to derive paths from the live repo.
|
|
379
|
-
return `// Local helpers — keep this file self-contained (no @shrkcrft/* imports).
|
|
380
|
-
|
|
381
|
-
const KnowledgePriority = {
|
|
382
|
-
Critical: 'critical',
|
|
383
|
-
High: 'high',
|
|
384
|
-
Medium: 'medium',
|
|
385
|
-
Low: 'low',
|
|
386
|
-
} as const;
|
|
387
|
-
|
|
388
|
-
const KnowledgeType = { Path: 'path' } as const;
|
|
389
|
-
|
|
390
|
-
function definePathConvention<T>(convention: T): T {
|
|
391
|
-
return { ...convention, type: KnowledgeType.Path } as T;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
// TODO: replace the examples below with real path conventions for this
|
|
395
|
-
// repository. Run \`shrk onboard --dry-run\` to see what the inference
|
|
396
|
-
// engine detects from the workspace.
|
|
397
|
-
|
|
398
|
-
export const appSrc = definePathConvention({
|
|
399
|
-
id: 'app.src',
|
|
400
|
-
title: 'Application source root',
|
|
401
|
-
path: 'src',
|
|
402
|
-
description: 'All application source lives here. Adjust to match this repo.',
|
|
403
|
-
priority: KnowledgePriority.Critical,
|
|
404
|
-
scope: ['typescript'],
|
|
405
|
-
tags: ['source-path', 'root'],
|
|
406
|
-
appliesWhen: ['generate-code'],
|
|
407
|
-
});
|
|
408
|
-
|
|
409
|
-
export const tests = definePathConvention({
|
|
410
|
-
id: 'app.tests',
|
|
411
|
-
title: 'Test files',
|
|
412
|
-
path: 'tests',
|
|
413
|
-
description: 'Test files. Many repos co-locate \`*.spec.ts\` next to the unit under test instead — pick one.',
|
|
414
|
-
priority: KnowledgePriority.Medium,
|
|
415
|
-
scope: ['typescript', 'testing'],
|
|
416
|
-
tags: ['test', 'source-path'],
|
|
417
|
-
appliesWhen: ['generate-test'],
|
|
418
|
-
});
|
|
419
|
-
|
|
420
|
-
export const docs = definePathConvention({
|
|
421
|
-
id: 'app.docs',
|
|
422
|
-
title: 'Documentation',
|
|
423
|
-
path: 'docs',
|
|
424
|
-
description: 'Long-form human-readable docs (optional).',
|
|
425
|
-
priority: KnowledgePriority.Low,
|
|
426
|
-
scope: ['typescript'],
|
|
427
|
-
tags: ['docs'],
|
|
428
|
-
appliesWhen: ['add-docs'],
|
|
429
|
-
});
|
|
430
|
-
|
|
431
|
-
export default [appSrc, tests, docs];
|
|
432
|
-
`;
|
|
433
|
-
}
|
package/dist/main.d.ts
CHANGED
package/dist/main.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";AACA,OAAO,EACL,eAAe,EAIhB,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";AACA,OAAO,EACL,eAAe,EAIhB,MAAM,uBAAuB,CAAC;AAqX/B,wBAAgB,aAAa,IAAI,eAAe,CA2V/C;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA2BrE;AAqGD;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CA4CxE"}
|
package/dist/main.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
2
|
import { CommandRegistry, extractGlobalCwd, parseArgs, } from "./command-registry.js";
|
|
3
3
|
import { initCommand } from "./commands/init.command.js";
|
|
4
4
|
import { inspectCommand } from "./commands/inspect.command.js";
|
|
@@ -120,6 +120,33 @@ import { buildSurfaceSummary, findCommandInSummary } from "./surface/surface-sum
|
|
|
120
120
|
import { makeSurfaceNotEnabledError, renderSurfaceNotEnabledText, SURFACE_NOT_ENABLED_EXIT_CODE, } from "./surface/not-enabled-error.js";
|
|
121
121
|
import { extractCommandPath, recordUsage, sanitizeFlagNames, } from "./usage/usage-log.js";
|
|
122
122
|
import { loadProjectConfig } from '@shrkcrft/config';
|
|
123
|
+
import { initTokenizer } from '@shrkcrft/context';
|
|
124
|
+
import { statSync } from 'node:fs';
|
|
125
|
+
import { resolve as resolvePath } from 'node:path';
|
|
126
|
+
function isUsableDirectory(path) {
|
|
127
|
+
try {
|
|
128
|
+
return statSync(path).isDirectory();
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
let tokenizerInitPromise = null;
|
|
135
|
+
/**
|
|
136
|
+
* Best-effort one-time upgrade from the estimator to gpt-tokenizer.
|
|
137
|
+
*
|
|
138
|
+
* The estimator is always active before this resolves, so commands that
|
|
139
|
+
* race the load still get a budget-safe (if slightly off) count. Subsequent
|
|
140
|
+
* `countTokens` calls get the real BPE count.
|
|
141
|
+
*/
|
|
142
|
+
async function ensureTokenizerReady() {
|
|
143
|
+
if (process.env.SHARKCRAFT_NO_REAL_TOKENIZER === '1')
|
|
144
|
+
return;
|
|
145
|
+
if (!tokenizerInitPromise) {
|
|
146
|
+
tokenizerInitPromise = initTokenizer().catch(() => false);
|
|
147
|
+
}
|
|
148
|
+
await tokenizerInitPromise;
|
|
149
|
+
}
|
|
123
150
|
export function buildRegistry() {
|
|
124
151
|
const registry = new CommandRegistry();
|
|
125
152
|
registry.register(initCommand);
|
|
@@ -491,9 +518,15 @@ async function isUsageEnabled(cwd) {
|
|
|
491
518
|
}
|
|
492
519
|
}
|
|
493
520
|
async function runCliInner(argv) {
|
|
521
|
+
await ensureTokenizerReady();
|
|
494
522
|
const registry = buildRegistry();
|
|
495
523
|
// Pre-parse the global --cwd so it can appear anywhere (incl. before the command).
|
|
496
524
|
const { cwd: globalCwd, rest: cleanArgv } = extractGlobalCwd(argv);
|
|
525
|
+
if (globalCwd !== undefined && !isUsableDirectory(globalCwd)) {
|
|
526
|
+
process.stderr.write(`error: --cwd "${globalCwd}" is not an existing directory.\n` +
|
|
527
|
+
`Resolved to: ${resolvePath(globalCwd)}\n`);
|
|
528
|
+
return 2;
|
|
529
|
+
}
|
|
497
530
|
const [first] = cleanArgv;
|
|
498
531
|
// bare invocation lands on the curated tiered view.
|
|
499
532
|
if (!first) {
|
|
@@ -678,19 +711,8 @@ function printDidYouMean(attempted) {
|
|
|
678
711
|
process.stderr.write(renderErrorFooter(footer));
|
|
679
712
|
}
|
|
680
713
|
// Entry point when invoked directly.
|
|
681
|
-
//
|
|
682
|
-
// Bun exposes `import.meta.main`; Node does not. When Node runs the
|
|
683
|
-
// compiled `dist/main.js` directly the path-suffix check (`main.js`)
|
|
684
|
-
// catches it. The npm bin shim points at `shrk` so that suffix also
|
|
685
|
-
// triggers it. Source dev under Bun still runs via `main.ts`.
|
|
686
714
|
const isMain = typeof import.meta !== 'undefined' && import.meta.main === true;
|
|
687
|
-
|
|
688
|
-
if (isMain ||
|
|
689
|
-
entryPath.endsWith('main.ts') ||
|
|
690
|
-
entryPath.endsWith('main.js') ||
|
|
691
|
-
entryPath.endsWith('shrk') ||
|
|
692
|
-
entryPath.endsWith('shrk.js') ||
|
|
693
|
-
entryPath.endsWith('shrk.cmd')) {
|
|
715
|
+
if (isMain || process.argv[1]?.endsWith('main.ts') || process.argv[1]?.endsWith('shrk')) {
|
|
694
716
|
const argv = process.argv.slice(2);
|
|
695
717
|
runCli(argv).then((code) => process.exit(code), (err) => {
|
|
696
718
|
process.stderr.write(`Fatal: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
@@ -12,7 +12,15 @@ export interface IFailureHint {
|
|
|
12
12
|
doc?: string;
|
|
13
13
|
}
|
|
14
14
|
export declare function renderFailureHints(hints: readonly IFailureHint[]): string;
|
|
15
|
-
export
|
|
15
|
+
export interface IDoctorHintsContext {
|
|
16
|
+
/**
|
|
17
|
+
* True when the workspace has no `sharkcraft/` folder. On a fresh repo
|
|
18
|
+
* the right next step is `shrk init`, not advanced suppressions/watch
|
|
19
|
+
* loops.
|
|
20
|
+
*/
|
|
21
|
+
sharkcraftFolderMissing?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export declare function doctorHints(context?: IDoctorHintsContext): IFailureHint[];
|
|
16
24
|
export declare function staleKnowledgeHints(): IFailureHint[];
|
|
17
25
|
export declare function templateDriftHints(): IFailureHint[];
|
|
18
26
|
export declare function fuzzyImpactAmbiguousHints(): IFailureHint[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"failure-hints.d.ts","sourceRoot":"","sources":["../../src/output/failure-hints.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,yBAAyB;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,GAAG,MAAM,CAUzE;AAID,wBAAgB,WAAW,
|
|
1
|
+
{"version":3,"file":"failure-hints.d.ts","sourceRoot":"","sources":["../../src/output/failure-hints.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,yBAAyB;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,GAAG,MAAM,CAUzE;AAID,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC;AAED,wBAAgB,WAAW,CAAC,OAAO,GAAE,mBAAwB,GAAG,YAAY,EAAE,CAa7E;AAED,wBAAgB,mBAAmB,IAAI,YAAY,EAAE,CAMpD;AAED,wBAAgB,kBAAkB,IAAI,YAAY,EAAE,CAMnD;AAED,wBAAgB,yBAAyB,IAAI,YAAY,EAAE,CAK1D;AAED,wBAAgB,6BAA6B,IAAI,YAAY,EAAE,CAK9D;AAED,wBAAgB,kBAAkB,IAAI,YAAY,EAAE,CAKnD;AAED,wBAAgB,wBAAwB,IAAI,YAAY,EAAE,CAKzD;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC;CACnC;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAiB9D;AAED,MAAM,MAAM,eAAe,GACvB,iBAAiB,GACjB,mBAAmB,GACnB,gBAAgB,GAChB,oBAAoB,GACpB,uBAAuB,GACvB,kBAAkB,GAClB,eAAe,GACf,2BAA2B,GAC3B,sBAAsB,GACtB,+BAA+B,GAC/B,wBAAwB,GACxB,8BAA8B,CAAC;AAEnC;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,YAAY,GAAG,SAAS,CA4E3G"}
|
|
@@ -11,8 +11,14 @@ export function renderFailureHints(hints) {
|
|
|
11
11
|
}
|
|
12
12
|
return lines.join('\n') + '\n';
|
|
13
13
|
}
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
export function doctorHints(context = {}) {
|
|
15
|
+
if (context.sharkcraftFolderMissing) {
|
|
16
|
+
return [
|
|
17
|
+
{ label: 'scaffold sharkcraft/ (auto-pick a preset)', command: 'shrk init --zero-config' },
|
|
18
|
+
{ label: 'preview the scaffold first', command: 'shrk init --zero-config --dry-run' },
|
|
19
|
+
{ label: 'try the killer demo (no folder required)', command: 'shrk check boundaries --changed-only --since main' },
|
|
20
|
+
];
|
|
21
|
+
}
|
|
16
22
|
return [
|
|
17
23
|
{ label: 'preview fix suggestions', command: 'shrk fix preview --action-hints' },
|
|
18
24
|
{ label: 'list suppressions', command: 'shrk doctor suppressions list' },
|
|
@@ -27,19 +27,11 @@ export interface IWatchPlan {
|
|
|
27
27
|
}
|
|
28
28
|
export declare function buildWatchPlan(options: IWatchLoopOptions, steps: readonly string[]): IWatchPlan;
|
|
29
29
|
import type { ParsedArgs } from '../command-registry.js';
|
|
30
|
-
export interface IWatchModeOptions {
|
|
31
|
-
/**
|
|
32
|
-
* Paths to watch when the user does not pass `--paths`. Defaults to
|
|
33
|
-
* `['sharkcraft']` if omitted. Use this for commands that scan code
|
|
34
|
-
* outside `sharkcraft/` (e.g. `check boundaries` scans the whole repo).
|
|
35
|
-
*/
|
|
36
|
-
defaultPaths?: readonly string[];
|
|
37
|
-
}
|
|
38
30
|
/**
|
|
39
31
|
* Run a command's `run` function inside a watch loop when --watch is set.
|
|
40
32
|
*
|
|
41
33
|
* @returns null if --watch is not set (caller proceeds as before), otherwise
|
|
42
34
|
* the exit code of the watch loop.
|
|
43
35
|
*/
|
|
44
|
-
export declare function maybeRunInWatchMode(args: ParsedArgs, runner: (innerArgs: ParsedArgs) => Promise<number
|
|
36
|
+
export declare function maybeRunInWatchMode(args: ParsedArgs, runner: (innerArgs: ParsedArgs) => Promise<number>): Promise<number | null>;
|
|
45
37
|
//# sourceMappingURL=watch-loop.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watch-loop.d.ts","sourceRoot":"","sources":["../../src/output/watch-loop.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,uCAAuC;IACvC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,4BAA4B;IAC5B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,wBAAwB;IACxB,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACvC;AAED,wBAAsB,YAAY,CAChC,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,kBAAkB,GAC3B,OAAO,CAAC,MAAM,CAAC,CA6DjB;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,0BAA0B,CAAC;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B;AAED,wBAAgB,cAAc,CAC5B,OAAO,EAAE,iBAAiB,EAC1B,KAAK,EAAE,SAAS,MAAM,EAAE,GACvB,UAAU,CAYZ;AAED,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAGzD
|
|
1
|
+
{"version":3,"file":"watch-loop.d.ts","sourceRoot":"","sources":["../../src/output/watch-loop.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,uCAAuC;IACvC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,4BAA4B;IAC5B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,wBAAwB;IACxB,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACvC;AAED,wBAAsB,YAAY,CAChC,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,kBAAkB,GAC3B,OAAO,CAAC,MAAM,CAAC,CA6DjB;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,0BAA0B,CAAC;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B;AAED,wBAAgB,cAAc,CAC5B,OAAO,EAAE,iBAAiB,EAC1B,KAAK,EAAE,SAAS,MAAM,EAAE,GACvB,UAAU,CAYZ;AAED,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAGzD;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,CAAC,SAAS,EAAE,UAAU,KAAK,OAAO,CAAC,MAAM,CAAC,GACjD,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA0BxB"}
|
|
@@ -81,41 +81,31 @@ export function buildWatchPlan(options, steps) {
|
|
|
81
81
|
steps,
|
|
82
82
|
};
|
|
83
83
|
}
|
|
84
|
-
import { flagBool, flagNumber,
|
|
84
|
+
import { flagBool, flagNumber, resolveCwd } from "../command-registry.js";
|
|
85
85
|
/**
|
|
86
86
|
* Run a command's `run` function inside a watch loop when --watch is set.
|
|
87
87
|
*
|
|
88
88
|
* @returns null if --watch is not set (caller proceeds as before), otherwise
|
|
89
89
|
* the exit code of the watch loop.
|
|
90
90
|
*/
|
|
91
|
-
export async function maybeRunInWatchMode(args, runner
|
|
91
|
+
export async function maybeRunInWatchMode(args, runner) {
|
|
92
92
|
if (!flagBool(args, 'watch'))
|
|
93
93
|
return null;
|
|
94
94
|
const cwd = resolveCwd(args);
|
|
95
95
|
const debounce = flagNumber(args, 'debounce') ?? 300;
|
|
96
96
|
const once = flagBool(args, 'once');
|
|
97
|
-
const pathsFlag = flagString(args, 'paths');
|
|
98
|
-
const userPaths = pathsFlag
|
|
99
|
-
? pathsFlag.split(',').map((s) => s.trim()).filter((s) => s.length > 0)
|
|
100
|
-
: [];
|
|
101
|
-
const paths = userPaths.length > 0
|
|
102
|
-
? userPaths
|
|
103
|
-
: options.defaultPaths && options.defaultPaths.length > 0
|
|
104
|
-
? options.defaultPaths
|
|
105
|
-
: ['sharkcraft'];
|
|
106
97
|
// Strip --watch so the inner snapshot doesn't recurse.
|
|
107
98
|
const innerFlags = new Map(args.flags);
|
|
108
99
|
innerFlags.delete('watch');
|
|
109
100
|
innerFlags.delete('once');
|
|
110
101
|
innerFlags.delete('debounce');
|
|
111
|
-
innerFlags.delete('paths');
|
|
112
102
|
const innerArgs = {
|
|
113
103
|
positional: args.positional,
|
|
114
104
|
flags: innerFlags,
|
|
115
105
|
multiFlags: args.multiFlags,
|
|
116
106
|
...(args.globalCwd ? { globalCwd: args.globalCwd } : {}),
|
|
117
107
|
};
|
|
118
|
-
return runWatchLoop({ cwd, debounce, once
|
|
108
|
+
return runWatchLoop({ cwd, debounce, once }, {
|
|
119
109
|
snapshot: async () => {
|
|
120
110
|
const ts = new Date().toLocaleTimeString();
|
|
121
111
|
process.stdout.write(`\n[watch] ${ts}\n`);
|