auriga-cli 1.28.0 → 1.29.1
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 +10 -10
- package/README.zh-CN.md +10 -10
- package/dist/api-types.d.ts +9 -9
- package/dist/apply-handlers.d.ts +1 -1
- package/dist/apply-handlers.js +3 -2
- package/dist/catalog.json +2 -2
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +27 -18
- package/dist/guide.js +7 -6
- package/dist/help.js +6 -5
- package/dist/preset.d.ts +1 -1
- package/dist/preset.js +1 -1
- package/dist/server.d.ts +2 -2
- package/dist/skills.js +1 -1
- package/dist/state.js +37 -20
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +26 -5
- package/dist/workflow-docs.d.ts +4 -0
- package/dist/workflow-docs.js +4 -0
- package/dist/workflow-markers.d.ts +3 -3
- package/dist/workflow-markers.js +9 -9
- package/dist/workflow.d.ts +3 -4
- package/dist/workflow.js +143 -89
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ This repo itself is a fully configured harness project. You can clone it to see
|
|
|
10
10
|
|
|
11
11
|
| Module | Description |
|
|
12
12
|
|---|---|
|
|
13
|
-
| **Workflow** | `
|
|
13
|
+
| **Workflow** | `AGENTS.md` auriga workflow: requirement clarification -> TDD -> Review, Harness principles, Subagent usage guide |
|
|
14
14
|
| **Skills** | External development process skills — systematic-debugging, TDD, verification, planning, playwright (spec authoring and architecture design ship as the `spec-design` and `arch-design` skills inside the `auriga-workflow` plugin) |
|
|
15
15
|
| **Recommended Skills** | Optional utility skills (e.g. `codex-agent`, `claude-code-agent`) you can add on top of the workflow skills |
|
|
16
16
|
| **Plugins** | Recommended Claude Code and Codex plugins — skill-creator, claude-md-management, playground, codex, auriga-workflow, auriga-notify, session-instructions-loader |
|
|
@@ -40,9 +40,9 @@ The leading `-y` belongs to `npx` (it auto-confirms package installation), **not
|
|
|
40
40
|
Non-interactive install commands:
|
|
41
41
|
|
|
42
42
|
```bash
|
|
43
|
-
npx -y auriga-cli install --preset # curated workflow core:
|
|
43
|
+
npx -y auriga-cli install --preset # curated workflow core: AGENTS.md/CLAUDE.md
|
|
44
44
|
# + workflow skills + auriga-workflow plugin
|
|
45
|
-
# (defaults: scope user, agent both, lang
|
|
45
|
+
# (defaults: scope user, agent both, lang zh-CN)
|
|
46
46
|
npx -y auriga-cli install --all # everything: workflow + skills + recommended + plugins
|
|
47
47
|
npx -y auriga-cli install recommended # just the opt-in utility skills
|
|
48
48
|
npx -y auriga-cli install plugins --agent codex --plugin session-instructions-loader
|
|
@@ -50,9 +50,9 @@ npx -y auriga-cli install <type> [--flags] # one of: workflow | skills | recom
|
|
|
50
50
|
npx -y auriga-cli --help # full catalog + flags
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
`--preset` is atomic — it cannot be combined with a `<type>` or any filter flag, but it accepts `--scope`, `--agent`, and `--lang` (preset defaults: `user` / `both` / `
|
|
53
|
+
`--preset` is atomic — it cannot be combined with a `<type>` or any filter flag, but it accepts `--scope`, `--agent`, and `--lang` (preset defaults: `user` / `both` / `zh-CN`, which differ from the per-category defaults).
|
|
54
54
|
|
|
55
|
-
Exit codes: `0` success, `1` fatal (precheck / parse / fetch), `2` partial success — `stderr` lists per-category `[OK]/[FAIL]` and a `Retry:` hint. After install, reload the Claude Code or Codex session so the new `
|
|
55
|
+
Exit codes: `0` success, `1` fatal (precheck / parse / fetch), `2` partial success — `stderr` lists per-category `[OK]/[FAIL]` and a `Retry:` hint. After install, reload the Claude Code or Codex session so the new `AGENTS.md` / skills / plugins / hook-plugin registrations are picked up.
|
|
56
56
|
|
|
57
57
|
### Web UI (opt-in)
|
|
58
58
|
|
|
@@ -76,21 +76,21 @@ Interactive menu — select what to install:
|
|
|
76
76
|
|
|
77
77
|
```
|
|
78
78
|
? Select what to install:
|
|
79
|
-
◉ Recommended preset —
|
|
79
|
+
◉ Recommended preset — AGENTS.md/CLAUDE.md + workflow skills + auriga-workflow plugin
|
|
80
80
|
◯ Optional skills — opt-in utility skills (claude-code-agent, codex-agent...)
|
|
81
81
|
◯ Other plugins — everything except auriga-workflow (auriga-notify, skill-creator, codex...)
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
The **Recommended preset** is checked by default and installs silently with the preset defaults (scope `user`, agent `both`, language `
|
|
84
|
+
The **Recommended preset** is checked by default and installs silently with the preset defaults (scope `user`, agent `both`, language `zh-CN`) — to fine-tune those, use the non-interactive `install --preset` flags. The other two items drill down into a per-item sub-selection. Plugin installation also asks which runtime to target: Claude Code, Codex, or both.
|
|
85
85
|
|
|
86
86
|
## Module Details
|
|
87
87
|
|
|
88
88
|
### Workflow
|
|
89
89
|
|
|
90
|
-
Installs `
|
|
90
|
+
Installs `AGENTS.md` into the target project and creates a `CLAUDE.md` symlink for Claude Code compatibility. Chinese is the default; English remains available with `--lang en`.
|
|
91
91
|
|
|
92
92
|
- **Extensible and upgradable**: the auriga workflow ships inside a managed block delimited by `<!-- AURIGA:WORKFLOW:v1 START/END -->` markers. Add your project-specific instructions *after* the END marker — re-running install upgrades the managed block in place and leaves your section untouched.
|
|
93
|
-
- A pre-marker `CLAUDE.md` (installed by an older version) is migrated
|
|
93
|
+
- A pre-marker `CLAUDE.md` (installed by an older version) is safely migrated into the new `AGENTS.md` primary shape on the next install, with the old file backed up to `CLAUDE.md.bak`. A foreign `AGENTS.md` or `CLAUDE.md` from another tool is kept as your user section below a fresh managed block.
|
|
94
94
|
- Covers: requirement clarification, TDD, code review, branch workflow, subagent orchestration
|
|
95
95
|
|
|
96
96
|
### Skills
|
|
@@ -134,7 +134,7 @@ npx -y auriga-cli install plugins --agent codex --plugin session-instructions-lo
|
|
|
134
134
|
| Plugin | Runtime | Description |
|
|
135
135
|
|---|---|---|
|
|
136
136
|
| skill-creator | Claude Code | Create and manage custom skills |
|
|
137
|
-
| claude-md-management | Claude Code / Codex | Audit and improve CLAUDE.md |
|
|
137
|
+
| claude-md-management | Claude Code / Codex | Audit and improve AGENTS.md / CLAUDE.md |
|
|
138
138
|
| playground | Claude Code / Codex | Build interactive HTML playgrounds |
|
|
139
139
|
| codex | Claude Code | Codex cross-model collaboration |
|
|
140
140
|
| auriga-workflow | Claude Code / Codex | The auriga workflow plugin — workflow skills plus the git lifecycle hooks that enforce them. Skills: `incremental-impl`, `test-designer`, `spec-design`, `arch-design`, `code-simplify`, `session-compound`, `goalify` (plans an autonomous goal and dispatches it via the built-in `/goal` command), `deep-review` (multi-dimensional PR review orchestrator — parallel per-dimension reviewers synthesized into an actionable punch list), `reviewer-creator` (scaffolds project-level custom reviewers under `docs/rules/review/`), and `git-workflow` (git lifecycle skill). Hooks: `commit-reminder` (PostToolUse on file edits — `Edit` / `Write` / `MultiEdit` in Claude Code, `apply_patch` in Codex — nudges to commit at the next semantic boundary when uncommitted diff vs `HEAD` exceeds 200 lines or 8 files), `pr-create-guard` (PostToolUse on `gh pr create` → injects a PR-body snapshot for five-element self-verification and flags non-Conventional-Commits titles), `pr-ready-guard` (PreToolUse on `gh pr ready` and non-draft `gh pr create` → blocks on stray planning docs, unfinalized active specs under `docs/specs/`, or unpushed commits), and `pr-merge-guard` (PreToolUse on `gh pr merge` → blocks while the PR body's Acceptance criteria section still has unchecked checklist items). The two PostToolUse hooks reach full Claude Code / Codex parity; Codex currently fails open on `pr-ready-guard`'s PreToolUse `additionalContext` informational path (block path identical). Installed by default through the plugin path. |
|
package/README.zh-CN.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
| 模块 | 说明 |
|
|
12
12
|
|---|---|
|
|
13
|
-
| **Workflow** | `
|
|
13
|
+
| **Workflow** | `AGENTS.md` 里的 auriga 工作流:需求澄清 → TDD → Review,Harness 原则,Subagent 使用指南 |
|
|
14
14
|
| **Skills** | 外部开发流程 skills —— systematic-debugging、TDD、verification、planning、playwright(spec 撰写与架构设计由 `auriga-workflow` 插件内的 `spec-design`、`arch-design` skill 提供)|
|
|
15
15
|
| **Recommended Skills** | 可选的工具类 skills(如 `codex-agent`、`claude-code-agent`),在 workflow skills 之外按需追加 |
|
|
16
16
|
| **Plugins** | 推荐的 Claude Code 和 Codex 插件 —— skill-creator、claude-md-management、playground、codex、auriga-workflow、auriga-notify、session-instructions-loader |
|
|
@@ -40,9 +40,9 @@ npx -y auriga-cli guide
|
|
|
40
40
|
非交互安装命令:
|
|
41
41
|
|
|
42
42
|
```bash
|
|
43
|
-
npx -y auriga-cli install --preset # 工作流核心:
|
|
43
|
+
npx -y auriga-cli install --preset # 工作流核心:AGENTS.md/CLAUDE.md
|
|
44
44
|
# + 工作流 skill + auriga-workflow 插件
|
|
45
|
-
# (默认:scope user、agent both、lang
|
|
45
|
+
# (默认:scope user、agent both、lang zh-CN)
|
|
46
46
|
npx -y auriga-cli install --all # 全装:workflow + skills + recommended + plugins
|
|
47
47
|
npx -y auriga-cli install recommended # 只装可选工具 skills
|
|
48
48
|
npx -y auriga-cli install plugins --agent codex --plugin session-instructions-loader
|
|
@@ -50,9 +50,9 @@ npx -y auriga-cli install <type> [--flags] # 单类:workflow | skills | recomm
|
|
|
50
50
|
npx -y auriga-cli --help # 完整 catalog + flag 说明
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
`--preset` 是原子标志 —— 不能与 `<type>` 或任何过滤标志同时使用,但可带 `--scope`、`--agent`、`--lang`(预设默认 `user` / `both` / `
|
|
53
|
+
`--preset` 是原子标志 —— 不能与 `<type>` 或任何过滤标志同时使用,但可带 `--scope`、`--agent`、`--lang`(预设默认 `user` / `both` / `zh-CN`,与分类安装的默认不同)。
|
|
54
54
|
|
|
55
|
-
退出码:`0` 成功;`1` 致命错误(前置检查 / 解析 / 拉取失败);`2` 部分成功——`stderr` 会列出逐类 `[OK]/[FAIL]` 和 `Retry:` 提示。装完后请重启 Claude Code 或 Codex 会话,让新的 `
|
|
55
|
+
退出码:`0` 成功;`1` 致命错误(前置检查 / 解析 / 拉取失败);`2` 部分成功——`stderr` 会列出逐类 `[OK]/[FAIL]` 和 `Retry:` 提示。装完后请重启 Claude Code 或 Codex 会话,让新的 `AGENTS.md` / skills / plugins / hook 插件注册生效。
|
|
56
56
|
|
|
57
57
|
### Web UI(可选)
|
|
58
58
|
|
|
@@ -76,21 +76,21 @@ npx auriga-cli
|
|
|
76
76
|
|
|
77
77
|
```
|
|
78
78
|
? Select what to install:
|
|
79
|
-
◉ Recommended preset —
|
|
79
|
+
◉ Recommended preset — AGENTS.md/CLAUDE.md + workflow skills + auriga-workflow plugin
|
|
80
80
|
◯ Optional skills — opt-in utility skills (claude-code-agent, codex-agent...)
|
|
81
81
|
◯ Other plugins — everything except auriga-workflow (auriga-notify, skill-creator, codex...)
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
**Recommended preset** 默认勾选,以预设默认值静默安装(scope `user`、agent `both`、语言 `
|
|
84
|
+
**Recommended preset** 默认勾选,以预设默认值静默安装(scope `user`、agent `both`、语言 `zh-CN`)—— 要精调这些参数,改用非交互的 `install --preset` 标志。另两项会下钻到逐项子勾选。安装插件时还会先选择目标运行时:Claude Code、Codex 或两者都装。
|
|
85
85
|
|
|
86
86
|
## 模块详情
|
|
87
87
|
|
|
88
88
|
### Workflow
|
|
89
89
|
|
|
90
|
-
将 `
|
|
90
|
+
将 `AGENTS.md` 安装到目标项目,并创建 `CLAUDE.md` 软链接以兼容 Claude Code。默认安装中文版本,英文可通过 `--lang en` 显式选择。
|
|
91
91
|
|
|
92
92
|
- **可扩展、可升级**:auriga 工作流被一对 `<!-- AURIGA:WORKFLOW:v1 START/END -->` 标记包成「受管区块」。把你的工程专属规则写在 END 标记**之后**——再次安装只就地升级受管区块,你的内容原样保留。
|
|
93
|
-
- 旧版本装下的、无标记的 `CLAUDE.md`
|
|
93
|
+
- 旧版本装下的、无标记的 `CLAUDE.md` 会在下次安装时安全迁移到新的 `AGENTS.md` 主文件形态,旧文件备份到 `CLAUDE.md.bak`。别的工具生成的 `AGENTS.md` 或 `CLAUDE.md` 会作为用户区保留在全新受管区块下方。
|
|
94
94
|
- 涵盖:需求澄清、TDD、代码 Review、分支工作流、Subagent 编排
|
|
95
95
|
|
|
96
96
|
### Skills
|
|
@@ -134,7 +134,7 @@ npx -y auriga-cli install plugins --agent codex --plugin session-instructions-lo
|
|
|
134
134
|
| 插件 | 运行时 | 说明 |
|
|
135
135
|
|---|---|---|
|
|
136
136
|
| skill-creator | Claude Code | 创建和管理自定义 skills |
|
|
137
|
-
| claude-md-management | Claude Code / Codex | 审计和改进 CLAUDE.md |
|
|
137
|
+
| claude-md-management | Claude Code / Codex | 审计和改进 AGENTS.md / CLAUDE.md |
|
|
138
138
|
| playground | Claude Code / Codex | 构建交互式 HTML playground |
|
|
139
139
|
| codex | Claude Code | Codex 跨模型协作 |
|
|
140
140
|
| auriga-workflow | Claude Code / Codex | auriga 工作流插件 —— 工作流 skill 加上强制执行工作流的 git 生命周期 hook。Skills:`incremental-impl`、`test-designer`、`spec-design`、`arch-design`、`code-simplify`、`session-compound`、`goalify`(plan 出自驱 goal 并通过内置 `/goal` 命令分发执行)、`deep-review`(多维度 PR review 编排器——并行派发各维度 reviewer,汇总成可执行的 punch list)、`reviewer-creator`(在 `docs/rules/review/` 下生成项目级自定义 reviewer)、`git-workflow`(git 生命周期 skill)。Hooks:`commit-reminder`(文件编辑的 PostToolUse —— Claude Code 匹配 `Edit` / `Write` / `MultiEdit`,Codex 匹配 `apply_patch` —— 未提交 diff 对比 `HEAD` 超过 200 行或 8 个文件时,提醒在下一个语义边界 commit)、`pr-create-guard`(`gh pr create` 的 PostToolUse —— 注入 PR body 快照供五要素自检,并对不符合 Conventional Commits 的标题提示)、`pr-ready-guard`(`gh pr ready` 与非 draft `gh pr create` 的 PreToolUse —— 拦截游离规划文档、`docs/specs/` 内未结案的活跃 spec、未 push commits)、`pr-merge-guard`(`gh pr merge` 的 PreToolUse —— PR body 的验收标准章节仍有未勾选清单项时拦截合并)。两个 PostToolUse hook 在 Claude Code / Codex 上完全对齐;Codex 仅对 `pr-ready-guard` 的 PreToolUse `additionalContext` 信息路径 fail-open(block 路径两边一致)。默认通过插件路径安装。 |
|
package/dist/api-types.d.ts
CHANGED
|
@@ -71,11 +71,11 @@ export interface PluginState {
|
|
|
71
71
|
}
|
|
72
72
|
export interface StateWarning {
|
|
73
73
|
code: "claude-cli-missing" | "codex-cli-missing" | "marketplace-offline" | "claude-code-not-installed" | "settings-unreadable" | "skill-malformed"
|
|
74
|
-
/**
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
| "workflow-foreign-claudemd";
|
|
74
|
+
/** Workflow instruction file is present but has no recognizable
|
|
75
|
+
* `# auriga Workflow (vX.Y.Z)` header. The row reports `not-installed`;
|
|
76
|
+
* install keeps the existing content in the user region before writing
|
|
77
|
+
* ours. */
|
|
78
|
+
| "workflow-foreign-agentsmd" | "workflow-foreign-claudemd";
|
|
79
79
|
message: string;
|
|
80
80
|
}
|
|
81
81
|
export type ApplyCategory = "workflow" | "skill" | "recommended-skill" | "plugin"
|
|
@@ -93,10 +93,10 @@ export type ApplyAction = "install" | "uninstall";
|
|
|
93
93
|
*/
|
|
94
94
|
export type ApplyScope = "project" | "user";
|
|
95
95
|
/**
|
|
96
|
-
* Workflow
|
|
96
|
+
* Workflow AGENTS.md language variant.
|
|
97
97
|
*
|
|
98
|
-
* - "
|
|
99
|
-
* - "
|
|
98
|
+
* - "zh-CN": Simplified Chinese workflow template (the default).
|
|
99
|
+
* - "en": English workflow template.
|
|
100
100
|
*
|
|
101
101
|
* Only meaningful for `category === "workflow"`; rejected for other
|
|
102
102
|
* categories so the API surface stays explicit.
|
|
@@ -120,7 +120,7 @@ export interface ApplyItemRef {
|
|
|
120
120
|
* server rejects this field for category="workflow" because workflow
|
|
121
121
|
* has no scope concept (it's a single file at the project root). */
|
|
122
122
|
scope?: ApplyScope;
|
|
123
|
-
/** Workflow
|
|
123
|
+
/** Workflow AGENTS.md language variant. Omitted = "zh-CN"
|
|
124
124
|
* default). The server accepts this field only for category="workflow"
|
|
125
125
|
* and category="preset" (the preset installs the workflow doc). */
|
|
126
126
|
lang?: ApplyLang;
|
package/dist/apply-handlers.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export interface ApplyHandlerContext {
|
|
|
11
11
|
* and the handler iterates the list, installing to each agent in turn.
|
|
12
12
|
* Names not in the map default to `["claude"]` (existing CLI default). */
|
|
13
13
|
pluginAgentsByName: Map<string, ("claude" | "codex")[]>;
|
|
14
|
-
/** Workflow language for install. Defaults to "
|
|
14
|
+
/** Workflow language for install. Defaults to "zh-CN". */
|
|
15
15
|
workflowLang?: ApplyLang;
|
|
16
16
|
}
|
|
17
17
|
export declare function buildDefaultApplyHandlers(ctx: ApplyHandlerContext): ApplyHandlers;
|
package/dist/apply-handlers.js
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
import { installPlugins, uninstallPlugin, } from "./plugins.js";
|
|
24
24
|
import { installPreset } from "./preset.js";
|
|
25
25
|
import { installRecommendedSkills, installSkills, uninstallSkill, } from "./skills.js";
|
|
26
|
+
import { DEFAULT_WORKFLOW_LANG } from "./utils.js";
|
|
26
27
|
import { installWorkflow, uninstallWorkflow } from "./workflow.js";
|
|
27
28
|
const ALL_ACTIONS = new Set([
|
|
28
29
|
"install",
|
|
@@ -37,7 +38,7 @@ function assertAction(action) {
|
|
|
37
38
|
}
|
|
38
39
|
export function buildDefaultApplyHandlers(ctx) {
|
|
39
40
|
const { packageRoot, cwd, pluginAgentsByName } = ctx;
|
|
40
|
-
const lang = ctx.workflowLang ??
|
|
41
|
+
const lang = ctx.workflowLang ?? DEFAULT_WORKFLOW_LANG;
|
|
41
42
|
const workflow = async (action, _name, { onLog, lang: requestedLang }) => {
|
|
42
43
|
assertAction(action);
|
|
43
44
|
// Per-item lang overrides the ctx default (the UI now drives this via
|
|
@@ -155,7 +156,7 @@ export function buildDefaultApplyHandlers(ctx) {
|
|
|
155
156
|
// The preset is a single apply item that drives the whole installPreset
|
|
156
157
|
// orchestration. scope / agent / lang come from the Dashboard's preset
|
|
157
158
|
// controls; omitted values fall back to the preset defaults
|
|
158
|
-
// (user / both /
|
|
159
|
+
// (user / both / zh-CN). Uninstall is not a preset operation.
|
|
159
160
|
const preset = async (action, _name, { onLog, scope, lang: requestedLang, agent }) => {
|
|
160
161
|
assertAction(action);
|
|
161
162
|
if (action !== "install") {
|
package/dist/catalog.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"generatedAt": "2026-05-
|
|
2
|
+
"generatedAt": "2026-05-17T06:16:55.450Z",
|
|
3
3
|
"workflowSkills": [
|
|
4
4
|
{
|
|
5
5
|
"name": "planning-with-files",
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
},
|
|
79
79
|
{
|
|
80
80
|
"name": "claude-md-management",
|
|
81
|
-
"description": "(Claude/Codex) Audit and improve CLAUDE.md files",
|
|
81
|
+
"description": "(Claude/Codex) Audit and improve AGENTS.md / CLAUDE.md files",
|
|
82
82
|
"agents": [
|
|
83
83
|
"claude",
|
|
84
84
|
"codex"
|
package/dist/cli.d.ts
CHANGED
|
@@ -49,7 +49,7 @@ type LegacyMenuValue = "preset" | "recommended" | "plugins";
|
|
|
49
49
|
*
|
|
50
50
|
* Workflow + Skills are absorbed by the「推荐预设」item.
|
|
51
51
|
* The preset label spells out the silent defaults (scope user / agent
|
|
52
|
-
* both / lang
|
|
52
|
+
* both / lang zh-CN) so a TTY user knows what they're getting — fine-tuning
|
|
53
53
|
* those goes through the non-interactive `install --preset` flags.
|
|
54
54
|
*/
|
|
55
55
|
export declare const LEGACY_MENU_CHOICES: ReadonlyArray<{
|
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { exec, fetchContentRoot, getPackageRoot, isNonInteractive, LANGUAGES, log, readPackageVersion, } from "./utils.js";
|
|
5
|
+
import { exec, DEFAULT_WORKFLOW_LANG, fetchContentRoot, getPackageRoot, isNonInteractive, LANGUAGES, log, readPackageVersion, } from "./utils.js";
|
|
6
6
|
import { installWorkflow } from "./workflow.js";
|
|
7
7
|
import { installSkills, installRecommendedSkills } from "./skills.js";
|
|
8
8
|
import { installPlugins } from "./plugins.js";
|
|
@@ -11,7 +11,7 @@ import { loadCatalog } from "./catalog.js";
|
|
|
11
11
|
import { renderHelp, renderTypeHelp } from "./help.js";
|
|
12
12
|
import { renderGuide } from "./guide.js";
|
|
13
13
|
import { CATEGORY_NAMES } from "./types.js";
|
|
14
|
-
const RELOAD_REMINDER = "\n⚠ Reload your Claude Code or Codex session to pick up the new harness (
|
|
14
|
+
const RELOAD_REMINDER = "\n⚠ Reload your Claude Code or Codex session to pick up the new harness (AGENTS.md / skills / plugins are loaded at session startup).\n";
|
|
15
15
|
const CATEGORY_SET = new Set(CATEGORY_NAMES);
|
|
16
16
|
const TYPE_FOR_FILTER = {
|
|
17
17
|
"--skill": "skills",
|
|
@@ -259,7 +259,7 @@ function validateInstall(out, filterFlag) {
|
|
|
259
259
|
// (workflow doc + workflow skills + auriga-workflow plugin) and cannot
|
|
260
260
|
// combine with a <type>, a sub-item filter, or --all. Unlike a category
|
|
261
261
|
// install it DOES accept --scope / --agent / --lang as preset modifiers
|
|
262
|
-
// (the preset defaults differ: user / both /
|
|
262
|
+
// (the preset defaults differ: user / both / zh-CN). --cwd is not a preset
|
|
263
263
|
// modifier — the workflow doc always lands in the current directory.
|
|
264
264
|
if (out.preset) {
|
|
265
265
|
if (out.all) {
|
|
@@ -475,7 +475,7 @@ async function runInstall(p) {
|
|
|
475
475
|
* succeed → 0; any step fails → 2 with per-step status on stderr.
|
|
476
476
|
*
|
|
477
477
|
* The preset defaults differ from a category install — scope=user,
|
|
478
|
-
* agent=both, lang=
|
|
478
|
+
* agent=both, lang=zh-CN — and are resolved here before handing off, so
|
|
479
479
|
* `installPreset` itself stays default-free (the TUI / Web UI callers
|
|
480
480
|
* resolve their own defaults the same way).
|
|
481
481
|
*/
|
|
@@ -489,7 +489,7 @@ async function runPreset(p) {
|
|
|
489
489
|
interactive: false,
|
|
490
490
|
scope: p.scope ?? "user",
|
|
491
491
|
agent,
|
|
492
|
-
lang: p.lang ??
|
|
492
|
+
lang: p.lang ?? DEFAULT_WORKFLOW_LANG,
|
|
493
493
|
});
|
|
494
494
|
for (const r of results) {
|
|
495
495
|
if (r.ok) {
|
|
@@ -507,7 +507,14 @@ async function runPreset(p) {
|
|
|
507
507
|
// The preset is one atomic "install the right defaults" action — the
|
|
508
508
|
// retry is the whole command again, not a per-category fan-out like
|
|
509
509
|
// runAll's hint.
|
|
510
|
-
|
|
510
|
+
const retryArgs = ["install", "--preset"];
|
|
511
|
+
if (p.scope)
|
|
512
|
+
retryArgs.push("--scope", p.scope);
|
|
513
|
+
if (p.agent)
|
|
514
|
+
retryArgs.push("--agent", p.agent);
|
|
515
|
+
if (p.lang)
|
|
516
|
+
retryArgs.push("--lang", p.lang);
|
|
517
|
+
process.stderr.write(`\nRetry:\n npx -y auriga-cli ${retryArgs.join(" ")}\n`);
|
|
511
518
|
if (failed.length < results.length) {
|
|
512
519
|
process.stderr.write(RELOAD_REMINDER);
|
|
513
520
|
}
|
|
@@ -619,7 +626,7 @@ async function runAll(p) {
|
|
|
619
626
|
process.stderr.write(` npx -y auriga-cli install ${s.category}${suffix}\n`);
|
|
620
627
|
}
|
|
621
628
|
// Partial success still installed assets that need a session reload
|
|
622
|
-
// (
|
|
629
|
+
// (AGENTS.md / skills / plugins load at startup). Without this hint
|
|
623
630
|
// the user may retry the failed category and act on stale state.
|
|
624
631
|
if (failed.length < status.length) {
|
|
625
632
|
process.stderr.write(RELOAD_REMINDER);
|
|
@@ -686,8 +693,9 @@ async function runUi(p, version) {
|
|
|
686
693
|
// - tarballRoot: where `dist/catalog.json` + the bundled DEV ui/dist live.
|
|
687
694
|
// Always read from the installed npm package; can't be fetched because
|
|
688
695
|
// dist/ is built artifact, not git content.
|
|
689
|
-
// - contentRoot: where the runtime install recipes live (
|
|
690
|
-
// marketplace manifests, extra_plugin_configs.json,
|
|
696
|
+
// - contentRoot: where the runtime install recipes live (workflow
|
|
697
|
+
// templates, marketplace manifests, extra_plugin_configs.json,
|
|
698
|
+
// skills-lock.json).
|
|
691
699
|
// These files are
|
|
692
700
|
// NOT in the npm tarball — the `files` allowlist only ships `dist/*`
|
|
693
701
|
// + npm defaults. They are fetched from GitHub, pinned to the CLI
|
|
@@ -750,7 +758,7 @@ async function runUi(p, version) {
|
|
|
750
758
|
return 1;
|
|
751
759
|
}
|
|
752
760
|
const applyCatalog = {
|
|
753
|
-
// Workflow is a singleton (one
|
|
761
|
+
// Workflow is a singleton (one AGENTS.md per project); we pick the
|
|
754
762
|
// sentinel name "workflow" to match what the Web UI's Dashboard sends
|
|
755
763
|
// and to remain semantically self-describing. The handler ignores the
|
|
756
764
|
// name argument either way.
|
|
@@ -767,8 +775,9 @@ async function runUi(p, version) {
|
|
|
767
775
|
pluginAgentsByName.set(name, def.agents);
|
|
768
776
|
}
|
|
769
777
|
const applyHandlers = buildDefaultApplyHandlers({
|
|
770
|
-
// contentRoot: install handlers read
|
|
771
|
-
// extra_plugin_configs.json, and skills-lock.json — all
|
|
778
|
+
// contentRoot: install handlers read workflow templates, marketplace
|
|
779
|
+
// manifests, extra_plugin_configs.json, and skills-lock.json — all
|
|
780
|
+
// CONTENT_FILES.
|
|
772
781
|
// Routing them at tarballRoot fails ENOENT for npm-installed users.
|
|
773
782
|
packageRoot: contentRoot,
|
|
774
783
|
cwd,
|
|
@@ -793,8 +802,8 @@ async function runUi(p, version) {
|
|
|
793
802
|
cwd,
|
|
794
803
|
// server reads dist/catalog.json (tarball-shipped) via
|
|
795
804
|
// buildScanCatalog on each /api/state call; install-time content
|
|
796
|
-
// (marketplace manifests, extra plugin config,
|
|
797
|
-
// into applyHandlers above with contentRoot.
|
|
805
|
+
// (workflow templates, marketplace manifests, extra plugin config, …)
|
|
806
|
+
// was already injected into applyHandlers above with contentRoot.
|
|
798
807
|
packageRoot: tarballRoot,
|
|
799
808
|
heartbeatTimeoutMs: UI_HEARTBEAT_TIMEOUT_MS,
|
|
800
809
|
applyHandlers,
|
|
@@ -878,13 +887,13 @@ function highlight(text) {
|
|
|
878
887
|
*
|
|
879
888
|
* Workflow + Skills are absorbed by the「推荐预设」item.
|
|
880
889
|
* The preset label spells out the silent defaults (scope user / agent
|
|
881
|
-
* both / lang
|
|
890
|
+
* both / lang zh-CN) so a TTY user knows what they're getting — fine-tuning
|
|
882
891
|
* those goes through the non-interactive `install --preset` flags.
|
|
883
892
|
*/
|
|
884
893
|
export const LEGACY_MENU_CHOICES = [
|
|
885
894
|
{
|
|
886
895
|
value: "preset",
|
|
887
|
-
name: "Recommended preset —
|
|
896
|
+
name: "Recommended preset — AGENTS.md/CLAUDE.md + workflow skills + auriga-workflow plugin (scope user · agent both · lang zh-CN)",
|
|
888
897
|
checked: true,
|
|
889
898
|
},
|
|
890
899
|
{
|
|
@@ -928,7 +937,7 @@ async function runLegacyMenu() {
|
|
|
928
937
|
return 0;
|
|
929
938
|
}
|
|
930
939
|
// 「推荐预设」silently uses the preset defaults (scope user / agent
|
|
931
|
-
// both / lang
|
|
940
|
+
// both / lang zh-CN) — it does not prompt for them. The other two items
|
|
932
941
|
// drill down into their category's per-item sub-selection as before.
|
|
933
942
|
if (picks.includes("preset")) {
|
|
934
943
|
console.log("\n--- Recommended preset ---\n");
|
|
@@ -936,7 +945,7 @@ async function runLegacyMenu() {
|
|
|
936
945
|
interactive: true,
|
|
937
946
|
scope: "user",
|
|
938
947
|
agent: "both",
|
|
939
|
-
lang:
|
|
948
|
+
lang: DEFAULT_WORKFLOW_LANG,
|
|
940
949
|
});
|
|
941
950
|
}
|
|
942
951
|
if (picks.includes("recommended")) {
|
package/dist/guide.js
CHANGED
|
@@ -20,7 +20,7 @@ export function renderGuide(opts) {
|
|
|
20
20
|
return `${h(`# auriga-cli bootstrap SOP (v${opts.version})`)}
|
|
21
21
|
|
|
22
22
|
This guide walks an Agent through installing the auriga harness
|
|
23
|
-
(
|
|
23
|
+
(AGENTS.md + skills + plugins) into the current repository.
|
|
24
24
|
|
|
25
25
|
Run each step in order. If any step fails with exit 1, stop and report.
|
|
26
26
|
If exit 2, see stderr for per-category status and follow the "Retry"
|
|
@@ -61,9 +61,10 @@ Per-type detail (flags + only that category's catalog slice):
|
|
|
61
61
|
|
|
62
62
|
${h("## Step 3 — Install")}
|
|
63
63
|
|
|
64
|
-
Recommended — the curated workflow preset (
|
|
64
|
+
Recommended — the curated workflow preset (AGENTS.md/CLAUDE.md +
|
|
65
65
|
workflow skills + the auriga-workflow plugin). Defaults: scope user,
|
|
66
|
-
agent both (Claude Code + Codex), lang
|
|
66
|
+
agent both (Claude Code + Codex), lang zh-CN. Scope applies to skills
|
|
67
|
+
and plugins; the workflow doc always writes to the current project:
|
|
67
68
|
${cmd("npx -y auriga-cli install --preset")}
|
|
68
69
|
|
|
69
70
|
Everything — workflow + skills + recommended skills + default plugins:
|
|
@@ -96,7 +97,7 @@ Exit codes:
|
|
|
96
97
|
|
|
97
98
|
${h("## Step 4 — Reload session (REQUIRED when installed non-interactively)")}
|
|
98
99
|
|
|
99
|
-
${warn("⚠")}
|
|
100
|
+
${warn("⚠")} AGENTS.md, .agents/skills/, and plugin enablement /
|
|
100
101
|
registrations are loaded at session startup. If you ran
|
|
101
102
|
\`npx -y auriga-cli install\` inside an existing Claude Code or Codex session
|
|
102
103
|
(e.g., \`claude -p\` / \`claude -p --worktree\` / \`codex exec\`), the current session
|
|
@@ -110,8 +111,8 @@ Action:
|
|
|
110
111
|
${h("## Step 5 — Verify install")}
|
|
111
112
|
|
|
112
113
|
Expected artifacts/checks:
|
|
113
|
-
-
|
|
114
|
-
-
|
|
114
|
+
- AGENTS.md (workflow manifesto, Chinese by default)
|
|
115
|
+
- CLAUDE.md -> AGENTS.md (Claude Code compatibility symlink)
|
|
115
116
|
- .agents/skills/<name>/ (one per installed skill)
|
|
116
117
|
- claude plugins list (shows Claude plugins, if Claude plugins selected)
|
|
117
118
|
- ~/.codex/config.toml (Codex plugin enablement, if Codex plugins selected)
|
package/dist/help.js
CHANGED
|
@@ -13,7 +13,8 @@ USAGE
|
|
|
13
13
|
npx auriga-cli install --preset [--scope <s>] [--agent <a>] [--lang <code>]
|
|
14
14
|
curated default set: workflow doc
|
|
15
15
|
+ workflow skills + auriga-workflow plugin
|
|
16
|
-
(defaults: scope user, agent both, lang
|
|
16
|
+
(defaults: scope user, agent both, lang zh-CN)
|
|
17
|
+
scope applies to skills/plugins; workflow writes current project
|
|
17
18
|
npx auriga-cli install --all [--scope <s>] [--agent <a>]
|
|
18
19
|
everything: workflow + skills
|
|
19
20
|
+ recommended + plugins
|
|
@@ -28,13 +29,13 @@ USAGE
|
|
|
28
29
|
npx -y auriga-cli install --preset
|
|
29
30
|
|
|
30
31
|
TYPES (exactly one with <type> form)
|
|
31
|
-
workflow
|
|
32
|
+
workflow AGENTS.md + CLAUDE.md symlink (workflow manifesto)
|
|
32
33
|
skills Default-on workflow skills (listed below)
|
|
33
34
|
recommended Opt-in utility skills (listed below)
|
|
34
35
|
plugins Claude Code and Codex plugins (listed below)
|
|
35
36
|
|
|
36
37
|
TYPE-SPECIFIC FLAGS
|
|
37
|
-
workflow: --lang <code> default
|
|
38
|
+
workflow: --lang <code> default zh-CN; available: zh-CN, en
|
|
38
39
|
--cwd <dir> default current working directory
|
|
39
40
|
skills: --skill <names...> space-separated; '*' = all
|
|
40
41
|
--scope <project|user> default project
|
|
@@ -80,11 +81,11 @@ USAGE
|
|
|
80
81
|
npx auriga-cli install workflow [--lang <code>] [--cwd <dir>]
|
|
81
82
|
|
|
82
83
|
FLAGS
|
|
83
|
-
--lang <code> default
|
|
84
|
+
--lang <code> default zh-CN; available: zh-CN, en
|
|
84
85
|
--cwd <dir> default current working directory
|
|
85
86
|
|
|
86
87
|
NOTE
|
|
87
|
-
workflow has no --scope flag (
|
|
88
|
+
workflow has no --scope flag (AGENTS.md primary + CLAUDE.md symlink).
|
|
88
89
|
`;
|
|
89
90
|
case "skills":
|
|
90
91
|
return `${header}
|
package/dist/preset.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type { PluginAgent } from "./utils.js";
|
|
|
6
6
|
*/
|
|
7
7
|
export declare const PRESET_PLUGINS: readonly ["auriga-workflow"];
|
|
8
8
|
/**
|
|
9
|
-
* installPreset 的输入。三个默认值(scope=user / agent=both / lang=
|
|
9
|
+
* installPreset 的输入。三个默认值(scope=user / agent=both / lang=zh-CN)
|
|
10
10
|
* 与分类安装不同,由调用方负责落定后再传入 —— 预设的默认不在本函数内
|
|
11
11
|
* 兜底,使「默认值是什么」对每个调用端都显式可见。
|
|
12
12
|
*/
|
package/dist/preset.js
CHANGED
package/dist/server.d.ts
CHANGED
|
@@ -5,8 +5,8 @@ export interface ApplyHandlerOptions {
|
|
|
5
5
|
* translate into the per-installer flag (`--scope project|user`). The
|
|
6
6
|
* workflow handler ignores it (workflow has no scope concept). */
|
|
7
7
|
scope?: "project" | "user";
|
|
8
|
-
/** Workflow
|
|
9
|
-
* preset handlers; other handlers ignore it. Omitted = "
|
|
8
|
+
/** Workflow AGENTS.md language variant. Meaningful for the workflow and
|
|
9
|
+
* preset handlers; other handlers ignore it. Omitted = "zh-CN". */
|
|
10
10
|
lang?: "en" | "zh-CN";
|
|
11
11
|
/** Preset install runtime. Only meaningful for the preset handler;
|
|
12
12
|
* other handlers ignore it. Omitted = "both". */
|
package/dist/skills.js
CHANGED
|
@@ -3,7 +3,7 @@ import os from "node:os";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { checkbox, select } from "@inquirer/prompts";
|
|
5
5
|
import { atomicWriteFile, exec, execAsync, log, withEsc } from "./utils.js";
|
|
6
|
-
// Curated default-on set: skills that the workflow
|
|
6
|
+
// Curated default-on set: skills that the shipped workflow template
|
|
7
7
|
// directly references. Anything else in skills-lock.json is surfaced via
|
|
8
8
|
// installRecommendedSkills as an opt-in utility.
|
|
9
9
|
export const WORKFLOW_SKILLS = [
|
package/dist/state.js
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
// own dev-repo layout. The truth sources:
|
|
4
4
|
//
|
|
5
5
|
// Workflow: ~/.claude/CLAUDE.md (user scope)
|
|
6
|
-
// <proj>/
|
|
6
|
+
// <proj>/AGENTS.md (project scope primary)
|
|
7
|
+
// <proj>/CLAUDE.md (project scope legacy fallback)
|
|
7
8
|
// Skills: ~/.claude/skills/<name>/SKILL.md (user scope)
|
|
8
9
|
// <proj>/.claude/skills/<name>/SKILL.md (project scope)
|
|
9
10
|
// Plugins(Claude): execPluginList(scope) + settings.json enabledPlugins
|
|
@@ -25,6 +26,7 @@ import os from "node:os";
|
|
|
25
26
|
import path from "node:path";
|
|
26
27
|
import { parse as parseToml } from "smol-toml";
|
|
27
28
|
import { hasAurigaHeader, parseMarkers } from "./workflow-markers.js";
|
|
29
|
+
import { WORKFLOW_COMPAT_FILE, WORKFLOW_PRIMARY_FILE, } from "./workflow-docs.js";
|
|
28
30
|
/**
|
|
29
31
|
* Shorten an absolute path by replacing the user's $HOME with `~`. Avoids
|
|
30
32
|
* leaking the full username in screenshots and keeps the TopBar label
|
|
@@ -152,29 +154,44 @@ function workflowPathsForScope(scope, projectRoot, home) {
|
|
|
152
154
|
if (scope === "user") {
|
|
153
155
|
return [path.join(home, ".claude", "CLAUDE.md")];
|
|
154
156
|
}
|
|
155
|
-
// Project:
|
|
156
|
-
//
|
|
157
|
-
//
|
|
158
|
-
//
|
|
159
|
-
// user
|
|
160
|
-
return [
|
|
157
|
+
// Project: prefer the current `<proj>/AGENTS.md` primary. Keep
|
|
158
|
+
// `<proj>/CLAUDE.md` as a legacy fallback so already-installed projects do
|
|
159
|
+
// not flash as missing before their next install flips the symlink direction.
|
|
160
|
+
// Never fall back to `<proj>/.claude/CLAUDE.md`: that path can collapse onto
|
|
161
|
+
// user scope when projectRoot === HOME.
|
|
162
|
+
return [
|
|
163
|
+
path.join(projectRoot, WORKFLOW_PRIMARY_FILE),
|
|
164
|
+
path.join(projectRoot, WORKFLOW_COMPAT_FILE),
|
|
165
|
+
];
|
|
161
166
|
}
|
|
162
|
-
function
|
|
163
|
-
|
|
164
|
-
|
|
167
|
+
function workflowForeignWarningCode(filePath) {
|
|
168
|
+
return path.basename(filePath) === WORKFLOW_PRIMARY_FILE
|
|
169
|
+
? "workflow-foreign-agentsmd"
|
|
170
|
+
: "workflow-foreign-claudemd";
|
|
171
|
+
}
|
|
172
|
+
function workflowForeignWarningMessage(filePath) {
|
|
173
|
+
const name = path.basename(filePath);
|
|
174
|
+
return `Foreign ${name} detected at the workflow path — no auriga-workflow header. Install will preserve existing content or link intent before replacing the workflow path.`;
|
|
175
|
+
}
|
|
176
|
+
function readFirstWorkflowCandidate(candidates) {
|
|
165
177
|
for (const candidate of candidates) {
|
|
166
178
|
try {
|
|
167
|
-
content
|
|
168
|
-
break;
|
|
179
|
+
return { content: fs.readFileSync(candidate, "utf8"), filePath: candidate };
|
|
169
180
|
}
|
|
170
181
|
catch {
|
|
171
182
|
// try next candidate
|
|
172
183
|
}
|
|
173
184
|
}
|
|
174
|
-
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
function scanWorkflow(scope, projectRoot, home, warnings) {
|
|
188
|
+
const candidates = workflowPathsForScope(scope, projectRoot, home);
|
|
189
|
+
const workflowFile = readFirstWorkflowCandidate(candidates);
|
|
190
|
+
if (workflowFile === null) {
|
|
175
191
|
return { status: "not-installed", observedScope: scope };
|
|
176
192
|
}
|
|
177
|
-
|
|
193
|
+
const { content, filePath } = workflowFile;
|
|
194
|
+
// "Is this our workflow instruction file?" — two recognizable shapes:
|
|
178
195
|
// - managed-block markers (the current install format). The START marker
|
|
179
196
|
// is an HTML comment ahead of the auriga header, so a first-non-blank-
|
|
180
197
|
// line header walk would miss it — detect the marker pair directly.
|
|
@@ -183,13 +200,13 @@ function scanWorkflow(scope, projectRoot, home, warnings) {
|
|
|
183
200
|
if (parseMarkers(content).kind === "marked" || hasAurigaHeader(content)) {
|
|
184
201
|
return { status: "installed", observedScope: scope };
|
|
185
202
|
}
|
|
186
|
-
//
|
|
187
|
-
// foreign — not our workflow. Report `not-installed` honestly; the install
|
|
188
|
-
// path
|
|
189
|
-
//
|
|
203
|
+
// The workflow path exists but is neither marked nor auriga-headed. The file
|
|
204
|
+
// is foreign — not our workflow. Report `not-installed` honestly; the install
|
|
205
|
+
// path keeps the foreign content as the user region below a fresh managed
|
|
206
|
+
// block, so nothing is lost.
|
|
190
207
|
warnings.push({
|
|
191
|
-
code:
|
|
192
|
-
message:
|
|
208
|
+
code: workflowForeignWarningCode(filePath),
|
|
209
|
+
message: workflowForeignWarningMessage(filePath),
|
|
193
210
|
});
|
|
194
211
|
return { status: "not-installed", observedScope: scope };
|
|
195
212
|
}
|
package/dist/utils.d.ts
CHANGED
|
@@ -92,6 +92,8 @@ export interface LangOption {
|
|
|
92
92
|
label: string;
|
|
93
93
|
file: string;
|
|
94
94
|
}
|
|
95
|
+
export declare const DEFAULT_WORKFLOW_LANG = "zh-CN";
|
|
96
|
+
export declare const DEFAULT_WORKFLOW_TEMPLATE_FILE = "AGENTS.template.zh-CN.md";
|
|
95
97
|
export declare const LANGUAGES: LangOption[];
|
|
96
98
|
/**
|
|
97
99
|
* Reads `version` from the packaged manifest. Throws when the package
|
package/dist/utils.js
CHANGED
|
@@ -100,9 +100,11 @@ export function execAsync(cmd, opts) {
|
|
|
100
100
|
});
|
|
101
101
|
});
|
|
102
102
|
}
|
|
103
|
+
export const DEFAULT_WORKFLOW_LANG = "zh-CN";
|
|
104
|
+
export const DEFAULT_WORKFLOW_TEMPLATE_FILE = "AGENTS.template.zh-CN.md";
|
|
103
105
|
export const LANGUAGES = [
|
|
104
|
-
{ value: "
|
|
105
|
-
{ value: "
|
|
106
|
+
{ value: "zh-CN", label: "中文", file: "AGENTS.template.zh-CN.md" },
|
|
107
|
+
{ value: "en", label: "English", file: "AGENTS.template.en.md" },
|
|
106
108
|
];
|
|
107
109
|
// --- Remote content ---
|
|
108
110
|
const REPO = "Ben2pc/auriga-cli";
|
|
@@ -146,12 +148,17 @@ function resolveContentRef() {
|
|
|
146
148
|
return "main";
|
|
147
149
|
}
|
|
148
150
|
const CONTENT_FILES = [
|
|
149
|
-
|
|
151
|
+
DEFAULT_WORKFLOW_TEMPLATE_FILE,
|
|
152
|
+
"AGENTS.template.en.md",
|
|
150
153
|
"skills-lock.json",
|
|
151
154
|
".claude-plugin/marketplace.json",
|
|
152
155
|
".agents/plugins/marketplace.json",
|
|
153
156
|
"extra_plugin_configs.json",
|
|
154
157
|
];
|
|
158
|
+
const LEGACY_CONTENT_FILE_FALLBACKS = {
|
|
159
|
+
"AGENTS.template.zh-CN.md": "AGENTS.md",
|
|
160
|
+
"AGENTS.template.en.md": "AGENTS.en.md",
|
|
161
|
+
};
|
|
155
162
|
async function fetchFile(file) {
|
|
156
163
|
const ref = resolveContentRef();
|
|
157
164
|
const url = `https://raw.githubusercontent.com/${REPO}/${ref}/${file}`;
|
|
@@ -160,6 +167,18 @@ async function fetchFile(file) {
|
|
|
160
167
|
throw new Error(`Failed to fetch ${url}: ${res.status}`);
|
|
161
168
|
return res.text();
|
|
162
169
|
}
|
|
170
|
+
async function fetchContentFile(file) {
|
|
171
|
+
try {
|
|
172
|
+
return await fetchFile(file);
|
|
173
|
+
}
|
|
174
|
+
catch (err) {
|
|
175
|
+
const legacyFile = LEGACY_CONTENT_FILE_FALLBACKS[file];
|
|
176
|
+
if (!legacyFile || !(err instanceof Error) || !/: 404$/.test(err.message)) {
|
|
177
|
+
throw err;
|
|
178
|
+
}
|
|
179
|
+
return fetchFile(legacyFile);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
163
182
|
async function fetchFileBinary(file) {
|
|
164
183
|
const ref = resolveContentRef();
|
|
165
184
|
const url = `https://raw.githubusercontent.com/${REPO}/${ref}/${file}`;
|
|
@@ -174,7 +193,7 @@ export async function fetchContentRoot() {
|
|
|
174
193
|
}
|
|
175
194
|
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "auriga-cli-"));
|
|
176
195
|
for (const file of CONTENT_FILES) {
|
|
177
|
-
const content = await
|
|
196
|
+
const content = await fetchContentFile(file);
|
|
178
197
|
const dest = path.join(tmpDir, file);
|
|
179
198
|
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
180
199
|
fs.writeFileSync(dest, content);
|
|
@@ -182,8 +201,10 @@ export async function fetchContentRoot() {
|
|
|
182
201
|
return tmpDir;
|
|
183
202
|
}
|
|
184
203
|
export async function fetchExtraContent(tmpDir, file) {
|
|
185
|
-
const content = await fetchFile(file);
|
|
186
204
|
const dest = path.join(tmpDir, file);
|
|
205
|
+
if (fs.existsSync(dest))
|
|
206
|
+
return;
|
|
207
|
+
const content = await fetchFile(file);
|
|
187
208
|
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
188
209
|
fs.writeFileSync(dest, content);
|
|
189
210
|
}
|
|
@@ -30,7 +30,7 @@ export type MarkerParse = {
|
|
|
30
30
|
endHash: string | null;
|
|
31
31
|
};
|
|
32
32
|
/**
|
|
33
|
-
* Classify
|
|
33
|
+
* Classify an AGENTS.md body by its managed-block markers.
|
|
34
34
|
*
|
|
35
35
|
* - `unmarked` — neither marker present (fresh-target / foreign / old-format)
|
|
36
36
|
* - `malformed` — exactly one marker, or END before START (can't safely splice)
|
|
@@ -38,7 +38,7 @@ export type MarkerParse = {
|
|
|
38
38
|
*/
|
|
39
39
|
export declare function parseMarkers(content: string): MarkerParse;
|
|
40
40
|
/**
|
|
41
|
-
* Build a marked
|
|
41
|
+
* Build a marked AGENTS.md from its three parts. The END marker hash is
|
|
42
42
|
* computed from `blockBody` here, so callers never hand-maintain it.
|
|
43
43
|
*
|
|
44
44
|
* `blockBody` is expected to end with a newline (it is the content the START
|
|
@@ -55,5 +55,5 @@ export declare function composeMarkedFile(opts: {
|
|
|
55
55
|
lang?: string;
|
|
56
56
|
}): string;
|
|
57
57
|
/** True when the first non-blank line is an auriga workflow header. Used to
|
|
58
|
-
* tell an old-format (pre-marker) auriga
|
|
58
|
+
* tell an old-format (pre-marker) auriga workflow file from a foreign one. */
|
|
59
59
|
export declare function hasAurigaHeader(content: string): boolean;
|
package/dist/workflow-markers.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
// Managed-block markers for the installed
|
|
1
|
+
// Managed-block markers for the installed AGENTS.md.
|
|
2
2
|
//
|
|
3
3
|
// auriga-cli installs its workflow document wrapped in a pair of HTML-comment
|
|
4
4
|
// markers. Everything *between* the markers is the "managed block" — owned by
|
|
5
5
|
// auriga-cli, replaced wholesale on upgrade. Everything *outside* (notably the
|
|
6
6
|
// region after the END marker) is the project's own — auriga-cli never touches
|
|
7
|
-
// it. This lets a downstream project extend its
|
|
7
|
+
// it. This lets a downstream project extend its AGENTS.md while still
|
|
8
8
|
// receiving workflow upgrades.
|
|
9
9
|
//
|
|
10
10
|
// Markers are HTML comments so both Claude Code and Codex (which read the same
|
|
11
|
-
// file via the
|
|
11
|
+
// file via the CLAUDE.md → AGENTS.md symlink) treat them as inert.
|
|
12
12
|
//
|
|
13
13
|
// This module is the single source of truth for the marker contract; it is
|
|
14
14
|
// imported by both src/workflow.ts (install / upgrade) and src/state.ts
|
|
@@ -21,9 +21,9 @@ export const MARKER_SCHEMA = "v1";
|
|
|
21
21
|
* START marker line, one per template language. Only the prose differs — the
|
|
22
22
|
* structural `AURIGA:WORKFLOW:v1 START` token is language-independent, so the
|
|
23
23
|
* parser (`START_LINE_RE`) keys on the token alone and never needs to know the
|
|
24
|
-
* language.
|
|
25
|
-
* gets the Chinese one, so a downstream file never
|
|
26
|
-
* wrong language for its document.
|
|
24
|
+
* language. `AGENTS.template.en.md` gets the English marker;
|
|
25
|
+
* `AGENTS.template.zh-CN.md` gets the Chinese one, so a downstream file never
|
|
26
|
+
* carries a comment in the wrong language for its document.
|
|
27
27
|
*/
|
|
28
28
|
const WORKFLOW_START_MARKERS = {
|
|
29
29
|
en: `<!-- AURIGA:WORKFLOW:${MARKER_SCHEMA} START — Managed block, maintained by auriga-cli. Do not edit by hand; upgrades replace it wholesale. Put project-specific instructions after the END marker below. -->`,
|
|
@@ -53,7 +53,7 @@ export function hashBlock(blockBody) {
|
|
|
53
53
|
return createHash("sha256").update(blockBody, "utf8").digest("hex").slice(0, 16);
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
|
-
* Classify
|
|
56
|
+
* Classify an AGENTS.md body by its managed-block markers.
|
|
57
57
|
*
|
|
58
58
|
* - `unmarked` — neither marker present (fresh-target / foreign / old-format)
|
|
59
59
|
* - `malformed` — exactly one marker, or END before START (can't safely splice)
|
|
@@ -87,7 +87,7 @@ export function parseMarkers(content) {
|
|
|
87
87
|
};
|
|
88
88
|
}
|
|
89
89
|
/**
|
|
90
|
-
* Build a marked
|
|
90
|
+
* Build a marked AGENTS.md from its three parts. The END marker hash is
|
|
91
91
|
* computed from `blockBody` here, so callers never hand-maintain it.
|
|
92
92
|
*
|
|
93
93
|
* `blockBody` is expected to end with a newline (it is the content the START
|
|
@@ -105,7 +105,7 @@ export function composeMarkedFile(opts) {
|
|
|
105
105
|
(opts.userRegion ?? ""));
|
|
106
106
|
}
|
|
107
107
|
/** True when the first non-blank line is an auriga workflow header. Used to
|
|
108
|
-
* tell an old-format (pre-marker) auriga
|
|
108
|
+
* tell an old-format (pre-marker) auriga workflow file from a foreign one. */
|
|
109
109
|
export function hasAurigaHeader(content) {
|
|
110
110
|
for (const line of content.split("\n")) {
|
|
111
111
|
if (line.trim().length === 0)
|
package/dist/workflow.d.ts
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { type InstallOpts } from "./utils.js";
|
|
2
2
|
export declare function installWorkflow(packageRoot: string, opts: InstallOpts): Promise<void>;
|
|
3
3
|
/**
|
|
4
|
-
* Uninstall the workflow (
|
|
4
|
+
* Uninstall the workflow (AGENTS.md + CLAUDE.md) from `opts.cwd`.
|
|
5
5
|
*
|
|
6
6
|
* Safety contract:
|
|
7
7
|
* - `opts.force` MUST be true. The CLI / server caller is responsible for
|
|
8
8
|
* confirming user intent BEFORE invoking this; we refuse otherwise.
|
|
9
|
-
* -
|
|
10
|
-
*
|
|
11
|
-
* diverged from the install pattern and probably hand-edited it.
|
|
9
|
+
* - Real files are removed only when they are recognizable auriga workflow
|
|
10
|
+
* files. Foreign instruction files are left in place with a warning.
|
|
12
11
|
* - Missing files are a no-op: callers can re-run uninstall idempotently.
|
|
13
12
|
* - `.claude/` is not touched; skills / plugins / hooks have their own
|
|
14
13
|
* uninstall paths.
|
package/dist/workflow.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { input, select } from "@inquirer/prompts";
|
|
4
|
-
import { LANGUAGES, fetchExtraContent, log, withEsc, } from "./utils.js";
|
|
4
|
+
import { DEFAULT_WORKFLOW_LANG, DEFAULT_WORKFLOW_TEMPLATE_FILE, LANGUAGES, fetchExtraContent, log, withEsc, } from "./utils.js";
|
|
5
5
|
import { composeMarkedFile, hasAurigaHeader, hashBlock, parseMarkers, } from "./workflow-markers.js";
|
|
6
|
+
import { LEGACY_AGENTS_SYMLINK_TARGET, WORKFLOW_COMPAT_FILE, WORKFLOW_COMPAT_SYMLINK_TARGET, WORKFLOW_PRIMARY_FILE, } from "./workflow-docs.js";
|
|
6
7
|
/**
|
|
7
8
|
* Back up `filePath` once. The canonical `<file>.bak` slot is reserved for the
|
|
8
9
|
* FIRST capture (the user's pre-auriga original) and is never overwritten — a
|
|
@@ -12,8 +13,8 @@ import { composeMarkedFile, hasAurigaHeader, hashBlock, parseMarkers, } from "./
|
|
|
12
13
|
* `verbatimSymlinks` copies a symlink AS a symlink, preserving its literal
|
|
13
14
|
* (possibly relative) target — a foreign AGENTS.md may be a symlink pointing
|
|
14
15
|
* elsewhere, and we want the backup to preserve that target verbatim rather
|
|
15
|
-
* than snapshot whatever it currently resolves to. A real file
|
|
16
|
-
*
|
|
16
|
+
* than snapshot whatever it currently resolves to. A real workflow file copies
|
|
17
|
+
* as a real file. `lstat` (not `existsSync`) probes the `.bak` slot so
|
|
17
18
|
* a backup that is itself a possibly-broken symlink still counts as present
|
|
18
19
|
* and is not silently overwritten.
|
|
19
20
|
*/
|
|
@@ -32,14 +33,26 @@ function backupOnce(filePath) {
|
|
|
32
33
|
fs.cpSync(filePath, dest, { verbatimSymlinks: true });
|
|
33
34
|
return dest;
|
|
34
35
|
}
|
|
36
|
+
function lstatMaybe(filePath) {
|
|
37
|
+
try {
|
|
38
|
+
return fs.lstatSync(filePath);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function isSymlinkTo(filePath, target) {
|
|
45
|
+
const stat = lstatMaybe(filePath);
|
|
46
|
+
return !!stat?.isSymbolicLink() && fs.readlinkSync(filePath) === target;
|
|
47
|
+
}
|
|
35
48
|
export async function installWorkflow(packageRoot, opts) {
|
|
36
49
|
const lang = opts.interactive
|
|
37
50
|
? await withEsc(select({
|
|
38
|
-
message: "
|
|
51
|
+
message: "Workflow language:",
|
|
39
52
|
choices: LANGUAGES.map((l) => ({ name: l.label, value: l.value })),
|
|
40
|
-
default:
|
|
53
|
+
default: DEFAULT_WORKFLOW_LANG,
|
|
41
54
|
}))
|
|
42
|
-
: (opts.lang ??
|
|
55
|
+
: (opts.lang ?? DEFAULT_WORKFLOW_LANG);
|
|
43
56
|
const targetDir = opts.interactive
|
|
44
57
|
? await withEsc(input({
|
|
45
58
|
message: "Workflow install target directory:",
|
|
@@ -56,19 +69,19 @@ export async function installWorkflow(packageRoot, opts) {
|
|
|
56
69
|
throw new Error(msg);
|
|
57
70
|
}
|
|
58
71
|
const langOpt = LANGUAGES.find((l) => l.value === lang);
|
|
59
|
-
// Lazy fetch: only download non-default language
|
|
60
|
-
if (langOpt.file !==
|
|
72
|
+
// Lazy fetch: only download non-default language files when needed.
|
|
73
|
+
if (langOpt.file !== DEFAULT_WORKFLOW_TEMPLATE_FILE) {
|
|
61
74
|
console.log(`Fetching ${langOpt.label} template...`);
|
|
62
75
|
await fetchExtraContent(packageRoot, langOpt.file);
|
|
63
76
|
}
|
|
64
|
-
const
|
|
65
|
-
const
|
|
66
|
-
const
|
|
77
|
+
const sourceWorkflow = path.join(packageRoot, langOpt.file);
|
|
78
|
+
const targetPrimary = path.join(resolved, WORKFLOW_PRIMARY_FILE);
|
|
79
|
+
const targetCompat = path.join(resolved, WORKFLOW_COMPAT_FILE);
|
|
67
80
|
// The packaged template is authored with managed-block markers. Extract its
|
|
68
81
|
// managed block (the auriga workflow body) and its user-region placeholder.
|
|
69
82
|
// Defensive fallback: if the template somehow lacks markers, treat the whole
|
|
70
83
|
// file as the managed block with an empty user region.
|
|
71
|
-
const sourceContent = fs.readFileSync(
|
|
84
|
+
const sourceContent = fs.readFileSync(sourceWorkflow, "utf8");
|
|
72
85
|
const sourceParsed = parseMarkers(sourceContent);
|
|
73
86
|
const sourceBlock = sourceParsed.kind === "marked"
|
|
74
87
|
? sourceParsed.blockBody
|
|
@@ -76,16 +89,43 @@ export async function installWorkflow(packageRoot, opts) {
|
|
|
76
89
|
? sourceContent
|
|
77
90
|
: sourceContent + "\n";
|
|
78
91
|
const templateUserRegion = sourceParsed.kind === "marked" ? sourceParsed.userRegion : "";
|
|
92
|
+
const primaryStat = lstatMaybe(targetPrimary);
|
|
93
|
+
const compatStat = lstatMaybe(targetCompat);
|
|
94
|
+
const legacyShape = primaryStat?.isSymbolicLink() === true &&
|
|
95
|
+
fs.readlinkSync(targetPrimary) === LEGACY_AGENTS_SYMLINK_TARGET &&
|
|
96
|
+
compatStat?.isFile() === true;
|
|
97
|
+
const primaryForeignSymlink = primaryStat?.isSymbolicLink() === true &&
|
|
98
|
+
fs.readlinkSync(targetPrimary) !== LEGACY_AGENTS_SYMLINK_TARGET;
|
|
99
|
+
const compatIsCurrentPrimary = !primaryStat &&
|
|
100
|
+
compatStat !== undefined &&
|
|
101
|
+
!isSymlinkTo(targetCompat, WORKFLOW_COMPAT_SYMLINK_TARGET);
|
|
102
|
+
const currentPath = primaryStat && !primaryStat.isSymbolicLink()
|
|
103
|
+
? targetPrimary
|
|
104
|
+
: legacyShape || compatIsCurrentPrimary
|
|
105
|
+
? targetCompat
|
|
106
|
+
: undefined;
|
|
107
|
+
let wrotePrimary = false;
|
|
108
|
+
const writePrimary = (content) => {
|
|
109
|
+
if (primaryStat?.isSymbolicLink()) {
|
|
110
|
+
if (primaryForeignSymlink) {
|
|
111
|
+
const bak = backupOnce(targetPrimary);
|
|
112
|
+
log.warn(`AGENTS.md 是指向其它目标的软链;已备份到 ${path.basename(bak)} 后改为主文件。`);
|
|
113
|
+
}
|
|
114
|
+
fs.unlinkSync(targetPrimary);
|
|
115
|
+
}
|
|
116
|
+
fs.writeFileSync(targetPrimary, content);
|
|
117
|
+
wrotePrimary = true;
|
|
118
|
+
};
|
|
79
119
|
// Installing the workflow doc is one of five cases. The managed block is
|
|
80
120
|
// always replaced with the packaged version; the cases differ in how the
|
|
81
121
|
// project's own content (the user region) is preserved or backed up.
|
|
82
|
-
if (!
|
|
122
|
+
if (!currentPath) {
|
|
83
123
|
// 1. Fresh install — write the marked template as-is, no backup.
|
|
84
|
-
|
|
85
|
-
log.ok(`
|
|
124
|
+
writePrimary(composeMarkedFile({ blockBody: sourceBlock, userRegion: templateUserRegion, lang }));
|
|
125
|
+
log.ok(`AGENTS.md installed (${langOpt.label})`);
|
|
86
126
|
}
|
|
87
127
|
else {
|
|
88
|
-
const current = fs.readFileSync(
|
|
128
|
+
const current = fs.readFileSync(currentPath, "utf8");
|
|
89
129
|
const parsed = parseMarkers(current);
|
|
90
130
|
if (parsed.kind === "marked") {
|
|
91
131
|
// 2. Upgrade — splice the managed block, preserve the user region.
|
|
@@ -97,80 +137,74 @@ export async function installWorkflow(packageRoot, opts) {
|
|
|
97
137
|
// marker). Can't prove the block is untouched, so back up
|
|
98
138
|
// conservatively rather than risk silently dropping an edit.
|
|
99
139
|
if (parsed.endHash === null) {
|
|
100
|
-
const bak = backupOnce(
|
|
101
|
-
log.warn(
|
|
140
|
+
const bak = backupOnce(currentPath);
|
|
141
|
+
log.warn(`工作流文档的受管区块缺少校验标记,无法确认是否被改动;升级前已备份到 ${path.basename(bak)}`);
|
|
102
142
|
}
|
|
103
143
|
else if (parsed.endHash !== hashBlock(parsed.blockBody)) {
|
|
104
|
-
const bak = backupOnce(
|
|
105
|
-
log.warn(
|
|
144
|
+
const bak = backupOnce(currentPath);
|
|
145
|
+
log.warn(`工作流文档的受管区块曾被手改;升级已整块覆盖该区块,改动前的文件见 ${path.basename(bak)}`);
|
|
106
146
|
}
|
|
107
|
-
|
|
147
|
+
writePrimary(composeMarkedFile({
|
|
108
148
|
prefix: parsed.prefix,
|
|
109
149
|
blockBody: sourceBlock,
|
|
110
150
|
userRegion: parsed.userRegion,
|
|
111
151
|
lang,
|
|
112
152
|
}));
|
|
113
|
-
log.ok(`
|
|
153
|
+
log.ok(`AGENTS.md upgraded (${langOpt.label}); your project section was preserved`);
|
|
114
154
|
}
|
|
115
155
|
else if (parsed.kind === "unmarked" && hasAurigaHeader(current)) {
|
|
116
|
-
// 3. Old-format migration — an auriga
|
|
156
|
+
// 3. Old-format migration — an auriga workflow doc from before markers
|
|
117
157
|
// existed. The user region can't be recovered from an unmarked file,
|
|
118
158
|
// so back the whole thing up and install fresh.
|
|
119
|
-
const bak = backupOnce(
|
|
120
|
-
|
|
121
|
-
log.warn(
|
|
159
|
+
const bak = backupOnce(currentPath);
|
|
160
|
+
writePrimary(composeMarkedFile({ blockBody: sourceBlock, userRegion: templateUserRegion, lang }));
|
|
161
|
+
log.warn(`检测到旧版工作流文档(无受管标记);已备份到 ${path.basename(bak)}。` +
|
|
122
162
|
`若你改过它,请从备份把工程定制手动迁移到 END 标记之后的用户区。`);
|
|
123
|
-
log.ok(`
|
|
163
|
+
log.ok(`AGENTS.md migrated to the managed-block format (${langOpt.label})`);
|
|
124
164
|
}
|
|
125
165
|
else if (parsed.kind === "unmarked") {
|
|
126
|
-
// 4. Foreign first install — a
|
|
166
|
+
// 4. Foreign first install — a workflow doc from another tool. Keep its
|
|
127
167
|
// content in place as the user region; no backup needed.
|
|
128
168
|
const foreign = current.endsWith("\n") ? current : current + "\n";
|
|
129
|
-
|
|
130
|
-
log.ok(`
|
|
169
|
+
writePrimary(composeMarkedFile({ blockBody: sourceBlock, userRegion: "\n" + foreign, lang }));
|
|
170
|
+
log.ok(`AGENTS.md installed (${langOpt.label}); your existing content was kept below the managed block`);
|
|
171
|
+
if (currentPath === targetPrimary) {
|
|
172
|
+
log.warn("AGENTS.md already existed; its content was kept below the managed block.");
|
|
173
|
+
}
|
|
131
174
|
}
|
|
132
175
|
else {
|
|
133
176
|
// 5. Malformed markers — can't locate the block boundaries safely.
|
|
134
177
|
// Back up and reinstall fresh rather than splice into a broken file.
|
|
135
|
-
const bak = backupOnce(
|
|
136
|
-
|
|
137
|
-
log.warn(
|
|
178
|
+
const bak = backupOnce(currentPath);
|
|
179
|
+
writePrimary(composeMarkedFile({ blockBody: sourceBlock, userRegion: templateUserRegion, lang }));
|
|
180
|
+
log.warn(`工作流文档的受管标记已损坏(${parsed.reason});已备份到 ${path.basename(bak)} 并重装。`);
|
|
138
181
|
}
|
|
139
182
|
}
|
|
140
|
-
// Point
|
|
141
|
-
//
|
|
142
|
-
//
|
|
143
|
-
//
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
// does not exist — nothing to preserve.
|
|
152
|
-
}
|
|
153
|
-
if (agentsStat) {
|
|
154
|
-
const pointsToClaude = agentsStat.isSymbolicLink() &&
|
|
155
|
-
fs.readlinkSync(targetAgents) === "CLAUDE.md";
|
|
156
|
-
if (!pointsToClaude) {
|
|
157
|
-
const bak = backupOnce(targetAgents);
|
|
158
|
-
log.warn(`AGENTS.md 不是指向 CLAUDE.md 的软链;已备份到 ${path.basename(bak)} 后替换为软链。`);
|
|
183
|
+
// Point CLAUDE.md at AGENTS.md via a compatibility symlink. If CLAUDE.md was
|
|
184
|
+
// the old primary file and its content was migrated above, replacing it with
|
|
185
|
+
// the symlink is safe. Otherwise preserve any real file or foreign symlink
|
|
186
|
+
// before replacing it.
|
|
187
|
+
const latestCompatStat = lstatMaybe(targetCompat);
|
|
188
|
+
if (latestCompatStat) {
|
|
189
|
+
const pointsToPrimary = isSymlinkTo(targetCompat, WORKFLOW_COMPAT_SYMLINK_TARGET);
|
|
190
|
+
const migratedFromCompat = currentPath === targetCompat && wrotePrimary && !latestCompatStat.isSymbolicLink();
|
|
191
|
+
if (!pointsToPrimary && !migratedFromCompat) {
|
|
192
|
+
const bak = backupOnce(targetCompat);
|
|
193
|
+
log.warn(`CLAUDE.md 不是指向 AGENTS.md 的软链;已备份到 ${path.basename(bak)} 后替换为软链。`);
|
|
159
194
|
}
|
|
160
|
-
fs.unlinkSync(
|
|
195
|
+
fs.unlinkSync(targetCompat);
|
|
161
196
|
}
|
|
162
|
-
fs.symlinkSync(
|
|
163
|
-
log.ok("
|
|
197
|
+
fs.symlinkSync(WORKFLOW_COMPAT_SYMLINK_TARGET, targetCompat);
|
|
198
|
+
log.ok("CLAUDE.md -> AGENTS.md symlink created");
|
|
164
199
|
}
|
|
165
200
|
/**
|
|
166
|
-
* Uninstall the workflow (
|
|
201
|
+
* Uninstall the workflow (AGENTS.md + CLAUDE.md) from `opts.cwd`.
|
|
167
202
|
*
|
|
168
203
|
* Safety contract:
|
|
169
204
|
* - `opts.force` MUST be true. The CLI / server caller is responsible for
|
|
170
205
|
* confirming user intent BEFORE invoking this; we refuse otherwise.
|
|
171
|
-
* -
|
|
172
|
-
*
|
|
173
|
-
* diverged from the install pattern and probably hand-edited it.
|
|
206
|
+
* - Real files are removed only when they are recognizable auriga workflow
|
|
207
|
+
* files. Foreign instruction files are left in place with a warning.
|
|
174
208
|
* - Missing files are a no-op: callers can re-run uninstall idempotently.
|
|
175
209
|
* - `.claude/` is not touched; skills / plugins / hooks have their own
|
|
176
210
|
* uninstall paths.
|
|
@@ -190,38 +224,58 @@ export async function uninstallWorkflow(opts) {
|
|
|
190
224
|
const emit = (line) => {
|
|
191
225
|
opts.onLog?.(line);
|
|
192
226
|
};
|
|
193
|
-
const targetClaude = path.join(resolved,
|
|
194
|
-
const targetAgents = path.join(resolved,
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
227
|
+
const targetClaude = path.join(resolved, WORKFLOW_COMPAT_FILE);
|
|
228
|
+
const targetAgents = path.join(resolved, WORKFLOW_PRIMARY_FILE);
|
|
229
|
+
const isAurigaWorkflowFile = (filePath) => {
|
|
230
|
+
try {
|
|
231
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
232
|
+
return parseMarkers(content).kind === "marked" || hasAurigaHeader(content);
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
const removeWorkflowPath = (filePath, name) => {
|
|
239
|
+
let stat;
|
|
240
|
+
try {
|
|
241
|
+
stat = fs.lstatSync(filePath);
|
|
242
|
+
}
|
|
243
|
+
catch (err) {
|
|
244
|
+
const code = err.code;
|
|
245
|
+
if (code === "ENOENT") {
|
|
246
|
+
log.skip(`${name} not present`);
|
|
247
|
+
emit(`${name} not present`);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
throw err;
|
|
251
|
+
}
|
|
210
252
|
if (stat.isSymbolicLink()) {
|
|
211
|
-
fs.
|
|
212
|
-
|
|
213
|
-
|
|
253
|
+
const linkTarget = fs.readlinkSync(filePath);
|
|
254
|
+
const isManagedSymlink = (name === WORKFLOW_PRIMARY_FILE && linkTarget === LEGACY_AGENTS_SYMLINK_TARGET) ||
|
|
255
|
+
(name === WORKFLOW_COMPAT_FILE && linkTarget === WORKFLOW_COMPAT_SYMLINK_TARGET);
|
|
256
|
+
if (isManagedSymlink) {
|
|
257
|
+
fs.unlinkSync(filePath);
|
|
258
|
+
log.ok(`${name} symlink removed`);
|
|
259
|
+
emit(`removed ${name} symlink`);
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
log.warn(`foreign ${name} symlink left in place`);
|
|
263
|
+
emit(`foreign ${name} symlink left in place`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
else if (stat.isFile() && isAurigaWorkflowFile(filePath)) {
|
|
267
|
+
fs.unlinkSync(filePath);
|
|
268
|
+
log.ok(`${name} removed`);
|
|
269
|
+
emit(`removed ${name}`);
|
|
214
270
|
}
|
|
215
271
|
else {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
log.warn("AGENTS.md is not a symlink; left in place");
|
|
219
|
-
emit("AGENTS.md is not a symlink; left in place");
|
|
272
|
+
log.warn(`foreign ${name} left in place`);
|
|
273
|
+
emit(`foreign ${name} left in place`);
|
|
220
274
|
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
275
|
+
};
|
|
276
|
+
// Remove AGENTS.md first because it is the current primary. lstatSync refuses
|
|
277
|
+
// to follow symlinks, so the legacy AGENTS.md -> CLAUDE.md shape is handled
|
|
278
|
+
// without deleting CLAUDE.md through the link.
|
|
279
|
+
removeWorkflowPath(targetAgents, "AGENTS.md");
|
|
280
|
+
removeWorkflowPath(targetClaude, "CLAUDE.md");
|
|
227
281
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "auriga-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.29.1",
|
|
4
4
|
"description": "Interactive CLI to install Claude Code harness modules (Workflow, Skills, Recommended Skills, Plugins)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"dev": "tsc --watch",
|
|
26
26
|
"start": "node dist/cli.js",
|
|
27
27
|
"pretest": "npm run build",
|
|
28
|
-
"test": "tsc -p tsconfig.test.json && DEV=1 node --test --experimental-test-module-mocks dist-test/tests/skills.test.js dist-test/tests/skills-uninstall.test.js dist-test/tests/catalog.test.js dist-test/tests/cli-parse.test.js dist-test/tests/install-nontty.test.js dist-test/tests/preset.test.js dist-test/tests/legacy-menu.test.js dist-test/tests/plugins.test.js dist-test/tests/plugins-uninstall.test.js dist-test/tests/content-fetch.test.js dist-test/tests/utils.test.js dist-test/tests/guide.test.js dist-test/tests/validators.test.js dist-test/tests/entrypoint.test.js dist-test/tests/state.test.js dist-test/tests/server.test.js dist-test/tests/server-auth.test.js dist-test/tests/server-apply.test.js dist-test/tests/apply-handlers.test.js dist-test/tests/ui-fetch.test.js dist-test/tests/workflow-markers.test.js dist-test/tests/workflow-install.test.js dist-test/tests/workflow-uninstall.test.js dist-test/tests/tarball-shape.test.js dist-test/tests/spec-design.test.js dist-test/tests/goalify.test.js dist-test/tests/plugin-skill-frontmatter.test.js",
|
|
29
|
-
"test:watch": "tsc -p tsconfig.test.json --watch & node --test --watch --experimental-test-module-mocks dist-test/tests/skills.test.js dist-test/tests/skills-uninstall.test.js dist-test/tests/catalog.test.js dist-test/tests/cli-parse.test.js dist-test/tests/install-nontty.test.js dist-test/tests/preset.test.js dist-test/tests/legacy-menu.test.js dist-test/tests/plugins.test.js dist-test/tests/plugins-uninstall.test.js dist-test/tests/content-fetch.test.js dist-test/tests/utils.test.js dist-test/tests/guide.test.js dist-test/tests/validators.test.js dist-test/tests/entrypoint.test.js dist-test/tests/state.test.js dist-test/tests/server.test.js dist-test/tests/server-auth.test.js dist-test/tests/server-apply.test.js dist-test/tests/apply-handlers.test.js dist-test/tests/ui-fetch.test.js dist-test/tests/workflow-markers.test.js dist-test/tests/workflow-install.test.js dist-test/tests/workflow-uninstall.test.js dist-test/tests/tarball-shape.test.js dist-test/tests/spec-design.test.js dist-test/tests/goalify.test.js dist-test/tests/plugin-skill-frontmatter.test.js",
|
|
28
|
+
"test": "tsc -p tsconfig.test.json && DEV=1 node --test --experimental-test-module-mocks dist-test/tests/skills.test.js dist-test/tests/skills-uninstall.test.js dist-test/tests/catalog.test.js dist-test/tests/cli-parse.test.js dist-test/tests/install-nontty.test.js dist-test/tests/preset.test.js dist-test/tests/legacy-menu.test.js dist-test/tests/plugins.test.js dist-test/tests/plugins-uninstall.test.js dist-test/tests/content-fetch.test.js dist-test/tests/utils.test.js dist-test/tests/guide.test.js dist-test/tests/validators.test.js dist-test/tests/entrypoint.test.js dist-test/tests/state.test.js dist-test/tests/server.test.js dist-test/tests/server-auth.test.js dist-test/tests/server-apply.test.js dist-test/tests/apply-handlers.test.js dist-test/tests/ui-fetch.test.js dist-test/tests/workflow-markers.test.js dist-test/tests/workflow-install.test.js dist-test/tests/workflow-uninstall.test.js dist-test/tests/tarball-shape.test.js dist-test/tests/spec-design.test.js dist-test/tests/goalify.test.js dist-test/tests/plugin-skill-frontmatter.test.js dist-test/tests/auriga-workflow-skills.test.js",
|
|
29
|
+
"test:watch": "tsc -p tsconfig.test.json --watch & node --test --watch --experimental-test-module-mocks dist-test/tests/skills.test.js dist-test/tests/skills-uninstall.test.js dist-test/tests/catalog.test.js dist-test/tests/cli-parse.test.js dist-test/tests/install-nontty.test.js dist-test/tests/preset.test.js dist-test/tests/legacy-menu.test.js dist-test/tests/plugins.test.js dist-test/tests/plugins-uninstall.test.js dist-test/tests/content-fetch.test.js dist-test/tests/utils.test.js dist-test/tests/guide.test.js dist-test/tests/validators.test.js dist-test/tests/entrypoint.test.js dist-test/tests/state.test.js dist-test/tests/server.test.js dist-test/tests/server-auth.test.js dist-test/tests/server-apply.test.js dist-test/tests/apply-handlers.test.js dist-test/tests/ui-fetch.test.js dist-test/tests/workflow-markers.test.js dist-test/tests/workflow-install.test.js dist-test/tests/workflow-uninstall.test.js dist-test/tests/tarball-shape.test.js dist-test/tests/spec-design.test.js dist-test/tests/goalify.test.js dist-test/tests/plugin-skill-frontmatter.test.js dist-test/tests/auriga-workflow-skills.test.js",
|
|
30
30
|
"pretest:e2e": "npm run build",
|
|
31
31
|
"test:e2e": "tsc -p tsconfig.test.json && node --test dist-test/tests/e2e-install.test.js",
|
|
32
32
|
"pretest:web-ui-e2e": "npm run build && npm --prefix ui ci && npm --prefix ui run build",
|