sysprom 1.0.7 → 1.1.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.
Files changed (113) hide show
  1. package/README.md +28 -28
  2. package/dist/src/canonical-json.d.ts +2 -0
  3. package/dist/src/cli/commands/add.d.ts +1 -1
  4. package/dist/src/cli/commands/add.js +2 -3
  5. package/dist/src/cli/commands/check.d.ts +6 -8
  6. package/dist/src/cli/commands/check.js +3 -8
  7. package/dist/src/cli/commands/graph.d.ts +3 -4
  8. package/dist/src/cli/commands/graph.js +3 -7
  9. package/dist/src/cli/commands/init.d.ts +15 -1
  10. package/dist/src/cli/commands/init.js +57 -27
  11. package/dist/src/cli/commands/plan.js +21 -39
  12. package/dist/src/cli/commands/query.js +10 -28
  13. package/dist/src/cli/commands/remove.d.ts +1 -1
  14. package/dist/src/cli/commands/remove.js +2 -3
  15. package/dist/src/cli/commands/rename.d.ts +1 -1
  16. package/dist/src/cli/commands/rename.js +2 -3
  17. package/dist/src/cli/commands/search.d.ts +1 -1
  18. package/dist/src/cli/commands/search.js +2 -3
  19. package/dist/src/cli/commands/stats.d.ts +6 -8
  20. package/dist/src/cli/commands/stats.js +3 -8
  21. package/dist/src/cli/commands/task.js +19 -24
  22. package/dist/src/cli/commands/update.js +6 -14
  23. package/dist/src/cli/commands/validate.d.ts +6 -8
  24. package/dist/src/cli/commands/validate.js +3 -8
  25. package/dist/src/cli/shared.d.ts +14 -3
  26. package/dist/src/cli/shared.js +61 -3
  27. package/dist/src/io.d.ts +5 -0
  28. package/dist/src/json-to-md.d.ts +1 -0
  29. package/dist/src/operations/add-node.d.ts +5 -0
  30. package/dist/src/operations/add-node.js +5 -0
  31. package/dist/src/operations/add-plan-task.d.ts +5 -0
  32. package/dist/src/operations/add-plan-task.js +5 -0
  33. package/dist/src/operations/add-relationship.d.ts +5 -0
  34. package/dist/src/operations/add-relationship.js +5 -0
  35. package/dist/src/operations/check.d.ts +5 -0
  36. package/dist/src/operations/check.js +5 -0
  37. package/dist/src/operations/define-operation.d.ts +31 -0
  38. package/dist/src/operations/define-operation.js +8 -0
  39. package/dist/src/operations/graph.d.ts +1 -0
  40. package/dist/src/operations/graph.js +1 -0
  41. package/dist/src/operations/init-document.d.ts +1 -0
  42. package/dist/src/operations/init-document.js +1 -0
  43. package/dist/src/operations/json-to-markdown.d.ts +1 -0
  44. package/dist/src/operations/json-to-markdown.js +1 -0
  45. package/dist/src/operations/mark-task-done.d.ts +5 -0
  46. package/dist/src/operations/mark-task-done.js +5 -0
  47. package/dist/src/operations/mark-task-undone.d.ts +5 -0
  48. package/dist/src/operations/mark-task-undone.js +5 -0
  49. package/dist/src/operations/markdown-to-json.d.ts +1 -0
  50. package/dist/src/operations/markdown-to-json.js +1 -0
  51. package/dist/src/operations/next-id.d.ts +6 -0
  52. package/dist/src/operations/next-id.js +6 -0
  53. package/dist/src/operations/node-history.d.ts +3 -0
  54. package/dist/src/operations/node-history.js +2 -0
  55. package/dist/src/operations/plan-add-task.d.ts +1 -0
  56. package/dist/src/operations/plan-add-task.js +1 -0
  57. package/dist/src/operations/plan-gate.d.ts +4 -0
  58. package/dist/src/operations/plan-gate.js +2 -0
  59. package/dist/src/operations/plan-init.d.ts +1 -0
  60. package/dist/src/operations/plan-init.js +1 -0
  61. package/dist/src/operations/plan-progress.d.ts +2 -0
  62. package/dist/src/operations/plan-progress.js +1 -0
  63. package/dist/src/operations/plan-status.d.ts +2 -0
  64. package/dist/src/operations/plan-status.js +1 -0
  65. package/dist/src/operations/query-node.d.ts +3 -0
  66. package/dist/src/operations/query-node.js +2 -0
  67. package/dist/src/operations/query-nodes.d.ts +1 -0
  68. package/dist/src/operations/query-nodes.js +1 -0
  69. package/dist/src/operations/query-relationships.d.ts +1 -0
  70. package/dist/src/operations/query-relationships.js +1 -0
  71. package/dist/src/operations/remove-node.d.ts +8 -0
  72. package/dist/src/operations/remove-node.js +7 -0
  73. package/dist/src/operations/remove-relationship.d.ts +5 -0
  74. package/dist/src/operations/remove-relationship.js +5 -0
  75. package/dist/src/operations/rename.d.ts +7 -0
  76. package/dist/src/operations/rename.js +7 -0
  77. package/dist/src/operations/search.d.ts +1 -0
  78. package/dist/src/operations/search.js +1 -0
  79. package/dist/src/operations/speckit-diff.d.ts +3 -0
  80. package/dist/src/operations/speckit-diff.js +2 -0
  81. package/dist/src/operations/speckit-export.d.ts +1 -0
  82. package/dist/src/operations/speckit-export.js +1 -0
  83. package/dist/src/operations/speckit-import.d.ts +1 -0
  84. package/dist/src/operations/speckit-import.js +1 -0
  85. package/dist/src/operations/speckit-sync.d.ts +3 -0
  86. package/dist/src/operations/speckit-sync.js +2 -0
  87. package/dist/src/operations/state-at.d.ts +3 -0
  88. package/dist/src/operations/state-at.js +2 -0
  89. package/dist/src/operations/stats.d.ts +3 -0
  90. package/dist/src/operations/stats.js +2 -0
  91. package/dist/src/operations/task-list.d.ts +6 -0
  92. package/dist/src/operations/task-list.js +6 -0
  93. package/dist/src/operations/timeline.d.ts +3 -0
  94. package/dist/src/operations/timeline.js +2 -0
  95. package/dist/src/operations/trace-from-node.d.ts +3 -0
  96. package/dist/src/operations/trace-from-node.js +2 -0
  97. package/dist/src/operations/update-metadata.d.ts +1 -0
  98. package/dist/src/operations/update-metadata.js +1 -0
  99. package/dist/src/operations/update-node.d.ts +5 -0
  100. package/dist/src/operations/update-node.js +5 -0
  101. package/dist/src/operations/update-plan-task.d.ts +5 -0
  102. package/dist/src/operations/update-plan-task.js +5 -0
  103. package/dist/src/operations/validate.d.ts +10 -0
  104. package/dist/src/operations/validate.js +9 -0
  105. package/dist/src/schema.d.ts +44 -0
  106. package/dist/src/schema.js +31 -0
  107. package/dist/src/speckit/generate.d.ts +6 -0
  108. package/dist/src/speckit/generate.js +6 -0
  109. package/dist/src/speckit/parse.d.ts +9 -0
  110. package/dist/src/speckit/parse.js +6 -0
  111. package/dist/src/speckit/plan.d.ts +5 -0
  112. package/dist/src/speckit/project.d.ts +6 -0
  113. package/package.json +1 -1
