sysprom 1.13.1 → 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 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<typeof argsSchema, typeof optsSchema>;
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 argsSchema = z.object({
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(args, opts) {
62
- const { outputPath, ioFormat } = resolveInitTarget(args.path, opts.format);
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
- export declare const json2mdCommand: CommandDef;
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
- function isArgs(arg) {
8
- return (typeof arg === "object" && arg !== null && "input" in arg && "output" in arg);
9
- }
10
- function isOpts(opt) {
11
- return typeof opt === "object" && opt !== null;
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
- args: z.object({
18
- input: z.string().describe("Path to SysProM JSON file"),
19
- output: z.string().describe("Output path (file or directory)"),
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
- export declare const md2jsonCommand: CommandDef;
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
- function isArgs(arg) {
8
- return (typeof arg === "object" && arg !== null && "input" in arg && "output" in arg);
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
- args: z.object({
15
- input: z.string().describe("Path to SysProM Markdown (file or directory)"),
16
- output: z.string().describe("Output JSON file path"),
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(args, opts) {
23
- const outputPath = args.output;
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 importArgs = z.object({
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(args, opts) {
64
- const specKitDir = resolve(args.speckitDir);
65
- const outputPath = resolve(args.output);
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 exportArgs = z.object({
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(args, opts) {
113
- const inputPath = resolve(args.input);
114
- const specKitDir = resolve(args.speckitDir);
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 syncArgs = z.object({
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
- args: syncArgs,
142
- opts: syncOpts,
143
- action(args, opts) {
144
- const inputPath = resolve(args.input);
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 diffArgs = z.object({
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
- args: diffArgs,
243
- opts: diffOpts,
244
- action(args, opts) {
245
- const inputPath = resolve(args.input);
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
- export declare const syncCommandDef: CommandDef;
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
- function isArgs(arg) {
51
- return (typeof arg === "object" && arg !== null && "input" in arg && "output" in arg);
52
- }
53
- function isOpts(opt) {
54
- return typeof opt === "object" && opt !== null;
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
- args: z.object({
61
- input: z.string().describe("Path to JSON file"),
62
- output: z.string().describe("Path to Markdown file"),
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)
@@ -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
  /**
@@ -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. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sysprom",
3
- "version": "1.13.1",
3
+ "version": "1.13.2",
4
4
  "description": "SysProM — System Provenance Model CLI and library",
5
5
  "author": "ExaDev",
6
6
  "homepage": "https://exadev.github.io/SysProM",