sysprom 1.13.0 → 1.13.2
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 +5 -5
- package/dist/src/cli/commands/init.d.ts +2 -4
- package/dist/src/cli/commands/init.js +4 -7
- package/dist/src/cli/commands/json2md.d.ts +8 -1
- package/dist/src/cli/commands/json2md.js +14 -25
- package/dist/src/cli/commands/md2json.d.ts +7 -1
- package/dist/src/cli/commands/md2json.js +10 -13
- package/dist/src/cli/commands/plan.js +3 -6
- package/dist/src/cli/commands/speckit.js +18 -30
- package/dist/src/cli/commands/sync.d.ts +10 -1
- package/dist/src/cli/commands/sync.js +26 -37
- package/dist/src/cli/program.js +31 -2
- package/dist/src/cli/shared.d.ts +0 -2
- package/dist/src/cli/shared.js +0 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,8 +23,8 @@ Both `sysprom` and `spm` are available as commands.
|
|
|
23
23
|
|
|
24
24
|
```sh
|
|
25
25
|
# Convert between formats
|
|
26
|
-
spm json2md .spm.json ./.spm
|
|
27
|
-
spm md2json ./.spm output.spm.json
|
|
26
|
+
spm json2md --input .spm.json --output ./.spm
|
|
27
|
+
spm md2json --input ./.spm --output output.spm.json
|
|
28
28
|
|
|
29
29
|
# Validate and summarise (auto-detects .spm.json in current directory)
|
|
30
30
|
spm validate
|
|
@@ -223,17 +223,17 @@ All significant activity — decisions, changes, new capabilities, and invariant
|
|
|
223
223
|
spm add decision --id D23 --name "My Decision" --context "Why this was needed"
|
|
224
224
|
|
|
225
225
|
# Or edit ./.spm/DECISIONS.md directly, then sync
|
|
226
|
-
spm md2json ./.spm .spm.json
|
|
226
|
+
spm md2json --input ./.spm --output .spm.json
|
|
227
227
|
```
|
|
228
228
|
|
|
229
229
|
Keep both representations in sync after any change:
|
|
230
230
|
|
|
231
231
|
```sh
|
|
232
232
|
# JSON → Markdown
|
|
233
|
-
spm json2md .spm.json ./.spm
|
|
233
|
+
spm json2md --input .spm.json --output ./.spm
|
|
234
234
|
|
|
235
235
|
# Markdown → JSON
|
|
236
|
-
spm md2json ./.spm .spm.json
|
|
236
|
+
spm md2json --input ./.spm --output .spm.json
|
|
237
237
|
```
|
|
238
238
|
|
|
239
239
|
> **Important:** Always keep `.spm.json` and `./.spm/` up to date with current activity and in sync with each other. Record all decisions, changes, and new capabilities as they happen. After any change to either representation, run the appropriate conversion command above. Validate with `spm validate` before committing.
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import * as z from "zod";
|
|
2
2
|
import type { CommandDef } from "../define-command.js";
|
|
3
|
-
declare const argsSchema: z.ZodObject<{
|
|
4
|
-
path: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
5
|
-
}, z.core.$strip>;
|
|
6
3
|
declare const optsSchema: z.ZodObject<{
|
|
4
|
+
path: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
7
5
|
title: z.ZodOptional<z.ZodString>;
|
|
8
6
|
scope: z.ZodOptional<z.ZodString>;
|
|
9
7
|
format: z.ZodOptional<z.ZodEnum<{
|
|
@@ -12,5 +10,5 @@ declare const optsSchema: z.ZodObject<{
|
|
|
12
10
|
dir: "dir";
|
|
13
11
|
}>>;
|
|
14
12
|
}, z.core.$strict>;
|
|
15
|
-
export declare const initCommand: CommandDef<
|
|
13
|
+
export declare const initCommand: CommandDef<z.ZodObject<z.ZodRawShape>, typeof optsSchema>;
|
|
16
14
|
export {};
|
|
@@ -35,15 +35,13 @@ function resolveInitTarget(pathArg, format) {
|
|
|
35
35
|
ioFormat: formatToIoFormat(fmt),
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
|
-
const
|
|
38
|
+
const optsSchema = z
|
|
39
|
+
.object({
|
|
39
40
|
path: z
|
|
40
41
|
.string()
|
|
41
42
|
.optional()
|
|
42
43
|
.default(".")
|
|
43
44
|
.describe("Target path (default: current directory)"),
|
|
44
|
-
});
|
|
45
|
-
const optsSchema = z
|
|
46
|
-
.object({
|
|
47
45
|
title: z.string().optional().describe("Document title"),
|
|
48
46
|
scope: z.string().optional().describe("Document scope"),
|
|
49
47
|
format: z
|
|
@@ -56,10 +54,9 @@ export const initCommand = {
|
|
|
56
54
|
name: "init",
|
|
57
55
|
description: initDocumentOp.def.description,
|
|
58
56
|
apiLink: initDocumentOp.def.name,
|
|
59
|
-
args: argsSchema,
|
|
60
57
|
opts: optsSchema,
|
|
61
|
-
action(
|
|
62
|
-
const { outputPath, ioFormat } = resolveInitTarget(
|
|
58
|
+
action(_args, opts) {
|
|
59
|
+
const { outputPath, ioFormat } = resolveInitTarget(opts.path, opts.format);
|
|
63
60
|
if (existsSync(outputPath)) {
|
|
64
61
|
console.error(`Already exists: ${outputPath}`);
|
|
65
62
|
process.exit(1);
|
|
@@ -1,2 +1,9 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
1
2
|
import type { CommandDef } from "../define-command.js";
|
|
2
|
-
|
|
3
|
+
declare const optsSchema: z.ZodObject<{
|
|
4
|
+
input: z.ZodString;
|
|
5
|
+
output: z.ZodString;
|
|
6
|
+
singleFile: z.ZodOptional<z.ZodBoolean>;
|
|
7
|
+
}, z.core.$strict>;
|
|
8
|
+
export declare const json2mdCommand: CommandDef<z.ZodObject<z.ZodRawShape>, typeof optsSchema>;
|
|
9
|
+
export {};
|
|
@@ -4,35 +4,24 @@ import { resolve } from "node:path";
|
|
|
4
4
|
import { SysProMDocument } from "../../schema.js";
|
|
5
5
|
import { jsonToMarkdown } from "../../json-to-md.js";
|
|
6
6
|
import { jsonToMarkdownOp } from "../../operations/index.js";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
const optsSchema = z
|
|
8
|
+
.object({
|
|
9
|
+
input: z.string().describe("Path to SysProM JSON file"),
|
|
10
|
+
output: z.string().describe("Output path (file or directory)"),
|
|
11
|
+
singleFile: z
|
|
12
|
+
.boolean()
|
|
13
|
+
.optional()
|
|
14
|
+
.describe("Force single-file output format"),
|
|
15
|
+
})
|
|
16
|
+
.strict();
|
|
13
17
|
export const json2mdCommand = {
|
|
14
18
|
name: "json2md",
|
|
15
19
|
description: jsonToMarkdownOp.def.description,
|
|
16
20
|
apiLink: jsonToMarkdownOp.def.name,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
opts: z
|
|
22
|
-
.object({
|
|
23
|
-
singleFile: z
|
|
24
|
-
.boolean()
|
|
25
|
-
.optional()
|
|
26
|
-
.describe("Force single-file output format"),
|
|
27
|
-
})
|
|
28
|
-
.strict(),
|
|
29
|
-
action(args, opts) {
|
|
30
|
-
if (!isArgs(args))
|
|
31
|
-
throw new Error("Invalid args");
|
|
32
|
-
if (!isOpts(opts))
|
|
33
|
-
throw new Error("Invalid opts");
|
|
34
|
-
const inputPath = resolve(args.input);
|
|
35
|
-
const outputPath = resolve(args.output);
|
|
21
|
+
opts: optsSchema,
|
|
22
|
+
action(_args, opts) {
|
|
23
|
+
const inputPath = resolve(opts.input);
|
|
24
|
+
const outputPath = resolve(opts.output);
|
|
36
25
|
const raw = JSON.parse(readFileSync(inputPath, "utf8"));
|
|
37
26
|
if (!SysProMDocument.is(raw)) {
|
|
38
27
|
const result = SysProMDocument.safeParse(raw);
|
|
@@ -1,2 +1,8 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
1
2
|
import type { CommandDef } from "../define-command.js";
|
|
2
|
-
|
|
3
|
+
declare const optsSchema: z.ZodObject<{
|
|
4
|
+
input: z.ZodString;
|
|
5
|
+
output: z.ZodString;
|
|
6
|
+
}, z.core.$strict>;
|
|
7
|
+
export declare const md2jsonCommand: CommandDef<z.ZodObject<z.ZodRawShape>, typeof optsSchema>;
|
|
8
|
+
export {};
|
|
@@ -4,23 +4,20 @@ import { resolve } from "node:path";
|
|
|
4
4
|
import { markdownToJson } from "../../md-to-json.js";
|
|
5
5
|
import { canonicalise } from "../../canonical-json.js";
|
|
6
6
|
import { markdownToJsonOp } from "../../operations/index.js";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
const optsSchema = z
|
|
8
|
+
.object({
|
|
9
|
+
input: z.string().describe("Path to SysProM Markdown (file or directory)"),
|
|
10
|
+
output: z.string().describe("Output JSON file path"),
|
|
11
|
+
})
|
|
12
|
+
.strict();
|
|
10
13
|
export const md2jsonCommand = {
|
|
11
14
|
name: "md2json",
|
|
12
15
|
description: markdownToJsonOp.def.description,
|
|
13
16
|
apiLink: markdownToJsonOp.def.name,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
opts: z.object({}).strict(),
|
|
19
|
-
action(args) {
|
|
20
|
-
if (!isArgs(args))
|
|
21
|
-
throw new Error("Invalid args");
|
|
22
|
-
const inputPath = resolve(args.input);
|
|
23
|
-
const outputPath = resolve(args.output);
|
|
17
|
+
opts: optsSchema,
|
|
18
|
+
action(_args, opts) {
|
|
19
|
+
const inputPath = resolve(opts.input);
|
|
20
|
+
const outputPath = resolve(opts.output);
|
|
24
21
|
const doc = markdownToJson(inputPath);
|
|
25
22
|
writeFileSync(outputPath, canonicalise(doc, { indent: "\t" }) + "\n");
|
|
26
23
|
console.log(`Written to ${outputPath}`);
|
|
@@ -6,10 +6,8 @@ import { planInitOp, planAddTaskOp, planStatusOp, planProgressOp, planGateOp, }
|
|
|
6
6
|
// ============================================================================
|
|
7
7
|
// Subcommands
|
|
8
8
|
// ============================================================================
|
|
9
|
-
const initArgs = z.object({
|
|
10
|
-
output: z.string().describe("Path to output SysProM file"),
|
|
11
|
-
});
|
|
12
9
|
const initOpts = z.object({
|
|
10
|
+
output: z.string().describe("Path to output SysProM file"),
|
|
13
11
|
prefix: z.string().describe("Plan prefix (e.g. PLAN)"),
|
|
14
12
|
name: z.string().optional().describe("Plan name (defaults to prefix)"),
|
|
15
13
|
});
|
|
@@ -17,10 +15,9 @@ const initSubcommand = {
|
|
|
17
15
|
name: "init",
|
|
18
16
|
description: planInitOp.def.description,
|
|
19
17
|
apiLink: planInitOp.def.name,
|
|
20
|
-
args: initArgs,
|
|
21
18
|
opts: initOpts,
|
|
22
|
-
action(
|
|
23
|
-
const outputPath =
|
|
19
|
+
action(_args, opts) {
|
|
20
|
+
const outputPath = opts.output;
|
|
24
21
|
const prefix = opts.prefix;
|
|
25
22
|
const name = opts.name ?? prefix;
|
|
26
23
|
if (existsSync(outputPath)) {
|
|
@@ -45,11 +45,9 @@ function compareDocuments(oldDoc, newDoc) {
|
|
|
45
45
|
// ============================================================================
|
|
46
46
|
// Subcommands
|
|
47
47
|
// ============================================================================
|
|
48
|
-
const
|
|
48
|
+
const importOpts = z.object({
|
|
49
49
|
speckitDir: z.string().describe("Path to Spec-Kit feature directory"),
|
|
50
50
|
output: z.string().describe("Path to output SysProM file"),
|
|
51
|
-
});
|
|
52
|
-
const importOpts = z.object({
|
|
53
51
|
prefix: z
|
|
54
52
|
.string()
|
|
55
53
|
.optional()
|
|
@@ -58,11 +56,10 @@ const importOpts = z.object({
|
|
|
58
56
|
const importSubcommand = {
|
|
59
57
|
name: "import",
|
|
60
58
|
description: speckitImportOp.def.description,
|
|
61
|
-
args: importArgs,
|
|
62
59
|
opts: importOpts,
|
|
63
|
-
action(
|
|
64
|
-
const specKitDir = resolve(
|
|
65
|
-
const outputPath = resolve(
|
|
60
|
+
action(_args, opts) {
|
|
61
|
+
const specKitDir = resolve(opts.speckitDir);
|
|
62
|
+
const outputPath = resolve(opts.output);
|
|
66
63
|
if (!existsSync(specKitDir)) {
|
|
67
64
|
console.error(`Error: Spec-Kit directory does not exist: ${specKitDir}`);
|
|
68
65
|
process.exit(1);
|
|
@@ -97,21 +94,18 @@ const importSubcommand = {
|
|
|
97
94
|
console.log(` ${String(nodeCount)} nodes, ${String(relationshipCount)} relationships`);
|
|
98
95
|
},
|
|
99
96
|
};
|
|
100
|
-
const
|
|
97
|
+
const exportOpts = z.object({
|
|
101
98
|
input: z.string().describe("Path to SysProM document"),
|
|
102
99
|
speckitDir: z.string().describe("Path to Spec-Kit output directory"),
|
|
103
|
-
});
|
|
104
|
-
const exportOpts = z.object({
|
|
105
100
|
prefix: z.string().describe("ID prefix identifying nodes to export"),
|
|
106
101
|
});
|
|
107
102
|
const exportSubcommand = {
|
|
108
103
|
name: "export",
|
|
109
104
|
description: speckitExportOp.def.description,
|
|
110
|
-
args: exportArgs,
|
|
111
105
|
opts: exportOpts,
|
|
112
|
-
action(
|
|
113
|
-
const inputPath = resolve(
|
|
114
|
-
const specKitDir = resolve(
|
|
106
|
+
action(_args, opts) {
|
|
107
|
+
const inputPath = resolve(opts.input);
|
|
108
|
+
const specKitDir = resolve(opts.speckitDir);
|
|
115
109
|
if (!opts.prefix) {
|
|
116
110
|
console.error("Error: --prefix flag is required for export (identifies which nodes to export)");
|
|
117
111
|
process.exit(1);
|
|
@@ -125,11 +119,9 @@ const exportSubcommand = {
|
|
|
125
119
|
console.log(` Generated Spec-Kit files with prefix: ${opts.prefix}`);
|
|
126
120
|
},
|
|
127
121
|
};
|
|
128
|
-
const
|
|
122
|
+
const syncSubOpts = z.object({
|
|
129
123
|
input: z.string().describe("Path to SysProM document"),
|
|
130
124
|
speckitDir: z.string().describe("Path to Spec-Kit directory"),
|
|
131
|
-
});
|
|
132
|
-
const syncOpts = z.object({
|
|
133
125
|
prefix: z
|
|
134
126
|
.string()
|
|
135
127
|
.optional()
|
|
@@ -138,11 +130,10 @@ const syncOpts = z.object({
|
|
|
138
130
|
const syncSubcommand = {
|
|
139
131
|
name: "sync",
|
|
140
132
|
description: speckitSyncOp.def.description,
|
|
141
|
-
|
|
142
|
-
opts
|
|
143
|
-
|
|
144
|
-
const
|
|
145
|
-
const specKitDir = resolve(args.speckitDir);
|
|
133
|
+
opts: syncSubOpts,
|
|
134
|
+
action(_args, opts) {
|
|
135
|
+
const inputPath = resolve(opts.input);
|
|
136
|
+
const specKitDir = resolve(opts.speckitDir);
|
|
146
137
|
if (!existsSync(inputPath)) {
|
|
147
138
|
console.error(`Error: Input file does not exist: ${inputPath}`);
|
|
148
139
|
process.exit(1);
|
|
@@ -226,11 +217,9 @@ const syncSubcommand = {
|
|
|
226
217
|
}
|
|
227
218
|
},
|
|
228
219
|
};
|
|
229
|
-
const
|
|
220
|
+
const diffSubOpts = z.object({
|
|
230
221
|
input: z.string().describe("Path to SysProM document"),
|
|
231
222
|
speckitDir: z.string().describe("Path to Spec-Kit directory"),
|
|
232
|
-
});
|
|
233
|
-
const diffOpts = z.object({
|
|
234
223
|
prefix: z
|
|
235
224
|
.string()
|
|
236
225
|
.optional()
|
|
@@ -239,11 +228,10 @@ const diffOpts = z.object({
|
|
|
239
228
|
const diffSubcommand = {
|
|
240
229
|
name: "diff",
|
|
241
230
|
description: speckitDiffOp.def.description,
|
|
242
|
-
|
|
243
|
-
opts
|
|
244
|
-
|
|
245
|
-
const
|
|
246
|
-
const specKitDir = resolve(args.speckitDir);
|
|
231
|
+
opts: diffSubOpts,
|
|
232
|
+
action(_args, opts) {
|
|
233
|
+
const inputPath = resolve(opts.input);
|
|
234
|
+
const specKitDir = resolve(opts.speckitDir);
|
|
247
235
|
if (!existsSync(inputPath)) {
|
|
248
236
|
console.error(`Error: Input file does not exist: ${inputPath}`);
|
|
249
237
|
process.exit(1);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
1
2
|
import type { CommandDef } from "../define-command.js";
|
|
2
3
|
import { type BidirectionalSyncResult, type ConflictStrategy } from "../../operations/index.js";
|
|
3
4
|
interface SyncCommandInput {
|
|
@@ -14,5 +15,13 @@ interface SyncCommandInput {
|
|
|
14
15
|
* const result = syncCommand({ jsonPath: "doc.spm.json", mdPath: "doc.spm.md" });
|
|
15
16
|
*/
|
|
16
17
|
export declare function syncCommand(input: SyncCommandInput): BidirectionalSyncResult;
|
|
17
|
-
|
|
18
|
+
declare const syncOpts: z.ZodObject<{
|
|
19
|
+
input: z.ZodString;
|
|
20
|
+
output: z.ZodString;
|
|
21
|
+
preferJson: z.ZodOptional<z.ZodBoolean>;
|
|
22
|
+
preferMd: z.ZodOptional<z.ZodBoolean>;
|
|
23
|
+
dryRun: z.ZodOptional<z.ZodBoolean>;
|
|
24
|
+
report: z.ZodOptional<z.ZodBoolean>;
|
|
25
|
+
}, z.core.$strict>;
|
|
26
|
+
export declare const syncCommandDef: CommandDef<z.ZodObject<z.ZodRawShape>, typeof syncOpts>;
|
|
18
27
|
export {};
|
|
@@ -47,47 +47,36 @@ export function syncCommand(input) {
|
|
|
47
47
|
}
|
|
48
48
|
return result;
|
|
49
49
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
50
|
+
const syncOpts = z
|
|
51
|
+
.object({
|
|
52
|
+
input: z.string().describe("Path to JSON file"),
|
|
53
|
+
output: z.string().describe("Path to Markdown file"),
|
|
54
|
+
preferJson: z
|
|
55
|
+
.boolean()
|
|
56
|
+
.optional()
|
|
57
|
+
.describe("Prefer JSON as source of truth in conflicts"),
|
|
58
|
+
preferMd: z
|
|
59
|
+
.boolean()
|
|
60
|
+
.optional()
|
|
61
|
+
.describe("Prefer Markdown as source of truth in conflicts"),
|
|
62
|
+
dryRun: z
|
|
63
|
+
.boolean()
|
|
64
|
+
.optional()
|
|
65
|
+
.describe("Preview changes without writing files"),
|
|
66
|
+
report: z
|
|
67
|
+
.boolean()
|
|
68
|
+
.optional()
|
|
69
|
+
.describe("Report conflicts without resolving"),
|
|
70
|
+
})
|
|
71
|
+
.strict();
|
|
56
72
|
export const syncCommandDef = {
|
|
57
73
|
name: "sync",
|
|
58
74
|
description: "Synchronise JSON and Markdown representations with conflict resolution",
|
|
59
75
|
apiLink: "syncDocuments",
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
opts: z
|
|
65
|
-
.object({
|
|
66
|
-
preferJson: z
|
|
67
|
-
.boolean()
|
|
68
|
-
.optional()
|
|
69
|
-
.describe("Prefer JSON as source of truth in conflicts"),
|
|
70
|
-
preferMd: z
|
|
71
|
-
.boolean()
|
|
72
|
-
.optional()
|
|
73
|
-
.describe("Prefer Markdown as source of truth in conflicts"),
|
|
74
|
-
dryRun: z
|
|
75
|
-
.boolean()
|
|
76
|
-
.optional()
|
|
77
|
-
.describe("Preview changes without writing files"),
|
|
78
|
-
report: z
|
|
79
|
-
.boolean()
|
|
80
|
-
.optional()
|
|
81
|
-
.describe("Report conflicts without resolving"),
|
|
82
|
-
})
|
|
83
|
-
.strict(),
|
|
84
|
-
action(args, opts) {
|
|
85
|
-
if (!isArgs(args))
|
|
86
|
-
throw new Error("Invalid args");
|
|
87
|
-
if (!isOpts(opts))
|
|
88
|
-
throw new Error("Invalid opts");
|
|
89
|
-
const jsonPath = resolve(args.input);
|
|
90
|
-
const mdPath = resolve(args.output);
|
|
76
|
+
opts: syncOpts,
|
|
77
|
+
action(_args, opts) {
|
|
78
|
+
const jsonPath = resolve(opts.input);
|
|
79
|
+
const mdPath = resolve(opts.output);
|
|
91
80
|
// Determine conflict strategy
|
|
92
81
|
let strategy = "json";
|
|
93
82
|
if (opts.preferMd)
|
package/dist/src/cli/program.js
CHANGED
|
@@ -1,6 +1,31 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
1
4
|
import { Command } from "commander";
|
|
2
|
-
import packageJson from "../../package.json" with { type: "json" };
|
|
3
5
|
import { buildCommander } from "./define-command.js";
|
|
6
|
+
let cachedVersion;
|
|
7
|
+
function getVersion() {
|
|
8
|
+
if (cachedVersion === undefined) {
|
|
9
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
// Works from both src/cli/ (../../) and dist/src/cli/ (../../../)
|
|
11
|
+
const candidates = [
|
|
12
|
+
resolve(__dirname, "../../package.json"),
|
|
13
|
+
resolve(__dirname, "../../../package.json"),
|
|
14
|
+
];
|
|
15
|
+
const pkgPath = candidates.find((p) => existsSync(p) && !p.includes("/dist/"));
|
|
16
|
+
if (!pkgPath)
|
|
17
|
+
throw new Error("Could not find sysprom package.json");
|
|
18
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
19
|
+
if (typeof pkg !== "object" ||
|
|
20
|
+
pkg === null ||
|
|
21
|
+
!("version" in pkg) ||
|
|
22
|
+
typeof pkg.version !== "string") {
|
|
23
|
+
throw new Error("Invalid package.json: missing version field");
|
|
24
|
+
}
|
|
25
|
+
cachedVersion = pkg.version;
|
|
26
|
+
}
|
|
27
|
+
return cachedVersion;
|
|
28
|
+
}
|
|
4
29
|
import { validateCommand } from "./commands/validate.js";
|
|
5
30
|
import { statsCommand } from "./commands/stats.js";
|
|
6
31
|
import { json2mdCommand } from "./commands/json2md.js";
|
|
@@ -22,7 +47,11 @@ export const program = new Command();
|
|
|
22
47
|
program
|
|
23
48
|
.name("sysprom")
|
|
24
49
|
.description("System Provenance Model CLI — record where every part of a system came from")
|
|
25
|
-
.
|
|
50
|
+
.option("-V, --version", "output the version number")
|
|
51
|
+
.on("option:version", () => {
|
|
52
|
+
console.log(getVersion());
|
|
53
|
+
process.exit(0);
|
|
54
|
+
})
|
|
26
55
|
.showHelpAfterError(true);
|
|
27
56
|
export const commands = [
|
|
28
57
|
validateCommand,
|
package/dist/src/cli/shared.d.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import * as z from "zod";
|
|
2
2
|
import { type Format } from "../io.js";
|
|
3
3
|
import type { SysProMDocument } from "../schema.js";
|
|
4
|
-
/** @deprecated Use --path option in readOpts/mutationOpts instead. */
|
|
5
|
-
export declare const inputArg: z.ZodString;
|
|
6
4
|
/** Empty args schema for commands that take no positional arguments. */
|
|
7
5
|
export declare const noArgs: z.ZodObject<{}, z.core.$strict>;
|
|
8
6
|
/**
|
package/dist/src/cli/shared.js
CHANGED
|
@@ -6,10 +6,6 @@ import { jsonToMarkdownMultiDoc } from "../json-to-md.js";
|
|
|
6
6
|
// ---------------------------------------------------------------------------
|
|
7
7
|
// Reusable CLI schemas — shared across all commands
|
|
8
8
|
// ---------------------------------------------------------------------------
|
|
9
|
-
/** @deprecated Use --path option in readOpts/mutationOpts instead. */
|
|
10
|
-
export const inputArg = z
|
|
11
|
-
.string()
|
|
12
|
-
.describe("SysProM document path (JSON, .md, or directory)");
|
|
13
9
|
/** Empty args schema for commands that take no positional arguments. */
|
|
14
10
|
export const noArgs = z.object({}).strict();
|
|
15
11
|
/** Shared --path option for specifying the SysProM document location. */
|