agents-gitflow-guard 0.0.8 → 0.0.10

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 CHANGED
@@ -36,12 +36,16 @@ You define your own branches —
36
36
 
37
37
  ## Quick Start — 30 seconds to a guarded repo
38
38
 
39
- **Step 1 — install**, one command, then restart DSH (plugins load at process startup):
39
+ **Step 1 — install**, then restart DSH (plugins load at process startup):
40
40
 
41
41
  ```bash
42
+ # installs the latest release
42
43
  dsh plugin --profile web add agents-gitflow-guard
44
+ # ...or pin an exact known-good version (recommended; also bypasses stale registry caches)
45
+ dsh plugin --profile web add agents-gitflow-guard@0.0.9
43
46
  ```
44
47
 
48
+ > **Version gotcha**: a bare `add` resolves whatever `latest` is at install time — on machines behind a stale npm/pnpm registry cache or mirror it may install an old version. If the installed version looks wrong, pin it explicitly. The peer-dependency *warning* pnpm may print is expected: DSH supplies `@deepseek-ai/cordis` / `@deepseek-ai/dsh-tools` through its shared profile module fallback at startup (the plugin works normally).
45
49
  **Step 2 — configure**, create `gitflow-guard.config.json` in your **project root**:
46
50
 
47
51
  ```jsonc
@@ -204,7 +208,7 @@ archive (optional; you archive after release)
204
208
  | **integration** | `branches.integration` | always | no direct push (default `pr`); features merge in via PR/MR |
205
209
  | **preview** | `branches.preview` (array) | optional | no direct push; updates via PR/MR only (env endpoints) |
206
210
  | **production** | `branches.production` (array) | optional | PR/MR only; merge by user only (`mergeBy: "user"`) |
207
- | **archive** | `branches.archive` (array) | optional | user-hand only agents cannot even create a PR |
211
+ | **archive** | `branches.archive` (array) | optional | archive PR/MR may be created by agents; the merge stays user-hand only |
208
212
 
209
213
  ### Customizing branch names & rules — any naming works
210
214
 
@@ -274,7 +278,7 @@ archive (optional; you archive after release)
274
278
  | direct push / force-push / delete integration / preview / production / archive | 🚫 block (integration/preview `flexible` direct push allowed) |
275
279
  | PR/MR: feature → integration / preview | ✅ allow |
276
280
  | PR/MR: feature → production | ✅ allow to create; **merge blocked** (you merge in UI) |
277
- | PR/MR targeting archive | 🚫 block |
281
+ | PR/MR into archive | ✅ create allowed; 🚫 merge blocked (you merge in UI) |
278
282
  | local `git merge feature/x` while on integration / preview | 🚫 block (PR/MR required); `update: flexible` allows |
279
283
  | chained commands (`checkout develop && merge feature/x`) | 🚫 blocked — branch switches are simulated per segment, no bypass |
280
284
 
@@ -295,7 +299,7 @@ The PR/MR target is resolved via `gh pr view` (GitHub) or `glab mr view` (GitLab
295
299
  **From the npm registry** — the standard path, already covered in [Quick Start](#quick-start--30-seconds-to-a-guarded-repo):
296
300
 
297
301
  ```bash
298
- dsh plugin --profile web add agents-gitflow-guard
302
+ dsh plugin --profile web add agents-gitflow-guard@0.0.9 # pin recommended, see note above
299
303
  ```
300
304
 
301
305
  Then restart DSH. Upgrades are the same command, followed by another restart.
package/README.zh.md CHANGED
@@ -35,12 +35,16 @@
35
35
 
36
36
  ## 快速开始——30 秒用上
37
37
 
38
- **第 1 步——安装**,一条命令,然后重启 DSH(插件在进程启动时加载):
38
+ **第 1 步——安装**,然后重启 DSH(插件在进程启动时加载):
39
39
 
40
40
  ```bash
41
+ # 安装最新版
41
42
  dsh plugin --profile web add agents-gitflow-guard
43
+ # ...或锁定已知良好版本(推荐; 同时绕开 registry 陈旧缓存)
44
+ dsh plugin --profile web add agents-gitflow-guard@0.0.9
42
45
  ```
43
46
 
47
+ > **版本坑**: 裸 `add` 装的是安装时刻的 `latest`——在 npm/pnpm 注册表缓存或镜像陈旧的机器上可能拿到旧版本。看到版本不对就锁版本。pnpm 打印的 peer 依赖 *警告* 属预期: DSH 启动时经共享模块回退提供 `@deepseek-ai/cordis` / `@deepseek-ai/dsh-tools`(插件正常工作)。
44
48
  **第 2 步——配置**,在**项目根目录**创建 `gitflow-guard.config.json`:
45
49
 
46
50
  ```jsonc
