ci: finalize pac status and gh heredoc guard
This commit is contained in:
@@ -92,9 +92,15 @@ bun scripts/cli.ts agentrun control-plane restart --node D601 --lane v02 --confi
|
||||
bun scripts/cli.ts agentrun control-plane trigger-current --node D601 --lane v02 --dry-run
|
||||
bun scripts/cli.ts agentrun control-plane trigger-current --node D601 --lane v02 --confirm
|
||||
bun scripts/cli.ts agentrun control-plane status --node D601 --lane v02 --full
|
||||
bun scripts/cli.ts platform-infra gitea mirror status --target JD01
|
||||
bun scripts/cli.ts platform-infra pipelines-as-code status --target JD01
|
||||
```
|
||||
|
||||
`status` 只读观察 YAML 选中 lane 的 source authority、对应 PipelineRun、GitOps latest、Argo Application、runtime workload、manager source commit 和 git mirror 摘要,并报告 Argo revision 是否对齐该 lane 的 GitOps latest。`v0.2` lane 的 source authority 只来自 k8s git-mirror snapshot:受控 sync 先为 branch tip 创建 `refs/unidesk/snapshots/agentrun-yaml-lane/<branch>/<commit>`,`status` / `trigger-current` / build 只读取该 snapshot 和 `sourceStageRef`,不得把 host source workspace、本地 fetch/pull、可变 branch ref 或 Pipeline 直连 GitHub 当 authoritative source。默认输出是 compact commander 视图:`target` 只保留 node/lane/source/runtime/CI/GitOps/git-mirror/database 摘要,关键结论在 `summary` 和 `alignment`,成功 probe 的 stdout/stderr tail、完整 YAML target、原始 `source`、`runtime`、`gitMirror` payload 默认省略;需要完整展开时使用返回的 `disclosure.fullCommand` 或显式加 `--full`,需要原始调试视图时加 `--raw`。`status` 额外支持 `--pipeline-run <name>` 与 `--source-commit <sha>` 定点查询;`--pipeline-run` 会读取 PipelineRun `revision` 参数作为 pinned source commit,并在 `alignment.branchDrift` / `summary.branchDrift` 中同时披露当前 snapshot tip、目标 source commit、PipelineRun source commit、是否已被当前 snapshot supersede 以及 `triggerLatest` 下一步。`status` 会向 stderr 输出 `agentrun.control-plane.status.progress` 阶段事件,覆盖 `source`、`runtime` 和 `git-mirror`,避免长时间聚合时无可见进展。`trigger-current` 会先执行 k8s git-mirror sync 并以 snapshot commit 创建 commit-pinned PipelineRun;同名 PipelineRun 正在运行或已经成功时必须拒绝重复触发,只允许在失败态或不存在时创建。该命令只提交 CI/CD 工作,不等待完整 PipelineRun 或 rollout 完成,后续用 `job status` 和 `status --pipeline-run <name>` 轮询。`refresh` 只对 YAML 声明的 Argo Application 执行 hard refresh,用于 GitOps promotion 已完成但 Argo 仍停留旧 revision 时的受控同步入口;它不直接 patch runtime workload。
|
||||
`status` 只读观察 YAML 选中 lane 的 source authority、对应 PipelineRun、GitOps latest、Argo Application、runtime workload、manager source commit 和 git mirror/Gitea 摘要,并报告 Argo revision 是否对齐该 lane 的 GitOps latest。未迁移的 legacy `v0.2` lane source authority 只来自 k8s git-mirror snapshot:受控 sync 先为 branch tip 创建 `refs/unidesk/snapshots/agentrun-yaml-lane/<branch>/<commit>`,`status` / `trigger-current` / build 只读取该 snapshot 和 `sourceStageRef`,不得把 host source workspace、本地 fetch/pull、可变 branch ref 或 Pipeline 直连 GitHub 当 authoritative source。默认输出是 compact commander 视图:`target` 只保留 node/lane/source/runtime/CI/GitOps/git-mirror/database 摘要,关键结论在 `summary` 和 `alignment`,成功 probe 的 stdout/stderr tail、完整 YAML target、原始 `source`、`runtime`、`gitMirror` payload 默认省略;需要完整展开时使用返回的 `disclosure.fullCommand` 或显式加 `--full`,需要原始调试视图时加 `--raw`。`status` 额外支持 `--pipeline-run <name>` 与 `--source-commit <sha>` 定点查询;`--pipeline-run` 会读取 PipelineRun `revision` 参数作为 pinned source commit,并在 `alignment.branchDrift` / `summary.branchDrift` 中同时披露当前 snapshot tip、目标 source commit、PipelineRun source commit、是否已被当前 snapshot supersede 以及 `triggerLatest` 下一步。`status` 会向 stderr 输出 `agentrun.control-plane.status.progress` 阶段事件,覆盖 `source`、`runtime` 和 `git-mirror`,避免长时间聚合时无可见进展。legacy `trigger-current` 会先执行 k8s git-mirror sync 并以 snapshot commit 创建 commit-pinned PipelineRun;同名 PipelineRun 正在运行或已经成功时必须拒绝重复触发,只允许在失败态或不存在时创建。该命令只提交 CI/CD 工作,不等待完整 PipelineRun 或 rollout 完成,后续用 `job status` 和 `status --pipeline-run <name>` 轮询。`refresh` 只对 YAML 声明的 Argo Application 执行 hard refresh,用于 GitOps promotion 已完成但 Argo 仍停留旧 revision 时的受控同步入口;它不直接 patch runtime workload。
|
||||
|
||||
JD01 `agentrun-jd01-v02` 已迁移为 Gitea webhook -> Pipelines-as-Code -> Tekton -> GitOps/Argo -> k8s runtime 的单一路径。该 lane 不再使用 branch-follower、Gitea Actions、act_runner 或自维护 `trigger-current` 作为 CI 触发器;对应 source authority、repo visibility、public exposure 和 mirror credentials 属于 `config/platform-infra/gitea.yaml`,PaC controller/Repository/webhook/Tekton 参数属于 `config/platform-infra/pipelines-as-code.yaml`。Gitea 的公开 Web UI 是 `https://gitea.pikapython.com`,但 CI、Argo 和 runtime 内部读取必须使用 `gitea-http.devops-infra.svc.cluster.local:3000` 的 ClusterIP URL,避免公网回环和 legacy git-mirror commit 缺失。
|
||||
|
||||
JD01 v0.2 PaC closeout 以 `bun scripts/cli.ts platform-infra pipelines-as-code status --target JD01` 为首选状态入口。默认输出必须能直接看到 webhook 是否存在、最新 PipelineRun/TaskRun duration、image status、env identity、digest、GitOps commit、Argo revision/health 和 runtime source/env annotation。env reuse 的通过证据是 `IMAGE_STATUS=reused`、同一 env identity 和稳定 digest;首次 cache miss 可以作为冷启动事实记录,但不能替代后续 env-reuse 秒级收口。
|
||||
|
||||
YAML-only lane 的 `trigger-current --confirm` 是受控长流程入口;k8s git-mirror snapshot sync、image build、GitOps publish、git-mirror flush 和 PipelineRun 创建必须拆成短提交与状态轮询,不得把 clone、build、push 或长时间 polling 放进一个顶层 `trans` 长连接。`trigger-current` 返回异步 job 时,先用 `bun scripts/cli.ts job status <jobId> --tail-bytes 12000` 观察 `agentrun-yaml-lane-trigger` progress,再用 `agentrun control-plane status --node <node> --lane <lane> --pipeline-run <name>` 观察 Tekton、GitOps 和 Argo 对齐。后台步骤的 `status` 与 `ok` 必须共同判定,`status=succeeded` 但 `ok=false` 是终态失败,不能继续轮询到超时。GitOps publish 必须使用隔离临时 clone/worktree,不能切换或污染任何固定 source workspace;`v0.2` 历史失败 publish 若留下 dirty/detached/GitOps branch 状态,不得通过 host workspace repair 恢复 source authority,只清理已知发布残留并从 git-mirror snapshot 重新触发。
|
||||
|
||||
|
||||
@@ -107,11 +107,11 @@ PipelineRun 失败或长时间未完成时,先按定点 `control-plane status
|
||||
- `hwlab cd status|audit|preflight|apply --env dev [--dry-run]` 是旧 D601 HWLAB DEV CD 指挥侧 wrapper,仅用于显式 legacy 诊断和迁移对照。默认通过 UniDesk provider `host.ssh` 进入 D601,再调用 HWLAB repo-owned `scripts/dev-cd-apply.mjs`,不内嵌发布 kubectl 逻辑:`status` 汇总固定 CD mirror、Git clean/main/origin-main、`deploy/deploy.json`/artifact catalog/report、D601 native k3s guard 和 CD Lease lock,并用 `scripts/dev-cd-apply.mjs --status --skip-live-verify` 取得 target/promotion 摘要;`audit` 在 k3s/CD 恢复后做只读健康审计,返回有界 JSON 的 blocker 分类、D601 guard/node、SecretRef 存在性、registry 可达性、Lease phase/holder/staleness、deploy.json 与 artifact/workload image 收敛、current Deployment image/revision/rollout、16666/16667 public health commit/readiness 和 DB/runtime durability 摘要;`preflight` 进一步检查必需 SecretRef 对象/键存在性并运行 HWLAB `scripts/dev-cd-apply.mjs --dry-run --skip-live-verify` 受控事务摘要。完整远端 stdout/stderr 写入 D601 `~/.state/unidesk-hwlab-cd/<run-id>/` 和本地 `.state/hwlab-cd/<run-id>/` task dump,stdout 只返回有界摘要。默认 HWLAB CD repo 是 `/home/ubuntu/hwlab_cd`,`/home/ubuntu/hwlab` runner 历史目录不得作为发布真相。wrapper 强制 `KUBECONFIG=/etc/rancher/k3s/k3s.yaml` 并只以这个显式目标作为 gate;显式目标出现 `docker-desktop`、`desktop-control-plane` 或 `127.0.0.1:11700` 信号会结构化拒绝,audit/preflight/apply --dry-run 都必须观察到 node `d601`。真实 apply 只暴露 `scripts/dev-cd-apply.mjs --apply --confirm-dev --confirmed-non-production --write-report` 命令形状并标注 host-commander-only,本 runner 不执行 live apply、rollout、Lease mutation 或 DEV deploy apply。长期规则见 `docs/reference/hwlab.md`。
|
||||
- `gh auth status [--repo owner/name]` 探测 GitHub 操作前置条件并输出脱敏 JSON:是否存在 `gh` binary、是否存在 `GH_TOKEN`/`GITHUB_TOKEN` 或可用 `gh auth token` fallback、REST API 是否可达、目标 repo 是否可见、issue 是否可读。degraded reason 必须归类为 `missing-binary`、`missing-token`、`auth-failed`、`github-transient`、`network-proxy-failed`、`permission-denied`、`repo-not-found`、`repo-forbidden`、`issue-not-found`、`pr-not-found`、`scope-insufficient`、`validation-failed`、`invalid-response` 或 `unsupported-command`,不得打印 token;失败对象必须包含 `runnerDisposition=infra-blocked|business-failed`,runner 应优先用该字段分流。`github-transient` 表示 GitHub DNS/API 连接在收到 HTTP 状态前失败,输出应带 `retryable=true` 或等价 commander action;这不是缺 token、认证失败、权限不足或 PR 语义失败。
|
||||
- `gh issue list [owner/repo] [--state open|closed|all] [--limit N] [--search text] [--title-prefix text] [--label label[,label...]]... [--repo owner/name] [--json number,title,state,url,updatedAt,createdAt,author,labels] [--raw|--full]` 通过 GitHub REST 列出 issue,默认 `state=open`、`limit=30`,输出稳定 JSON 且不依赖系统 `gh` binary。`owner/repo` 位置参数是 `--repo owner/repo` 的兼容别名;若位置 repo 与 `--repo` 冲突,或位置参数不是 `owner/repo`,必须结构化失败,禁止静默 fallback 到默认 repo。`--limit` 是 CLI 返回上限,不等同 GitHub 单页 `per_page`:当 `--limit > 100` 或默认页中混入 PR 时,CLI 必须分页抓取 GitHub REST/Search page,过滤 PR 后再返回 issue,并在输出中披露 `pagination.fetchedPages/rawCount/hasMore`;`hasMore=true` 时只能说明当前有界扫描未穷尽,禁止把它当作“仓库没有更多 issue”。`--search` 使用 GitHub Search Issues API,并自动追加 `repo:<owner>/<name>`、`type:issue` 和 state qualifier,用于创建新 issue 前做低摩擦查重;`--title-prefix` 在当前有界结果内按 issue 标题 `startsWith` 做本地过滤,输出 `titleFilter.inputCount/outputCount/filteredOut`,适合 `[FEEDBACK]` 等标题规范去重;未知 state 或未知 `--json` 字段必须结构化失败并带 `runnerDisposition=business-failed`。`--label` 是 GitHub REST `labels=label1,label2` 或 Search `label:` 服务端过滤,支持重复 `--label` 和逗号分隔;filter 不在本命令上下文中使用(如 `issue read`、`pr list`)必须结构化失败并指明 `gh issue create/list/stale-close` 才是合法作用域。GitHub issues API 可能混入 PR,CLI 会从 `.data.issues` 中过滤 pull request。`--raw|--full` 在 `gh issue list` 上是绕过 20 KiB stdout 截断的显式开关:响应结果会带 `noDump=true`,`output.ts` 据此跳过 head/tail 替换并把完整数据 inline 输出;当响应未超阈值时 `--raw|--full` 行为等价默认。
|
||||
- `gh issue lifecycle`:`--state` 只能作为 `gh issue list` / `gh issue board-row list` / `gh pr list` 的过滤参数;`gh issue update` / `gh issue edit` 只写 body/title,**不接受** `--state` 改 open/closed。把 `gh issue update <n> --state closed` 落到错命令上时,CLI 必须返回 `validation-failed` 并显式提示 `gh issue close <n>` / `gh issue reopen <n>`(PR 用 `gh pr close|reopen <n>`),并把 5 条受支持命令放进 `supportedCommands`,禁止把"无 `--state` 改 issue 状态"的命令升级为"接受 `--state`"。`gh issue close|reopen` 成功输出默认是 compact issue 摘要,不得回显完整 `issue.body`;人工正文读取优先使用 `trans gh:/owner/repo/issue/<number> cat|rg`,需要 JSON 结构化元数据时再使用返回的 `readCommands` 或 `gh issue view --json body|--full|--raw`。生命周期 close/reopen 的评论推荐用 `--comment-stdin <<'EOF'` 直接写 heredoc/stdin;短单行可用 `--comment`,已有复用文件才用 `--comment-file`。需要附长篇 CLI 验收证据时,先用 `gh issue comment create <n> --body-stdin <<'EOF'` 写证据评论,再用 `gh issue close <n> --comment <短引用>` 关闭。issue 硬删除走 `close`,PR 硬删除走 `close`,两者都没有"delete"语义。
|
||||
- `gh issue comment create <number|owner/repo#number> --repo owner/name --body-stdin`、`gh issue comment update|edit <commentId> --repo owner/name --body-stdin`、`gh issue comment delete <commentId|owner/repo#number> --repo owner/name`、`gh issue close <number|owner/repo#number> --repo owner/name [--comment <text>|--comment-stdin]`、`gh issue reopen <number|owner/repo#number> --repo owner/name [--comment <text>|--comment-stdin]`、`gh issue update <number|owner/repo#number> --repo owner/name [--title ...] [--body-stdin]`、`gh issue edit <number|owner/repo#number> ...`、`gh issue board-row get|update|add|move|delete|upsert <number|owner/repo#number> --repo owner/name ...` 都接受与 `gh issue view|read`、`gh pr *` 一致的 `owner/repo#number` 位置 shorthand;shorthand 与显式 `--repo` 冲突时结构化失败并把两者都回显到错误对象里,避免静默改写目标 repo。`gh issue view|read`、`gh pr view|read|files|diff|preflight|closeout|comment create|comment update|comment edit|comment delete|close|reopen|merge|edit|update` 已长期支持该 shorthand;comment update/edit/delete 的 `--number` 表示 commentId,不是 issue/PR number。issue 写命令对齐后整个 `gh` 子命令在 shorthand 行为上保持一致,不再需要把 `pikasTech/HWLAB#621` 拆成 `621 --repo pikasTech/HWLAB`。来源:HWLAB #621 CLI 验收 `gh issue comment create pikasTech/HWLAB#621` 摩擦改进。
|
||||
- `gh issue lifecycle`:`--state` 只能作为 `gh issue list` / `gh issue board-row list` / `gh pr list` 的过滤参数;`gh issue update` / `gh issue edit` 只写 body/title,**不接受** `--state` 改 open/closed。把 `gh issue update <n> --state closed` 落到错命令上时,CLI 必须返回 `validation-failed` 并显式提示 `gh issue close <n>` / `gh issue reopen <n>`(PR 用 `gh pr close|reopen <n>`),并把 5 条受支持命令放进 `supportedCommands`,禁止把"无 `--state` 改 issue 状态"的命令升级为"接受 `--state`"。`gh issue close|reopen` 成功输出默认是 compact issue 摘要,不得回显完整 `issue.body`;人工正文读取优先使用 `trans gh:/owner/repo/issue/<number> cat|rg`,需要 JSON 结构化元数据时再使用返回的 `readCommands` 或 `gh issue view --json body|--full|--raw`。生命周期 close/reopen 的评论只支持 `--comment-stdin <<'EOF'` quoted heredoc/stdin;内联 `--comment` 和生命周期 `--comment-file` 都必须结构化拒绝,避免 shell 转义污染 Markdown。需要附长篇 CLI 验收证据时,先用 `gh issue comment create <n> --body-stdin <<'EOF'` 写证据评论,再用 `gh issue close <n> --comment-stdin <<'EOF'` 写简短中文收口。issue 硬删除走 `close`,PR 硬删除走 `close`,两者都没有"delete"语义。
|
||||
- `gh issue comment create <number|owner/repo#number> --repo owner/name --body-stdin`、`gh issue comment update|edit <commentId> --repo owner/name --body-stdin`、`gh issue comment delete <commentId|owner/repo#number> --repo owner/name`、`gh issue close <number|owner/repo#number> --repo owner/name [--comment-stdin]`、`gh issue reopen <number|owner/repo#number> --repo owner/name [--comment-stdin]`、`gh issue update <number|owner/repo#number> --repo owner/name [--title ...] [--body-stdin]`、`gh issue edit <number|owner/repo#number> ...`、`gh issue board-row get|update|add|move|delete|upsert <number|owner/repo#number> --repo owner/name ...` 都接受与 `gh issue view|read`、`gh pr *` 一致的 `owner/repo#number` 位置 shorthand;shorthand 与显式 `--repo` 冲突时结构化失败并把两者都回显到错误对象里,避免静默改写目标 repo。`gh issue view|read`、`gh pr view|read|files|diff|preflight|closeout|comment create|comment update|comment edit|comment delete|close|reopen|merge|edit|update` 已长期支持该 shorthand;comment update/edit/delete 的 `--number` 表示 commentId,不是 issue/PR number。issue 写命令对齐后整个 `gh` 子命令在 shorthand 行为上保持一致,不再需要把 `pikasTech/HWLAB#621` 拆成 `621 --repo pikasTech/HWLAB`。来源:HWLAB #621 CLI 验收 `gh issue comment create pikasTech/HWLAB#621` 摩擦改进。
|
||||
|
||||
- `gh issue stale-close [--repo owner/name] [--inactive-hours N] [--limit N] [--label label[,label...]]... [--dry-run]` 是可复用批量生命周期清理入口,用于“超过 N 小时无回复或修改的 open issue 一律关闭”这类策略。判定基准固定为 GitHub `updatedAt < observedAt - inactiveHours`,issue comment、body/title 修改和 state 变化都会刷新 `updatedAt` 并视为活跃;PR 必须过滤,不参与 issue 关闭。默认 `inactive-hours=48`,默认扫描预算为 issue list 上限,输出必须包含 `observedAt`、`cutoffAt`、`scannedCount`、`staleCount`、`pagination.hasMore`、候选/关闭 issue 的 compact 摘要和失败列表,不得打印完整正文。正式关闭前建议先跑 `--dry-run`;真实执行后用同一命令加 `--dry-run` 验证 `staleCount=0`,且只有 `hasMore=false` 才能把当前扫描视为完整穷尽。HWLAB 当前长期策略使用 `bun scripts/cli.ts gh issue stale-close --repo pikasTech/HWLAB --inactive-hours 48 --dry-run` 观察,再移除 `--dry-run` 关闭。
|
||||
- `gh issue view <number|url|owner/repo#number> [--repo owner/name] [--json body,title,state,comments] [--raw|--full]` 通过 GitHub REST 读取 issue title/body/state/url 和 comments,默认输出 JSON;`read` 只保留为 UniDesk 兼容别名。`view` 对齐 GitHub CLI 标准位置参数:接受正整数、`https://github.com/owner/repo/issues/<number>` URL 或 `owner/repo#number` shorthand。`--number N` 也作为低摩擦兼容别名用于单 issue/comment 数字目标命令,并在成功响应里返回 `standardSyntaxHint` 提示标准位置参数写法;comment update/edit/delete 中的 `--number` 表示 commentId,不是 issue number;`list/create/scan-escape/cleanup-plan/board-audit/board-row list` 这类没有单数字目标的命令仍拒绝 `--number`。URL 和 shorthand 会自动派生 `--repo owner/repo` 与 issue number;若同时提供冲突的显式 `--repo`,CLI 必须结构化失败并给出 `gh issue view <number> --repo owner/repo --json body,title,state,comments` 与 shorthand raw 的可执行命令。兼容旧脚本的 `--json body` 和 `--json body,title,state,comments` 字段选择,且正文仍稳定暴露在 `.data.issue.body`,避免调用方因为 JSON 路径变化把空值当成正文。字段白名单是 `body,title,state,comments,number,url,author,createdAt,updatedAt`,未知字段必须结构化失败并带 `runnerDisposition=business-failed`。`--raw` 与 `--full` 是显式完整披露别名:view/read 会选择完整支持字段集;issue update/edit 只有显式传入时才在成功响应里包含完整 `.data.issue.body`。当最终 `gh` JSON 超过 20 KiB 时,CLI 必须把完整 JSON 写入 `/tmp/unidesk-cli-output/*.json`,stdout 只返回 `outputTruncated=true`、dump path、总 bytes/lines 和 head/tail 预览。默认 list/view 输出仍不得扩散到无界非 JSON 文本。`gh issue create --title <title> --body-stdin [--label label[,label...]]... [--dry-run]`、`gh issue update <number> --mode replace|append --body-stdin [--title ...] [--dry-run] [--full|--raw]`、`gh issue comment create <number> (--body-stdin|--body <short-text>) [--dry-run]`、`gh issue comment update|edit <commentId> (--body-stdin|--body <short-text>) [--dry-run]`、`gh issue comment delete <commentId> [--dry-run]`、`gh issue close|reopen <number> [--comment <short-text>|--comment-stdin] [--dry-run]`、`gh issue stale-close [--inactive-hours N] [--dry-run]` 都走 REST,不依赖 `gh` binary。`--body-stdin` 和 `--comment-stdin` 是多行 Markdown 的第一等 heredoc/stdin 入口;`--body-file` / `--comment-file` 只在已有复用文件时使用。`--body` 仅用于 issue comment 的短单行文本;空白、多行、疑似 shell 污染、secret-like 或过长 inline body 必须结构化失败。`comment update/edit` 使用 GitHub issue comment PATCH 端点并保留评论 ID,日常修正文案优先用 update/edit,delete 只用于确实需要删除的评论。`--label` 用于 `issue create`、`issue list` 和 `issue stale-close`,支持重复传入和逗号分隔;`issue create --dry-run` 会展示解析后的 labels 与 request plan,正式创建时把 labels 放入 GitHub REST create-issue payload,GitHub 返回不存在 label 等 422 校验失败时 CLI 结构化返回 `validation-failed`,不静默成功。`gh issue delete <number>` 是结构化 `unsupported-command`,因为 GitHub REST 不支持 issue 硬删除;生命周期删除语义请使用 `close`。
|
||||
- `gh issue view <number|url|owner/repo#number> [--repo owner/name] [--json body,title,state,comments] [--raw|--full]` 通过 GitHub REST 读取 issue title/body/state/url 和 comments,默认输出 JSON;`read` 只保留为 UniDesk 兼容别名。`view` 对齐 GitHub CLI 标准位置参数:接受正整数、`https://github.com/owner/repo/issues/<number>` URL 或 `owner/repo#number` shorthand。`--number N` 也作为低摩擦兼容别名用于单 issue/comment 数字目标命令,并在成功响应里返回 `standardSyntaxHint` 提示标准位置参数写法;comment update/edit/delete 中的 `--number` 表示 commentId,不是 issue number;`list/create/scan-escape/cleanup-plan/board-audit/board-row list` 这类没有单数字目标的命令仍拒绝 `--number`。URL 和 shorthand 会自动派生 `--repo owner/repo` 与 issue number;若同时提供冲突的显式 `--repo`,CLI 必须结构化失败并给出 `gh issue view <number> --repo owner/repo --json body,title,state,comments` 与 shorthand raw 的可执行命令。兼容旧脚本的 `--json body` 和 `--json body,title,state,comments` 字段选择,且正文仍稳定暴露在 `.data.issue.body`,避免调用方因为 JSON 路径变化把空值当成正文。字段白名单是 `body,title,state,comments,number,url,author,createdAt,updatedAt`,未知字段必须结构化失败并带 `runnerDisposition=business-failed`。`--raw` 与 `--full` 是显式完整披露别名:view/read 会选择完整支持字段集;issue update/edit 只有显式传入时才在成功响应里包含完整 `.data.issue.body`。当最终 `gh` JSON 超过 20 KiB 时,CLI 必须把完整 JSON 写入 `/tmp/unidesk-cli-output/*.json`,stdout 只返回 `outputTruncated=true`、dump path、总 bytes/lines 和 head/tail 预览。默认 list/view 输出仍不得扩散到无界非 JSON 文本。`gh issue create --title <title> --body-stdin [--label label[,label...]]... [--dry-run]`、`gh issue update <number> --mode replace|append --body-stdin [--title ...] [--dry-run] [--full|--raw]`、`gh issue comment create <number> (--body-stdin|--body <short-text>) [--dry-run]`、`gh issue comment update|edit <commentId> (--body-stdin|--body <short-text>) [--dry-run]`、`gh issue comment delete <commentId> [--dry-run]`、`gh issue close|reopen <number> [--comment-stdin] [--dry-run]`、`gh issue stale-close [--inactive-hours N] [--dry-run]` 都走 REST,不依赖 `gh` binary。`--body-stdin` 和 `--comment-stdin` 是多行 Markdown 的第一等 heredoc/stdin 入口;`--body-file` 只在已有复用文件时使用;生命周期 `--comment-file` 不支持。`--body` 仅用于 issue comment 的短单行文本;空白、多行、疑似 shell 污染、secret-like 或过长 inline body 必须结构化失败。`comment update/edit` 使用 GitHub issue comment PATCH 端点并保留评论 ID,日常修正文案优先用 update/edit,delete 只用于确实需要删除的评论。`--label` 用于 `issue create`、`issue list` 和 `issue stale-close`,支持重复传入和逗号分隔;`issue create --dry-run` 会展示解析后的 labels 与 request plan,正式创建时把 labels 放入 GitHub REST create-issue payload,GitHub 返回不存在 label 等 422 校验失败时 CLI 结构化返回 `validation-failed`,不静默成功。`gh issue delete <number>` 是结构化 `unsupported-command`,因为 GitHub REST 不支持 issue 硬删除;生命周期删除语义请使用 `close`。
|
||||
- `gh issue update <number> --mode replace|append --body-stdin` 是正文更新主入口,`edit` 保留为兼容别名。`replace` 用 heredoc/stdin 正文替换现有 body;`append` 先读取当前 body,再按 UTF-8 stdin 字节追加,保留真实换行、反引号和 Markdown 表格。更新默认拒绝字面量 `null`、空白正文和过短正文;只有真实需要写短正文时才允许显式加 `--allow-short-body`,返回 JSON 会报告该风险。#20 总看板和指挥简报类 issue 是长期 body-only issue,`--body-profile auto` 会按 issue number 自动启用 #20/#24 legacy guard:#20 必须包含 `## 看板(OPEN)`,#24 legacy 指挥简报必须包含 `## 常驻观察与长期建议`。显式 `--body-profile commander-brief` 不再固定 #24;#24 仍兼容,标题为 `YYYY-MM-DD 指挥简报(北京时间)` 或既有正文首行/关键 heading 表明为每日滚动指挥简报的 issue 也合法,并仍必须包含 `## 常驻观察与长期建议`。对非简报 issue 显式使用 `commander-brief` 会结构化失败为 `profile-issue-mismatch`。`--dry-run` 不 PATCH GitHub,输出有界 `bodyPreview`/`bodyPreviewLines`、新正文长度、SHA、关键标题检查结果、字面量 `\n`、反引号、Markdown 表格、shell 污染信号、`guard`、`concurrency`、`bodyOnlySafety` 和 `wouldPatch`;若环境里有 `GH_TOKEN` 或 `GITHUB_TOKEN`,dry-run 还会只读抓取旧正文长度、SHA 和 `updatedAt` 作为更新前对照。正式写入默认先读取当前 issue,执行 guard 和显式 `--expect-*` 并发校验,再 PATCH;成功输出 compact issue 摘要、old/new body SHA、updatedAt、bodySource 和 drill-down `readCommands`,不包含完整 `issue.body`。完整正文必须显式 `--full|--raw` 或后续执行 `readCommands.body/full/raw` 获取。
|
||||
- #20 只允许承担长期 UniDesk 指挥官 / Code Queue / CLI / infra 治理总看板职责;每日进展必须写入当天滚动指挥简报 issue,并由 #20 顶部“指挥简报索引”引用。HWLAB 用户反馈、Cloud Workbench、DEV-LIVE、M3 虚拟硬件可信闭环等产品 issue 必须写到 `pikasTech/HWLAB`;#20 只可记录 UniDesk 侧 commander/Code Queue/CLI/infra 支撑工作。`gh issue view/read 20` 会返回 `codeQueueBoardHint`;`gh issue update/edit 20` 的 body guard 会拒绝 `## 更新 YYYY-MM-DD HH:mm 北京时间`、`## YYYY-MM-DD HH:mm 北京时间指挥更新` 和 `### YYYY-MM-DD HH:mm CST:...` 这类简报段落;把 `pikasTech/HWLAB#N`、`HWLAB#N` 或 HWLAB 产品/live 验证行写入 #20 时只返回 warning 和 `codeQueueBoardHint`,不再拒绝正文 replace,以避免历史正文或治理交叉引用造成次生阻塞;`gh issue board-row list|get|update|add|move|delete|upsert --board-issue 20` 也会返回同一 hint,提醒不要把每日简报或 HWLAB 产品看板混入 #20。
|
||||
- `gh issue edit 24 --body-stdin --notify-claudeqq-brief-diff [--dry-run] <<'EOF'` 是 legacy #24 指挥简报的通知入口。正式执行会先读取 GitHub 上 #24 旧正文并通过 #24 body profile guard,再从 heredoc/stdin 读取新正文;随后先 PATCH issue 主体,再把本次新增的 `## 更新 YYYY-MM-DD HH:MM 北京时间` 段落发送给 ClaudeQQ,ClaudeQQ 失败不会回滚 issue 正文,失败只体现在返回 JSON 的 `claudeqq.ok=false` 和结构化 `degradedReason`。每日滚动简报 issue 可用普通 `gh issue update <number> --body-profile commander-brief --dry-run` 和并发 guard 更新,但此通知 helper 仍只支持 #24。带通知 flag 的 `--dry-run` 不 PATCH、不发送;它按新正文做发送预览,并在输出中标明非 dry-run 才会读取旧正文做可靠 diff。默认 ClaudeQQ 目标是私聊 `645275593`,默认 base URL 是 UniDesk 受控入口 `http://backend-core:8080/api/microservices/claudeqq/proxy`;`UNIDESK_COMMANDER_BRIEF_CLAUDEQQ_BASE_URL` 只接受 backend-core `/api/microservices/claudeqq/proxy` 等价路径,非 proxy URL 会结构化为 `notification-path-unavailable`。可用 `UNIDESK_COMMANDER_BRIEF_CLAUDEQQ_ENABLED`、`UNIDESK_COMMANDER_BRIEF_CLAUDEQQ_TARGET_TYPE`、`UNIDESK_COMMANDER_BRIEF_CLAUDEQQ_USER_ID`、`UNIDESK_COMMANDER_BRIEF_CLAUDEQQ_GROUP_ID` 和 `UNIDESK_COMMANDER_BRIEF_CLAUDEQQ_TIMEOUT_MS` 调整开关、目标和超时。
|
||||
|
||||
@@ -10,6 +10,15 @@
|
||||
- Do not hide image versions, namespace names, endpoint URLs, FRP ports, or profile lists in Python/TOML/JSON helper constants when they are UniDesk-owned choices. External tools may still require their own TOML/JSON/env file formats at the edge.
|
||||
- Fresh node outbound bootstrap uses the zero-dependency host proxy boundary defined in `docs/reference/yaml-first-ops.md`. Platform-infra egress proxy settings may provide the benchmark-validated proxy source and workload consumer settings, but a new node must not depend on Docker, k3s, containerd or package-manager network access to install the initial host proxy client.
|
||||
|
||||
## Gitea And Pipelines-as-Code Boundary
|
||||
|
||||
- Gitea mirror and Pipelines-as-Code are platform-infra CI source/trigger services operated by UniDesk. Their durable configuration lives in `config/platform-infra/gitea.yaml` and `config/platform-infra/pipelines-as-code.yaml`; do not hide repo URLs, mirror repo names, webhook settings, public exposure, FRP/Caddy ports, token sourceRefs or PaC Repository params in helper constants.
|
||||
- The canonical Gitea entrypoints are `bun scripts/cli.ts platform-infra gitea plan|apply|status|validate|mirror --target <node>` and `bun scripts/cli.ts platform-infra gitea mirror plan|bootstrap|sync|status --target <node>`. Mirror bootstrap/sync must repair declared repo/org visibility such as `publicRead: true`; create-time defaults alone are not enough for long-lived repos.
|
||||
- The canonical PaC entrypoints are `bun scripts/cli.ts platform-infra pipelines-as-code plan|apply|status|webhook-test --target <node>`. PaC status is the operator-facing closeout surface for migrated CI lanes and must expose webhook count, latest PipelineRun/TaskRun duration, image status, env identity, digest, GitOps commit, Argo revision and runtime provenance without requiring raw `kubectl`, `tkn` or Gitea UI inspection.
|
||||
- Public Gitea UI may use the YAML-declared HTTPS hostname, but k8s-internal consumers must use the ClusterIP service URL from YAML. Internal CI/Argo/runtime reads must not loop through public DNS/Caddy/FRP, and migrated lanes must not fall back to legacy git-mirror read URLs when the commit exists only in Gitea.
|
||||
- A PaC-migrated lane must keep a single trigger path: Gitea webhook -> Pipelines-as-Code -> Tekton -> GitOps/Argo -> k8s runtime. Do not add Gitea Actions, `act_runner`, branch-follower or custom script fallback unless a later issue explicitly changes the architecture.
|
||||
- k8s runtime remains Docker-free from the point it pulls already built images. CI build steps may use YAML-declared native build tooling, but Docker socket/daemon access must not become part of the runtime plane.
|
||||
|
||||
## Secret Distribution Boundary
|
||||
|
||||
- UniDesk-owned platform service credential distribution must be YAML-controlled: declare the sourceRef, source key, target Secret, and target key first, then use the controlled CLI to sync/apply it. Runtime Kubernetes Secrets, pod env, logs, and database state are observation surfaces, not credential source of truth.
|
||||
|
||||
Reference in New Issue
Block a user