@teurons/vds 0.0.1 → 0.0.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 ADDED
@@ -0,0 +1,52 @@
1
+ # @teurons/vds
2
+
3
+ The `vds` command. It starts, checks and indexes a VDS workspace on your machine.
4
+
5
+ VDS keeps a product's spec as files: capabilities that hold rules written in EARS,
6
+ scenarios in Gherkin, and flows that point at those rules in order.
7
+ This package is an early alpha and is published on the `next` tag.
8
+
9
+ ## Set it up with your AI agent
10
+
11
+ Copy this prompt into Claude Code, Codex or any coding agent, run from the root of your project:
12
+
13
+ ```text
14
+ Set up VDS in this project.
15
+
16
+ 1. Run `npx -y @teurons/vds@next init vds-workspace`. It creates the
17
+ capabilities, flows and scenarios folders, a VDS.md guide and a .vds.json.
18
+ If it says a workspace already exists, stop and tell me what it found.
19
+ 2. Add `"vds": "vds"` to package.json scripts and @teurons/vds@next to
20
+ devDependencies if this project uses npm, pnpm or yarn. Otherwise skip this.
21
+ 3. Read vds-workspace/VDS.md and follow it from now on whenever you work on
22
+ the spec.
23
+ 4. Add a short section to this project's AGENTS.md (or CLAUDE.md if that is
24
+ what exists) saying: the product spec lives in vds-workspace; read
25
+ vds-workspace/VDS.md before changing it; run `vds index vds-workspace`
26
+ first and `vds check vds-workspace` before finishing.
27
+ 5. Run `npx @teurons/vds@next check vds-workspace` and confirm it prints valid.
28
+ 6. Tell me what you created and changed, file by file.
29
+ ```
30
+
31
+ ## Commands
32
+
33
+ ```sh
34
+ npx @teurons/vds@next init [folder] # start a workspace (never overwrites one)
35
+ npx @teurons/vds@next check [folder] # print every problem; exit 1 if any
36
+ npx @teurons/vds@next index [folder] # print the index: every flow and rule, one line each
37
+ ```
38
+
39
+ `folder` defaults to the current folder.
40
+
41
+ ## A workspace
42
+
43
+ ```text
44
+ vds-workspace/
45
+ VDS.md how agents and people work on this spec
46
+ .vds.json local settings, such as the studio port
47
+ capabilities/<CODE>.yaml rules, each one EARS statement with an id like ONB-01
48
+ flows/<id>.yaml versioned flows whose steps point at rule ids
49
+ scenarios/<RULE-ID>.feature Gherkin scenarios, one file per rule
50
+ ```
51
+
52
+ Needs Node 20 or later.
package/dist/vds.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  // src/bin.js
4
4
  import { readdirSync, readFileSync as readFileSync2 } from "node:fs";
5
- import { join, resolve } from "node:path";
5
+ import { join as join2, resolve } from "node:path";
6
6
 
7
7
  // ../../specs/js/load.js
8
8
  import { readFileSync } from "node:fs";
@@ -93,22 +93,72 @@ function loadMapper() {
93
93
  return instantiate(mapperModule());
94
94
  }
95
95
 
96
- // src/bin.js
96
+ // src/init.js
97
+ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
98
+ import { createServer } from "node:net";
99
+ import { join } from "node:path";
97
100
  var FOLDERS = ["capabilities", "flows", "scenarios"];
101
+ var FIRST_PORT = 4600;
102
+ var GUIDE = `# Working in this VDS workspace
103
+
104
+ This folder holds the product's requirements, flows and scenarios as plain files.
105
+ Read and write them with the vds command.
106
+
107
+ ## Layout
108
+
109
+ - capabilities/<CODE>.yaml: one capability and its requirements (ids like ONB-01).
110
+ - flows/<id>.yaml: a journey made of states; each state points at requirement ids.
111
+ - scenarios/<REQ-ID>.feature: Given, When, Then scenarios for one requirement.
112
+
113
+ ## How to work
114
+
115
+ 1. Run \`vds index\` first. It prints one line per flow and requirement, so you know what exists.
116
+ 2. Open one file at a time. Read only the file you are changing.
117
+ 3. Write requirements in EARS: "When <trigger>, the system SHALL <response>." The system is always the subject.
118
+ 4. Point flows at requirement ids. A state lists the ids it needs under \`requirements:\`.
119
+ 5. Run \`vds check\` before you finish. It prints "valid" when nothing is wrong; fix every problem it lists.
120
+ `;
121
+ async function freePort() {
122
+ for (let port = FIRST_PORT; ; port++) {
123
+ const free = await new Promise((resolve2) => {
124
+ const server = createServer();
125
+ server.once("error", () => resolve2(false));
126
+ server.listen(port, () => server.close(() => resolve2(true)));
127
+ });
128
+ if (free) return port;
129
+ }
130
+ }
131
+ async function init(root) {
132
+ const found = [...FOLDERS, "VDS.md"].filter((name) => existsSync(join(root, name)));
133
+ if (found.length > 0) {
134
+ console.error(`nothing changed; this folder already has: ${found.join(", ")}`);
135
+ return 1;
136
+ }
137
+ const port = await freePort();
138
+ for (const dir of FOLDERS) mkdirSync(join(root, dir), { recursive: true });
139
+ writeFileSync(join(root, "VDS.md"), GUIDE);
140
+ writeFileSync(join(root, ".vds.json"), `${JSON.stringify({ port })}
141
+ `);
142
+ return 0;
143
+ }
144
+
145
+ // src/bin.js
146
+ var FOLDERS2 = ["capabilities", "flows", "scenarios"];
98
147
  function readWorkspace(root) {
99
148
  const files = {};
100
- for (const dir of FOLDERS) {
149
+ for (const dir of FOLDERS2) {
101
150
  let names = [];
102
151
  try {
103
- names = readdirSync(join(root, dir));
152
+ names = readdirSync(join2(root, dir));
104
153
  } catch {
105
154
  continue;
106
155
  }
107
- for (const name of names) files[`${dir}/${name}`] = readFileSync2(join(root, dir, name), "utf8");
156
+ for (const name of names) files[`${dir}/${name}`] = readFileSync2(join2(root, dir, name), "utf8");
108
157
  }
109
158
  return files;
110
159
  }
111
160
  async function main([command, folder = "."]) {
161
+ if (command === "init") return init(resolve(folder));
112
162
  const mapper = await loadMapper();
113
163
  const files = readWorkspace(resolve(folder));
114
164
  if (command === "check") {
@@ -126,7 +176,7 @@ async function main([command, folder = "."]) {
126
176
  process.stdout.write(mapper.v2Index(files));
127
177
  return 0;
128
178
  }
129
- console.error("usage: vds check [folder] | vds index [folder]");
179
+ console.error("usage: vds init [folder] | vds check [folder] | vds index [folder]");
130
180
  return 2;
131
181
  }
132
182
  process.exitCode = await main(process.argv.slice(2));
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teurons/vds",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "The vds command: check, index and run a VDS workspace on your machine.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -12,18 +12,7 @@
12
12
  "engines": {
13
13
  "node": ">=20"
14
14
  },
15
- "scripts": {
16
- "build": "node build.mjs",
17
- "test": "vitest run",
18
- "prepack": "node build.mjs",
19
- "release": "node release.mjs"
20
- },
21
15
  "dependencies": {},
22
- "devDependencies": {
23
- "@vds/mapper": "workspace:*",
24
- "esbuild": "0.28.1",
25
- "vitest": "5.0.1"
26
- },
27
16
  "license": "UNLICENSED",
28
17
  "repository": {
29
18
  "type": "git",