@@ -201,7 +205,7 @@ archive(可选, 发布后你亲手归档)
201
205
  | **integration** | `branches.integration` | 必填 | 禁直推(默认 `pr`);feature 只经 PR/MR 合入 |
202
206
  | **preview** | `branches.preview`(数组) | 可选 | 禁直推;只走 PR/MR(环境终点) |
203
207
  | **production** | `branches.production`(数组) | 可选 | 只走 PR/MR;合并仅限你(`mergeBy: "user"`) |
204
- | **archive** | `branches.archive`(数组) | 可选 | 仅用户——agent 连建 PR 都不行 |
208
+ | **archive** | `branches.archive`(数组) | 可选 | 允许 agent 创建指向它的 PR/MR; 合并仍限用户亲手 |
205
209
 
206
210
  ### 自定义分支名与规则——任何命名都可以
207
211
 
@@ -292,7 +296,7 @@ PR/MR 目标通过 `gh pr view`(GitHub)或 `glab mr view`(GitLab)解析;没有
292
296
  **从 npm registry**——标准路径,已在[快速开始](#快速开始30-秒用上)覆盖:
293
297
 
294
298
  ```bash
295
- dsh plugin --profile web add agents-gitflow-guard
299
+ dsh plugin --profile web add agents-gitflow-guard@0.0.9 # 建议锁版本, 见上文提示
296
300
  ```
297
301
 
298
302
  然后重启 DSH。升级用同一命令,再重启一次。
@@ -438,7 +442,7 @@ MIT,免费,无条件。随便用、随便改、随便发,唯一义务是保留
438
442
  | **integration** | 集成分支,唯一必填角色(`branches.integration`);feature 经 PR/MR 合入;受保护 |
439
443
  | **preview** | 可选环境终点分支(`branches.preview`,数组);只走 PR/MR 更新 |
440
444
  | **production** | 可选生产分支(`branches.production`,数组);PR/MR + 合并仅限用户 |
441
- | **archive** | 可选发布后归档分支(`branches.archive`);仅用户亲手 |
445
+ | **archive** | `branches.archive`(数组) | 可选 | 允许 agent 创建指向它的 PR/MR; 合并仍限用户亲手 |
442
446
  | **feature 分支** | 你的工作分支,由 `featurePattern` 识别;自由区 |
443
447
  | **门禁矩阵** | 把每条被分类的命令映射为放行/拦截的判定表 |
444
448
  | **pre-execute** | 工具管线中拦截发生的钩子——在命令运行之前 |
package/lib/cli.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { c as findRepoRoot, d as resolveLocale, f as loadConfig, i as formatDeny, l as gitRunner, m as classify, o as stateDir, p as roleMatches, r as evaluateCommand, s as currentBranch, u as makeT } from "./src-2TtpUFC9.mjs";
1
+ import { c as findRepoRoot, d as resolveLocale, f as loadConfig, i as formatDeny, l as gitRunner, m as classify, o as stateDir, p as roleMatches, r as evaluateCommand, s as currentBranch, u as makeT } from "./src-CeEqUVQP.mjs";
2
2
  import { readFile } from "node:fs/promises";
3
3
  import { join } from "node:path";
4
4
  //#region src/platform.ts
package/lib/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { a as name, i as formatDeny, n as apply, o as stateDir, r as evaluateCommand, t as appendAudit } from "./src-2TtpUFC9.mjs";
1
+ import { a as name, i as formatDeny, n as apply, o as stateDir, r as evaluateCommand, t as appendAudit } from "./src-CeEqUVQP.mjs";
2
2
  export { appendAudit, apply, evaluateCommand, formatDeny, name, stateDir };
@@ -97,6 +97,7 @@ function parsePush(args, ctx) {
97
97
  for (const a of args) if (a === "-f" || a === "--force" || a === "--force-with-lease" || a.startsWith("--force-with-lease=")) force = true;
98
98
  else if (a === "--delete" || a === "-d") isDelete = true;
99
99
  else if (a === "--all" || a === "--mirror") all = true;
100
+ else if (a === "--tags") return [{ kind: "other" }];
100
101
  else if (a.startsWith("-")) {} else nonFlag.push(a);
101
102
  if (all) return [{
102
103
  kind: "push",
@@ -113,10 +114,15 @@ function parsePush(args, ctx) {
113
114
  delete: false
114
115
  }];
115
116
  return refspecs.map((ref) => {
117
+ let refForce = force;
118
+ if (ref.startsWith("+")) {
119
+ refForce = true;
120
+ ref = ref.slice(1);
121
+ }
116
122
  if (ref.startsWith(":")) return {
117
123
  kind: "push",
118
124
  dst: stripRefPrefix(ref.slice(1)) || null,
119
- force,
125
+ force: refForce,
120
126
  delete: true
121
127
  };
122
128
  const colon = ref.indexOf(":");
@@ -126,20 +132,20 @@ function parsePush(args, ctx) {
126
132
  return {
127
133
  kind: "push",
128
134
  dst: dst ? stripRefPrefix(dst) : null,
129
- force,
135
+ force: refForce,
130
136
  delete: deleteTarget || isDelete
131
137
  };
132
138
  }
133
139
  if (ref === "HEAD") return {
134
140
  kind: "push",
135
141
  dst: ctx.currentBranch ?? null,
136
- force,
142
+ force: refForce,
137
143
  delete: isDelete
138
144
  };
139
145
  return {
140
146
  kind: "push",
141
147
  dst: stripRefPrefix(ref),
142
- force,
148
+ force: refForce,
143
149
  delete: isDelete
144
150
  };
145
151
  });
@@ -379,8 +385,6 @@ const en = {
379
385
  "mergeFeature.next": (v) => `Push the feature branch first, then open a PR/MR into ${v.branch}.`,
380
386
  "prCreateNoTarget.why": () => "Cannot determine the PR/MR target branch",
381
387
  "prCreateNoTarget.next": (v) => `Specify --base/--target-branch explicitly (e.g. \`gh pr create --base ${v.base}\`).`,
382
- "prCreateArchive.why": () => "Archive branches are user-managed; PRs/MRs into them are not allowed",
383
- "prCreateArchive.next": () => "Do the release/archive yourself in your terminal or UI.",
384
388
  "prCreateHead.why": (v) => `Current branch (${v.head}) is not a feature branch, so it cannot be the source of a PR/MR into ${v.role}`,
385
389
  "prCreateHead.next": () => "Open the PR/MR into integration/preview/production from a feature/topic branch.",
386
390
  "prMergeProduction.why": () => "Merging into production is allowed only by you (click merge)",
@@ -449,8 +453,6 @@ const zh = {
449
453
  "mergeFeature.next": (v) => `先推 feature 分支, 再创建指向 ${v.branch} 的 PR/MR`,
450
454
  "prCreateNoTarget.why": () => "无法确定 PR/MR 目标分支",
451
455
  "prCreateNoTarget.next": (v) => `请显式指定 --base/--target-branch(如 gh pr create --base ${v.base})`,
452
- "prCreateArchive.why": () => "归档分支(archive)仅用户亲手操作, 不允许创建指向它的 PR/MR",
453
- "prCreateArchive.next": () => "发布/归档由你自己在终端或 UI 完成",
454
456
  "prCreateHead.why": (v) => `当前分支(${v.head})不是 feature 分支, 不能作为指向${v.role}的 PR/MR 源`,
455
457
  "prCreateHead.next": () => "请从 feature/topic 分支上创建指向集成/预览/生产分支的 PR/MR",
456
458
  "prMergeProduction.why": () => "合入生产(production)分支仅允许用户亲手点合并",
@@ -598,7 +600,6 @@ function decidePrCreate(c, facts, config, t) {
598
600
  const targetRole = roleOfBranch(c.target, config);
599
601
  const head = facts.currentBranch;
600
602
  const headRole = roleOfBranch(head, config);
601
- if (targetRole === "archive") return deny(t("prCreateArchive.why"), t("prCreateArchive.next"));
602
603
  if (targetRole === "integration" || targetRole === "preview" || targetRole === "production") {
603
604
  if (headRole !== "feature") return deny(t("prCreateHead.why", {
604
605
  head: head ?? t("head.unknown"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agents-gitflow-guard",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "description": "A configurable branch-role guard for AI coding agents (DSH / Claude Code / Codex / OpenCode / Antigravity) — integration/preview/production/archive, each with its own update rules",
5
5
  "license": "MIT",
6
6
  "type": "module",