@popoverai/dotrequirements 0.33.0 → 0.34.1
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 +2 -2
- package/dist/cli.js +13 -1
- package/dist/cloud.d.ts +5 -1
- package/dist/cloud.js +6 -2
- package/dist/commands/acceptance-test.js +1 -1
- package/dist/commands/board/index.d.ts +13 -0
- package/dist/commands/board/index.js +96 -0
- package/dist/commands/branch-merge.d.ts +78 -0
- package/dist/commands/branch-merge.js +129 -0
- package/dist/commands/diff.js +15 -5
- package/dist/commands/mockup/index.d.ts +11 -0
- package/dist/commands/mockup/index.js +82 -0
- package/dist/commands/scores/index.d.ts +50 -0
- package/dist/commands/scores/index.js +190 -0
- package/dist/commands/solution/ask.d.ts +9 -0
- package/dist/commands/solution/ask.js +27 -0
- package/dist/commands/solution/author.d.ts +19 -0
- package/dist/commands/solution/author.js +202 -0
- package/dist/commands/solution/branch.d.ts +103 -0
- package/dist/commands/solution/branch.js +341 -0
- package/dist/commands/solution/brief.d.ts +81 -0
- package/dist/commands/solution/brief.js +47 -0
- package/dist/commands/solution/checkout.d.ts +27 -0
- package/dist/commands/solution/checkout.js +66 -0
- package/dist/commands/solution/client.d.ts +16 -0
- package/dist/commands/solution/client.js +46 -0
- package/dist/commands/solution/contract.d.ts +9 -0
- package/dist/commands/solution/contract.js +23 -0
- package/dist/commands/solution/create.d.ts +14 -0
- package/dist/commands/solution/create.js +52 -0
- package/dist/commands/solution/demo-script.d.ts +28 -0
- package/dist/commands/solution/demo-script.js +43 -0
- package/dist/commands/solution/image.d.ts +60 -0
- package/dist/commands/solution/image.js +148 -0
- package/dist/commands/solution/index.d.ts +12 -0
- package/dist/commands/solution/index.js +282 -0
- package/dist/commands/solution/look-up.d.ts +9 -0
- package/dist/commands/solution/look-up.js +69 -0
- package/dist/commands/solution/next.d.ts +12 -0
- package/dist/commands/solution/next.js +48 -0
- package/dist/commands/solution/plan-file.d.ts +22 -0
- package/dist/commands/solution/plan-file.js +33 -0
- package/dist/commands/solution/preview-screenshot.d.ts +21 -0
- package/dist/commands/solution/preview-screenshot.js +56 -0
- package/dist/commands/solution/pull-request.d.ts +25 -0
- package/dist/commands/solution/pull-request.js +117 -0
- package/dist/commands/solution/pushing.d.ts +66 -0
- package/dist/commands/solution/pushing.js +185 -0
- package/dist/commands/solution/rehearse.d.ts +10 -0
- package/dist/commands/solution/rehearse.js +24 -0
- package/dist/commands/solution/request.d.ts +3 -0
- package/dist/commands/solution/request.js +13 -0
- package/dist/commands/solution/review.d.ts +27 -0
- package/dist/commands/solution/review.js +104 -0
- package/dist/commands/solution/run-file.d.ts +43 -0
- package/dist/commands/solution/run-file.js +69 -0
- package/dist/commands/solution/share.d.ts +62 -0
- package/dist/commands/solution/share.js +346 -0
- package/dist/commands/solution/stall.d.ts +14 -0
- package/dist/commands/solution/stall.js +41 -0
- package/dist/commands/solution/start.d.ts +14 -0
- package/dist/commands/solution/start.js +31 -0
- package/dist/commands/solution/status.d.ts +39 -0
- package/dist/commands/solution/status.js +145 -0
- package/dist/commands/solution/summary.d.ts +13 -0
- package/dist/commands/solution/summary.js +5 -0
- package/dist/commands/solution/things.d.ts +118 -0
- package/dist/commands/solution/things.js +78 -0
- package/dist/commands/solution/thread.d.ts +13 -0
- package/dist/commands/solution/thread.js +53 -0
- package/dist/commands/solution/upload.d.ts +24 -0
- package/dist/commands/solution/upload.js +27 -0
- package/dist/commands/solution/video.d.ts +88 -0
- package/dist/commands/solution/video.js +364 -0
- package/dist/commands/solution/working-folder.d.ts +44 -0
- package/dist/commands/solution/working-folder.js +64 -0
- package/dist/commands/sync.d.ts +2 -1
- package/dist/commands/sync.js +21 -5
- package/dist/convex.d.ts +54 -0
- package/dist/convex.js +64 -0
- package/dist/push/core.js +7 -2
- package/dist/rehearsal/derive.d.ts +23 -0
- package/dist/rehearsal/derive.js +112 -0
- package/dist/rehearsal/driver.d.ts +44 -0
- package/dist/rehearsal/driver.js +337 -0
- package/dist/rehearsal/earlier.d.ts +25 -0
- package/dist/rehearsal/earlier.js +138 -0
- package/dist/rehearsal/index.d.ts +5 -0
- package/dist/rehearsal/index.js +4 -0
- package/dist/rehearsal/live.d.ts +72 -0
- package/dist/rehearsal/live.js +301 -0
- package/dist/rehearsal/report.d.ts +4 -0
- package/dist/rehearsal/report.js +69 -0
- package/dist/rehearsal/types.d.ts +377 -0
- package/dist/rehearsal/types.js +8 -0
- package/dist/requirements/index.d.ts +6 -0
- package/dist/requirements/index.js +24 -0
- package/dist/schema/browser.d.ts +2 -1
- package/dist/schema/browser.js +6 -1
- package/dist/schema/file-writer.d.ts +5 -0
- package/dist/schema/file-writer.js +4 -0
- package/dist/schema/parser.d.ts +11 -2
- package/dist/schema/parser.js +11 -7
- package/dist/schema/provenance.d.ts +27 -0
- package/dist/schema/provenance.js +66 -0
- package/dist/schema/schemas.d.ts +40 -0
- package/dist/schema/schemas.js +4 -0
- package/dist/sync/execute.d.ts +10 -1
- package/dist/sync/execute.js +68 -5
- package/dist/sync/index.d.ts +1 -1
- package/dist/sync/index.js +1 -1
- package/dist/sync/publish.d.ts +7 -0
- package/dist/sync/segment.js +4 -1
- package/dist/sync/snapshot.d.ts +23 -1
- package/dist/sync/snapshot.js +75 -3
- package/dist/sync/solution-documents.d.ts +74 -0
- package/dist/sync/solution-documents.js +135 -0
- package/dist/sync/types.d.ts +20 -0
- package/package.json +3 -2
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a solution's documents live, the sync's half (SOLDOC; the decision
|
|
3
|
+
* is in docs/working/four-areas-prototype.md, "Where a solution's documents
|
|
4
|
+
* live"). A document that belongs to a solution and is not a requirements
|
|
5
|
+
* document lives in a solution directory, `.requirements/solutions/<solution>/`,
|
|
6
|
+
* named for its outcome; the `.requirements.md` name is what makes a file a
|
|
7
|
+
* requirements document, wherever it sits. A new file declares its belonging
|
|
8
|
+
* by its path; once the frontmatter carries it, the frontmatter is the truth.
|
|
9
|
+
*/
|
|
10
|
+
import * as path from "node:path";
|
|
11
|
+
import { sanitizeFileName } from "./local-files.js";
|
|
12
|
+
export const SOLUTIONS_DIR = "solutions";
|
|
13
|
+
/** The solution directory a file sits directly in, if any (SOLDOC-8.1). */
|
|
14
|
+
export function solutionDirOf(filePath) {
|
|
15
|
+
const parts = filePath.split(/[\\/]/);
|
|
16
|
+
const fileName = parts.at(-1);
|
|
17
|
+
const solutionSlug = parts.at(-2);
|
|
18
|
+
if (!fileName ||
|
|
19
|
+
!solutionSlug ||
|
|
20
|
+
parts.at(-3) !== SOLUTIONS_DIR ||
|
|
21
|
+
parts.at(-4) !== ".requirements" ||
|
|
22
|
+
!fileName.endsWith(".md")) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
return { solutionSlug, outcomeSlug: stemOf(fileName) };
|
|
26
|
+
}
|
|
27
|
+
/** `pitch` for `pitch.md` and for `pitch.requirements.md`. */
|
|
28
|
+
export function stemOf(fileName) {
|
|
29
|
+
return fileName.replace(/\.requirements\.md$/, "").replace(/\.md$/, "");
|
|
30
|
+
}
|
|
31
|
+
/** SOLDOC-3: the name, never the content. Undefined for a file the rule doesn't reach. */
|
|
32
|
+
export function requirementsDocByName(filePath) {
|
|
33
|
+
if (!solutionDirOf(filePath))
|
|
34
|
+
return undefined;
|
|
35
|
+
return filePath.endsWith(".requirements.md");
|
|
36
|
+
}
|
|
37
|
+
/** The directory a solution's documents live in, by name. */
|
|
38
|
+
export function directoryOf(solution) {
|
|
39
|
+
return solution.directory ?? sanitizeFileName(solution.title);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* What a pushed file belongs to (SOLDOC-4, SOLDOC-5): the frontmatter's
|
|
43
|
+
* belonging when it has one, else what its path claims, resolved against
|
|
44
|
+
* the project's solutions. A frontmatter that disagrees with the path is
|
|
45
|
+
* kept and reported; a path that resolves to nothing refuses the push.
|
|
46
|
+
*/
|
|
47
|
+
export function resolveBelonging(filePath, frontmatter, claim, solutions) {
|
|
48
|
+
const declared = frontmatter.solution && frontmatter.outcome
|
|
49
|
+
? { solutionId: frontmatter.solution, outcome: frontmatter.outcome }
|
|
50
|
+
: undefined;
|
|
51
|
+
if (!claim)
|
|
52
|
+
return { belonging: declared };
|
|
53
|
+
const name = path.basename(filePath);
|
|
54
|
+
if (declared) {
|
|
55
|
+
// SOLDOC-5: the frontmatter wins; the path is layout. Say when they part.
|
|
56
|
+
const owner = solutions?.find((s) => s.solutionId === declared.solutionId);
|
|
57
|
+
if (owner && directoryOf(owner) !== claim.solutionSlug) {
|
|
58
|
+
return {
|
|
59
|
+
belonging: declared,
|
|
60
|
+
warning: `${name}: its path names a different solution than its frontmatter ("${owner.title}"); the frontmatter's belonging is kept.`,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
// Read against the solution's other outcomes too: `spec-2` names Spec 2,
|
|
64
|
+
// not the Spec, when the plan has both.
|
|
65
|
+
if (outcomeNamedBy(claim.outcomeSlug, [
|
|
66
|
+
...(owner?.outcomes ?? []),
|
|
67
|
+
declared.outcome,
|
|
68
|
+
]) !== declared.outcome) {
|
|
69
|
+
return {
|
|
70
|
+
belonging: declared,
|
|
71
|
+
warning: `${name}: its filename names a different outcome than its frontmatter ("${declared.outcome}"); the frontmatter's belonging is kept.`,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return { belonging: declared };
|
|
75
|
+
}
|
|
76
|
+
// SOLDOC-4, SOLDOC-9: a new file's path is its declaration, read against
|
|
77
|
+
// each solution's own directory name.
|
|
78
|
+
const matches = (solutions ?? []).filter((s) => directoryOf(s) === claim.solutionSlug);
|
|
79
|
+
if (matches.length === 0) {
|
|
80
|
+
throw new Error(`${name}: its directory "${claim.solutionSlug}" matches no solution in the project, so it can't be placed. Name the directory as the solution's is named: its title as a slug, with its numeric suffix when an older solution has the same title.`);
|
|
81
|
+
}
|
|
82
|
+
if (matches.length > 1) {
|
|
83
|
+
throw new Error(`${name}: its directory "${claim.solutionSlug}" matches more than one solution (${matches.map((s) => `"${s.title}"`).join(", ")}), so it can't be placed.`);
|
|
84
|
+
}
|
|
85
|
+
const [solution] = matches;
|
|
86
|
+
const outcome = outcomeNamedBy(claim.outcomeSlug, solution.outcomes);
|
|
87
|
+
if (!outcome) {
|
|
88
|
+
throw new Error(`${name}: "${claim.outcomeSlug}" matches no outcome of "${solution.title}". Its plan produces: ${solution.outcomes.map((o) => `${o} (${sanitizeFileName(o)}.md)`).join(", ")}.`);
|
|
89
|
+
}
|
|
90
|
+
return { belonging: { solutionId: solution.solutionId, outcome } };
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* SOLDOC-4, SOLDOC-19: the outcome a file's stem names, of those given: the
|
|
94
|
+
* one whose slug the stem is, or else the one whose slug it is followed by a
|
|
95
|
+
* suffix from -2 up, as an outcome's later documents are named. So `spec-2`
|
|
96
|
+
* is Spec 2's when there is a Spec 2, and the Spec's otherwise.
|
|
97
|
+
*/
|
|
98
|
+
export function outcomeNamedBy(stem, outcomes) {
|
|
99
|
+
const plain = outcomes.find((o) => sanitizeFileName(o) === stem);
|
|
100
|
+
if (plain !== undefined)
|
|
101
|
+
return plain;
|
|
102
|
+
const later = /^(.+)-([1-9]\d*)$/.exec(stem);
|
|
103
|
+
if (!later || Number(later[2]) < 2)
|
|
104
|
+
return undefined;
|
|
105
|
+
return outcomes.find((o) => sanitizeFileName(o) === later[1]);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* SOLDOC-6, SOLDOC-9, SOLDOC-19: where a pulled document that belongs to a
|
|
109
|
+
* solution lands when it has no file yet: in the solution's own directory,
|
|
110
|
+
* at the file name the backend gives it, which counts the outcome's other
|
|
111
|
+
* documents. A backend from before it was sent leaves it out, and the
|
|
112
|
+
* outcome's plain name stands in: its slug, with the `.requirements.md` name
|
|
113
|
+
* when it is a requirements document. When that file is taken, the document
|
|
114
|
+
* takes the outcome's next free name from -2 up.
|
|
115
|
+
*/
|
|
116
|
+
export function solutionDocumentPath(requirementsDir, solutionDirectory, outcome, isRequirementsDoc, fileName, taken = () => false) {
|
|
117
|
+
const suffix = isRequirementsDoc ? ".requirements.md" : ".md";
|
|
118
|
+
const directory = path.join(requirementsDir, SOLUTIONS_DIR, solutionDirectory || "solution");
|
|
119
|
+
const slug = sanitizeFileName(outcome) || "outcome";
|
|
120
|
+
// Only a plain file name of the document's kind, never a path.
|
|
121
|
+
const given = fileName &&
|
|
122
|
+
fileName === path.basename(fileName) &&
|
|
123
|
+
!fileName.startsWith(".") &&
|
|
124
|
+
stemOf(fileName) !== "" &&
|
|
125
|
+
fileName.endsWith(suffix) &&
|
|
126
|
+
(isRequirementsDoc || !fileName.endsWith(".requirements.md"))
|
|
127
|
+
? fileName
|
|
128
|
+
: `${slug}${suffix}`;
|
|
129
|
+
let candidate = path.join(directory, given);
|
|
130
|
+
for (let n = 2; taken(candidate); n++) {
|
|
131
|
+
candidate = path.join(directory, `${slug}-${n}${suffix}`);
|
|
132
|
+
}
|
|
133
|
+
return candidate;
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=solution-documents.js.map
|
package/dist/sync/types.d.ts
CHANGED
|
@@ -29,6 +29,9 @@ export interface LocalDocument {
|
|
|
29
29
|
defaultPrefix?: string;
|
|
30
30
|
/** document.attachments from frontmatter (ATTACH-10). */
|
|
31
31
|
attachments?: Attachment[];
|
|
32
|
+
/** SOLDOC-5: the belonging the frontmatter declares. */
|
|
33
|
+
solution?: string;
|
|
34
|
+
outcome?: string;
|
|
32
35
|
/** Frontmatter-stripped markdown body (the comparison unit, SYNC-ARCH-1). */
|
|
33
36
|
body?: string;
|
|
34
37
|
parseError?: string;
|
|
@@ -46,6 +49,18 @@ export interface CloudDocument {
|
|
|
46
49
|
body: string;
|
|
47
50
|
version: number;
|
|
48
51
|
updatedAt: number;
|
|
52
|
+
/** SOLDOC-6: which solution and outcome it belongs to, with the solution's title and directory name. */
|
|
53
|
+
solution?: {
|
|
54
|
+
solutionId: string;
|
|
55
|
+
outcome: string;
|
|
56
|
+
title: string | null;
|
|
57
|
+
/** SOLDOC-9: the solution's directory name; absent from an older backend. */
|
|
58
|
+
directory?: string | null;
|
|
59
|
+
/** SOLDOC-19: the document's file name in that directory; absent from an older backend. */
|
|
60
|
+
fileName?: string | null;
|
|
61
|
+
};
|
|
62
|
+
/** SOLDOC-2/3: absent means a requirements document. */
|
|
63
|
+
isRequirementsDoc?: boolean;
|
|
49
64
|
}
|
|
50
65
|
export interface LocalSnapshot {
|
|
51
66
|
documents: LocalDocument[];
|
|
@@ -54,6 +69,11 @@ export interface CloudSnapshot {
|
|
|
54
69
|
projectName: string;
|
|
55
70
|
projectSlug: string;
|
|
56
71
|
documents: CloudDocument[];
|
|
72
|
+
/**
|
|
73
|
+
* SOLACCESS-2.2: whether the project's team has solutions, as the export
|
|
74
|
+
* read it; absent from an older backend, which reads as no.
|
|
75
|
+
*/
|
|
76
|
+
solutions?: boolean;
|
|
57
77
|
}
|
|
58
78
|
/**
|
|
59
79
|
* A single point of difference within a paired document, for verbose
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@popoverai/dotrequirements",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.1",
|
|
4
4
|
"description": "Requirements as testable, human-readable data — CLI and test harness for spec-driven development with AI coding agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
"./schema": "./dist/schema/index.js",
|
|
14
14
|
"./schema/browser": "./dist/schema/browser.js",
|
|
15
15
|
"./style-guide": "./dist/requirements/style-guide.js",
|
|
16
|
-
"./greenfield": "./dist/requirements/greenfield.js"
|
|
16
|
+
"./greenfield": "./dist/requirements/greenfield.js",
|
|
17
|
+
"./rehearsal": "./dist/rehearsal/index.js"
|
|
17
18
|
},
|
|
18
19
|
"publishConfig": {
|
|
19
20
|
"access": "public"
|