@popoverai/dotrequirements 0.32.1 → 0.34.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/dist/cli.js +32 -7
- package/dist/cloud.d.ts +18 -0
- package/dist/cloud.js +38 -0
- 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/create-requirement-document.js +2 -2
- package/dist/commands/diff.js +15 -5
- package/dist/commands/init.js +7 -6
- package/dist/commands/link.js +27 -21
- package/dist/commands/mockup/index.d.ts +11 -0
- package/dist/commands/mockup/index.js +82 -0
- package/dist/commands/report.js +22 -9
- package/dist/commands/review-test.js +3 -2
- 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 +281 -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 +42 -0
- package/dist/commands/solution/run-file.js +63 -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 +11 -0
- package/dist/commands/solution/start.js +20 -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/style-check.js +4 -4
- package/dist/commands/sync.d.ts +2 -1
- package/dist/commands/sync.js +21 -5
- package/dist/convex.d.ts +64 -10
- package/dist/convex.js +75 -10
- package/dist/harness/finalize.js +16 -8
- package/dist/harness/reportingStatus.js +2 -11
- 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/cloud-ai.d.ts +0 -6
- package/dist/requirements/cloud-ai.js +2 -11
- package/dist/requirements/cloud-coverage.js +4 -4
- package/dist/requirements/index.d.ts +6 -0
- package/dist/requirements/index.js +24 -0
- package/dist/schema/browser.d.ts +1 -1
- package/dist/schema/browser.js +3 -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/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 +76 -24
- 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/publish.js +2 -2
- package/dist/sync/segment.js +4 -1
- package/dist/sync/snapshot.d.ts +27 -5
- package/dist/sync/snapshot.js +92 -15
- package/dist/sync/solution-documents.d.ts +64 -0
- package/dist/sync/solution-documents.js +97 -0
- package/dist/sync/types.d.ts +19 -1
- package/dist/utils/command-error.d.ts +19 -0
- package/dist/utils/command-error.js +44 -0
- package/dist/utils/oauth-flow.js +2 -2
- package/dist/utils/project-selector.js +4 -4
- package/dist/version-messages.d.ts +28 -0
- package/dist/version-messages.js +87 -0
- package/package.json +3 -2
- package/dist/config.d.ts +0 -5
- package/dist/config.js +0 -12
package/dist/schema/schemas.d.ts
CHANGED
|
@@ -86,6 +86,8 @@ export declare const MetadataSchema: z.ZodObject<{
|
|
|
86
86
|
id: z.ZodOptional<z.ZodString>;
|
|
87
87
|
title: z.ZodOptional<z.ZodString>;
|
|
88
88
|
defaultPrefix: z.ZodOptional<z.ZodString>;
|
|
89
|
+
solution: z.ZodOptional<z.ZodString>;
|
|
90
|
+
outcome: z.ZodOptional<z.ZodString>;
|
|
89
91
|
attachments: z.ZodEffects<z.ZodEffects<z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
|
|
90
92
|
url: z.ZodString;
|
|
91
93
|
title: z.ZodOptional<z.ZodString>;
|
|
@@ -112,6 +114,8 @@ export declare const MetadataSchema: z.ZodObject<{
|
|
|
112
114
|
id?: string | undefined;
|
|
113
115
|
title?: string | undefined;
|
|
114
116
|
defaultPrefix?: string | undefined;
|
|
117
|
+
solution?: string | undefined;
|
|
118
|
+
outcome?: string | undefined;
|
|
115
119
|
attachments?: {
|
|
116
120
|
url: string;
|
|
117
121
|
title?: string | undefined;
|
|
@@ -120,6 +124,8 @@ export declare const MetadataSchema: z.ZodObject<{
|
|
|
120
124
|
id?: string | undefined;
|
|
121
125
|
title?: string | undefined;
|
|
122
126
|
defaultPrefix?: string | undefined;
|
|
127
|
+
solution?: string | undefined;
|
|
128
|
+
outcome?: string | undefined;
|
|
123
129
|
attachments?: {
|
|
124
130
|
url: string;
|
|
125
131
|
title?: string | undefined;
|
|
@@ -133,6 +139,8 @@ export declare const MetadataSchema: z.ZodObject<{
|
|
|
133
139
|
id?: string | undefined;
|
|
134
140
|
title?: string | undefined;
|
|
135
141
|
defaultPrefix?: string | undefined;
|
|
142
|
+
solution?: string | undefined;
|
|
143
|
+
outcome?: string | undefined;
|
|
136
144
|
attachments?: {
|
|
137
145
|
url: string;
|
|
138
146
|
title?: string | undefined;
|
|
@@ -146,6 +154,8 @@ export declare const MetadataSchema: z.ZodObject<{
|
|
|
146
154
|
id?: string | undefined;
|
|
147
155
|
title?: string | undefined;
|
|
148
156
|
defaultPrefix?: string | undefined;
|
|
157
|
+
solution?: string | undefined;
|
|
158
|
+
outcome?: string | undefined;
|
|
149
159
|
attachments?: {
|
|
150
160
|
url: string;
|
|
151
161
|
title?: string | undefined;
|
|
@@ -213,6 +223,8 @@ export declare const RequirementsFileSchema: z.ZodObject<{
|
|
|
213
223
|
id: z.ZodOptional<z.ZodString>;
|
|
214
224
|
title: z.ZodOptional<z.ZodString>;
|
|
215
225
|
defaultPrefix: z.ZodOptional<z.ZodString>;
|
|
226
|
+
solution: z.ZodOptional<z.ZodString>;
|
|
227
|
+
outcome: z.ZodOptional<z.ZodString>;
|
|
216
228
|
attachments: z.ZodEffects<z.ZodEffects<z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
|
|
217
229
|
url: z.ZodString;
|
|
218
230
|
title: z.ZodOptional<z.ZodString>;
|
|
@@ -239,6 +251,8 @@ export declare const RequirementsFileSchema: z.ZodObject<{
|
|
|
239
251
|
id?: string | undefined;
|
|
240
252
|
title?: string | undefined;
|
|
241
253
|
defaultPrefix?: string | undefined;
|
|
254
|
+
solution?: string | undefined;
|
|
255
|
+
outcome?: string | undefined;
|
|
242
256
|
attachments?: {
|
|
243
257
|
url: string;
|
|
244
258
|
title?: string | undefined;
|
|
@@ -247,6 +261,8 @@ export declare const RequirementsFileSchema: z.ZodObject<{
|
|
|
247
261
|
id?: string | undefined;
|
|
248
262
|
title?: string | undefined;
|
|
249
263
|
defaultPrefix?: string | undefined;
|
|
264
|
+
solution?: string | undefined;
|
|
265
|
+
outcome?: string | undefined;
|
|
250
266
|
attachments?: {
|
|
251
267
|
url: string;
|
|
252
268
|
title?: string | undefined;
|
|
@@ -260,6 +276,8 @@ export declare const RequirementsFileSchema: z.ZodObject<{
|
|
|
260
276
|
id?: string | undefined;
|
|
261
277
|
title?: string | undefined;
|
|
262
278
|
defaultPrefix?: string | undefined;
|
|
279
|
+
solution?: string | undefined;
|
|
280
|
+
outcome?: string | undefined;
|
|
263
281
|
attachments?: {
|
|
264
282
|
url: string;
|
|
265
283
|
title?: string | undefined;
|
|
@@ -273,6 +291,8 @@ export declare const RequirementsFileSchema: z.ZodObject<{
|
|
|
273
291
|
id?: string | undefined;
|
|
274
292
|
title?: string | undefined;
|
|
275
293
|
defaultPrefix?: string | undefined;
|
|
294
|
+
solution?: string | undefined;
|
|
295
|
+
outcome?: string | undefined;
|
|
276
296
|
attachments?: {
|
|
277
297
|
url: string;
|
|
278
298
|
title?: string | undefined;
|
|
@@ -288,6 +308,8 @@ export declare const RequirementsFileSchema: z.ZodObject<{
|
|
|
288
308
|
id: z.ZodOptional<z.ZodString>;
|
|
289
309
|
title: z.ZodOptional<z.ZodString>;
|
|
290
310
|
defaultPrefix: z.ZodOptional<z.ZodString>;
|
|
311
|
+
solution: z.ZodOptional<z.ZodString>;
|
|
312
|
+
outcome: z.ZodOptional<z.ZodString>;
|
|
291
313
|
attachments: z.ZodEffects<z.ZodEffects<z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
|
|
292
314
|
url: z.ZodString;
|
|
293
315
|
title: z.ZodOptional<z.ZodString>;
|
|
@@ -314,6 +336,8 @@ export declare const RequirementsFileSchema: z.ZodObject<{
|
|
|
314
336
|
id?: string | undefined;
|
|
315
337
|
title?: string | undefined;
|
|
316
338
|
defaultPrefix?: string | undefined;
|
|
339
|
+
solution?: string | undefined;
|
|
340
|
+
outcome?: string | undefined;
|
|
317
341
|
attachments?: {
|
|
318
342
|
url: string;
|
|
319
343
|
title?: string | undefined;
|
|
@@ -322,6 +346,8 @@ export declare const RequirementsFileSchema: z.ZodObject<{
|
|
|
322
346
|
id?: string | undefined;
|
|
323
347
|
title?: string | undefined;
|
|
324
348
|
defaultPrefix?: string | undefined;
|
|
349
|
+
solution?: string | undefined;
|
|
350
|
+
outcome?: string | undefined;
|
|
325
351
|
attachments?: {
|
|
326
352
|
url: string;
|
|
327
353
|
title?: string | undefined;
|
|
@@ -335,6 +361,8 @@ export declare const RequirementsFileSchema: z.ZodObject<{
|
|
|
335
361
|
id?: string | undefined;
|
|
336
362
|
title?: string | undefined;
|
|
337
363
|
defaultPrefix?: string | undefined;
|
|
364
|
+
solution?: string | undefined;
|
|
365
|
+
outcome?: string | undefined;
|
|
338
366
|
attachments?: {
|
|
339
367
|
url: string;
|
|
340
368
|
title?: string | undefined;
|
|
@@ -348,6 +376,8 @@ export declare const RequirementsFileSchema: z.ZodObject<{
|
|
|
348
376
|
id?: string | undefined;
|
|
349
377
|
title?: string | undefined;
|
|
350
378
|
defaultPrefix?: string | undefined;
|
|
379
|
+
solution?: string | undefined;
|
|
380
|
+
outcome?: string | undefined;
|
|
351
381
|
attachments?: {
|
|
352
382
|
url: string;
|
|
353
383
|
title?: string | undefined;
|
|
@@ -363,6 +393,8 @@ export declare const RequirementsFileSchema: z.ZodObject<{
|
|
|
363
393
|
id: z.ZodOptional<z.ZodString>;
|
|
364
394
|
title: z.ZodOptional<z.ZodString>;
|
|
365
395
|
defaultPrefix: z.ZodOptional<z.ZodString>;
|
|
396
|
+
solution: z.ZodOptional<z.ZodString>;
|
|
397
|
+
outcome: z.ZodOptional<z.ZodString>;
|
|
366
398
|
attachments: z.ZodEffects<z.ZodEffects<z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
|
|
367
399
|
url: z.ZodString;
|
|
368
400
|
title: z.ZodOptional<z.ZodString>;
|
|
@@ -389,6 +421,8 @@ export declare const RequirementsFileSchema: z.ZodObject<{
|
|
|
389
421
|
id?: string | undefined;
|
|
390
422
|
title?: string | undefined;
|
|
391
423
|
defaultPrefix?: string | undefined;
|
|
424
|
+
solution?: string | undefined;
|
|
425
|
+
outcome?: string | undefined;
|
|
392
426
|
attachments?: {
|
|
393
427
|
url: string;
|
|
394
428
|
title?: string | undefined;
|
|
@@ -397,6 +431,8 @@ export declare const RequirementsFileSchema: z.ZodObject<{
|
|
|
397
431
|
id?: string | undefined;
|
|
398
432
|
title?: string | undefined;
|
|
399
433
|
defaultPrefix?: string | undefined;
|
|
434
|
+
solution?: string | undefined;
|
|
435
|
+
outcome?: string | undefined;
|
|
400
436
|
attachments?: {
|
|
401
437
|
url: string;
|
|
402
438
|
title?: string | undefined;
|
|
@@ -410,6 +446,8 @@ export declare const RequirementsFileSchema: z.ZodObject<{
|
|
|
410
446
|
id?: string | undefined;
|
|
411
447
|
title?: string | undefined;
|
|
412
448
|
defaultPrefix?: string | undefined;
|
|
449
|
+
solution?: string | undefined;
|
|
450
|
+
outcome?: string | undefined;
|
|
413
451
|
attachments?: {
|
|
414
452
|
url: string;
|
|
415
453
|
title?: string | undefined;
|
|
@@ -423,6 +461,8 @@ export declare const RequirementsFileSchema: z.ZodObject<{
|
|
|
423
461
|
id?: string | undefined;
|
|
424
462
|
title?: string | undefined;
|
|
425
463
|
defaultPrefix?: string | undefined;
|
|
464
|
+
solution?: string | undefined;
|
|
465
|
+
outcome?: string | undefined;
|
|
426
466
|
attachments?: {
|
|
427
467
|
url: string;
|
|
428
468
|
title?: string | undefined;
|
package/dist/schema/schemas.js
CHANGED
|
@@ -147,6 +147,10 @@ export const MetadataSchema = z.object({
|
|
|
147
147
|
id: z.string().optional(), // Cloud document link - filled by push when creating
|
|
148
148
|
title: z.string().optional(), // Legacy fallback — the body's leading H1 is the title
|
|
149
149
|
defaultPrefix: z.string().optional(), // Editor hint for new requirement keys
|
|
150
|
+
// SOLDOC-5: the solution (by id) and the outcome (by name) this document
|
|
151
|
+
// belongs to. Written by the sync; the truth once present.
|
|
152
|
+
solution: z.string().optional(),
|
|
153
|
+
outcome: z.string().optional(),
|
|
150
154
|
// ATTACH-10: links attached to the document (a Miro board, a reference
|
|
151
155
|
// page). Round-trips through sync — the cloud stores them as document
|
|
152
156
|
// metadata, the file carries them here.
|
package/dist/sync/execute.d.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import type { PlannedAction, SyncMode } from "./plan.js";
|
|
11
11
|
import type { CloudAuth } from "./snapshot.js";
|
|
12
|
+
import { type SolutionForSync } from "./solution-documents.js";
|
|
12
13
|
import type { CloudSnapshot, DocumentComparison } from "./types.js";
|
|
13
14
|
export interface SyncOutcome {
|
|
14
15
|
cloudCreated: number;
|
|
@@ -59,6 +60,8 @@ export interface SyncOutcome {
|
|
|
59
60
|
name: string;
|
|
60
61
|
warning: string;
|
|
61
62
|
}>;
|
|
63
|
+
/** SOLDOC-5.1/5.2: a file whose path and frontmatter disagree about where it belongs. Optional so an outcome built before the field existed still reads. */
|
|
64
|
+
belongingWarnings?: string[];
|
|
62
65
|
/** SYNC-CLI-EDIT-3.1: files whose notation the cloud changed on storing —
|
|
63
66
|
* list markers, emphasis characters, spacing. Counted so the sync can say
|
|
64
67
|
* the reformatting happened and why, instead of leaving Jaime to discover
|
|
@@ -85,5 +88,11 @@ export interface SyncOutcome {
|
|
|
85
88
|
* writes require a project slug in `auth`; a read-only share run has none and
|
|
86
89
|
* its plan carries no cloud-writing actions.
|
|
87
90
|
*/
|
|
88
|
-
export declare function executePlan(plan: PlannedAction[], cloud: CloudSnapshot, auth: CloudAuth, workspaceRoot: string, mode: SyncMode
|
|
91
|
+
export declare function executePlan(plan: PlannedAction[], cloud: CloudSnapshot, auth: CloudAuth, workspaceRoot: string, mode: SyncMode,
|
|
92
|
+
/**
|
|
93
|
+
* The project's solutions, as `projectSolutions` read them; null (the
|
|
94
|
+
* default) when the project's team doesn't have solutions
|
|
95
|
+
* (SOLACCESS-2.2), so no file is placed as a solution's.
|
|
96
|
+
*/
|
|
97
|
+
solutions?: SolutionForSync[] | null): Promise<SyncOutcome>;
|
|
89
98
|
//# sourceMappingURL=execute.d.ts.map
|
package/dist/sync/execute.js
CHANGED
|
@@ -10,13 +10,15 @@
|
|
|
10
10
|
import * as fs from "node:fs";
|
|
11
11
|
import * as path from "node:path";
|
|
12
12
|
import { ConvexHttpClient } from "convex/browser";
|
|
13
|
-
import {
|
|
13
|
+
import { convexUrl } from "../cloud.js";
|
|
14
14
|
import { api } from "../convex.js";
|
|
15
15
|
import { parseFilesForPushIndividually, WEB_APP_URL } from "../push/core.js";
|
|
16
16
|
import { composeMarkdownWithTitle, splitLeadingH1, writeRequirementsFile, } from "../schema/index.js";
|
|
17
|
+
import { commandErrorMessage } from "../utils/command-error.js";
|
|
17
18
|
import { cloudAttachmentRemovals, resolveAttachments } from "./attachments.js";
|
|
18
|
-
import { resolveLocalPath } from "./local-files.js";
|
|
19
|
+
import { resolveLocalPath, sanitizeFileName } from "./local-files.js";
|
|
19
20
|
import { publishToCloud } from "./publish.js";
|
|
21
|
+
import { requirementsDocByName, resolveBelonging, solutionDirOf, solutionDocumentPath, } from "./solution-documents.js";
|
|
20
22
|
function emptyOutcome() {
|
|
21
23
|
return {
|
|
22
24
|
cloudCreated: 0,
|
|
@@ -34,6 +36,7 @@ function emptyOutcome() {
|
|
|
34
36
|
writeBackWarnings: [],
|
|
35
37
|
importWarnings: [],
|
|
36
38
|
publishWarnings: [],
|
|
39
|
+
belongingWarnings: [],
|
|
37
40
|
normalized: [],
|
|
38
41
|
renames: [],
|
|
39
42
|
inferredPrefixes: [],
|
|
@@ -44,9 +47,15 @@ function emptyOutcome() {
|
|
|
44
47
|
* writes require a project slug in `auth`; a read-only share run has none and
|
|
45
48
|
* its plan carries no cloud-writing actions.
|
|
46
49
|
*/
|
|
47
|
-
export async function executePlan(plan, cloud, auth, workspaceRoot, mode
|
|
50
|
+
export async function executePlan(plan, cloud, auth, workspaceRoot, mode,
|
|
51
|
+
/**
|
|
52
|
+
* The project's solutions, as `projectSolutions` read them; null (the
|
|
53
|
+
* default) when the project's team doesn't have solutions
|
|
54
|
+
* (SOLACCESS-2.2), so no file is placed as a solution's.
|
|
55
|
+
*/
|
|
56
|
+
solutions = null) {
|
|
48
57
|
const outcome = emptyOutcome();
|
|
49
|
-
const client = new ConvexHttpClient(
|
|
58
|
+
const client = new ConvexHttpClient(convexUrl());
|
|
50
59
|
const cloudById = new Map(cloud.documents.map((d) => [d.documentId, d]));
|
|
51
60
|
const requirementsDir = path.join(workspaceRoot, ".requirements");
|
|
52
61
|
const usedPaths = new Set();
|
|
@@ -63,7 +72,7 @@ export async function executePlan(plan, cloud, auth, workspaceRoot, mode) {
|
|
|
63
72
|
outcome.invalid.push(doc);
|
|
64
73
|
break;
|
|
65
74
|
case "cloud_write":
|
|
66
|
-
await cloudWrite(auth, doc, cloudById, outcome, mode);
|
|
75
|
+
await cloudWrite(auth, doc, cloudById, outcome, mode, solutions);
|
|
67
76
|
break;
|
|
68
77
|
case "cloud_delete":
|
|
69
78
|
await cloudDelete(client, auth, doc, outcome);
|
|
@@ -83,14 +92,14 @@ export async function executePlan(plan, cloud, auth, workspaceRoot, mode) {
|
|
|
83
92
|
await syncResidualAttachments(client, auth, doc, action, outcome, mode);
|
|
84
93
|
}
|
|
85
94
|
catch (err) {
|
|
86
|
-
outcome.errors.push({ name, error:
|
|
95
|
+
outcome.errors.push({ name, error: commandErrorMessage(err) });
|
|
87
96
|
}
|
|
88
97
|
}
|
|
89
98
|
return outcome;
|
|
90
99
|
}
|
|
91
100
|
/**
|
|
92
101
|
* Attachment-only operations for whatever the body action didn't cover.
|
|
93
|
-
* The push goes through
|
|
102
|
+
* The push goes through syncAttachments — a metadata patch, never the
|
|
94
103
|
* publish path, so naming a link cannot displace anyone's working document.
|
|
95
104
|
*/
|
|
96
105
|
async function syncResidualAttachments(client, auth, doc, action, outcome, mode) {
|
|
@@ -110,12 +119,11 @@ async function syncResidualAttachments(client, auth, doc, action, outcome, mode)
|
|
|
110
119
|
if (!auth.projectSlug) {
|
|
111
120
|
throw new Error("Cannot sync attachments without project credentials.");
|
|
112
121
|
}
|
|
113
|
-
await client.mutation(api.documents.mutations.
|
|
122
|
+
await client.mutation(api.documents.mutations.syncAttachments, {
|
|
114
123
|
projectAuth: {
|
|
115
124
|
projectSlug: auth.projectSlug,
|
|
116
125
|
projectSecret: auth.projectSecret,
|
|
117
126
|
},
|
|
118
|
-
target: { type: "project", slug: auth.projectSlug },
|
|
119
127
|
documentId: doc.documentId,
|
|
120
128
|
attachments: res.cloudFinal,
|
|
121
129
|
// Compare-and-set: the resolution was computed from the snapshot's
|
|
@@ -161,18 +169,7 @@ async function syncResidualAttachments(client, auth, doc, action, outcome, mode)
|
|
|
161
169
|
outcome.attachmentWrites++;
|
|
162
170
|
}
|
|
163
171
|
}
|
|
164
|
-
|
|
165
|
-
* Servers throw ConvexError({kind, message}) for expected failures; production
|
|
166
|
-
* redacts the Error message to "Server Error" but preserves error.data.
|
|
167
|
-
* Surface the human-readable message rather than the blob.
|
|
168
|
-
*/
|
|
169
|
-
function errorDisplayMessage(err) {
|
|
170
|
-
const data = err.data;
|
|
171
|
-
if (data && typeof data.message === "string")
|
|
172
|
-
return data.message;
|
|
173
|
-
return err instanceof Error ? err.message : String(err);
|
|
174
|
-
}
|
|
175
|
-
async function cloudWrite(auth, doc, cloudById, outcome, mode) {
|
|
172
|
+
async function cloudWrite(auth, doc, cloudById, outcome, mode, solutions) {
|
|
176
173
|
if (!auth.projectSlug || !doc.filePath) {
|
|
177
174
|
throw new Error("Cannot write to the cloud without project credentials.");
|
|
178
175
|
}
|
|
@@ -181,6 +178,24 @@ async function cloudWrite(auth, doc, cloudById, outcome, mode) {
|
|
|
181
178
|
if (!parsed)
|
|
182
179
|
throw new Error(`Could not parse ${path.basename(doc.filePath)}`);
|
|
183
180
|
const meta = parsed.metadata.document;
|
|
181
|
+
// SOLDOC-3/4/5: what the file's name and place say about it. A file in a
|
|
182
|
+
// solution directory with no frontmatter declares its belonging by its
|
|
183
|
+
// path; one with frontmatter keeps that, and a disagreeing path is reported.
|
|
184
|
+
// SOLACCESS-2.2: without solutions, a file is placed as it was before them.
|
|
185
|
+
const withSolutions = solutions !== null;
|
|
186
|
+
const resolved = withSolutions
|
|
187
|
+
? resolveBelonging(doc.filePath, { solution: meta?.solution, outcome: meta?.outcome }, solutionDirOf(doc.filePath), solutions)
|
|
188
|
+
: { belonging: undefined, warning: undefined };
|
|
189
|
+
if (resolved.warning) {
|
|
190
|
+
outcome.belongingWarnings = [
|
|
191
|
+
...(outcome.belongingWarnings ?? []),
|
|
192
|
+
resolved.warning,
|
|
193
|
+
];
|
|
194
|
+
}
|
|
195
|
+
const belonging = resolved.belonging;
|
|
196
|
+
const isRequirementsDoc = withSolutions
|
|
197
|
+
? requirementsDocByName(doc.filePath)
|
|
198
|
+
: undefined;
|
|
184
199
|
// SYNC-TITLE-1.1: a legacy file whose title lives only in frontmatter (no body
|
|
185
200
|
// H1) must reach the cloud self-describing. Materialize the title as the body's
|
|
186
201
|
// leading H1 BEFORE the push — so the cloud row carries the H1 on first write
|
|
@@ -225,6 +240,8 @@ async function cloudWrite(auth, doc, cloudById, outcome, mode) {
|
|
|
225
240
|
: []
|
|
226
241
|
: undefined,
|
|
227
242
|
runMarker: parsed.metadata.ctsRun,
|
|
243
|
+
solution: belonging,
|
|
244
|
+
isRequirementsDoc,
|
|
228
245
|
});
|
|
229
246
|
const documentId = saveResult.documentId;
|
|
230
247
|
// ATTACH-10.3.1.0: the publish above is the push that removes cloud
|
|
@@ -330,6 +347,9 @@ async function cloudWrite(auth, doc, cloudById, outcome, mode) {
|
|
|
330
347
|
// the title.
|
|
331
348
|
writeRequirementsFile(doc.filePath, {
|
|
332
349
|
documentId,
|
|
350
|
+
// SOLDOC-4.1: the belonging the path declared is written into the
|
|
351
|
+
// frontmatter, where it is the truth from now on.
|
|
352
|
+
belonging,
|
|
333
353
|
// The prefix just pushed is the file's own (or the one inferred from
|
|
334
354
|
// its first key, DOC-HEADER-11.4, which the write-back materializes).
|
|
335
355
|
defaultPrefix: meta?.defaultPrefix
|
|
@@ -361,12 +381,11 @@ async function cloudDelete(client, auth, doc, outcome) {
|
|
|
361
381
|
if (!auth.projectSlug || !doc.documentId) {
|
|
362
382
|
throw new Error("Cannot delete from the cloud without project credentials.");
|
|
363
383
|
}
|
|
364
|
-
await client.mutation(api.documents.mutations.
|
|
384
|
+
await client.mutation(api.documents.mutations.deleteForSync, {
|
|
365
385
|
projectAuth: {
|
|
366
386
|
projectSlug: auth.projectSlug,
|
|
367
387
|
projectSecret: auth.projectSecret,
|
|
368
388
|
},
|
|
369
|
-
target: { type: "project", slug: auth.projectSlug },
|
|
370
389
|
documentId: doc.documentId,
|
|
371
390
|
});
|
|
372
391
|
outcome.cloudDeleted++;
|
|
@@ -377,8 +396,9 @@ function localWrite(doc, cloudById, usedPaths, requirementsDir, outcome, mode) {
|
|
|
377
396
|
throw new Error(`No cloud content for ${doc.title}`);
|
|
378
397
|
if (!fs.existsSync(requirementsDir))
|
|
379
398
|
fs.mkdirSync(requirementsDir, { recursive: true });
|
|
380
|
-
const filePath =
|
|
399
|
+
const filePath = placeCloudDocument(cloudDoc, doc.filePath, usedPaths, requirementsDir);
|
|
381
400
|
usedPaths.add(filePath);
|
|
401
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
382
402
|
// DOC-HEADER-11.6/11.7: a cloud document with no prefix means "nothing to
|
|
383
403
|
// impose" under an additive sync and "no prefix" under cloud-wins authority
|
|
384
404
|
// — so a prefix Jaime wrote is only ever removed by the mode they ran to
|
|
@@ -402,10 +422,42 @@ function localWrite(doc, cloudById, usedPaths, requirementsDir, outcome, mode) {
|
|
|
402
422
|
defaultPrefix,
|
|
403
423
|
attachments,
|
|
404
424
|
version: cloudDoc.version,
|
|
425
|
+
belonging: cloudDoc.solution
|
|
426
|
+
? {
|
|
427
|
+
solutionId: cloudDoc.solution.solutionId,
|
|
428
|
+
outcome: cloudDoc.solution.outcome,
|
|
429
|
+
}
|
|
430
|
+
: undefined,
|
|
405
431
|
}, cloudDoc.body);
|
|
406
432
|
if (changed)
|
|
407
433
|
outcome.localWritten++;
|
|
408
434
|
}
|
|
435
|
+
/**
|
|
436
|
+
* SOLDOC-6: where a pulled document lands. A file it is already linked to
|
|
437
|
+
* keeps its path (SYNC-DISCOVERY-2.0); a document that belongs to a solution
|
|
438
|
+
* lands in that solution's directory, named for its outcome; a document
|
|
439
|
+
* that is not a requirements document and belongs to no solution has no
|
|
440
|
+
* place, and the pull says so rather than guessing.
|
|
441
|
+
*/
|
|
442
|
+
function placeCloudDocument(cloudDoc, existingPath, usedPaths, requirementsDir) {
|
|
443
|
+
if (existingPath)
|
|
444
|
+
return existingPath;
|
|
445
|
+
const isRequirementsDoc = cloudDoc.isRequirementsDoc !== false;
|
|
446
|
+
if (cloudDoc.solution) {
|
|
447
|
+
// SOLDOC-9: the solution's own directory name; a backend from before it
|
|
448
|
+
// was sent leaves it out, and the title's slug stands in.
|
|
449
|
+
const candidate = solutionDocumentPath(requirementsDir, cloudDoc.solution.directory ??
|
|
450
|
+
sanitizeFileName(cloudDoc.solution.title ?? cloudDoc.solution.solutionId), cloudDoc.solution.outcome, isRequirementsDoc);
|
|
451
|
+
if (usedPaths.has(candidate) || fs.existsSync(candidate)) {
|
|
452
|
+
throw new Error(`"${cloudDoc.title}" belongs at ${path.relative(path.dirname(requirementsDir), candidate)}, but another file is already there.`);
|
|
453
|
+
}
|
|
454
|
+
return candidate;
|
|
455
|
+
}
|
|
456
|
+
if (!isRequirementsDoc) {
|
|
457
|
+
throw new Error(`"${cloudDoc.title}" is not a requirements document and belongs to no solution, so the pull has nowhere to put it.`);
|
|
458
|
+
}
|
|
459
|
+
return resolveLocalPath(cloudDoc, existingPath, usedPaths, requirementsDir);
|
|
460
|
+
}
|
|
409
461
|
function localDelete(doc, outcome) {
|
|
410
462
|
if (!doc.filePath)
|
|
411
463
|
return;
|
package/dist/sync/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type { ComparisonResult, DocumentComparison } from "./types.js";
|
|
|
6
6
|
export { compareSnapshots, duplicateIdAbortMessage, duplicateLocalDocumentIds, } from "./compare.js";
|
|
7
7
|
export { displayName, formatUnitDetail, formatVerdictLine, resolutionHint, scopeToken, } from "./render.js";
|
|
8
8
|
export { segmentBody } from "./segment.js";
|
|
9
|
-
export { acquireCloudSnapshot, acquireLocalSnapshot, type CloudAuth, readLocalDocument, } from "./snapshot.js";
|
|
9
|
+
export { acquireCloudSnapshot, acquireLocalSnapshot, type CloudAuth, foreignDocumentNotes, projectSolutions, readLocalDocument, } from "./snapshot.js";
|
|
10
10
|
export type { CloudDocument, CloudSnapshot, ComparisonResult, DocumentComparison, LocalDocument, LocalSnapshot, UnitDetail, Verdict, } from "./types.js";
|
|
11
11
|
export { verdictLabel } from "./types.js";
|
|
12
12
|
/**
|
package/dist/sync/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import * as path from "node:path";
|
|
|
6
6
|
export { compareSnapshots, duplicateIdAbortMessage, duplicateLocalDocumentIds, } from "./compare.js";
|
|
7
7
|
export { displayName, formatUnitDetail, formatVerdictLine, resolutionHint, scopeToken, } from "./render.js";
|
|
8
8
|
export { segmentBody } from "./segment.js";
|
|
9
|
-
export { acquireCloudSnapshot, acquireLocalSnapshot, readLocalDocument, } from "./snapshot.js";
|
|
9
|
+
export { acquireCloudSnapshot, acquireLocalSnapshot, foreignDocumentNotes, projectSolutions, readLocalDocument, } from "./snapshot.js";
|
|
10
10
|
export { verdictLabel } from "./types.js";
|
|
11
11
|
/**
|
|
12
12
|
* Does a document match one scope token? A token may name a local file (path or
|
package/dist/sync/publish.d.ts
CHANGED
|
@@ -32,6 +32,13 @@ export interface PublishParams {
|
|
|
32
32
|
title?: string;
|
|
33
33
|
}>;
|
|
34
34
|
runMarker?: string;
|
|
35
|
+
/** SOLDOC-4/5: the belonging the file declares. */
|
|
36
|
+
solution?: {
|
|
37
|
+
solutionId: string;
|
|
38
|
+
outcome: string;
|
|
39
|
+
};
|
|
40
|
+
/** SOLDOC-3: what the file's name says; undefined where the rule doesn't reach. */
|
|
41
|
+
isRequirementsDoc?: boolean;
|
|
35
42
|
}
|
|
36
43
|
/**
|
|
37
44
|
* What the server reports back: the document, any run-marker complaint, and any
|
package/dist/sync/publish.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* repo unable to push. Recoverable rather than lossy — see
|
|
12
12
|
* docs/working/publishing-and-unpublished-changes.md.
|
|
13
13
|
*/
|
|
14
|
-
import {
|
|
14
|
+
import { webApiUrl } from "../cloud.js";
|
|
15
15
|
/**
|
|
16
16
|
* POST to `/api/publish`. Returns the saved document; throws with the server's
|
|
17
17
|
* own message on failure, which is what Jaime reads in the sync output.
|
|
@@ -21,7 +21,7 @@ import { DEFAULT_API_BASE_URL } from "../requirements/cloud-ai.js";
|
|
|
21
21
|
* apply next time.
|
|
22
22
|
*/
|
|
23
23
|
export async function publishToCloud(params) {
|
|
24
|
-
const apiBaseUrl =
|
|
24
|
+
const apiBaseUrl = webApiUrl();
|
|
25
25
|
const response = await fetch(`${apiBaseUrl}/api/publish`, {
|
|
26
26
|
method: "POST",
|
|
27
27
|
headers: { "Content-Type": "application/json" },
|
package/dist/sync/segment.js
CHANGED
|
@@ -6,7 +6,10 @@
|
|
|
6
6
|
* normalized text (prose has no stable id, so a reworded passage reads as a
|
|
7
7
|
* removal-plus-addition — a conflict, per DIFF-4.3).
|
|
8
8
|
*/
|
|
9
|
-
|
|
9
|
+
// From the fs-free modules, not the schema index, so the backend can bundle
|
|
10
|
+
// the comparator for merging a solution's branch (BRANCH-7).
|
|
11
|
+
import { getAllRequirements, parseRequirementBlock, splitRequirementFenceContent, } from "../schema/parser-core.js";
|
|
12
|
+
import { canonicalRequirementKey, canonicalRequirementPath, } from "../schema/schemas.js";
|
|
10
13
|
/** Matches a fenced dotrequirements block; group 1 is its inner content. */
|
|
11
14
|
const FENCE = /```dotrequirements\n([\s\S]*?)```/gm;
|
|
12
15
|
/**
|
package/dist/sync/snapshot.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Snapshot acquisition for the comparator — kept separate from comparison so
|
|
3
3
|
* the comparator stays a pure function (compare.ts). The local half reads the
|
|
4
|
-
* workspace; the cloud half is one
|
|
4
|
+
* workspace; the cloud half is one export query.
|
|
5
5
|
*/
|
|
6
|
+
import type { SolutionForSync } from "./solution-documents.js";
|
|
6
7
|
import type { CloudSnapshot, LocalDocument, LocalSnapshot } from "./types.js";
|
|
7
8
|
/**
|
|
8
9
|
* Read and classify one requirements file into a LocalDocument. A file whose
|
|
@@ -15,16 +16,37 @@ export declare function readLocalDocument(filePath: string): LocalDocument;
|
|
|
15
16
|
* Build the local snapshot from the workspace, or from an explicit set of file
|
|
16
17
|
* paths (scope). Files are always read fresh from disk.
|
|
17
18
|
*/
|
|
18
|
-
export declare function acquireLocalSnapshot(workspaceRoot: string, filePaths?: string[]
|
|
19
|
+
export declare function acquireLocalSnapshot(workspaceRoot: string, filePaths?: string[], options?: {
|
|
20
|
+
solutions?: boolean;
|
|
21
|
+
}): Promise<LocalSnapshot>;
|
|
22
|
+
/**
|
|
23
|
+
* The project's solutions as the sync places files by them (SOLDOC-4), or
|
|
24
|
+
* null when the project's team doesn't have solutions, so the sync behaves
|
|
25
|
+
* as it did before solutions (SOLACCESS-2.2). Whether it has them is the
|
|
26
|
+
* export's answer — the one the cloud side was read with — so the local
|
|
27
|
+
* side can't follow a different one. A share run places nothing, so it
|
|
28
|
+
* needs no list. A failure to fetch the list fails the sync, as does a
|
|
29
|
+
* switch flipped between the two reads: guessing would leave solution
|
|
30
|
+
* documents out of the repo's side, and a repo-wins sync would delete them
|
|
31
|
+
* from the cloud.
|
|
32
|
+
*/
|
|
33
|
+
export declare function projectSolutions(auth: CloudAuth, cloud: CloudSnapshot): Promise<SolutionForSync[] | null>;
|
|
19
34
|
export interface CloudAuth {
|
|
20
35
|
/** projectSlug + projectSecret for full access, or a bare share token. */
|
|
21
36
|
projectSlug?: string;
|
|
22
37
|
projectSecret: string;
|
|
23
38
|
}
|
|
24
39
|
/**
|
|
25
|
-
* Build the cloud snapshot with one
|
|
26
|
-
*
|
|
27
|
-
*
|
|
40
|
+
* Build the cloud snapshot with one export query: the project's own, with a
|
|
41
|
+
* project secret, or the share endpoint, with a bare share token (the token
|
|
42
|
+
* names the project) — the read-only path never writes back.
|
|
28
43
|
*/
|
|
29
44
|
export declare function acquireCloudSnapshot(auth: CloudAuth): Promise<CloudSnapshot>;
|
|
45
|
+
/**
|
|
46
|
+
* SYNC-FAIL-5: of the ids the workspace's files carry, the ones that name
|
|
47
|
+
* another project's document, each with the words a push of that file gets,
|
|
48
|
+
* so `dotreq diff` says what `dotreq sync` will. A backend that can't answer
|
|
49
|
+
* leaves the diff as it was rather than failing it.
|
|
50
|
+
*/
|
|
51
|
+
export declare function foreignDocumentNotes(auth: CloudAuth, documentIds: string[]): Promise<Map<string, string>>;
|
|
30
52
|
//# sourceMappingURL=snapshot.d.ts.map
|