Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ shadow-dev branch plan --name 20260925-fix-login
shadow-dev branch execute --name 20260925-fix-login --confirm

# ③ 写代码……完成后勾任务(任务清单来自 brief 正文)
# 动到的文件超出 brief 声明集时,先用 amend 登记:有实际扩面即作废已通过的 review,必须重审
# shadow-dev change amend --name 20260925-fix-login --files src/login.ts,src/session.ts --confirm
shadow-dev task set --name 20260925-fix-login --task task-1 --state done --confirm

# ④ 审查(任务全部勾选才允许写 passed)
Expand Down Expand Up @@ -162,7 +164,7 @@ shadow-dev issue execute --name <名称> --confirm

| 命令 | 作用 |
|------|------|
| `change create \| approve \| list` | 创建 / 批准变更 brief;`list` 列变更(`--all` 含归档、`--archived` 只列归档) |
| `change create \| approve \| amend \| list` | 创建 / 批准变更 brief;`amend` 登记实现期扩面;`list` 列变更(`--all` 含归档、`--archived` 只列归档) |
| `branch plan \| execute` | 从基线分支建功能分支 |
| `sync plan \| execute` | fast-forward 同步上游(分叉时拒绝自动合并) |
| `conflict inspect` | 检查活动变更间的文件重叠 |
Expand Down Expand Up @@ -210,7 +212,7 @@ shadow-dev issue execute --name <名称> --confirm
|----|------|-----------|
| 0 | 成功 | — |
| 1 | 输入/校验错误 | `PLAN_HASH_INVALID`、`BRIEF_NOT_FOUND`、`NAME_REQUIRED`、`TASKS_NOT_COMPLETE`、`REVIEW_NOT_PASSED`、`PR_NOT_MERGED`、`ARTIFACT_INVALID`、`ARTIFACT_INCOMPATIBLE`、`UNMANAGED_TARGET`、`BLOG_FILE_NOT_FOUND`、`BLOG_TITLE_REQUIRED` |
| 2 | 缺少确认或凭证 | `CONFIRMATION_REQUIRED`、`PLAN_HASH_REQUIRED`、`BLOG_FILE_REQUIRED` |
| 2 | 缺少确认或凭证 | `CONFIRMATION_REQUIRED`、`PLAN_HASH_REQUIRED`、`BLOG_FILE_REQUIRED`、`AMEND_INPUT_REQUIRED` |
| 3 | 外部系统失败 | `GITHUB_TOKEN_REQUIRED`、`GITHUB_API_ERROR`、`API_TIMEOUT`、`GIT_PUSH_FAILED`、`DOWNLOAD_FAILED`、`RELEASE_NOT_FOUND` |
| 4 | 不支持的操作 | `UNSUPPORTED_OPERATION`(如 `git add .`、绝对路径) |

