@popoverai/dotrequirements 0.27.3 → 0.28.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 +24 -20
- package/dist/cli.js +34 -12
- package/dist/commands/aliases.d.ts +26 -0
- package/dist/commands/aliases.js +31 -0
- package/dist/commands/diff.d.ts +14 -0
- package/dist/commands/diff.js +62 -0
- package/dist/commands/init.js +5 -5
- package/dist/commands/link.d.ts +1 -1
- package/dist/commands/link.js +13 -7
- package/dist/commands/sync-common.d.ts +21 -0
- package/dist/commands/sync-common.js +24 -0
- package/dist/commands/sync.d.ts +26 -0
- package/dist/commands/sync.js +182 -0
- package/dist/convex.d.ts +1 -1
- package/dist/convex.js +2 -2
- package/dist/push/core.d.ts +18 -116
- package/dist/push/core.js +16 -267
- package/dist/push/index.d.ts +3 -3
- package/dist/push/index.js +4 -4
- package/dist/requirements/style-guide.js +3 -3
- package/dist/schema/schemas.js +1 -1
- package/dist/sync/compare.d.ts +21 -0
- package/dist/sync/compare.js +285 -0
- package/dist/sync/execute.d.ts +48 -0
- package/dist/sync/execute.js +186 -0
- package/dist/sync/index.d.ts +21 -0
- package/dist/sync/index.js +52 -0
- package/dist/sync/local-files.d.ts +26 -0
- package/dist/sync/local-files.js +91 -0
- package/dist/sync/plan.d.ts +39 -0
- package/dist/sync/plan.js +90 -0
- package/dist/sync/render.d.ts +17 -0
- package/dist/sync/render.js +46 -0
- package/dist/sync/segment.d.ts +40 -0
- package/dist/sync/segment.js +76 -0
- package/dist/sync/snapshot.d.ts +30 -0
- package/dist/sync/snapshot.js +118 -0
- package/dist/sync/types.d.ts +82 -0
- package/dist/sync/types.js +12 -0
- package/dist/templates/context-file-section.md +2 -1
- package/dist/templates/requirements-readme.js +3 -4
- package/dist/templates/requirements-readme.ts +3 -4
- package/dist/templates/skills/codebase-to-spec/SKILL.md +2 -2
- package/dist/utils/oauth-flow.d.ts +2 -0
- package/dist/utils/oauth-flow.js +8 -1
- package/dist/utils/project-settings.d.ts +8 -2
- package/dist/utils/project-settings.js +47 -24
- package/package.json +1 -1
- package/dist/commands/pull.d.ts +0 -8
- package/dist/commands/pull.js +0 -230
- package/dist/commands/push.d.ts +0 -6
- package/dist/commands/push.js +0 -244
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `dotreq sync` — reconcile the repo and the cloud under a direction/authority
|
|
3
|
+
* mode (SYNC-MODE-*). The daily gesture is the unmarked form; flags narrow
|
|
4
|
+
* direction (`--cloud-contributes` / `--repo-contributes`) or assign authority
|
|
5
|
+
* (`--repo-wins` / `--cloud-wins`).
|
|
6
|
+
*/
|
|
7
|
+
import * as path from "node:path";
|
|
8
|
+
import * as readline from "node:readline";
|
|
9
|
+
import { executePlan } from "../sync/execute.js";
|
|
10
|
+
import { acquireCloudSnapshot, acquireLocalSnapshot, compareSnapshots, duplicateLocalDocumentIds, filterByScope, resolutionHint, } from "../sync/index.js";
|
|
11
|
+
import { buildPlan, resolveMode, } from "../sync/plan.js";
|
|
12
|
+
import { brand } from "../utils/brand.js";
|
|
13
|
+
import { resolveCloudAuth } from "./sync-common.js";
|
|
14
|
+
/**
|
|
15
|
+
* The CLI entry point: exits non-zero on unresolved trouble (SYNC-MODE-1.5,
|
|
16
|
+
* SYNC-FAIL-1/4). `init`/`link` call `syncCommand` directly instead — their
|
|
17
|
+
* success is linking/onboarding, and a conflict in one spec file must not fail
|
|
18
|
+
* the whole command (the report lines still print).
|
|
19
|
+
*/
|
|
20
|
+
export async function syncCliAction(scope, options) {
|
|
21
|
+
const result = await syncCommand(scope, options);
|
|
22
|
+
if (result === "trouble") {
|
|
23
|
+
process.exitCode = 1;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export async function syncCommand(scope, options) {
|
|
27
|
+
const workspaceRoot = process.cwd();
|
|
28
|
+
// SHARE-TOKEN-CLI-1.3: a read-only token can only bring requirements down.
|
|
29
|
+
let mode;
|
|
30
|
+
if (options.share) {
|
|
31
|
+
mode = "cloud_contributes";
|
|
32
|
+
if (options.repoWins || options.cloudWins || options.repoContributes) {
|
|
33
|
+
console.log("A share token is read-only — syncing the cloud's requirements down only; other mode flags are ignored.");
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
mode = resolveMode(options);
|
|
38
|
+
}
|
|
39
|
+
const auth = resolveCloudAuth(options);
|
|
40
|
+
const [local, cloud] = await Promise.all([
|
|
41
|
+
acquireLocalSnapshot(workspaceRoot),
|
|
42
|
+
acquireCloudSnapshot(auth),
|
|
43
|
+
]);
|
|
44
|
+
// SYNC-MODE-4.4 (and 4.4.0 for --yes): an empty repo is indistinguishable from a wrong working
|
|
45
|
+
// directory or a failed checkout — never treat it as intent to delete every
|
|
46
|
+
// cloud document. --yes does not override: it consents to listed deletions,
|
|
47
|
+
// not to this. (Cloud deletion has no recovery path; the mirror-image case
|
|
48
|
+
// — cloud-wins deleting local files — is recoverable via git.)
|
|
49
|
+
if (mode === "repo_wins" &&
|
|
50
|
+
local.documents.length === 0 &&
|
|
51
|
+
cloud.documents.length > 0) {
|
|
52
|
+
throw new Error(`Refusing to sync --repo-wins: no requirement documents found under ${workspaceRoot}, ` +
|
|
53
|
+
`but the cloud project has ${cloud.documents.length}. An empty repo usually means a wrong ` +
|
|
54
|
+
`working directory or a failed checkout, and proceeding would permanently delete every ` +
|
|
55
|
+
`cloud document. If the repo's requirements really are gone on purpose, delete the cloud ` +
|
|
56
|
+
`documents from the web app instead.`);
|
|
57
|
+
}
|
|
58
|
+
// SHARE-TOKEN-CLI-1.2: show whose project this is.
|
|
59
|
+
if (options.share) {
|
|
60
|
+
console.log(`Project: "${cloud.projectName}"`);
|
|
61
|
+
}
|
|
62
|
+
// SYNC-FAIL-3: two files claiming one document id would both write it — abort
|
|
63
|
+
// before any write, naming both files and the shared id.
|
|
64
|
+
const dupes = duplicateLocalDocumentIds(local);
|
|
65
|
+
if (dupes.length > 0) {
|
|
66
|
+
const d = dupes[0];
|
|
67
|
+
throw new Error(`Two files claim the same document ID "${d.documentId}":\n` +
|
|
68
|
+
d.filePaths.map((p) => ` ${p}`).join("\n") +
|
|
69
|
+
`\nEach file must map to its own cloud document. Remove the "id:" line from the copy's frontmatter, then sync again.`);
|
|
70
|
+
}
|
|
71
|
+
const comparison = compareSnapshots(local, cloud);
|
|
72
|
+
const { documents, unmatched } = filterByScope(comparison, scope, workspaceRoot);
|
|
73
|
+
for (const token of unmatched) {
|
|
74
|
+
console.log(`No document matched scope "${token}".`);
|
|
75
|
+
}
|
|
76
|
+
const plan = buildPlan(documents, mode);
|
|
77
|
+
// SYNC-MODE-4: name every deletion before writing anything.
|
|
78
|
+
const deletions = plan.filter((p) => p.action === "cloud_delete" || p.action === "local_delete");
|
|
79
|
+
if (deletions.length > 0) {
|
|
80
|
+
// SYNC-MODE-4.3: a non-interactive run cannot consent — refuse rather than
|
|
81
|
+
// hanging on a prompt that will never answer (or worse, deleting silently).
|
|
82
|
+
if (!options.yes && !process.stdin.isTTY) {
|
|
83
|
+
throw new Error(`This sync would delete ${deletions.length} document(s), and there is no terminal to confirm on. ` +
|
|
84
|
+
`Re-run with --yes to consent to the deletions listed by \`dotreq diff\`.`);
|
|
85
|
+
}
|
|
86
|
+
if (!(await confirmDeletions(deletions, options.yes))) {
|
|
87
|
+
console.log("Sync cancelled.");
|
|
88
|
+
return "cancelled";
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (plan.every((p) => p.action === "skip")) {
|
|
92
|
+
console.log(`✓ Repo and ${brand} cloud are already in sync.`);
|
|
93
|
+
return "clean";
|
|
94
|
+
}
|
|
95
|
+
console.log(`\nSyncing with ${brand} cloud...`);
|
|
96
|
+
const outcome = await executePlan(plan, cloud, auth, workspaceRoot);
|
|
97
|
+
// Report.
|
|
98
|
+
if (outcome.cloudCreated)
|
|
99
|
+
console.log(` Created in cloud: ${outcome.cloudCreated}`);
|
|
100
|
+
if (outcome.cloudUpdated)
|
|
101
|
+
console.log(` Updated in cloud: ${outcome.cloudUpdated}`);
|
|
102
|
+
if (outcome.cloudDeleted)
|
|
103
|
+
console.log(` Deleted from cloud: ${outcome.cloudDeleted}`);
|
|
104
|
+
if (outcome.localWritten)
|
|
105
|
+
console.log(` Written locally: ${outcome.localWritten}`);
|
|
106
|
+
if (outcome.localDeleted)
|
|
107
|
+
console.log(` Deleted locally: ${outcome.localDeleted}`);
|
|
108
|
+
for (const conflict of outcome.conflicts) {
|
|
109
|
+
console.log(` ! conflict: ${path.basename(conflict.filePath ?? conflict.title)} — ${resolutionHint(conflict)}`);
|
|
110
|
+
}
|
|
111
|
+
for (const invalid of outcome.invalid) {
|
|
112
|
+
console.log(` ✗ invalid file: ${path.basename(invalid.filePath ?? invalid.title)}${invalid.error ? ` — ${invalid.error}` : ""}`);
|
|
113
|
+
}
|
|
114
|
+
for (const err of outcome.errors) {
|
|
115
|
+
console.log(` ✗ failed: ${err.name} — ${err.error}`);
|
|
116
|
+
}
|
|
117
|
+
// IMPORT-3: marker failures are loud but never fatal.
|
|
118
|
+
for (const { name, status } of outcome.importWarnings) {
|
|
119
|
+
if (status === "already_used") {
|
|
120
|
+
console.log(` ⚠ ${name}: this file's import marker was already used, so its requirements were saved as natively authored (they count toward your plan's requirement limit). Re-running codebase-to-spec produces a fresh marker.`);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
console.log(` ⚠ ${name}: this file's import marker was not recognized — your CLI may need updating. Its requirements were saved as natively authored (they count toward your plan's requirement limit).`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// SYNC-FAIL-2.1: saved to cloud, but the local file couldn't be updated —
|
|
127
|
+
// give the re-link recovery step so a retry doesn't mint a duplicate.
|
|
128
|
+
for (const w of outcome.writeBackWarnings) {
|
|
129
|
+
console.log(` ⚠ ${w.name}: saved to the cloud, but the local file could not be updated (${w.error}). ` +
|
|
130
|
+
`To avoid creating a duplicate, add "id: ${w.documentId}" under "document:" in ${w.filePath}, then sync again.`);
|
|
131
|
+
}
|
|
132
|
+
// SYNC-LAND-1: land the user on their synced documents.
|
|
133
|
+
if (outcome.synced.length > 0) {
|
|
134
|
+
console.log(`\nReview in ${brand}:`);
|
|
135
|
+
for (const s of outcome.synced)
|
|
136
|
+
console.log(` ${s.name} → ${s.url}`);
|
|
137
|
+
}
|
|
138
|
+
const hadTrouble = outcome.conflicts.length > 0 ||
|
|
139
|
+
outcome.invalid.length > 0 ||
|
|
140
|
+
outcome.errors.length > 0;
|
|
141
|
+
if (hadTrouble) {
|
|
142
|
+
console.log("\n⚠ Sync completed with unresolved items (see above).");
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
console.log("\n✓ Sync complete.");
|
|
146
|
+
}
|
|
147
|
+
// SHARE-TOKEN-CLI-3: point the onboarding user at full access.
|
|
148
|
+
if (options.share) {
|
|
149
|
+
console.log("\n─────────────────────────────────────────────────────────");
|
|
150
|
+
console.log("Next steps to get full access (sync to cloud, coverage):");
|
|
151
|
+
console.log(" Run: dotrequirements link");
|
|
152
|
+
console.log("─────────────────────────────────────────────────────────");
|
|
153
|
+
}
|
|
154
|
+
return hadTrouble ? "trouble" : "clean";
|
|
155
|
+
}
|
|
156
|
+
async function confirmDeletions(deletions, skip) {
|
|
157
|
+
const cloudDeletes = deletions.filter((d) => d.action === "cloud_delete");
|
|
158
|
+
const localDeletes = deletions.filter((d) => d.action === "local_delete");
|
|
159
|
+
console.log("\nThis will PERMANENTLY delete:");
|
|
160
|
+
for (const d of cloudDeletes) {
|
|
161
|
+
console.log(` from cloud: ${d.doc.title}`);
|
|
162
|
+
}
|
|
163
|
+
for (const d of localDeletes) {
|
|
164
|
+
console.log(` from disk: ${d.doc.filePath ? path.basename(d.doc.filePath) : d.doc.title}`);
|
|
165
|
+
}
|
|
166
|
+
if (skip) {
|
|
167
|
+
console.log("(--yes: proceeding without confirmation)");
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
const rl = readline.createInterface({
|
|
171
|
+
input: process.stdin,
|
|
172
|
+
output: process.stdout,
|
|
173
|
+
});
|
|
174
|
+
return new Promise((resolve) => {
|
|
175
|
+
rl.question("\nContinue? [y/N] ", (answer) => {
|
|
176
|
+
rl.close();
|
|
177
|
+
const a = answer.trim().toLowerCase();
|
|
178
|
+
resolve(a === "y" || a === "yes");
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=sync.js.map
|
package/dist/convex.d.ts
CHANGED
|
@@ -20,11 +20,11 @@ export declare const api: {
|
|
|
20
20
|
exportForCli: import("convex/server").FunctionReference<"query", "public", any, any, string | undefined>;
|
|
21
21
|
exportProjectForCli: import("convex/server").FunctionReference<"query", "public", any, any, string | undefined>;
|
|
22
22
|
checkDocumentsExist: import("convex/server").FunctionReference<"query", "public", any, any, string | undefined>;
|
|
23
|
-
getDocumentsMetadata: import("convex/server").FunctionReference<"query", "public", any, any, string | undefined>;
|
|
24
23
|
};
|
|
25
24
|
mutations: {
|
|
26
25
|
create: import("convex/server").FunctionReference<"mutation", "public", any, any, string | undefined>;
|
|
27
26
|
update: import("convex/server").FunctionReference<"mutation", "public", any, any, string | undefined>;
|
|
27
|
+
deleteForCli: import("convex/server").FunctionReference<"mutation", "public", any, any, string | undefined>;
|
|
28
28
|
};
|
|
29
29
|
saveWithRequirements: {
|
|
30
30
|
saveWithRequirements: import("convex/server").FunctionReference<"mutation", "public", any, any, string | undefined>;
|
package/dist/convex.js
CHANGED
|
@@ -24,12 +24,12 @@ export const api = {
|
|
|
24
24
|
exportForCli: query("documents/queries:exportForCli"),
|
|
25
25
|
exportProjectForCli: query("documents/queries:exportProjectForCli"),
|
|
26
26
|
checkDocumentsExist: query("documents/queries:checkDocumentsExist"),
|
|
27
|
-
// SYNC-CLI-EDIT-2: Get document metadata for conflict detection
|
|
28
|
-
getDocumentsMetadata: query("documents/queries:getDocumentsMetadata"),
|
|
29
27
|
},
|
|
30
28
|
mutations: {
|
|
31
29
|
create: mutation("documents/mutations:create"),
|
|
32
30
|
update: mutation("documents/mutations:update"),
|
|
31
|
+
// SYNC-MODE-3: delete a cloud document from the CLI (repo-wins)
|
|
32
|
+
deleteForCli: mutation("documents/mutations:deleteForCli"),
|
|
33
33
|
},
|
|
34
34
|
// SYNC-ARCH-1: Save document with requirements derivation
|
|
35
35
|
saveWithRequirements: {
|
package/dist/push/core.d.ts
CHANGED
|
@@ -1,22 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* - Parsing local files
|
|
7
|
-
* - Dry run validation with Convex
|
|
8
|
-
* - Conflict detection
|
|
9
|
-
* - Executing the push
|
|
10
|
-
* - Updating local files with document IDs and timestamps
|
|
2
|
+
* Shared parse-and-write-back primitives for syncing local requirements files
|
|
3
|
+
* to the cloud. The comparator-driven sync path (`packages/cli/src/sync/`)
|
|
4
|
+
* consumes these; the former dry-run/execute push pipeline was retired with the
|
|
5
|
+
* `push` command (its behavior now lives in the sync executor).
|
|
11
6
|
*/
|
|
12
7
|
import type { Metadata } from "../schema/index.js";
|
|
13
|
-
export interface PushCredentials {
|
|
14
|
-
projectId: string;
|
|
15
|
-
projectSecret: string;
|
|
16
|
-
convexUrl: string;
|
|
17
|
-
}
|
|
18
8
|
/**
|
|
19
|
-
* Parsed file ready
|
|
9
|
+
* Parsed file ready to sync.
|
|
20
10
|
* SYNC-ARCH-1: Documents are the sync unit, not individual requirements.
|
|
21
11
|
*/
|
|
22
12
|
export interface ParsedFile {
|
|
@@ -28,111 +18,31 @@ export interface ParsedFile {
|
|
|
28
18
|
requirementCount: number;
|
|
29
19
|
/**
|
|
30
20
|
* DOC-HEADER-14: the frontmatter exactly as the user wrote it, including
|
|
31
|
-
* keys the schema doesn't recognize — merged back on the post-
|
|
21
|
+
* keys the schema doesn't recognize — merged back on the post-sync rewrite
|
|
32
22
|
* so those keys survive.
|
|
33
23
|
*/
|
|
34
24
|
rawFrontmatter?: Record<string, unknown>;
|
|
35
25
|
/** DOC-HEADER-11.4: true when defaultPrefix was inferred from the first requirement rather than read from frontmatter */
|
|
36
26
|
inferredDefaultPrefix?: boolean;
|
|
37
27
|
}
|
|
38
|
-
/**
|
|
39
|
-
* Cloud document metadata for conflict detection.
|
|
40
|
-
* SYNC-CLI-EDIT-2: Compare pulledAt with cloud updatedAt.
|
|
41
|
-
*/
|
|
42
|
-
export interface CloudDocumentMetadata {
|
|
43
|
-
documentId: string;
|
|
44
|
-
version: number;
|
|
45
|
-
updatedAt: number;
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Dry run result from saveWithRequirements.
|
|
49
|
-
*/
|
|
50
|
-
export interface DryRunResultItem {
|
|
51
|
-
dryRun: true;
|
|
52
|
-
action: "create" | "update" | "not_found" | "invalid";
|
|
53
|
-
documentId?: string;
|
|
54
|
-
title?: string;
|
|
55
|
-
warning?: string;
|
|
56
|
-
error?: string;
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* File with its dry run result.
|
|
60
|
-
*/
|
|
61
|
-
export interface FileWithDryRun {
|
|
62
|
-
file: ParsedFile;
|
|
63
|
-
result: DryRunResultItem;
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Conflict information for a file.
|
|
67
|
-
*/
|
|
68
|
-
export interface ConflictInfo {
|
|
69
|
-
item: FileWithDryRun;
|
|
70
|
-
cloudMeta: CloudDocumentMetadata;
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Result of the dry run phase.
|
|
74
|
-
*/
|
|
75
|
-
export interface DryRunResult {
|
|
76
|
-
updates: FileWithDryRun[];
|
|
77
|
-
creates: FileWithDryRun[];
|
|
78
|
-
notFound: FileWithDryRun[];
|
|
79
|
-
invalid: FileWithDryRun[];
|
|
80
|
-
conflicts: ConflictInfo[];
|
|
81
|
-
totalRequirements: number;
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Outcome of run-marker handling for one pushed file (IMPORT-2/3).
|
|
85
|
-
* Mirrors the server's ImportStatus.
|
|
86
|
-
*/
|
|
87
|
-
export type ImportStatus = "imported" | "invalid_marker" | "unsupported_version" | "already_used" | "ignored_update" | "none";
|
|
88
28
|
/** Base URL of the web app, where synced documents are reviewed. */
|
|
89
29
|
export declare const WEB_APP_URL = "https://app.dotrequirements.io";
|
|
90
|
-
/**
|
|
91
|
-
* Result of the execute phase.
|
|
92
|
-
*/
|
|
93
|
-
export interface PushResult {
|
|
94
|
-
created: number;
|
|
95
|
-
updated: number;
|
|
96
|
-
/** filePath disambiguates when two pushed files share a basename */
|
|
97
|
-
errors: Array<{
|
|
98
|
-
fileName: string;
|
|
99
|
-
filePath: string;
|
|
100
|
-
error: string;
|
|
101
|
-
}>;
|
|
102
|
-
/** IMPORT-3: marker failures that must be surfaced to the user, per file */
|
|
103
|
-
importWarnings: Array<{
|
|
104
|
-
fileName: string;
|
|
105
|
-
status: Extract<ImportStatus, "invalid_marker" | "unsupported_version" | "already_used">;
|
|
106
|
-
}>;
|
|
107
|
-
/** SYNC-LAND-1: each successfully synced document, with its web URL */
|
|
108
|
-
synced: Array<{
|
|
109
|
-
fileName: string;
|
|
110
|
-
documentId: string;
|
|
111
|
-
url: string;
|
|
112
|
-
}>;
|
|
113
|
-
/**
|
|
114
|
-
* SYNC-FAIL-2: cloud save succeeded but the local file write-back failed.
|
|
115
|
-
* These documents are synced (counted in created/updated and listed in
|
|
116
|
-
* `synced`) — the warning carries what the user needs to re-link the file
|
|
117
|
-
* without creating a duplicate.
|
|
118
|
-
*/
|
|
119
|
-
writeBackWarnings: Array<{
|
|
120
|
-
fileName: string;
|
|
121
|
-
filePath: string;
|
|
122
|
-
documentId: string;
|
|
123
|
-
error: string;
|
|
124
|
-
}>;
|
|
125
|
-
}
|
|
126
30
|
/**
|
|
127
31
|
* Extract markdown content from a file, stripping YAML frontmatter.
|
|
128
32
|
*/
|
|
129
33
|
export declare function extractMarkdownContent(rawContent: string): string;
|
|
130
34
|
/**
|
|
131
|
-
*
|
|
35
|
+
* DOC-HEADER-14: merge the validated (and sync-updated) metadata over the raw
|
|
36
|
+
* frontmatter so unrecognized keys survive the rewrite while the fields the
|
|
37
|
+
* sync owns (document ID, pulledAt, defaultPrefix, version) stay updated.
|
|
38
|
+
*/
|
|
39
|
+
export declare function mergeMetadataWithRawFrontmatter(metadata: Metadata, rawFrontmatter: Record<string, unknown> | undefined): Metadata;
|
|
40
|
+
/**
|
|
41
|
+
* Parse files for sync. Returns parsed files with metadata and content.
|
|
132
42
|
*
|
|
133
43
|
* Throws (via `parseRequirementsFromFile`) if any file is syntactically
|
|
134
44
|
* invalid. Callers that need one bad file not to abort the batch should parse
|
|
135
|
-
* files individually and collect failures
|
|
45
|
+
* files individually and collect failures.
|
|
136
46
|
*/
|
|
137
47
|
export declare function parseFilesForPush(filePaths: string[]): {
|
|
138
48
|
parsedFiles: ParsedFile[];
|
|
@@ -145,11 +55,11 @@ export interface ParseFailure {
|
|
|
145
55
|
/**
|
|
146
56
|
* SYNC-FAIL-4.0: parse files one at a time so a single invalid file cannot
|
|
147
57
|
* abort the batch — its failure is collected per file while the valid files
|
|
148
|
-
* still parse.
|
|
149
|
-
* so their isolation semantics cannot drift.
|
|
58
|
+
* still parse.
|
|
150
59
|
*
|
|
151
60
|
* Note: cross-file checks that need the whole batch (e.g. SYNC-FAIL-3
|
|
152
|
-
* duplicate document IDs) are enforced
|
|
61
|
+
* duplicate document IDs) are enforced by the sync path against the local
|
|
62
|
+
* snapshot, not here.
|
|
153
63
|
*/
|
|
154
64
|
export declare function parseFilesForPushIndividually(filePaths: string[]): {
|
|
155
65
|
parsedFiles: ParsedFile[];
|
|
@@ -157,17 +67,9 @@ export declare function parseFilesForPushIndividually(filePaths: string[]): {
|
|
|
157
67
|
parseFailures: ParseFailure[];
|
|
158
68
|
};
|
|
159
69
|
/**
|
|
160
|
-
* SYNC-FAIL-3: two ParsedFiles carrying the same document.id would both
|
|
70
|
+
* SYNC-FAIL-3: two ParsedFiles carrying the same document.id would both sync
|
|
161
71
|
* as updates to one cloud document — last writer wins and the first spec is
|
|
162
72
|
* silently destroyed. Abort instead, naming both files and the shared id.
|
|
163
73
|
*/
|
|
164
74
|
export declare function assertNoDuplicateDocumentIds(parsedFiles: ParsedFile[]): void;
|
|
165
|
-
/**
|
|
166
|
-
* Execute dry run phase: validate all files against Convex and detect conflicts.
|
|
167
|
-
*/
|
|
168
|
-
export declare function dryRunPush(parsedFiles: ParsedFile[], credentials: PushCredentials): Promise<DryRunResult>;
|
|
169
|
-
/**
|
|
170
|
-
* Execute the push: save all pushable files to Convex and update local files.
|
|
171
|
-
*/
|
|
172
|
-
export declare function executePush(dryRunResult: DryRunResult, credentials: PushCredentials): Promise<PushResult>;
|
|
173
75
|
//# sourceMappingURL=core.d.ts.map
|