sysprom 1.0.7 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -28
- package/dist/src/canonical-json.d.ts +2 -0
- package/dist/src/cli/commands/add.d.ts +1 -1
- package/dist/src/cli/commands/add.js +2 -3
- package/dist/src/cli/commands/check.d.ts +6 -8
- package/dist/src/cli/commands/check.js +3 -8
- package/dist/src/cli/commands/graph.d.ts +3 -4
- package/dist/src/cli/commands/graph.js +3 -7
- package/dist/src/cli/commands/init.d.ts +15 -1
- package/dist/src/cli/commands/init.js +57 -27
- package/dist/src/cli/commands/plan.js +21 -39
- package/dist/src/cli/commands/query.js +10 -28
- package/dist/src/cli/commands/remove.d.ts +1 -1
- package/dist/src/cli/commands/remove.js +2 -3
- package/dist/src/cli/commands/rename.d.ts +1 -1
- package/dist/src/cli/commands/rename.js +2 -3
- package/dist/src/cli/commands/search.d.ts +1 -1
- package/dist/src/cli/commands/search.js +2 -3
- package/dist/src/cli/commands/stats.d.ts +6 -8
- package/dist/src/cli/commands/stats.js +3 -8
- package/dist/src/cli/commands/task.js +19 -24
- package/dist/src/cli/commands/update.js +6 -14
- package/dist/src/cli/commands/validate.d.ts +6 -8
- package/dist/src/cli/commands/validate.js +3 -8
- package/dist/src/cli/shared.d.ts +18 -3
- package/dist/src/cli/shared.js +100 -3
- package/dist/src/io.d.ts +5 -0
- package/dist/src/json-to-md.d.ts +1 -0
- package/dist/src/operations/add-node.d.ts +5 -0
- package/dist/src/operations/add-node.js +5 -0
- package/dist/src/operations/add-plan-task.d.ts +5 -0
- package/dist/src/operations/add-plan-task.js +5 -0
- package/dist/src/operations/add-relationship.d.ts +5 -0
- package/dist/src/operations/add-relationship.js +5 -0
- package/dist/src/operations/check.d.ts +5 -0
- package/dist/src/operations/check.js +5 -0
- package/dist/src/operations/define-operation.d.ts +31 -0
- package/dist/src/operations/define-operation.js +8 -0
- package/dist/src/operations/graph.d.ts +1 -0
- package/dist/src/operations/graph.js +1 -0
- package/dist/src/operations/init-document.d.ts +1 -0
- package/dist/src/operations/init-document.js +1 -0
- package/dist/src/operations/json-to-markdown.d.ts +1 -0
- package/dist/src/operations/json-to-markdown.js +1 -0
- package/dist/src/operations/mark-task-done.d.ts +5 -0
- package/dist/src/operations/mark-task-done.js +5 -0
- package/dist/src/operations/mark-task-undone.d.ts +5 -0
- package/dist/src/operations/mark-task-undone.js +5 -0
- package/dist/src/operations/markdown-to-json.d.ts +1 -0
- package/dist/src/operations/markdown-to-json.js +1 -0
- package/dist/src/operations/next-id.d.ts +6 -0
- package/dist/src/operations/next-id.js +6 -0
- package/dist/src/operations/node-history.d.ts +3 -0
- package/dist/src/operations/node-history.js +2 -0
- package/dist/src/operations/plan-add-task.d.ts +1 -0
- package/dist/src/operations/plan-add-task.js +1 -0
- package/dist/src/operations/plan-gate.d.ts +4 -0
- package/dist/src/operations/plan-gate.js +2 -0
- package/dist/src/operations/plan-init.d.ts +1 -0
- package/dist/src/operations/plan-init.js +1 -0
- package/dist/src/operations/plan-progress.d.ts +2 -0
- package/dist/src/operations/plan-progress.js +1 -0
- package/dist/src/operations/plan-status.d.ts +2 -0
- package/dist/src/operations/plan-status.js +1 -0
- package/dist/src/operations/query-node.d.ts +3 -0
- package/dist/src/operations/query-node.js +2 -0
- package/dist/src/operations/query-nodes.d.ts +1 -0
- package/dist/src/operations/query-nodes.js +1 -0
- package/dist/src/operations/query-relationships.d.ts +1 -0
- package/dist/src/operations/query-relationships.js +1 -0
- package/dist/src/operations/remove-node.d.ts +8 -0
- package/dist/src/operations/remove-node.js +7 -0
- package/dist/src/operations/remove-relationship.d.ts +5 -0
- package/dist/src/operations/remove-relationship.js +5 -0
- package/dist/src/operations/rename.d.ts +7 -0
- package/dist/src/operations/rename.js +7 -0
- package/dist/src/operations/search.d.ts +1 -0
- package/dist/src/operations/search.js +1 -0
- package/dist/src/operations/speckit-diff.d.ts +3 -0
- package/dist/src/operations/speckit-diff.js +2 -0
- package/dist/src/operations/speckit-export.d.ts +1 -0
- package/dist/src/operations/speckit-export.js +1 -0
- package/dist/src/operations/speckit-import.d.ts +1 -0
- package/dist/src/operations/speckit-import.js +1 -0
- package/dist/src/operations/speckit-sync.d.ts +3 -0
- package/dist/src/operations/speckit-sync.js +2 -0
- package/dist/src/operations/state-at.d.ts +3 -0
- package/dist/src/operations/state-at.js +2 -0
- package/dist/src/operations/stats.d.ts +3 -0
- package/dist/src/operations/stats.js +2 -0
- package/dist/src/operations/task-list.d.ts +6 -0
- package/dist/src/operations/task-list.js +6 -0
- package/dist/src/operations/timeline.d.ts +3 -0
- package/dist/src/operations/timeline.js +2 -0
- package/dist/src/operations/trace-from-node.d.ts +3 -0
- package/dist/src/operations/trace-from-node.js +2 -0
- package/dist/src/operations/update-metadata.d.ts +1 -0
- package/dist/src/operations/update-metadata.js +1 -0
- package/dist/src/operations/update-node.d.ts +5 -0
- package/dist/src/operations/update-node.js +5 -0
- package/dist/src/operations/update-plan-task.d.ts +5 -0
- package/dist/src/operations/update-plan-task.js +5 -0
- package/dist/src/operations/validate.d.ts +10 -0
- package/dist/src/operations/validate.js +9 -0
- package/dist/src/schema.d.ts +44 -0
- package/dist/src/schema.js +31 -0
- package/dist/src/speckit/generate.d.ts +6 -0
- package/dist/src/speckit/generate.js +6 -0
- package/dist/src/speckit/parse.d.ts +9 -0
- package/dist/src/speckit/parse.js +6 -0
- package/dist/src/speckit/plan.d.ts +5 -0
- package/dist/src/speckit/project.d.ts +6 -0
- 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 {
|
|
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(
|
|
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 {
|
|
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(
|
|
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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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 {
|
|
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(
|
|
16
|
-
const { doc } = loadDoc(
|
|
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 {
|
|
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
|
|
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(
|
|
22
|
-
const { doc } =
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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 {
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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 {
|
|
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(
|
|
16
|
-
const { doc } = loadDoc(
|
|
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."));
|
package/dist/src/cli/shared.d.ts
CHANGED
|
@@ -1,14 +1,29 @@
|
|
|
1
1
|
import * as z from "zod";
|
|
2
2
|
import { type Format } from "../io.js";
|
|
3
3
|
import type { SysProMDocument } from "../schema.js";
|
|
4
|
-
/**
|
|
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. .sysprom.json 5. .sysprom.md 6. .sysprom/
|
|
13
|
+
* 7. *.spm.json 8. *.spm.md 9. *.spm/
|
|
14
|
+
* 10. *.sysprom.json 11. *.sysprom.md 12. *.sysprom/
|
|
15
|
+
*
|
|
16
|
+
* All matching is case-insensitive. Glob tiers must have exactly one match.
|
|
17
|
+
*/
|
|
18
|
+
export declare function resolveInput(input?: string, cwd?: string): string;
|
|
6
19
|
/** Common output/persistence options for read-only commands. */
|
|
7
20
|
export declare const readOpts: z.ZodObject<{
|
|
21
|
+
path: z.ZodOptional<z.ZodString>;
|
|
8
22
|
json: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
9
23
|
}, z.core.$strip>;
|
|
10
24
|
/** Common output/persistence options for mutation commands. */
|
|
11
25
|
export declare const mutationOpts: z.ZodObject<{
|
|
26
|
+
path: z.ZodOptional<z.ZodString>;
|
|
12
27
|
json: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
13
28
|
dryRun: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
14
29
|
sync: z.ZodOptional<z.ZodString>;
|
|
@@ -20,7 +35,7 @@ export interface LoadedDoc {
|
|
|
20
35
|
format: Format;
|
|
21
36
|
path: string;
|
|
22
37
|
}
|
|
23
|
-
/** Load a document from a CLI input path. */
|
|
24
|
-
export declare function loadDoc(input
|
|
38
|
+
/** Load a document from a CLI input path (auto-resolved if omitted). */
|
|
39
|
+
export declare function loadDoc(input?: string): LoadedDoc;
|
|
25
40
|
/** Persist a document and optionally sync to markdown. */
|
|
26
41
|
export declare function persistDoc(doc: SysProMDocument, loaded: LoadedDoc, opts: MutationOpts): void;
|
package/dist/src/cli/shared.js
CHANGED
|
@@ -1,19 +1,116 @@
|
|
|
1
1
|
import * as z from "zod";
|
|
2
|
+
import { 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
|
-
/**
|
|
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. .sysprom.json 5. .sysprom.md 6. .sysprom/
|
|
28
|
+
* 7. *.spm.json 8. *.spm.md 9. *.spm/
|
|
29
|
+
* 10. *.sysprom.json 11. *.sysprom.md 12. *.sysprom/
|
|
30
|
+
*
|
|
31
|
+
* All matching is case-insensitive. Glob tiers must have exactly one match.
|
|
32
|
+
*/
|
|
33
|
+
export function resolveInput(input, cwd) {
|
|
34
|
+
if (input)
|
|
35
|
+
return input;
|
|
36
|
+
const dir = resolve(cwd ?? ".");
|
|
37
|
+
// Exact names to check, in priority order (case-insensitive)
|
|
38
|
+
const exactNames = [
|
|
39
|
+
".spm.json",
|
|
40
|
+
".spm.md",
|
|
41
|
+
".spm",
|
|
42
|
+
".sysprom.json",
|
|
43
|
+
".sysprom.md",
|
|
44
|
+
".sysprom",
|
|
45
|
+
];
|
|
46
|
+
const entries = readdirSync(dir);
|
|
47
|
+
for (const name of exactNames) {
|
|
48
|
+
const isDirSuffix = name.endsWith(".spm") || name.endsWith(".sysprom");
|
|
49
|
+
const found = entries.filter((e) => e.toLowerCase() === name);
|
|
50
|
+
if (found.length > 1) {
|
|
51
|
+
throw new Error(`Multiple SysProM documents found: ${found.join(", ")}. Specify one explicitly.`);
|
|
52
|
+
}
|
|
53
|
+
if (found.length === 1) {
|
|
54
|
+
const candidate = join(dir, found[0]);
|
|
55
|
+
if (isDirSuffix) {
|
|
56
|
+
try {
|
|
57
|
+
if (statSync(candidate).isDirectory())
|
|
58
|
+
return candidate;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
/* skip */
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
return candidate;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Glob suffixes in priority order (case-insensitive)
|
|
70
|
+
const globSuffixes = [
|
|
71
|
+
".spm.json",
|
|
72
|
+
".spm.md",
|
|
73
|
+
".spm",
|
|
74
|
+
".sysprom.json",
|
|
75
|
+
".sysprom.md",
|
|
76
|
+
".sysprom",
|
|
77
|
+
];
|
|
78
|
+
for (const suffix of globSuffixes) {
|
|
79
|
+
const isDirSuffix = suffix === ".spm" || suffix === ".sysprom";
|
|
80
|
+
const matches = entries
|
|
81
|
+
.filter((e) => {
|
|
82
|
+
const lower = e.toLowerCase();
|
|
83
|
+
return lower.endsWith(suffix) && lower !== suffix;
|
|
84
|
+
})
|
|
85
|
+
.map((e) => join(dir, e))
|
|
86
|
+
.filter((p) => {
|
|
87
|
+
if (isDirSuffix) {
|
|
88
|
+
try {
|
|
89
|
+
return statSync(p).isDirectory();
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return true;
|
|
96
|
+
});
|
|
97
|
+
if (matches.length === 1)
|
|
98
|
+
return matches[0];
|
|
99
|
+
if (matches.length > 1) {
|
|
100
|
+
const names = matches.map((m) => m.slice(dir.length + 1)).join(", ");
|
|
101
|
+
throw new Error(`Multiple SysProM documents found: ${names}. Specify one explicitly.`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
throw new Error("No SysProM document found in current directory. Specify a path or run `spm init`.");
|
|
105
|
+
}
|
|
11
106
|
/** Common output/persistence options for read-only commands. */
|
|
12
107
|
export const readOpts = z.object({
|
|
108
|
+
path: pathOpt,
|
|
13
109
|
json: z.boolean().optional().default(false).describe("output as JSON"),
|
|
14
110
|
});
|
|
15
111
|
/** Common output/persistence options for mutation commands. */
|
|
16
112
|
export const mutationOpts = z.object({
|
|
113
|
+
path: pathOpt,
|
|
17
114
|
json: z.boolean().optional().default(false).describe("output as JSON"),
|
|
18
115
|
dryRun: z
|
|
19
116
|
.boolean()
|
|
@@ -25,9 +122,9 @@ export const mutationOpts = z.object({
|
|
|
25
122
|
.optional()
|
|
26
123
|
.describe("sync to markdown directory after saving"),
|
|
27
124
|
});
|
|
28
|
-
/** Load a document from a CLI input path. */
|
|
125
|
+
/** Load a document from a CLI input path (auto-resolved if omitted). */
|
|
29
126
|
export function loadDoc(input) {
|
|
30
|
-
return loadDocument(input);
|
|
127
|
+
return loadDocument(resolveInput(input));
|
|
31
128
|
}
|
|
32
129
|
/** Persist a document and optionally sync to markdown. */
|
|
33
130
|
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
|
/**
|
package/dist/src/json-to-md.d.ts
CHANGED
|
@@ -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.",
|