Expand Down
1 change: 1 addition & 0 deletions cli.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ async function handle(r, p, o) {
if (d === 'task' && a === 'set') return { ok: true, command: 'task.set', data: task.set(r, o) }
if (d === 'change' && a === 'create') return { ok: true, command: 'change.create', data: change.create(r, o) }
if (d === 'change' && a === 'approve') return { ok: true, command: 'change.approve', data: change.approve(r, o) }
if (d === 'change' && a === 'amend') return { ok: true, command: 'change.amend', data: change.amend(r, o) }
if (d === 'change' && a === 'list') return { ok: true, command: 'change.list', data: change.list(r, o) }
// 生态分发域:宿主无关、不要求 git 仓库,r 允许为 null
if (d === 'workflow') return await workflow.handle(a, o)
Expand Down
1 change: 1 addition & 0 deletions lib/commands.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const COMMANDS = {
'repo.inspect': c('repo inspect', '查看仓库状态(分支、HEAD、脏文件)', 'show repository state (branch, HEAD, dirty files)', [], 'shadow-dev repo inspect'),
'change.create': c('change create', '创建变更 brief', 'create a change brief', [N, f('--type', false, 'feature|fix|build|chore|docs|refactor|style|test,默认 feat', 'one of feature|fix|build|chore|docs|refactor|style|test, default feat'), f('--scope', false, '影响范围', 'scope'), f('--base-branch', false, '基线分支,默认 main', 'base branch, default main'), FI, f('--body-file', false, 'brief 正文来源文件', 'file supplying the brief body'), f('--repository', false, 'GitHub owner/repo', 'GitHub owner/repo'), CF], 'shadow-dev change create --name <change-name> --type feature --confirm', 'change approve --name {name} --confirm'),
'change.approve': c('change approve', '批准 brief(draft → proposed)', 'approve the brief (draft → proposed)', [N, CF], 'shadow-dev change approve --name <change-name> --confirm', 'branch plan --name {name}'),
'change.amend': c('change amend', '修订 brief 声明的文件集与 scope(实现期扩面登记;会作废已通过的 review)', 'revise the brief declared file set and scope (records mid-implementation scope growth; voids a passed review)', [N, f('--files', true, '逗号分隔的文件全集,替换而非追加(反斜杠自动归一,空集拒绝)', 'comma-separated FULL file set, replacement rather than additive (backslashes normalized, empty set rejected)'), f('--scope', false, '影响范围覆盖,缺省保持原值', 'scope override, current value kept when omitted'), CF], 'shadow-dev change amend --name <change-name> --files a.mjs,b.mjs --confirm', null),
'change.list': c('change list', '列出变更的名称、类型、状态与分支(默认只列活动)', 'list changes with name, type, status and branch (active only by default)', [f('--all', false, '同时包含已归档变更(与 --archived 同传时按 --all 处理)', 'include archived changes as well (--all wins when both are passed)'), f('--archived', false, '只列已归档变更', 'list archived changes only')], 'shadow-dev change list'),
'issue.plan': c('issue plan', '预览由 brief 确定性渲染的统一结构 issue(stdout 只回摘要)', 'plan the unified-structure issue rendered from the brief (stdout carries a lean summary)', [N, f('--title', false, '标题覆盖,缺省 = [type] 前缀 + brief H1,回落变更名', 'title override; default = [type] prefix + brief H1, falling back to the change name'), f('--body', false, '可选「补充」节内容;正文骨架由 brief 分节自动渲染', 'optional 补充 section text; the skeleton is rendered from brief sections'), f('--labels', false, '逗号分隔标签', 'comma-separated labels')], 'shadow-dev issue plan --name <change-name> --labels feature', 'issue execute --name {name} --plan-hash {planHash} --confirm'),
'issue.execute': c('issue execute', '创建 GitHub issue(正文读 brief 快照与 plan 校验)', 'create the GitHub issue (body re-derived from the brief and hash-checked)', [N, PH, CF], 'shadow-dev issue execute --name <change-name> --confirm', null),
Expand Down
25 changes: 25 additions & 0 deletions lib/domains/change.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,28 @@ export function approve(r, o) {
write(b)
return { name: o.name, status: 'proposed' }
}

// 实现期扩面登记:files 全集替换(scope 可选覆盖),无差异即幂等返回不动盘(与 briefStateCommit「无差异不造空提交」同源)。
// 有实际差异且 review 已 passed 时一律打回 pending——review 不记录当时覆盖的文件集,不作废就等于给归档门开了旁路。
export function amend(r, o) {
confirm(o)
const n = name(o)
const after = fileList(o.files)
if (!after.length) throw err('AMEND_INPUT_REQUIRED', 'AMEND_INPUT_REQUIRED: --files is required and must not be empty', 2)
const b = brief(r, n)
const before = b.data.files || []
const scopeBefore = b.data.scope ?? null
const scopeAfter = o.scope === undefined ? scopeBefore : (o.scope || null)
const added = after.filter(x => !before.includes(x))
const removed = before.filter(x => !after.includes(x))
const scopeChanged = scopeAfter !== scopeBefore
if (!added.length && !removed.length && !scopeChanged) {
return { name: n, files: after, added, removed, scope: scopeAfter, reviewReset: false, changed: false, nextStep: null }
}
b.data.files = after
if (scopeChanged) b.data.scope = scopeAfter
const reviewReset = b.data.review?.conclusion === 'passed'
if (reviewReset) b.data.review = { conclusion: 'pending', verifiedCommit: null, verifiedAt: null }
write(b)
return { name: n, files: after, added, removed, scope: scopeAfter, reviewReset, changed: true, nextStep: reviewReset ? `review plan --name ${n}` : `conflict inspect --name ${n}` }
}
1 change: 1 addition & 0 deletions lib/i18n.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const HINTS = {
NOT_GIT_REPOSITORY: { zh: '当前目录不在 git 仓库内', en: 'not inside a git repository' },
NAME_REQUIRED: { zh: '缺少必填参数(详见下列参数行与示例)', en: 'missing required argument (see flag lines below)' },
CHANGE_EXISTS: { zh: '同名变更已存在(shadow-docs/changes/<name>)', en: 'a change with this name already exists under shadow-docs/changes' },
AMEND_INPUT_REQUIRED: { zh: '--files 必填且不得为空(逗号分隔的文件全集,替换而非追加)', en: '--files is required and must not be empty (comma-separated full set, replacement rather than additive)' },
BRIEF_NOT_FOUND: { zh: 'brief 不存在;先运行 shadow-dev change create --name <变更名>', en: 'brief not found; run shadow-dev change create --name <change> first' },
BRIEF_FRONTMATTER_REQUIRED: { zh: 'brief 缺少 --- 包裹的 frontmatter', en: 'brief is missing its --- frontmatter block' },
BODY_FILE_NOT_FOUND: { zh: '--body-file 指向的文件不存在', en: 'the --body-file path does not exist' },
Expand Down
Loading
Loading