@prd-improve/cli 1.0.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 +38 -0
- package/dist/anchor-slicer.d.ts +18 -0
- package/dist/anchor-slicer.js +114 -0
- package/dist/anchor-slicer.js.map +1 -0
- package/dist/api/client.d.ts +68 -0
- package/dist/api/client.js +175 -0
- package/dist/api/client.js.map +1 -0
- package/dist/changelog.d.ts +9 -0
- package/dist/changelog.js +34 -0
- package/dist/changelog.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +258 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/admin/_adminJson.d.ts +18 -0
- package/dist/commands/admin/_adminJson.js +27 -0
- package/dist/commands/admin/_adminJson.js.map +1 -0
- package/dist/commands/admin/_authResolve.d.ts +8 -0
- package/dist/commands/admin/_authResolve.js +56 -0
- package/dist/commands/admin/_authResolve.js.map +1 -0
- package/dist/commands/admin/index.d.ts +22 -0
- package/dist/commands/admin/index.js +100 -0
- package/dist/commands/admin/index.js.map +1 -0
- package/dist/commands/admin/io.d.ts +15 -0
- package/dist/commands/admin/io.js +30 -0
- package/dist/commands/admin/io.js.map +1 -0
- package/dist/commands/admin/member.d.ts +43 -0
- package/dist/commands/admin/member.js +362 -0
- package/dist/commands/admin/member.js.map +1 -0
- package/dist/commands/admin/project.d.ts +40 -0
- package/dist/commands/admin/project.js +182 -0
- package/dist/commands/admin/project.js.map +1 -0
- package/dist/commands/admin/team.d.ts +31 -0
- package/dist/commands/admin/team.js +157 -0
- package/dist/commands/admin/team.js.map +1 -0
- package/dist/commands/admin/teamMember.d.ts +33 -0
- package/dist/commands/admin/teamMember.js +262 -0
- package/dist/commands/admin/teamMember.js.map +1 -0
- package/dist/commands/admin/token.d.ts +29 -0
- package/dist/commands/admin/token.js +125 -0
- package/dist/commands/admin/token.js.map +1 -0
- package/dist/commands/admin/user.d.ts +2 -0
- package/dist/commands/admin/user.js +85 -0
- package/dist/commands/admin/user.js.map +1 -0
- package/dist/commands/config.d.ts +9 -0
- package/dist/commands/config.js +178 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/context.d.ts +11 -0
- package/dist/commands/context.js +235 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/diff.d.ts +6 -0
- package/dist/commands/diff.js +208 -0
- package/dist/commands/diff.js.map +1 -0
- package/dist/commands/freeze.d.ts +10 -0
- package/dist/commands/freeze.js +269 -0
- package/dist/commands/freeze.js.map +1 -0
- package/dist/commands/init.d.ts +24 -0
- package/dist/commands/init.js +229 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/login.d.ts +26 -0
- package/dist/commands/login.js +241 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +6 -0
- package/dist/commands/logout.js +75 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/migrate-yaml.d.ts +17 -0
- package/dist/commands/migrate-yaml.js +288 -0
- package/dist/commands/migrate-yaml.js.map +1 -0
- package/dist/commands/project.d.ts +7 -0
- package/dist/commands/project.js +87 -0
- package/dist/commands/project.js.map +1 -0
- package/dist/commands/pull.d.ts +16 -0
- package/dist/commands/pull.js +197 -0
- package/dist/commands/pull.js.map +1 -0
- package/dist/commands/push.d.ts +9 -0
- package/dist/commands/push.js +392 -0
- package/dist/commands/push.js.map +1 -0
- package/dist/commands/refresh.d.ts +9 -0
- package/dist/commands/refresh.js +123 -0
- package/dist/commands/refresh.js.map +1 -0
- package/dist/commands/status.d.ts +7 -0
- package/dist/commands/status.js +190 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/team.d.ts +6 -0
- package/dist/commands/team.js +84 -0
- package/dist/commands/team.js.map +1 -0
- package/dist/commands/validate.d.ts +5 -0
- package/dist/commands/validate.js +129 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/commands/whoami.d.ts +6 -0
- package/dist/commands/whoami.js +81 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/config/adminBackend.d.ts +43 -0
- package/dist/config/adminBackend.js +33 -0
- package/dist/config/adminBackend.js.map +1 -0
- package/dist/config/rc.d.ts +70 -0
- package/dist/config/rc.js +148 -0
- package/dist/config/rc.js.map +1 -0
- package/dist/config/schema.d.ts +132 -0
- package/dist/config/schema.js +36 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/diff/engine.d.ts +35 -0
- package/dist/diff/engine.js +305 -0
- package/dist/diff/engine.js.map +1 -0
- package/dist/diff/render.d.ts +18 -0
- package/dist/diff/render.js +129 -0
- package/dist/diff/render.js.map +1 -0
- package/dist/formatter/colors.d.ts +17 -0
- package/dist/formatter/colors.js +35 -0
- package/dist/formatter/colors.js.map +1 -0
- package/dist/formatter/human.d.ts +7 -0
- package/dist/formatter/human.js +70 -0
- package/dist/formatter/human.js.map +1 -0
- package/dist/fs/atomicWrite.d.ts +7 -0
- package/dist/fs/atomicWrite.js +37 -0
- package/dist/fs/atomicWrite.js.map +1 -0
- package/dist/i18n/dispatch.d.ts +19 -0
- package/dist/i18n/dispatch.js +27 -0
- package/dist/i18n/dispatch.js.map +1 -0
- package/dist/i18n/en.d.ts +3 -0
- package/dist/i18n/en.js +275 -0
- package/dist/i18n/en.js.map +1 -0
- package/dist/i18n/help.d.ts +3 -0
- package/dist/i18n/help.en.d.ts +149 -0
- package/dist/i18n/help.en.js +150 -0
- package/dist/i18n/help.en.js.map +1 -0
- package/dist/i18n/help.js +7 -0
- package/dist/i18n/help.js.map +1 -0
- package/dist/i18n/help.zh.d.ts +149 -0
- package/dist/i18n/help.zh.js +150 -0
- package/dist/i18n/help.zh.js.map +1 -0
- package/dist/i18n/helpFormat.d.ts +7 -0
- package/dist/i18n/helpFormat.js +51 -0
- package/dist/i18n/helpFormat.js.map +1 -0
- package/dist/i18n/helpGroups.d.ts +3 -0
- package/dist/i18n/helpGroups.js +11 -0
- package/dist/i18n/helpGroups.js.map +1 -0
- package/dist/i18n/index.d.ts +16 -0
- package/dist/i18n/index.js +46 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/i18n/peekLang.d.ts +1 -0
- package/dist/i18n/peekLang.js +16 -0
- package/dist/i18n/peekLang.js.map +1 -0
- package/dist/i18n/zh.d.ts +680 -0
- package/dist/i18n/zh.js +288 -0
- package/dist/i18n/zh.js.map +1 -0
- package/dist/parser/discover.d.ts +2 -0
- package/dist/parser/discover.js +69 -0
- package/dist/parser/discover.js.map +1 -0
- package/dist/parser/load-yaml.d.ts +11 -0
- package/dist/parser/load-yaml.js +25 -0
- package/dist/parser/load-yaml.js.map +1 -0
- package/dist/pkgVersion.d.ts +9 -0
- package/dist/pkgVersion.js +22 -0
- package/dist/pkgVersion.js.map +1 -0
- package/dist/renderer/context-md.d.ts +27 -0
- package/dist/renderer/context-md.js +444 -0
- package/dist/renderer/context-md.js.map +1 -0
- package/dist/renderer/refresh-md.d.ts +18 -0
- package/dist/renderer/refresh-md.js +93 -0
- package/dist/renderer/refresh-md.js.map +1 -0
- package/dist/schema/index.d.ts +2 -0
- package/dist/schema/index.js +3 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/modules.d.ts +461 -0
- package/dist/schema/modules.js +184 -0
- package/dist/schema/modules.js.map +1 -0
- package/dist/schema/prd.d.ts +1018 -0
- package/dist/schema/prd.js +65 -0
- package/dist/schema/prd.js.map +1 -0
- package/dist/sync/cliRcHelpers.d.ts +25 -0
- package/dist/sync/cliRcHelpers.js +62 -0
- package/dist/sync/cliRcHelpers.js.map +1 -0
- package/dist/sync/conflicts.d.ts +7 -0
- package/dist/sync/conflicts.js +72 -0
- package/dist/sync/conflicts.js.map +1 -0
- package/dist/sync/headProbe.d.ts +1 -0
- package/dist/sync/headProbe.js +95 -0
- package/dist/sync/headProbe.js.map +1 -0
- package/dist/sync/normalize.d.ts +10 -0
- package/dist/sync/normalize.js +13 -0
- package/dist/sync/normalize.js.map +1 -0
- package/dist/sync/syncJson.d.ts +18 -0
- package/dist/sync/syncJson.js +42 -0
- package/dist/sync/syncJson.js.map +1 -0
- package/dist/types.d.ts +70 -0
- package/dist/types.js +21 -0
- package/dist/types.js.map +1 -0
- package/dist/validators/blocking.d.ts +2 -0
- package/dist/validators/blocking.js +25 -0
- package/dist/validators/blocking.js.map +1 -0
- package/dist/validators/duplicate-ids.d.ts +2 -0
- package/dist/validators/duplicate-ids.js +58 -0
- package/dist/validators/duplicate-ids.js.map +1 -0
- package/dist/validators/references.d.ts +5 -0
- package/dist/validators/references.js +165 -0
- package/dist/validators/references.js.map +1 -0
- package/dist/validators/required-modules.d.ts +8 -0
- package/dist/validators/required-modules.js +59 -0
- package/dist/validators/required-modules.js.map +1 -0
- package/dist/validators/runner.d.ts +11 -0
- package/dist/validators/runner.js +73 -0
- package/dist/validators/runner.js.map +1 -0
- package/dist/workspace.d.ts +32 -0
- package/dist/workspace.js +37 -0
- package/dist/workspace.js.map +1 -0
- package/dist/yaml-indexer.d.ts +15 -0
- package/dist/yaml-indexer.js +112 -0
- package/dist/yaml-indexer.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `prd migrate-yaml [<slug>]` — schema v0.1 → v0.2 yaml upgrader.
|
|
3
|
+
*
|
|
4
|
+
* Spec §5.2 / Task 8. Independent from `prd refresh` (refresh = "sync upstream
|
|
5
|
+
* PRD heading slice into yaml index"; this command = pure schema version bump).
|
|
6
|
+
*
|
|
7
|
+
* Two modes:
|
|
8
|
+
* - single slug: migrate one feature
|
|
9
|
+
* - no slug: batch-iterate every feature in .prd/features/*\/working/prd.yaml
|
|
10
|
+
* and report rolled-up counts at the end
|
|
11
|
+
*
|
|
12
|
+
* Hard invariant (reviewer I6 patch): SERVER-VALIDATE before writing yaml.
|
|
13
|
+
* If the user types a non-existent team / project slug we MUST refuse to
|
|
14
|
+
* persist it — otherwise the yaml goes to v0.2 but every push 410s forever,
|
|
15
|
+
* "bricked" until a hand-edit. We probe via the scoped feature-list endpoint
|
|
16
|
+
* (`GET /api/teams/:t/projects/:p/features`) which is already mounted; a 200
|
|
17
|
+
* proves team+project exist AND user has membership, a 404 means at least one
|
|
18
|
+
* of the three is missing (anti-enumeration uniform per spec §3.4).
|
|
19
|
+
*
|
|
20
|
+
* yaml mutation: eemeli/yaml's `Document.setIn(...)` lets us insert
|
|
21
|
+
* `meta.team` into an existing meta map. Other comments / key order / values
|
|
22
|
+
* remain in place. We do NOT try harder than the library's built-in
|
|
23
|
+
* comment-preservation — best-effort is sufficient for v0.1 yaml which has at
|
|
24
|
+
* most a handful of head comments.
|
|
25
|
+
*/
|
|
26
|
+
import { existsSync, readFileSync, writeFileSync, readdirSync, statSync, } from "node:fs";
|
|
27
|
+
import { join } from "node:path";
|
|
28
|
+
import { parseDocument } from "yaml";
|
|
29
|
+
import { createInterface } from "node:readline";
|
|
30
|
+
import { apiFetch, projectUrl } from "../api/client.js";
|
|
31
|
+
import { loadRcWithWarn, requireBackend } from "../sync/cliRcHelpers.js";
|
|
32
|
+
import { getMessages, readLocale } from "../i18n/index.js";
|
|
33
|
+
import * as c from "../formatter/colors.js";
|
|
34
|
+
/**
|
|
35
|
+
* Resolve target (team, project) for a single feature given precedence:
|
|
36
|
+
* 1. --team / --project flags (explicit)
|
|
37
|
+
* 2. .prdrc backends.<n> default_team / default_project (per spec §6.3)
|
|
38
|
+
* 3. interactive prompt: confirm rc defaults, or hand-fill
|
|
39
|
+
*
|
|
40
|
+
* Returns null on user decline / non-interactive without flags.
|
|
41
|
+
*/
|
|
42
|
+
async function resolveTeamProject(opts, rcDefaults, m, prompt) {
|
|
43
|
+
// 1) Flags win unconditionally.
|
|
44
|
+
if (opts.team && opts.project) {
|
|
45
|
+
return { team: opts.team, project: opts.project };
|
|
46
|
+
}
|
|
47
|
+
// 2) --non-interactive: only flag-driven path is allowed. We refuse to read
|
|
48
|
+
// .prdrc defaults without an explicit user opt-in because the user may
|
|
49
|
+
// not realize the .prdrc has stale defaults (CI scripts using
|
|
50
|
+
// --non-interactive must spell out their intent).
|
|
51
|
+
if (opts.nonInteractive) {
|
|
52
|
+
process.stderr.write(c.fail("✗ ") + m.migrate_yaml_non_interactive_missing_flags + "\n");
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
// 3) Interactive: prefer rc defaults if both are set — surface a Y/n prompt.
|
|
56
|
+
if (rcDefaults.team && rcDefaults.project) {
|
|
57
|
+
const ans = await prompt(m.migrate_yaml_prompt_confirm({
|
|
58
|
+
team: rcDefaults.team,
|
|
59
|
+
project: rcDefaults.project,
|
|
60
|
+
}));
|
|
61
|
+
if (ans.trim() === "" || /^y(es)?$/i.test(ans.trim())) {
|
|
62
|
+
return { team: rcDefaults.team, project: rcDefaults.project };
|
|
63
|
+
}
|
|
64
|
+
// User said "n" → fall through to manual entry below.
|
|
65
|
+
}
|
|
66
|
+
// 4) No defaults (or user declined) → hand-fill.
|
|
67
|
+
let team = opts.team;
|
|
68
|
+
if (!team) {
|
|
69
|
+
const ans = await prompt(m.migrate_yaml_prompt_team);
|
|
70
|
+
team = ans.trim();
|
|
71
|
+
if (!team) {
|
|
72
|
+
process.stderr.write(c.fail("✗ ") + m.migrate_yaml_skipped_user_no + "\n");
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
let project = opts.project;
|
|
77
|
+
if (!project) {
|
|
78
|
+
const ans = await prompt(m.migrate_yaml_prompt_project);
|
|
79
|
+
project = ans.trim();
|
|
80
|
+
if (!project) {
|
|
81
|
+
process.stderr.write(c.fail("✗ ") + m.migrate_yaml_skipped_user_no + "\n");
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return { team, project };
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Probe `GET /api/teams/:team/projects/:project/features` — 200 means both
|
|
89
|
+
* team and project exist AND the caller has at least viewer membership; any
|
|
90
|
+
* other status (most importantly 404) means refuse-to-write.
|
|
91
|
+
*/
|
|
92
|
+
async function verifyTeamProjectOnServer(backend, team, project, fetchFn) {
|
|
93
|
+
const res = await apiFetch(backend, projectUrl(team, project, "features"), {
|
|
94
|
+
fetchFn,
|
|
95
|
+
});
|
|
96
|
+
if (res.ok)
|
|
97
|
+
return { ok: true };
|
|
98
|
+
if (res.network) {
|
|
99
|
+
return { ok: false, reason: "network", message: res.message };
|
|
100
|
+
}
|
|
101
|
+
// Any non-2xx (404 anti-enum, 401, 403, 5xx) → treat as miss. We don't try
|
|
102
|
+
// to distinguish team-miss vs project-miss vs membership-miss because spec
|
|
103
|
+
// §3.4 explicitly collapses them server-side. The user gets one actionable
|
|
104
|
+
// error: "ask admin or fix the slug".
|
|
105
|
+
return { ok: false, reason: "miss" };
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Migrate one feature's working/prd.yaml in place.
|
|
109
|
+
*
|
|
110
|
+
* Returns `FeatureOutcome` so the batch driver can roll up a summary line.
|
|
111
|
+
* Writes user-facing IO directly (per-feature `·` / `✓` / `✗` lines).
|
|
112
|
+
*/
|
|
113
|
+
async function migrateOneFeature(slug, yamlPath, backend, resolved, m, fetchFn) {
|
|
114
|
+
const raw = readFileSync(yamlPath, "utf8");
|
|
115
|
+
let doc;
|
|
116
|
+
try {
|
|
117
|
+
doc = parseDocument(raw);
|
|
118
|
+
}
|
|
119
|
+
catch (e) {
|
|
120
|
+
process.stderr.write(c.fail("✗ ") +
|
|
121
|
+
m.migrate_yaml_parse_error({ slug, message: e.message }) +
|
|
122
|
+
"\n");
|
|
123
|
+
return "failed";
|
|
124
|
+
}
|
|
125
|
+
const schemaVersion = doc.get("schema_version");
|
|
126
|
+
if (schemaVersion === "v0.2") {
|
|
127
|
+
process.stdout.write(m.migrate_yaml_already_v02({ slug }) + "\n");
|
|
128
|
+
return "skipped";
|
|
129
|
+
}
|
|
130
|
+
if (schemaVersion !== "v0.1") {
|
|
131
|
+
process.stderr.write(c.fail("✗ ") +
|
|
132
|
+
m.migrate_yaml_unknown_schema({ slug, got: String(schemaVersion) }) +
|
|
133
|
+
"\n");
|
|
134
|
+
return "failed";
|
|
135
|
+
}
|
|
136
|
+
// Server validation — refuse to write yaml if (team, project) is bogus.
|
|
137
|
+
const verify = await verifyTeamProjectOnServer(backend, resolved.team, resolved.project, fetchFn);
|
|
138
|
+
if (!verify.ok) {
|
|
139
|
+
if (verify.reason === "network") {
|
|
140
|
+
process.stderr.write(c.fail("✗ ") +
|
|
141
|
+
m.migrate_yaml_server_network_error({
|
|
142
|
+
message: verify.message ?? "(no message)",
|
|
143
|
+
}) +
|
|
144
|
+
"\n");
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
process.stderr.write(c.fail("✗ ") +
|
|
148
|
+
m.migrate_yaml_server_miss({
|
|
149
|
+
team: resolved.team,
|
|
150
|
+
project: resolved.project,
|
|
151
|
+
}) +
|
|
152
|
+
"\n");
|
|
153
|
+
}
|
|
154
|
+
return "failed";
|
|
155
|
+
}
|
|
156
|
+
// Mutate the Document in place and serialize. eemeli/yaml preserves head
|
|
157
|
+
// comments, key order on existing keys, and indentation. The newly added
|
|
158
|
+
// meta.team key lands at the end of the meta map (acceptable — meta is a
|
|
159
|
+
// small map, exact insertion position isn't load-bearing for schema).
|
|
160
|
+
doc.setIn(["meta", "team"], resolved.team);
|
|
161
|
+
doc.setIn(["meta", "project"], resolved.project);
|
|
162
|
+
doc.set("schema_version", "v0.2");
|
|
163
|
+
const newYaml = String(doc);
|
|
164
|
+
writeFileSync(yamlPath, newYaml, "utf8");
|
|
165
|
+
process.stdout.write(c.pass("✓ ") +
|
|
166
|
+
m.migrate_yaml_written({
|
|
167
|
+
slug,
|
|
168
|
+
team: resolved.team,
|
|
169
|
+
project: resolved.project,
|
|
170
|
+
}) +
|
|
171
|
+
"\n");
|
|
172
|
+
return "upgraded";
|
|
173
|
+
}
|
|
174
|
+
/** Default stdin-backed prompt. Tests inject via `opts.promptFn`. */
|
|
175
|
+
function defaultPrompt(question) {
|
|
176
|
+
return new Promise((resolve) => {
|
|
177
|
+
const rl = createInterface({
|
|
178
|
+
input: process.stdin,
|
|
179
|
+
output: process.stdout,
|
|
180
|
+
});
|
|
181
|
+
rl.question(question, (answer) => {
|
|
182
|
+
rl.close();
|
|
183
|
+
resolve(answer);
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
/** Walk .prd/features/ and return feature slugs that have working/prd.yaml. */
|
|
188
|
+
function listFeatureSlugs(cwd) {
|
|
189
|
+
const featuresDir = join(cwd, ".prd", "features");
|
|
190
|
+
if (!existsSync(featuresDir))
|
|
191
|
+
return [];
|
|
192
|
+
let entries;
|
|
193
|
+
try {
|
|
194
|
+
entries = readdirSync(featuresDir);
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
return [];
|
|
198
|
+
}
|
|
199
|
+
const slugs = [];
|
|
200
|
+
for (const entry of entries) {
|
|
201
|
+
const yamlPath = join(featuresDir, entry, "working", "prd.yaml");
|
|
202
|
+
try {
|
|
203
|
+
if (statSync(yamlPath).isFile())
|
|
204
|
+
slugs.push(entry);
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
// missing working/prd.yaml — skip silently (workspace may contain
|
|
208
|
+
// half-initialized features, common during user setup).
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return slugs.sort();
|
|
212
|
+
}
|
|
213
|
+
export async function runMigrateYamlCommand(opts, cwd) {
|
|
214
|
+
const m = getMessages(readLocale());
|
|
215
|
+
// .prd workspace gate — runs before backend resolve so users without a
|
|
216
|
+
// workspace get the actionable "run prd init" hint rather than a
|
|
217
|
+
// backend-loading error.
|
|
218
|
+
const prdDir = join(cwd, ".prd");
|
|
219
|
+
if (!existsSync(prdDir)) {
|
|
220
|
+
process.stderr.write(c.fail("✗ ") + m.migrate_yaml_workspace_not_init + "\n");
|
|
221
|
+
return 1;
|
|
222
|
+
}
|
|
223
|
+
// Resolve backend before any per-feature work — server validation is
|
|
224
|
+
// mandatory and we want to fail fast on "no backend" rather than after
|
|
225
|
+
// prompting the user for slug values.
|
|
226
|
+
const loaded = loadRcWithWarn(opts.rcPath);
|
|
227
|
+
if (loaded.hadError)
|
|
228
|
+
return 1;
|
|
229
|
+
const backend = requireBackend(loaded.rc, { backend: opts.backend });
|
|
230
|
+
if (!backend)
|
|
231
|
+
return 1;
|
|
232
|
+
// Resolve .prdrc defaults from the backend the user is actually using.
|
|
233
|
+
// (`requireBackend` already returned its name as `backend.name`; we look it
|
|
234
|
+
// up in the rc to pull default_team / default_project.)
|
|
235
|
+
const rcEntry = loaded.rc && backend.name !== "(env)"
|
|
236
|
+
? loaded.rc.backends[backend.name]
|
|
237
|
+
: undefined;
|
|
238
|
+
const rcDefaults = {
|
|
239
|
+
team: rcEntry?.default_team,
|
|
240
|
+
project: rcEntry?.default_project,
|
|
241
|
+
};
|
|
242
|
+
const prompt = opts.promptFn ?? defaultPrompt;
|
|
243
|
+
// Batch mode: no slug → iterate all features.
|
|
244
|
+
if (!opts.slug) {
|
|
245
|
+
const slugs = listFeatureSlugs(cwd);
|
|
246
|
+
if (slugs.length === 0) {
|
|
247
|
+
process.stdout.write(m.migrate_yaml_batch_no_features + "\n");
|
|
248
|
+
return 0;
|
|
249
|
+
}
|
|
250
|
+
let upgraded = 0;
|
|
251
|
+
let skipped = 0;
|
|
252
|
+
let failed = 0;
|
|
253
|
+
for (const slug of slugs) {
|
|
254
|
+
const yamlPath = join(cwd, ".prd", "features", slug, "working", "prd.yaml");
|
|
255
|
+
// Resolve per-feature (could differ per slug if user types a different
|
|
256
|
+
// team/project at the prompt). Cache once when flags + defaults force
|
|
257
|
+
// the same answer; otherwise re-prompt is the path the spec requires.
|
|
258
|
+
const resolved = await resolveTeamProject(opts, rcDefaults, m, prompt);
|
|
259
|
+
if (!resolved) {
|
|
260
|
+
failed++;
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
const outcome = await migrateOneFeature(slug, yamlPath, backend, resolved, m, opts.fetchFn);
|
|
264
|
+
if (outcome === "upgraded")
|
|
265
|
+
upgraded++;
|
|
266
|
+
else if (outcome === "skipped")
|
|
267
|
+
skipped++;
|
|
268
|
+
else
|
|
269
|
+
failed++;
|
|
270
|
+
}
|
|
271
|
+
process.stdout.write(m.migrate_yaml_batch_summary({ upgraded, skipped, failed }) + "\n");
|
|
272
|
+
return failed > 0 ? 1 : 0;
|
|
273
|
+
}
|
|
274
|
+
// Single-slug mode.
|
|
275
|
+
const yamlPath = join(cwd, ".prd", "features", opts.slug, "working", "prd.yaml");
|
|
276
|
+
if (!existsSync(yamlPath)) {
|
|
277
|
+
process.stderr.write(c.fail("✗ ") +
|
|
278
|
+
m.migrate_yaml_feature_yaml_missing({ slug: opts.slug, path: yamlPath }) +
|
|
279
|
+
"\n");
|
|
280
|
+
return 1;
|
|
281
|
+
}
|
|
282
|
+
const resolved = await resolveTeamProject(opts, rcDefaults, m, prompt);
|
|
283
|
+
if (!resolved)
|
|
284
|
+
return 1;
|
|
285
|
+
const outcome = await migrateOneFeature(opts.slug, yamlPath, backend, resolved, m, opts.fetchFn);
|
|
286
|
+
return outcome === "failed" ? 1 : 0;
|
|
287
|
+
}
|
|
288
|
+
//# sourceMappingURL=migrate-yaml.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate-yaml.js","sourceRoot":"","sources":["../../src/commands/migrate-yaml.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `prd project list --team <slug>` — UAT2-G1 (spec §6.2 / plan §Task 7).
|
|
3
|
+
*
|
|
4
|
+
* USER-视角只读视图:列出当前 PAT 用户在指定 team 下能看见的 project(=自己
|
|
5
|
+
* 有 membership 的 project),并附上 my_role 和 feature_count。
|
|
6
|
+
*
|
|
7
|
+
* 与 `prd admin project list` 的区别同 team.ts:走 ~/.prdrc + Bearer PAT,
|
|
8
|
+
* 不需要 PRDSERVER_ADMIN_TOKEN。
|
|
9
|
+
*
|
|
10
|
+
* Server endpoint:GET /api/teams/:teamSlug/projects(T-v1.1-9 Part A)。
|
|
11
|
+
* 返回 { ok:true, data:[{slug, name, my_role, feature_count}] }
|
|
12
|
+
*
|
|
13
|
+
* 404 处理:server 在 teamScopeMiddleware 里把 "team 不存在" 和 "你没看见这个
|
|
14
|
+
* team 的任何 project" 都返回 404(防 enumeration),CLI 这边映射为同一句话
|
|
15
|
+
* "team not found or no membership" 比较安全。
|
|
16
|
+
*/
|
|
17
|
+
import { apiFetch } from "../api/client.js";
|
|
18
|
+
import { loadRcWithWarn, requireBackend } from "../sync/cliRcHelpers.js";
|
|
19
|
+
import { getMessages, readLocale } from "../i18n/index.js";
|
|
20
|
+
import * as c from "../formatter/colors.js";
|
|
21
|
+
function renderTable(rows, headers) {
|
|
22
|
+
const cols = [
|
|
23
|
+
{ key: "slug", label: headers.slug },
|
|
24
|
+
{ key: "name", label: headers.name },
|
|
25
|
+
{ key: "role", label: headers.role },
|
|
26
|
+
{ key: "features", label: headers.features },
|
|
27
|
+
];
|
|
28
|
+
const dataRows = rows.map((r) => ({
|
|
29
|
+
slug: r.slug,
|
|
30
|
+
name: r.name,
|
|
31
|
+
role: r.my_role,
|
|
32
|
+
features: String(r.feature_count),
|
|
33
|
+
}));
|
|
34
|
+
const widths = cols.map((col) => Math.max(col.label.length, ...dataRows.map((row) => row[col.key].length)));
|
|
35
|
+
const fmt = (vals) => vals.map((v, i) => v.padEnd(widths[i])).join(" ").trimEnd();
|
|
36
|
+
const lines = [];
|
|
37
|
+
lines.push(fmt(cols.map((col) => col.label)));
|
|
38
|
+
for (const row of dataRows) {
|
|
39
|
+
lines.push(fmt(cols.map((col) => row[col.key])));
|
|
40
|
+
}
|
|
41
|
+
return lines.join("\n");
|
|
42
|
+
}
|
|
43
|
+
export async function runProjectListCommand(opts, cwd) {
|
|
44
|
+
void cwd;
|
|
45
|
+
const m = getMessages(readLocale());
|
|
46
|
+
if (!opts.team) {
|
|
47
|
+
process.stderr.write(c.fail("✗ ") + m.project_list_team_required + "\n");
|
|
48
|
+
return 1;
|
|
49
|
+
}
|
|
50
|
+
const loaded = loadRcWithWarn(opts.rcPath);
|
|
51
|
+
if (loaded.hadError)
|
|
52
|
+
return 1;
|
|
53
|
+
const backend = requireBackend(loaded.rc, { backend: opts.backend });
|
|
54
|
+
if (!backend)
|
|
55
|
+
return 1;
|
|
56
|
+
const res = await apiFetch(backend, `/api/teams/${encodeURIComponent(opts.team)}/projects`, { fetchFn: opts.fetchFn });
|
|
57
|
+
if (!res.ok) {
|
|
58
|
+
if (res.code === "UNAUTHENTICATED") {
|
|
59
|
+
process.stderr.write(c.fail("✗ ") + m.whoami_unauth + "\n");
|
|
60
|
+
return 1;
|
|
61
|
+
}
|
|
62
|
+
if (res.status === 404) {
|
|
63
|
+
process.stderr.write(c.fail("✗ ") + m.admin_team_not_found({ slug: opts.team }) + "\n");
|
|
64
|
+
return 1;
|
|
65
|
+
}
|
|
66
|
+
if (res.network) {
|
|
67
|
+
process.stderr.write(c.fail("✗ ") + m.push_network_error({ message: res.message }) + "\n");
|
|
68
|
+
return 1;
|
|
69
|
+
}
|
|
70
|
+
process.stderr.write(c.fail("✗ ") + `Failed: ${res.code} — ${res.message}\n`);
|
|
71
|
+
return 1;
|
|
72
|
+
}
|
|
73
|
+
const rows = res.body.data;
|
|
74
|
+
if (rows.length === 0) {
|
|
75
|
+
process.stdout.write(m.project_list_empty({ team: opts.team }) + "\n");
|
|
76
|
+
return 0;
|
|
77
|
+
}
|
|
78
|
+
const table = renderTable(rows, {
|
|
79
|
+
slug: m.project_list_header_slug,
|
|
80
|
+
name: m.project_list_header_name,
|
|
81
|
+
role: m.project_list_header_role,
|
|
82
|
+
features: m.project_list_header_features,
|
|
83
|
+
});
|
|
84
|
+
process.stdout.write(table + "\n");
|
|
85
|
+
return 0;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/commands/project.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface PullOptions {
|
|
2
|
+
slug: string;
|
|
3
|
+
backend?: string;
|
|
4
|
+
force?: boolean;
|
|
5
|
+
/** Stash local working/prd.yaml to .prd/.conflicts/ before fast-forward. */
|
|
6
|
+
stash?: boolean;
|
|
7
|
+
fetchFn?: typeof fetch;
|
|
8
|
+
rcPath?: string;
|
|
9
|
+
/**
|
|
10
|
+
* v1.1: explicit scope override for fresh-clone pulls where local yaml and
|
|
11
|
+
* sync.json both lack team/project. CLI flag wiring lives in cli.ts (T7).
|
|
12
|
+
*/
|
|
13
|
+
team?: string;
|
|
14
|
+
project?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function runPullCommand(opts: PullOptions, cwd: string): Promise<number>;
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `prd pull <slug> [--backend <name>] [--force] [--stash]` (T6, design §6.3;
|
|
3
|
+
* v1.1 spec §4.2 / §6.2 + UAT F7 / F8).
|
|
4
|
+
*
|
|
5
|
+
* Dirty detection:
|
|
6
|
+
* sha256( normalizeLineEndings(working/prd.yaml) ) !== sync.json.last_synced_hash
|
|
7
|
+
* Note the line-ending normalize step — must mirror server (T5) so CRLF
|
|
8
|
+
* checkouts from git on Windows don't flag identical bytes as "dirty".
|
|
9
|
+
*
|
|
10
|
+
* --force overwrites local working/. No stash (user already warned).
|
|
11
|
+
*
|
|
12
|
+
* Fresh-clone path: no local working/, no sync.json → just write what server
|
|
13
|
+
* returns, sync.json initialized with server's ETag.
|
|
14
|
+
*
|
|
15
|
+
* F7 (UAT polish): If-None-Match → 304 → print "已是最新" + exit 0 without
|
|
16
|
+
* overwrite.
|
|
17
|
+
*
|
|
18
|
+
* F8 (UAT polish): dirty check happens BEFORE any stash directory creation.
|
|
19
|
+
* Bare `prd pull` against dirty working/ rejects with exit 1 and produces no
|
|
20
|
+
* .conflicts/ noise. `--stash` is the only path that calls stashConflict().
|
|
21
|
+
*/
|
|
22
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
23
|
+
import { join, dirname } from "node:path";
|
|
24
|
+
import { createHash } from "node:crypto";
|
|
25
|
+
import { apiFetch, parseMetaScope, projectUrl } from "../api/client.js";
|
|
26
|
+
import { loadRcWithWarn, requireBackend } from "../sync/cliRcHelpers.js";
|
|
27
|
+
import { readSyncJson, writeSyncJson } from "../sync/syncJson.js";
|
|
28
|
+
import { normalizeLineEndings } from "../sync/normalize.js";
|
|
29
|
+
import { stashConflict } from "../sync/conflicts.js";
|
|
30
|
+
import { getMessages, readLocale } from "../i18n/index.js";
|
|
31
|
+
import * as c from "../formatter/colors.js";
|
|
32
|
+
export async function runPullCommand(opts, cwd) {
|
|
33
|
+
const m = getMessages(readLocale());
|
|
34
|
+
if (!opts.slug) {
|
|
35
|
+
process.stderr.write(c.fail("✗ ") + "Usage: prd pull <slug>\n");
|
|
36
|
+
return 1;
|
|
37
|
+
}
|
|
38
|
+
const loaded = loadRcWithWarn(opts.rcPath);
|
|
39
|
+
if (loaded.hadError)
|
|
40
|
+
return 1;
|
|
41
|
+
const backend = requireBackend(loaded.rc, { backend: opts.backend });
|
|
42
|
+
if (!backend)
|
|
43
|
+
return 1;
|
|
44
|
+
const workingDir = join(cwd, ".prd", "features", opts.slug, "working");
|
|
45
|
+
const workingPath = join(workingDir, "prd.yaml");
|
|
46
|
+
const sync = readSyncJson(cwd, opts.slug);
|
|
47
|
+
// F8 (UAT polish): inspect dirty state BEFORE we do anything fetch-related
|
|
48
|
+
// or stash-related. Bare `prd pull` against dirty working/ must reject
|
|
49
|
+
// with exit 1 and produce no .conflicts/ noise. The stash path runs later,
|
|
50
|
+
// only when isDirty && opts.stash.
|
|
51
|
+
let isDirty = false;
|
|
52
|
+
let dirtyLocalYaml = "";
|
|
53
|
+
if (existsSync(workingPath) && sync) {
|
|
54
|
+
if (sync.backend_url && sync.backend_url !== backend.url) {
|
|
55
|
+
process.stderr.write(c.fail("✗ ") +
|
|
56
|
+
m.pull_backend_url_changed({
|
|
57
|
+
old: sync.backend_url,
|
|
58
|
+
current: backend.url,
|
|
59
|
+
}) +
|
|
60
|
+
"\n");
|
|
61
|
+
return 1;
|
|
62
|
+
}
|
|
63
|
+
dirtyLocalYaml = readFileSync(workingPath, "utf8");
|
|
64
|
+
const localBytes = normalizeLineEndings(dirtyLocalYaml);
|
|
65
|
+
const localHash = "sha256:" + createHash("sha256").update(localBytes).digest("hex");
|
|
66
|
+
isDirty = localHash !== sync.last_synced_hash;
|
|
67
|
+
}
|
|
68
|
+
// F8: refuse on dirty unless --force or --stash. --force overwrites
|
|
69
|
+
// silently; --stash preserves local in .conflicts/ before fast-forward
|
|
70
|
+
// (B-5 fix: gives users a first-class "save local + take remote" path so
|
|
71
|
+
// they don't have to choose between `--force` data loss and the push/pull
|
|
72
|
+
// deadlock documented in the T11 dogfood report). Critically, stash dir
|
|
73
|
+
// creation must NOT happen here — only after the server fetch succeeds.
|
|
74
|
+
if (isDirty && !opts.force && !opts.stash) {
|
|
75
|
+
process.stderr.write(c.fail("✗ ") +
|
|
76
|
+
m.pull_refuse_dirty({ path: workingPath }) +
|
|
77
|
+
"\n");
|
|
78
|
+
return 1;
|
|
79
|
+
}
|
|
80
|
+
// v1.1 scope resolution (spec §4.2). Priority:
|
|
81
|
+
// 1. opts.team/project (explicit flag)
|
|
82
|
+
// 2. working/prd.yaml meta (parseMetaScope)
|
|
83
|
+
// 3. sync.json.team / sync.json.project
|
|
84
|
+
// With --force we tolerate parse failures on local yaml (the whole point
|
|
85
|
+
// of --force is "blow away whatever junk is there"), so we'll fall through
|
|
86
|
+
// to sync.json or opts in that case rather than refuse.
|
|
87
|
+
let scope = null;
|
|
88
|
+
if (opts.team && opts.project) {
|
|
89
|
+
scope = { team: opts.team, project: opts.project, feature: opts.slug };
|
|
90
|
+
}
|
|
91
|
+
else if (existsSync(workingPath)) {
|
|
92
|
+
const localContent = dirtyLocalYaml || readFileSync(workingPath, "utf8");
|
|
93
|
+
try {
|
|
94
|
+
scope = parseMetaScope(localContent);
|
|
95
|
+
}
|
|
96
|
+
catch (e) {
|
|
97
|
+
if (opts.force && sync?.team && sync?.project) {
|
|
98
|
+
scope = {
|
|
99
|
+
team: sync.team,
|
|
100
|
+
project: sync.project,
|
|
101
|
+
feature: opts.slug,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
process.stderr.write(c.fail("✗ ") + e.message + "\n");
|
|
106
|
+
process.stderr.write(m.api_v0_gone_hint + "\n");
|
|
107
|
+
return 1;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
else if (sync?.team && sync?.project) {
|
|
112
|
+
scope = { team: sync.team, project: sync.project, feature: opts.slug };
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
process.stderr.write(c.fail("✗ ") + m.pull_scope_unresolvable({ slug: opts.slug }) + "\n");
|
|
116
|
+
return 1;
|
|
117
|
+
}
|
|
118
|
+
const featureUrl = projectUrl(scope.team, scope.project, "features", scope.feature);
|
|
119
|
+
// F7 (UAT polish): conditional GET via If-None-Match. Server returns 304
|
|
120
|
+
// with no body if local base matches remote → CLI prints "已是最新" and
|
|
121
|
+
// exits 0 without touching working/. Skip when --force so the explicit
|
|
122
|
+
// "blow away local junk and re-download" path always re-fetches the yaml.
|
|
123
|
+
const conditionalHeaders = {};
|
|
124
|
+
if (sync?.base_version_id && !opts.force) {
|
|
125
|
+
conditionalHeaders["If-None-Match"] = `"${sync.base_version_id}"`;
|
|
126
|
+
}
|
|
127
|
+
const res = await apiFetch(backend, `${featureUrl}?for=pull`, { fetchFn: opts.fetchFn, headers: conditionalHeaders });
|
|
128
|
+
if (res.ok && res.status === 304) {
|
|
129
|
+
process.stdout.write(m.pull_already_up_to_date({
|
|
130
|
+
slug: opts.slug,
|
|
131
|
+
version: sync?.base_version_id ?? "(unknown)",
|
|
132
|
+
}) + "\n");
|
|
133
|
+
return 0;
|
|
134
|
+
}
|
|
135
|
+
if (!res.ok) {
|
|
136
|
+
if (res.code === "API_V0_GONE" || res.status === 410) {
|
|
137
|
+
process.stderr.write(c.fail("✗ ") + m.api_v0_gone_hint + "\n");
|
|
138
|
+
return 1;
|
|
139
|
+
}
|
|
140
|
+
if (res.code === "FEATURE_NOT_FOUND" || res.status === 404) {
|
|
141
|
+
process.stderr.write(c.fail("✗ ") + m.pull_remote_not_found({ slug: opts.slug }) + "\n");
|
|
142
|
+
return 1;
|
|
143
|
+
}
|
|
144
|
+
if (res.network) {
|
|
145
|
+
process.stderr.write(c.fail("✗ ") + m.push_network_error({ message: res.message }) + "\n");
|
|
146
|
+
return 1;
|
|
147
|
+
}
|
|
148
|
+
process.stderr.write(c.fail("✗ ") + `Pull failed: ${res.code} — ${res.message}\n`);
|
|
149
|
+
return 1;
|
|
150
|
+
}
|
|
151
|
+
// Server sends YAML as text (Content-Type: application/yaml) — apiFetch
|
|
152
|
+
// falls back to text() for non-JSON, so res.body is the raw yaml string.
|
|
153
|
+
const yamlText = typeof res.body === "string" ? res.body : String(res.body);
|
|
154
|
+
const normalized = normalizeLineEndings(yamlText);
|
|
155
|
+
const etag = res.headers.get("ETag") ?? res.headers.get("etag");
|
|
156
|
+
if (!etag) {
|
|
157
|
+
process.stderr.write(c.fail("✗ ") + `Server response missing ETag header\n`);
|
|
158
|
+
return 1;
|
|
159
|
+
}
|
|
160
|
+
const version = etag.replace(/^"|"$/g, "");
|
|
161
|
+
if (!existsSync(dirname(workingPath))) {
|
|
162
|
+
mkdirSync(dirname(workingPath), { recursive: true });
|
|
163
|
+
}
|
|
164
|
+
let stashDir;
|
|
165
|
+
if (opts.stash && isDirty) {
|
|
166
|
+
// stashConflict writes local.yaml + remote.yaml + README.md AND overwrites
|
|
167
|
+
// working/prd.yaml with remote — exact semantics we want for `--stash`.
|
|
168
|
+
stashDir = stashConflict(cwd, opts.slug, {
|
|
169
|
+
localYaml: dirtyLocalYaml,
|
|
170
|
+
remoteYaml: normalized,
|
|
171
|
+
baseVersionId: sync?.base_version_id,
|
|
172
|
+
remoteVersionId: version,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
writeFileSync(workingPath, normalized, "utf8");
|
|
177
|
+
}
|
|
178
|
+
const hash = "sha256:" + createHash("sha256").update(normalized).digest("hex");
|
|
179
|
+
writeSyncJson(cwd, opts.slug, {
|
|
180
|
+
base_version_id: version,
|
|
181
|
+
last_synced_hash: hash,
|
|
182
|
+
last_pulled_at: new Date().toISOString(),
|
|
183
|
+
last_pushed_at: sync?.last_pushed_at,
|
|
184
|
+
backend_url: backend.url,
|
|
185
|
+
team: scope.team,
|
|
186
|
+
project: scope.project,
|
|
187
|
+
});
|
|
188
|
+
if (stashDir) {
|
|
189
|
+
process.stdout.write(c.pass("✓ ") + m.pull_stash_success({ dir: stashDir }) + "\n");
|
|
190
|
+
}
|
|
191
|
+
else if (opts.force) {
|
|
192
|
+
process.stdout.write(c.pass("✓ ") + m.pull_force_overwrote({ slug: opts.slug }) + "\n");
|
|
193
|
+
}
|
|
194
|
+
process.stdout.write(c.pass("✓ ") + m.pull_success({ slug: opts.slug, version }) + "\n");
|
|
195
|
+
return 0;
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=pull.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pull.js","sourceRoot":"","sources":["../../src/commands/pull.ts"],"names":[],"mappings":"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"}
|