@@ -1,11 +1,11 @@
1
1
  import * as z from "zod";
2
2
  import type { CommandDef } from "../define-command.js";
3
3
  declare const argsSchema: z.ZodObject<{
4
- input: z.ZodString;
5
4
  oldId: z.ZodString;
6
5
  newId: z.ZodString;
7
6
  }, z.core.$strip>;
8
7
  declare const optsSchema: z.ZodObject<{
8
+ path: z.ZodOptional<z.ZodString>;
9
9
  json: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
10
10
  dryRun: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
11
11
  sync: z.ZodOptional<z.ZodString>;
@@ -1,8 +1,7 @@
1
1
  import * as z from "zod";
2
2
  import { renameOp } from "../../operations/index.js";
3
- import { inputArg, mutationOpts, loadDoc, persistDoc } from "../shared.js";
3
+ import { mutationOpts, loadDoc, persistDoc } from "../shared.js";
4
4
  const argsSchema = z.object({
5
- input: inputArg,
6
5
  oldId: z.string().describe("Current node ID"),
7
6
  newId: z.string().describe("New node ID"),
8
7
  });
@@ -15,7 +14,7 @@ export const renameCommand = {
15
14
  opts: optsSchema,
16
15
  action(args, opts) {
17
16
  try {
18
- const loaded = loadDoc(args.input);
17
+ const loaded = loadDoc(opts.path);
19
18
  const { doc } = loaded;
20
19
  const updated = renameOp({ doc, oldId: args.oldId, newId: args.newId });
21
20
  persistDoc(updated, loaded, opts);
@@ -1,10 +1,10 @@
1
1
  import * as z from "zod";
2
2
  import type { CommandDef } from "../define-command.js";
3
3
  declare const argsSchema: z.ZodObject<{
4
- input: z.ZodString;
5
4
  term: z.ZodString;
6
5
  }, z.core.$strip>;
7
6
  declare const optsSchema: z.ZodObject<{
7
+ path: z.ZodOptional<z.ZodString>;
8
8
  json: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
9
9
  }, z.core.$strip>;
10
10
  export declare const searchCommand: CommandDef<typeof argsSchema, typeof optsSchema>;
@@ -1,9 +1,8 @@
1
1
  import * as z from "zod";
2
2
  import { searchOp } from "../../operations/index.js";
3
- import { inputArg, readOpts, loadDoc } from "../shared.js";
3
+ import { readOpts, loadDoc } from "../shared.js";
4
4
  import { textToString } from "../../text.js";
5
5
  const argsSchema = z.object({
6
- input: inputArg,
7
6
  term: z.string().describe("Search term"),
8
7
  });
9
8
  const optsSchema = readOpts;
@@ -14,7 +13,7 @@ export const searchCommand = {
14
13
  args: argsSchema,
15
14
  opts: optsSchema,
16
15
  action(args, opts) {
17
- const { doc } = loadDoc(args.input);
16
+ const { doc } = loadDoc(opts.path);
18
17
  const matches = searchOp({ doc, term: args.term });
19
18
  if (opts.json) {
20
19
  console.log(JSON.stringify(matches, null, 2));
@@ -1,10 +1,8 @@
1
- import * as z from "zod";
2
1
  import type { CommandDef } from "../define-command.js";
3
- declare const argsSchema: z.ZodObject<{
4
- input: z.ZodString;
5
- }, z.core.$strip>;
6
- declare const optsSchema: z.ZodObject<{
7
- json: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
8
- }, z.core.$strip>;
9
- export declare const statsCommand: CommandDef<typeof argsSchema, typeof optsSchema>;
2
+ import { noArgs } from "../shared.js";
3
+ declare const optsSchema: import("zod").ZodObject<{
4
+ path: import("zod").ZodOptional<import("zod").ZodString>;
5
+ json: import("zod").ZodDefault<import("zod").ZodOptional<import("zod").ZodBoolean>>;
6
+ }, import("zod/v4/core").$strip>;
7
+ export declare const statsCommand: CommandDef<typeof noArgs, typeof optsSchema>;
10
8
  export {};
@@ -1,19 +1,14 @@
1
- import * as z from "zod";
2
1
  import pc from "picocolors";
3
2
  import { statsOp } from "../../operations/index.js";
4
- import { inputArg, readOpts, loadDoc } from "../shared.js";
5
- const argsSchema = z.object({
6
- input: inputArg,
7
- });
3
+ import { readOpts, loadDoc } from "../shared.js";
8
4
  const optsSchema = readOpts;
9
5
  export const statsCommand = {
10
6
  name: "stats",
11
7
  description: statsOp.def.description,
12
8
  apiLink: statsOp.def.name,
13
- args: argsSchema,
14
9
  opts: optsSchema,
15
- action(args) {
16
- const { doc } = loadDoc(args.input);
10
+ action(_args, opts) {
11
+ const { doc } = loadDoc(opts.path);
17
12
  const s = statsOp({ doc });
18
13
  console.log(`${pc.bold("SysProM Document")}: ${s.title}`);
19
14
  console.log("");
@@ -1,25 +1,20 @@
1
1
  import * as z from "zod";
2
- import { loadDocument, saveDocument } from "../../io.js";
2
+ import { loadDoc, mutationOpts, persistDoc } from "../shared.js";
3
3
  import { addPlanTaskOp, markTaskDoneOp, markTaskUndoneOp, taskListOp, } from "../../operations/index.js";
4
4
  // ============================================================================
5
5
  // Subcommands
6
6
  // ============================================================================
7
- const listArgs = z.object({
8
- input: z.string().describe("Path to SysProM document"),
9
- });
10
- const listOpts = z.object({
7
+ const listOpts = mutationOpts.pick({ path: true, json: true }).extend({
11
8
  change: z.string().optional().describe("Filter by change ID"),
12
9
  pending: z.boolean().optional().describe("Show only pending tasks"),
13
- json: z.boolean().optional().describe("Output as JSON"),
14
10
  });
15
11
  const listSubcommand = {
16
12
  name: "list",
17
13
  description: taskListOp.def.description,
18
14
  apiLink: taskListOp.def.name,
19
- args: listArgs,
20
15
  opts: listOpts,
21
- action(args, opts) {
22
- const { doc } = loadDocument(args.input);
16
+ action(_args, opts) {
17
+ const { doc } = loadDoc(opts.path);
23
18
  try {
24
19
  const rows = taskListOp({
25
20
  doc,
@@ -47,26 +42,26 @@ const listSubcommand = {
47
42
  },
48
43
  };
49
44
  const addArgs = z.object({
50
- input: z.string().describe("Path to SysProM document"),
51
45
  changeId: z.string().describe("Change node ID"),
52
46
  description: z.string().describe("Task description"),
53
47
  });
54
- const addOpts = z.object({});
48
+ const addOpts = mutationOpts.pick({ path: true });
55
49
  const addSubcommand = {
56
50
  name: "add",
57
51
  description: addPlanTaskOp.def.description,
58
52
  apiLink: addPlanTaskOp.def.name,
59
53
  args: addArgs,
60
54
  opts: addOpts,
61
- action(args) {
62
- const { doc, format, path } = loadDocument(args.input);
55
+ action(args, opts) {
56
+ const loaded = loadDoc(opts.path);
57
+ const { doc } = loaded;
63
58
  try {
64
59
  const newDoc = addPlanTaskOp({
65
60
  doc,
66
61
  changeId: args.changeId,
67
62
  description: args.description,
68
63
  });
69
- saveDocument(newDoc, format, path);
64
+ persistDoc(newDoc, loaded, { ...opts, json: false, dryRun: false });
70
65
  const node = newDoc.nodes.find((n) => n.id === args.changeId);
71
66
  if (!node)
72
67
  throw new Error(`Node ${args.changeId} not found`);
@@ -80,19 +75,19 @@ const addSubcommand = {
80
75
  },
81
76
  };
82
77
  const doneArgs = z.object({
83
- input: z.string().describe("Path to SysProM document"),
84
78
  changeId: z.string().describe("Change node ID"),
85
79
  taskIndex: z.string().describe("Task index"),
86
80
  });
87
- const doneOpts = z.object({});
81
+ const doneOpts = mutationOpts.pick({ path: true });
88
82
  const doneSubcommand = {
89
83
  name: "done",
90
84
  description: markTaskDoneOp.def.description,
91
85
  apiLink: markTaskDoneOp.def.name,
92
86
  args: doneArgs,
93
87
  opts: doneOpts,
94
- action(args) {
95
- const { doc, format, path } = loadDocument(args.input);
88
+ action(args, opts) {
89
+ const loaded = loadDoc(opts.path);
90
+ const { doc } = loaded;
96
91
  const taskIndex = parseInt(args.taskIndex, 10);
97
92
  if (isNaN(taskIndex) || taskIndex < 0) {
98
93
  console.error(`Invalid task index: ${args.taskIndex}`);
@@ -104,7 +99,7 @@ const doneSubcommand = {
104
99
  changeId: args.changeId,
105
100
  taskIndex,
106
101
  });
107
- saveDocument(newDoc, format, path);
102
+ persistDoc(newDoc, loaded, { ...opts, json: false, dryRun: false });
108
103
  console.log(`Marked task ${String(taskIndex)} done on ${args.changeId}`);
109
104
  }
110
105
  catch (err) {
@@ -114,19 +109,19 @@ const doneSubcommand = {
114
109
  },
115
110
  };
116
111
  const undoneArgs = z.object({
117
- input: z.string().describe("Path to SysProM document"),
118
112
  changeId: z.string().describe("Change node ID"),
119
113
  taskIndex: z.string().describe("Task index"),
120
114
  });
121
- const undoneOpts = z.object({});
115
+ const undoneOpts = mutationOpts.pick({ path: true });
122
116
  const undoneSubcommand = {
123
117
  name: "undone",
124
118
  description: markTaskUndoneOp.def.description,
125
119
  apiLink: markTaskUndoneOp.def.name,
126
120
  args: undoneArgs,
127
121
  opts: undoneOpts,
128
- action(args) {
129
- const { doc, format, path } = loadDocument(args.input);
122
+ action(args, opts) {
123
+ const loaded = loadDoc(opts.path);
124
+ const { doc } = loaded;
130
125
  const taskIndex = parseInt(args.taskIndex, 10);
131
126
  if (isNaN(taskIndex) || taskIndex < 0) {
132
127
  console.error(`Invalid task index: ${args.taskIndex}`);
@@ -138,7 +133,7 @@ const undoneSubcommand = {
138
133
  changeId: args.changeId,
139
134
  taskIndex,
140
135
  });
141
- saveDocument(newDoc, format, path);
136
+ persistDoc(newDoc, loaded, { ...opts, json: false, dryRun: false });
142
137
  console.log(`Marked task ${String(taskIndex)} undone on ${args.changeId}`);
143
138
  }
144
139
  catch (err) {
@@ -1,7 +1,7 @@
1
1
  import * as z from "zod";
2
2
  import { RelationshipType, NodeStatus } from "../../schema.js";
3
3
  import { updateNodeOp, addRelationshipOp, removeRelationshipOp, updateMetadataOp, } from "../../operations/index.js";
4
- import { inputArg, mutationOpts, loadDoc, persistDoc } from "../shared.js";
4
+ import { mutationOpts, loadDoc, persistDoc } from "../shared.js";
5
5
  // ---------------------------------------------------------------------------
6
6
  // CLI helper functions
7
7
  // ---------------------------------------------------------------------------
@@ -25,7 +25,6 @@ function parseMetaValue(val) {
25
25
  // Arg/opt schemas
26
26
  // ---------------------------------------------------------------------------
27
27
  const updateNodeArgs = z.object({
28
- input: inputArg,
29
28
  id: z.string().describe("node ID to update"),
30
29
  });
31
30
  const updateNodeOpts = mutationOpts.extend({
@@ -39,22 +38,17 @@ const updateNodeOpts = mutationOpts.extend({
39
38
  .describe("set lifecycle state (key=value format)"),
40
39
  });
41
40
  const addRelArgs = z.object({
42
- input: inputArg,
43
41
  from: z.string().describe("source node ID"),
44
42
  type: RelationshipType.describe("relationship type"),
45
43
  to: z.string().describe("target node ID"),
46
44
  });
47
45
  const addRelOpts = mutationOpts;
48
46
  const removeRelArgs = z.object({
49
- input: inputArg,
50
47
  from: z.string().describe("source node ID"),
51
48
  type: RelationshipType.describe("relationship type"),
52
49
  to: z.string().describe("target node ID"),
53
50
  });
54
51
  const removeRelOpts = mutationOpts;
55
- const metaArgs = z.object({
56
- input: inputArg,
57
- });
58
52
  const metaOpts = mutationOpts.extend({
59
53
  fields: z
60
54
  .array(z.string())
@@ -72,7 +66,7 @@ const nodeSubcommand = {
72
66
  action(rawArgs, rawOpts) {
73
67
  const args = updateNodeArgs.parse(rawArgs);
74
68
  const opts = updateNodeOpts.parse(rawOpts);
75
- const loaded = loadDoc(args.input);
69
+ const loaded = loadDoc(opts.path);
76
70
  const { doc } = loaded;
77
71
  const node = doc.nodes.find((n) => n.id === args.id);
78
72
  if (!node) {
@@ -126,7 +120,7 @@ const addRelSubcommand = {
126
120
  action(rawArgs, rawOpts) {
127
121
  const args = addRelArgs.parse(rawArgs);
128
122
  const opts = addRelOpts.parse(rawOpts);
129
- const loaded = loadDoc(args.input);
123
+ const loaded = loadDoc(opts.path);
130
124
  const { doc } = loaded;
131
125
  const newDoc = addRelationshipOp({
132
126
  doc,
@@ -151,7 +145,7 @@ const removeRelSubcommand = {
151
145
  action(rawArgs, rawOpts) {
152
146
  const args = removeRelArgs.parse(rawArgs);
153
147
  const opts = removeRelOpts.parse(rawOpts);
154
- const loaded = loadDoc(args.input);
148
+ const loaded = loadDoc(opts.path);
155
149
  const { doc } = loaded;
156
150
  const newDoc = removeRelationshipOp({
157
151
  doc,
@@ -172,16 +166,14 @@ const metaSubcommand = {
172
166
  name: "meta",
173
167
  description: updateMetadataOp.def.description,
174
168
  apiLink: updateMetadataOp.def.name,
175
- args: metaArgs,
176
169
  opts: metaOpts,
177
- action(rawArgs, rawOpts) {
178
- const args = metaArgs.parse(rawArgs);
170
+ action(_rawArgs, rawOpts) {
179
171
  const opts = metaOpts.parse(rawOpts);
180
172
  if (opts.fields.length === 0) {
181
173
  console.error("No metadata fields specified. Use --fields key=value");
182
174
  process.exit(1);
183
175
  }
184
- const loaded = loadDoc(args.input);
176
+ const loaded = loadDoc(opts.path);
185
177
  const { doc } = loaded;
186
178
  const fields = {};
187
179
  for (const kv of opts.fields) {
@@ -1,10 +1,8 @@
1
- import * as z from "zod";
2
1
  import type { CommandDef } from "../define-command.js";
3
- declare const argsSchema: z.ZodObject<{
4
- input: z.ZodString;
5
- }, z.core.$strip>;
6
- declare const optsSchema: z.ZodObject<{
7
- json: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
8
- }, z.core.$strip>;
9
- export declare const validateCommand: CommandDef<typeof argsSchema, typeof optsSchema>;
2
+ import { noArgs } from "../shared.js";
3
+ declare const optsSchema: import("zod").ZodObject<{
4
+ path: import("zod").ZodOptional<import("zod").ZodString>;
5
+ json: import("zod").ZodDefault<import("zod").ZodOptional<import("zod").ZodBoolean>>;
6
+ }, import("zod/v4/core").$strip>;
7
+ export declare const validateCommand: CommandDef<typeof noArgs, typeof optsSchema>;
10
8
  export {};
@@ -1,19 +1,14 @@
1
- import * as z from "zod";
2
1
  import pc from "picocolors";
3
2
  import { validateOp } from "../../operations/index.js";
4
- import { inputArg, readOpts, loadDoc } from "../shared.js";
5
- const argsSchema = z.object({
6
- input: inputArg,
7
- });
3
+ import { readOpts, loadDoc } from "../shared.js";
8
4
  const optsSchema = readOpts;
9
5
  export const validateCommand = {
10
6
  name: "validate",
11
7
  description: validateOp.def.description,
12
8
  apiLink: validateOp.def.name,
13
- args: argsSchema,
14
9
  opts: optsSchema,
15
- action(args) {
16
- const { doc } = loadDoc(args.input);
10
+ action(_args, opts) {
11
+ const { doc } = loadDoc(opts.path);
17
12
  const result = validateOp({ doc });
18
13
  if (result.valid) {
19
14
  console.log(pc.green("Valid SysProM document."));
@@ -1,14 +1,25 @@
1
1
  import * as z from "zod";
2
2
  import { type Format } from "../io.js";
3
3
  import type { SysProMDocument } from "../schema.js";
4
- /** Positional argument for a SysProM document path. */
4
+ /** @deprecated Use --path option in readOpts/mutationOpts instead. */
5
5
  export declare const inputArg: z.ZodString;
6
+ /** Empty args schema for commands that take no positional arguments. */
7
+ export declare const noArgs: z.ZodObject<{}, z.core.$strict>;
8
+ /**
9
+ * Resolve a SysProM document path. If no explicit path is given, search the
10
+ * working directory by priority:
11
+ * 1. .spm.json 2. .spm.md 3. .spm/
12
+ * 4. *.spm.json 5. *.spm.md 6. *.spm/ (glob — must be unique)
13
+ */
14
+ export declare function resolveInput(input?: string, cwd?: string): string;
6
15
  /** Common output/persistence options for read-only commands. */
7
16
  export declare const readOpts: z.ZodObject<{
17
+ path: z.ZodOptional<z.ZodString>;
8
18
  json: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
9
19
  }, z.core.$strip>;
10
20
  /** Common output/persistence options for mutation commands. */
11
21
  export declare const mutationOpts: z.ZodObject<{
22
+ path: z.ZodOptional<z.ZodString>;
12
23
  json: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
13
24
  dryRun: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
14
25
  sync: z.ZodOptional<z.ZodString>;
@@ -20,7 +31,7 @@ export interface LoadedDoc {
20
31
  format: Format;
21
32
  path: string;
22
33
  }
23
- /** Load a document from a CLI input path. */
24
- export declare function loadDoc(input: string): LoadedDoc;
34
+ /** Load a document from a CLI input path (auto-resolved if omitted). */
35
+ export declare function loadDoc(input?: string): LoadedDoc;
25
36
  /** Persist a document and optionally sync to markdown. */
26
37
  export declare function persistDoc(doc: SysProMDocument, loaded: LoadedDoc, opts: MutationOpts): void;
@@ -1,19 +1,77 @@
1
1
  import * as z from "zod";
2
+ import { existsSync, readdirSync, statSync } from "node:fs";
3
+ import { join, resolve } from "node:path";
2
4
  import { loadDocument, saveDocument } from "../io.js";
3
5
  import { jsonToMarkdownMultiDoc } from "../json-to-md.js";
4
6
  // ---------------------------------------------------------------------------
5
7
  // Reusable CLI schemas — shared across all commands
6
8
  // ---------------------------------------------------------------------------
7
- /** Positional argument for a SysProM document path. */
9
+ /** @deprecated Use --path option in readOpts/mutationOpts instead. */
8
10
  export const inputArg = z
9
11
  .string()
10
12
  .describe("SysProM document path (JSON, .md, or directory)");
13
+ /** Empty args schema for commands that take no positional arguments. */
14
+ export const noArgs = z.object({}).strict();
15
+ /** Shared --path option for specifying the SysProM document location. */
16
+ const pathOpt = z
17
+ .string()
18
+ .optional()
19
+ .describe("SysProM document path (auto-detected if omitted)");
20
+ // ---------------------------------------------------------------------------
21
+ // Default input resolution
22
+ // ---------------------------------------------------------------------------
23
+ /**
24
+ * Resolve a SysProM document path. If no explicit path is given, search the
25
+ * working directory by priority:
26
+ * 1. .spm.json 2. .spm.md 3. .spm/
27
+ * 4. *.spm.json 5. *.spm.md 6. *.spm/ (glob — must be unique)
28
+ */
29
+ export function resolveInput(input, cwd) {
30
+ if (input)
31
+ return input;
32
+ const dir = resolve(cwd ?? ".");
33
+ // Priority 1–3: exact names
34
+ const exact = [".spm.json", ".spm.md", ".spm"];
35
+ for (const name of exact) {
36
+ const candidate = join(dir, name);
37
+ if (existsSync(candidate))
38
+ return candidate;
39
+ }
40
+ // Priority 4–6: glob by suffix
41
+ const entries = readdirSync(dir);
42
+ const suffixes = [".spm.json", ".spm.md", ".spm"];
43
+ for (const suffix of suffixes) {
44
+ const matches = entries
45
+ .filter((e) => e.endsWith(suffix) && e !== suffix)
46
+ .map((e) => join(dir, e))
47
+ .filter((p) => {
48
+ if (suffix === ".spm") {
49
+ try {
50
+ return statSync(p).isDirectory();
51
+ }
52
+ catch {
53
+ return false;
54
+ }
55
+ }
56
+ return true;
57
+ });
58
+ if (matches.length === 1)
59
+ return matches[0];
60
+ if (matches.length > 1) {
61
+ const names = matches.map((m) => m.slice(dir.length + 1)).join(", ");
62
+ throw new Error(`Multiple SysProM documents found: ${names}. Specify one explicitly.`);
63
+ }
64
+ }
65
+ throw new Error("No SysProM document found in current directory. Specify a path or run `spm init`.");
66
+ }
11
67
  /** Common output/persistence options for read-only commands. */
12
68
  export const readOpts = z.object({
69
+ path: pathOpt,
13
70
  json: z.boolean().optional().default(false).describe("output as JSON"),
14
71
  });
15
72
  /** Common output/persistence options for mutation commands. */
16
73
  export const mutationOpts = z.object({
74
+ path: pathOpt,
17
75
  json: z.boolean().optional().default(false).describe("output as JSON"),
18
76
  dryRun: z
19
77
  .boolean()
@@ -25,9 +83,9 @@ export const mutationOpts = z.object({
25
83
  .optional()
26
84
  .describe("sync to markdown directory after saving"),
27
85
  });
28
- /** Load a document from a CLI input path. */
86
+ /** Load a document from a CLI input path (auto-resolved if omitted). */
29
87
  export function loadDoc(input) {
30
- return loadDocument(input);
88
+ return loadDocument(resolveInput(input));
31
89
  }
32
90
  /** Persist a document and optionally sync to markdown. */
33
91
  export function persistDoc(doc, loaded, opts) {
package/dist/src/io.d.ts CHANGED
@@ -1,8 +1,13 @@
1
1
  import { SysProMDocument } from "./schema.js";
2
+ /** Supported serialisation formats for SysProM documents. */
2
3
  export type Format = "json" | "single-md" | "multi-md";
4
+ /** The result of loading a SysProM document from disc. */
3
5
  export interface LoadedDocument {
6
+ /** The parsed SysProM document. */
4
7
  doc: SysProMDocument;
8
+ /** The detected serialisation format. */
5
9
  format: Format;
10
+ /** The resolved absolute path the document was loaded from. */
6
11
  path: string;
7
12
  }
8
13
  /**
@@ -1,4 +1,5 @@
1
1
  import { type SysProMDocument } from "./schema.js";
2
+ /** Options for controlling JSON-to-Markdown conversion. */
2
3
  export interface ConvertOptions {
3
4
  form: "single-file" | "multi-doc";
4
5
  }
@@ -1,4 +1,9 @@
1
1
  import * as z from "zod";
2
+ /**
3
+ * Add a node to a SysProM document. Returns a new document with the node appended.
4
+ *
5
+ * @throws If a node with the same ID already exists.
6
+ */
2
7
  export declare const addNodeOp: import("./define-operation.js").DefinedOperation<z.ZodObject<{
3
8
  doc: z.ZodObject<{
4
9
  $schema: z.ZodOptional<z.ZodString>;
@@ -1,6 +1,11 @@
1
1
  import * as z from "zod";
2
2
  import { defineOperation } from "./define-operation.js";
3
3
  import { SysProMDocument, Node } from "../schema.js";
4
+ /**
5
+ * Add a node to a SysProM document. Returns a new document with the node appended.
6
+ *
7
+ * @throws If a node with the same ID already exists.
8
+ */
4
9
  export const addNodeOp = defineOperation({
5
10
  name: "addNode",
6
11
  description: "Add a node to the document. Throws if the ID already exists.",
@@ -1,4 +1,9 @@
1
1
  import * as z from "zod";
2
+ /**
3
+ * Append a new task to a change node's plan array. Returns a new document with the task added.
4
+ *
5
+ * @throws If the change node is not found.
6
+ */
2
7
  export declare const addPlanTaskOp: import("./define-operation.js").DefinedOperation<z.ZodObject<{
3
8
  doc: z.ZodObject<{
4
9
  $schema: z.ZodOptional<z.ZodString>;
@@ -1,6 +1,11 @@
1
1
  import * as z from "zod";
2
2
  import { defineOperation } from "./define-operation.js";
3
3
  import { SysProMDocument } from "../schema.js";
4
+ /**
5
+ * Append a new task to a change node's plan array. Returns a new document with the task added.
6
+ *
7
+ * @throws If the change node is not found.
8
+ */
4
9
  export const addPlanTaskOp = defineOperation({
5
10
  name: "addPlanTask",
6
11
  description: "Append a new task to a change node's plan array. Returns a new document.",
@@ -1,4 +1,9 @@
1
1
  import * as z from "zod";
2
+ /**
3
+ * Add a relationship to a SysProM document. Returns a new document with the relationship appended.
4
+ *
5
+ * @throws If either endpoint node does not exist in the document.
6
+ */
2
7
  export declare const addRelationshipOp: import("./define-operation.js").DefinedOperation<z.ZodObject<{
3
8
  doc: z.ZodObject<{
4
9
  $schema: z.ZodOptional<z.ZodString>;
@@ -1,6 +1,11 @@
1
1
  import * as z from "zod";
2
2
  import { defineOperation } from "./define-operation.js";
3
3
  import { SysProMDocument, Relationship } from "../schema.js";
4
+ /**
5
+ * Add a relationship to a SysProM document. Returns a new document with the relationship appended.
6
+ *
7
+ * @throws If either endpoint node does not exist in the document.
8
+ */
4
9
  export const addRelationshipOp = defineOperation({
5
10
  name: "addRelationship",
6
11
  description: "Add a relationship to the document. Throws if either endpoint node does not exist.",
@@ -1,4 +1,9 @@
1
1
  import * as z from "zod";
2
+ /**
3
+ * Check a SysProM document for quality issues and warnings beyond schema
4
+ * validation — missing rationale, context, scope, descriptions, orphan nodes,
5
+ * and dangling scope references.
6
+ */
2
7
  export declare const checkOp: import("./define-operation.js").DefinedOperation<z.ZodObject<{
3
8
  doc: z.ZodObject<{
4
9
  $schema: z.ZodOptional<z.ZodString>;
@@ -50,6 +50,11 @@ function performCheck(doc) {
50
50
  }
51
51
  return { warnings, info };
52
52
  }
53
+ /**
54
+ * Check a SysProM document for quality issues and warnings beyond schema
55
+ * validation — missing rationale, context, scope, descriptions, orphan nodes,
56
+ * and dangling scope references.
57
+ */
53
58
  export const checkOp = defineOperation({
54
59
  name: "check",
55
60
  description: "Check a SysProM document for issues and warnings. Performs quality/lint checks beyond schema validation.",
@@ -1,14 +1,45 @@
1
1
  import * as z from "zod";
2
+ /**
3
+ * Definition of a SysProM operation — a named, typed function with Zod schemas
4
+ * for input validation and output description.
5
+ *
6
+ * @typeParam TInput - Zod schema type for the operation's input.
7
+ * @typeParam TOutput - Zod schema type for the operation's output.
8
+ */
2
9
  export interface OperationDef<TInput extends z.ZodType = z.ZodType, TOutput extends z.ZodType = z.ZodType> {
10
+ /** Machine-readable operation name (e.g. `"addNode"`). */
3
11
  name: string;
12
+ /** Human-readable description of what the operation does. */
4
13
  description: string;
14
+ /** Zod schema used to validate the operation's input. */
5
15
  input: TInput;
16
+ /** Zod schema describing the operation's output shape. */
6
17
  output: TOutput;
18
+ /** The implementation function. */
7
19
  fn: (input: z.infer<TInput>) => z.infer<TOutput>;
8
20
  }
21
+ /**
22
+ * A callable operation with attached metadata. Can be invoked directly as a
23
+ * function, and also exposes `.def`, `.inputSchema`, and `.outputSchema` for
24
+ * introspection.
25
+ *
26
+ * @typeParam TInput - Zod schema type for the operation's input.
27
+ * @typeParam TOutput - Zod schema type for the operation's output.
28
+ */
9
29
  export type DefinedOperation<TInput extends z.ZodType = z.ZodType, TOutput extends z.ZodType = z.ZodType> = ((input: z.infer<TInput>) => z.infer<TOutput>) & {
30
+ /** The full operation definition including name, description, and schemas. */
10
31
  def: OperationDef<TInput, TOutput>;
32
+ /** Zod schema for validating input before execution. */
11
33
  inputSchema: TInput;
34
+ /** Zod schema describing the output shape. */
12
35
  outputSchema: TOutput;
13
36
  };
37
+ /**
38
+ * Create a callable operation from a definition. The returned function validates
39
+ * input against the Zod schema before delegating to the implementation.
40
+ *
41
+ * @param def - The operation definition with name, schemas, and implementation.
42
+ * @returns A callable function with `.def`, `.inputSchema`, and `.outputSchema` attached.
43
+ * @throws If the input fails Zod validation.
44
+ */
14
45
  export declare function defineOperation<TInput extends z.ZodType, TOutput extends z.ZodType>(def: OperationDef<TInput, TOutput>): DefinedOperation<TInput, TOutput>;