@ai-content-space/loopx 0.2.4 → 0.2.7
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 +106 -10
- package/README.zh-CN.md +106 -10
- package/docs/loopx/design/finish/345/255/246/344/271/240/345/256/241/350/256/241/351/234/200/346/261/202/350/256/276/350/256/241/346/226/207/346/241/243.md +707 -0
- package/docs/loopx/memory/2026-06-09-stale-archive-hook-guidance.md +15 -0
- package/docs/loopx/memory/README.md +25 -0
- package/docs/loopx/plans/2026-06-08-finish-audit-change-window.md +933 -0
- package/docs/loopx/plans/2026-06-08-finish-learning-audit.md +410 -0
- package/docs/loopx/plans/2026-06-09-cli-onboarding-install-surface.md +1277 -0
- package/docs/loopx/specs/installation.md +33 -0
- package/package.json +18 -2
- package/plugins/loopx/.codex-plugin/plugin.json +1 -1
- package/plugins/loopx/skills/clarify/SKILL.md +1 -1
- package/plugins/loopx/skills/debug/SKILL.md +1 -1
- package/plugins/loopx/skills/doc-readability/SKILL.md +1 -1
- package/plugins/loopx/skills/exec/SKILL.md +11 -1
- package/plugins/loopx/skills/final-review/SKILL.md +1 -1
- package/plugins/loopx/skills/finish/SKILL.md +39 -7
- package/plugins/loopx/skills/fix-review/SKILL.md +1 -1
- package/plugins/loopx/skills/go-style/SKILL.md +1 -1
- package/plugins/loopx/skills/kratos/SKILL.md +1 -1
- package/plugins/loopx/skills/plan/SKILL.md +1 -1
- package/plugins/loopx/skills/refactor-plan/SKILL.md +1 -1
- package/plugins/loopx/skills/review/SKILL.md +1 -1
- package/plugins/loopx/skills/spec/SKILL.md +1 -1
- package/plugins/loopx/skills/subagent-exec/SKILL.md +13 -1
- package/plugins/loopx/skills/tdd/SKILL.md +1 -1
- package/plugins/loopx/skills/verify/SKILL.md +1 -1
- package/scripts/claude-workflow-hook.mjs +50 -1
- package/scripts/codex-workflow-hook.mjs +33 -12
- package/scripts/install-skills.mjs +58 -3
- package/scripts/verify-skills.mjs +83 -7
- package/skills/clarify/SKILL.md +1 -1
- package/skills/debug/SKILL.md +1 -1
- package/skills/doc-readability/SKILL.md +1 -1
- package/skills/exec/SKILL.md +11 -1
- package/skills/final-review/SKILL.md +1 -1
- package/skills/finish/SKILL.md +39 -7
- package/skills/fix-review/SKILL.md +1 -1
- package/skills/go-style/SKILL.md +1 -1
- package/skills/kratos/SKILL.md +1 -1
- package/skills/plan/SKILL.md +1 -1
- package/skills/refactor-plan/SKILL.md +1 -1
- package/skills/review/SKILL.md +1 -1
- package/skills/spec/SKILL.md +1 -1
- package/skills/subagent-exec/SKILL.md +13 -1
- package/skills/tdd/SKILL.md +1 -1
- package/skills/verify/SKILL.md +1 -1
- package/src/cli.mjs +473 -86
- package/src/finish-runtime.mjs +1184 -0
- package/src/install-discovery.mjs +37 -0
- package/src/next-skill.mjs +8 -10
- package/src/workflow.mjs +19 -26
- package/skills/deepsearch/SKILL.md +0 -38
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Installation And CLI Onboarding Spec
|
|
2
|
+
|
|
3
|
+
This file records stable loopx product-surface rules for first-use CLI output, installer behavior, hook guidance, and packaged skill scope.
|
|
4
|
+
|
|
5
|
+
## Human And JSON Output
|
|
6
|
+
|
|
7
|
+
- `loopx --help` must start with a short quickstart path: install skills, init, clarify, status.
|
|
8
|
+
- `loopx init`, `loopx doctor`, and `loopx install-skills` default to concise human output.
|
|
9
|
+
- Full runtime payloads require explicit `--json`.
|
|
10
|
+
- Commands in `--json` mode must not print interactive prompt text into stdout.
|
|
11
|
+
|
|
12
|
+
## Archive Compatibility
|
|
13
|
+
|
|
14
|
+
- `archive` is hidden compatibility, not part of the public v1 product flow.
|
|
15
|
+
- Default help, README public command lists, next-step helpers, and workflow hooks must not recommend `loopx archive` or `$archive`.
|
|
16
|
+
- If old persisted runtime state contains archive recommendations, hooks must replace them:
|
|
17
|
+
- done/archive/completed state -> `$finish`
|
|
18
|
+
- approved review state -> `loopx approve <slug> --from review --to done`
|
|
19
|
+
|
|
20
|
+
## Installer Behavior
|
|
21
|
+
|
|
22
|
+
- `loopx install-skills --dry-run` is read-only. It must not write skills, hooks, lock files, settings, or template hashes.
|
|
23
|
+
- All-target dry-run summaries must render the follow-up command as `loopx install-skills --target all --yes`.
|
|
24
|
+
- `--dir` is valid only with a single target. `--target all --dir <path>` must fail before writing files.
|
|
25
|
+
- `loopx install-skills` must exit nonzero whenever its final payload has `ok: false`, in both human and JSON modes.
|
|
26
|
+
- Postinstall opt-outs are `LOOPX_SKIP_POSTINSTALL=1` and `LOOPX_POSTINSTALL=0`.
|
|
27
|
+
- Postinstall opt-out with `--json` must preserve JSON stdout.
|
|
28
|
+
|
|
29
|
+
## Published Skill Surface
|
|
30
|
+
|
|
31
|
+
- The package root `skills/` surface is exactly `skills/RESOLVER.md` plus the directories in `LOOPX_BUNDLED_SKILLS`.
|
|
32
|
+
- Auxiliary root skill sources must not be published by explicit or broad `package.json.files` entries.
|
|
33
|
+
- `scripts/verify-skills.mjs` and the package governance tests are the release gates for this surface.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-content-space/loopx",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.7",
|
|
5
5
|
"description": "Skill-first workflow suite for agentic coding assistants",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -30,7 +30,23 @@
|
|
|
30
30
|
"scripts/codex-workflow-hook.mjs",
|
|
31
31
|
"assets/logo.svg",
|
|
32
32
|
"src/",
|
|
33
|
-
"skills/",
|
|
33
|
+
"skills/RESOLVER.md",
|
|
34
|
+
"skills/clarify/",
|
|
35
|
+
"skills/debug/",
|
|
36
|
+
"skills/doc-readability/",
|
|
37
|
+
"skills/exec/",
|
|
38
|
+
"skills/final-review/",
|
|
39
|
+
"skills/finish/",
|
|
40
|
+
"skills/fix-review/",
|
|
41
|
+
"skills/go-style/",
|
|
42
|
+
"skills/kratos/",
|
|
43
|
+
"skills/plan/",
|
|
44
|
+
"skills/refactor-plan/",
|
|
45
|
+
"skills/review/",
|
|
46
|
+
"skills/spec/",
|
|
47
|
+
"skills/subagent-exec/",
|
|
48
|
+
"skills/tdd/",
|
|
49
|
+
"skills/verify/",
|
|
34
50
|
"templates/",
|
|
35
51
|
"plugins/loopx/",
|
|
36
52
|
"!plugins/loopx/scripts/plugin-install.test.mjs"
|
|
@@ -3,7 +3,7 @@ name: clarify
|
|
|
3
3
|
description: "Grills ambiguous loopx work until material questions are answered, then routes to spec or plan using a design gate. Not for clear implementation tasks, approved specs, or code changes."
|
|
4
4
|
when_to_use: "clarify, requirements, ambiguous request, unclear scope, non-goals, decision boundaries, acceptance criteria, 需求澄清, 范围不清"
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.2.
|
|
6
|
+
version: "0.2.7"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# loopx Clarify
|
|
@@ -3,7 +3,7 @@ name: debug
|
|
|
3
3
|
description: "Finds root cause for bugs, failing tests, build failures, regressions, and unexpected behavior before fixes. Not for new feature planning or routine code review."
|
|
4
4
|
when_to_use: "debug, bug, test failure, build failure, regression, unexpected behavior, root cause, 报错, 失败, 回归, 排查"
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.2.
|
|
6
|
+
version: "0.2.7"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Systematic Debugging
|
|
@@ -3,7 +3,7 @@ name: doc-readability
|
|
|
3
3
|
description: "Use when evaluating, rewriting, or editing documents for human readability, unclear viewpoints, AI-like prose, bloated specs, PRDs, requirements docs, meeting notes, strategy docs, or internal knowledge-base articles. Not for code review, implementation planning, or file-format conversion."
|
|
4
4
|
when_to_use: "document readability, PRD assessment, requirements gaps, AI-like prose, unclear viewpoint, rewrite docs, editing docs, 文档可读性, 去AI味, 需求文档评估"
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.2.
|
|
6
|
+
version: "0.2.7"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Doc Readability
|
|
@@ -3,7 +3,7 @@ name: exec
|
|
|
3
3
|
description: "Executes a written loopx implementation plan sequentially with review checkpoints. Not for unclear plans, missing requirements, or subagent-first execution."
|
|
4
4
|
when_to_use: "written implementation plan, inline execution, sequential plan execution, review checkpoints, no subagent lane"
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.2.
|
|
6
|
+
version: "0.2.7"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Exec
|
|
@@ -24,6 +24,16 @@ Load plan, review critically, execute all tasks, report when complete.
|
|
|
24
24
|
3. If concerns: Raise them with your human partner before starting
|
|
25
25
|
4. If no concerns: create update_plan and proceed
|
|
26
26
|
|
|
27
|
+
### Step 1.5: Record Finish Baseline
|
|
28
|
+
|
|
29
|
+
Before editing files or running the first task, run:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
loopx finish-start <slug> --source <plan-path>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Use the plan filename slug when no workflow slug is available. This preserves the starting `HEAD` for finish learning/spec audit after the execution commits code.
|
|
36
|
+
|
|
27
37
|
### Step 2: Execute Tasks
|
|
28
38
|
|
|
29
39
|
For each task:
|
|
@@ -3,7 +3,7 @@ name: final-review
|
|
|
3
3
|
description: "Performs whole-feature review after implementation and staged task review. Not for per-task review, unresolved scope, implementation, or pure documentation polish."
|
|
4
4
|
when_to_use: "final-review, final code review, whole feature review, integration review, pre-finish review, after subagent-exec, runtime risk review, 最终评审"
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.2.
|
|
6
|
+
version: "0.2.7"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Final Review
|
|
@@ -3,7 +3,7 @@ name: finish
|
|
|
3
3
|
description: "Finishes completed loopx development work after tests pass by presenting merge, PR, keep, or discard options. Not for unfinished work or failing verification."
|
|
4
4
|
when_to_use: "implementation complete, tests pass, finish branch, create pull request, merge locally, keep branch, discard work"
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.2.
|
|
6
|
+
version: "0.2.7"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Finish
|
|
@@ -66,18 +66,33 @@ git merge-base HEAD main 2>/dev/null || git merge-base HEAD master 2>/dev/null
|
|
|
66
66
|
|
|
67
67
|
Or ask: "This branch split from main - is that correct?"
|
|
68
68
|
|
|
69
|
-
### Step 4: Learning Extraction
|
|
69
|
+
### Step 4: Audit-First Learning Extraction
|
|
70
70
|
|
|
71
|
-
Run
|
|
71
|
+
Run `finish-audit` before presenting merge, PR, keep, or discard options.
|
|
72
|
+
|
|
73
|
+
`loopx:exec` and `loopx:subagent-exec` should have run `finish-start` before implementation. `finish-audit` uses that baseline to preserve committed `baseline..HEAD` evidence after the working tree is clean. It may also generate `audit.extraction_candidates` as draft memory/spec review prompts. These drafts are not automatically written to memory or specs.
|
|
72
74
|
|
|
73
75
|
Allowed inputs:
|
|
74
|
-
-
|
|
76
|
+
- `finish-state.json` `audit.change_window`, especially `baseline..HEAD` commits and changed files
|
|
77
|
+
- `finish-state.json` `audit.extraction_candidates`
|
|
78
|
+
- current uncommitted git diff and `git status --short`
|
|
75
79
|
- executed verification output
|
|
76
80
|
- plan, spec, and review artifacts used in this task
|
|
77
81
|
- explicit user decisions in the current conversation
|
|
78
82
|
- existing `.loopx/memory/MEMORY.md` and `.loopx/memory/index.jsonl`
|
|
83
|
+
- existing `docs/loopx/memory/*.md`
|
|
79
84
|
- existing `docs/loopx/specs/*.md`
|
|
80
85
|
|
|
86
|
+
An empty git diff does not mean there is no learning candidate. When `audit.change_window.commit_count > 0`, inspect the committed range before deciding memory/spec candidates. "Already committed" is not a rejection reason; reject only when the committed change window contains no durable behavior, contract, invariant, pitfall, or user decision worth preserving.
|
|
87
|
+
|
|
88
|
+
Read the audit state from `.loopx/finish/<audit-id>/finish-state.json` before deciding what to record.
|
|
89
|
+
After learning extraction, update `finish-state.json` before any `done` record:
|
|
90
|
+
- set `status` to `"audited"`
|
|
91
|
+
- for every `audit.extraction_candidates[]` item, add either a matching `accepted_candidates` with evidence or a matching `rejected_candidates[]` item with `rejection_reason`
|
|
92
|
+
- when no extraction candidates exist and no candidate is accepted, replace `no_candidates_reason` with a specific reason
|
|
93
|
+
|
|
94
|
+
`finish-record --status done` will reject an audit while generated extraction candidates remain unreviewed.
|
|
95
|
+
|
|
81
96
|
Learning extraction priority:
|
|
82
97
|
1. Durable behavior, contracts, or constraints proven by the implementation
|
|
83
98
|
2. State, file, CLI, API, install, migration, compatibility, or test invariants
|
|
@@ -87,11 +102,19 @@ Learning extraction priority:
|
|
|
87
102
|
|
|
88
103
|
Do not infer durable rules from agent intuition alone. Do not promote unverified implementation details.
|
|
89
104
|
|
|
105
|
+
When the audit has no candidates, record `none` with the scanned inputs and a reason in `no_candidates_reason`.
|
|
106
|
+
Keep rejected candidates explicit when draft candidates are not accepted.
|
|
107
|
+
Accepted candidates require evidence from the audit state. Rejected candidates require reasons.
|
|
108
|
+
choice recording must persist the user's completion choice through `finish-record` before presenting the final completion outcome.
|
|
109
|
+
|
|
90
110
|
#### Memory
|
|
91
111
|
|
|
92
|
-
Memory
|
|
112
|
+
Memory has two scopes:
|
|
113
|
+
|
|
114
|
+
- local memory: agent-queryable project context for one machine; not repo-tracked
|
|
115
|
+
- shared memory: lightweight project knowledge that should follow a user across machines; repo-tracked
|
|
93
116
|
|
|
94
|
-
Use:
|
|
117
|
+
Use local memory for machine-local facts, short-lived handoffs, and context that is useful only to the current agent environment:
|
|
95
118
|
|
|
96
119
|
```text
|
|
97
120
|
.loopx/memory/MEMORY.md
|
|
@@ -104,7 +127,13 @@ Use:
|
|
|
104
127
|
|
|
105
128
|
`index.jsonl` is a curated active index, not an append-only history. It should point only to active memory cards worth querying.
|
|
106
129
|
|
|
107
|
-
Use memory
|
|
130
|
+
Use shared memory for concise, evidence-backed notes that are useful across machines but not stable enough for specs:
|
|
131
|
+
|
|
132
|
+
```text
|
|
133
|
+
docs/loopx/memory/
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Use memory only for facts that will help a future agent avoid rework, avoid mistakes, or preserve a decision. Do not record process negatives such as "no spec promotion". Do not store secrets, raw conversation logs, or machine-local paths in shared memory.
|
|
108
137
|
|
|
109
138
|
One finish run may write 0-3 active memory cards. If more learnings appear, consolidate, promote to spec, archive stale cards, or skip low-signal items.
|
|
110
139
|
|
|
@@ -123,6 +152,8 @@ Allowed memory `type` values:
|
|
|
123
152
|
|
|
124
153
|
Finish may automatically update `.loopx/memory/MEMORY.md`, `.loopx/memory/index.jsonl`, and active memory cards. The final response must list the memory changes.
|
|
125
154
|
|
|
155
|
+
When accepting an `audit.extraction_candidates[]` item with `kind: "memory"` and `scope: "shared"`, write the accepted note under `docs/loopx/memory/` so it is visible in the git diff. Promote shared memory to `docs/loopx/specs/` when it becomes a durable rule that planning or review should depend on.
|
|
156
|
+
|
|
126
157
|
#### Spec Candidates
|
|
127
158
|
|
|
128
159
|
Spec extraction is conditional. Run the audit every time, but write spec candidates only when the task produced stable, shared, reusable project rules.
|
|
@@ -295,6 +326,7 @@ Use this shape:
|
|
|
295
326
|
```text
|
|
296
327
|
Memory:
|
|
297
328
|
- updated: .loopx/memory/MEMORY.md
|
|
329
|
+
- shared: docs/loopx/memory/<file>.md
|
|
298
330
|
- entries: <N> added, <N> archived
|
|
299
331
|
- summary:
|
|
300
332
|
- <high-signal memory change>
|
|
@@ -3,7 +3,7 @@ name: fix-review
|
|
|
3
3
|
description: "Handles received code review feedback with verification, technical evaluation, pushback, and one-item-at-a-time fixes. Not for requesting a new review or implementing unrelated changes."
|
|
4
4
|
when_to_use: "fix-review, received code review feedback, review comments, reviewer suggestions, requested changes, 处理评审意见"
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.2.
|
|
6
|
+
version: "0.2.7"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Fix Review
|
|
@@ -3,7 +3,7 @@ name: go-style
|
|
|
3
3
|
description: "Applies loopx Go coding style for .go edits, tests, errors, context, naming, and interface boundaries. Not for non-Go code or Kratos-specific architecture by itself."
|
|
4
4
|
when_to_use: "go-style, Go, golang, .go files, go tests, gofmt, idiomatic Go, Go style, Go 代码"
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.2.
|
|
6
|
+
version: "0.2.7"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Go Style
|
|
@@ -3,7 +3,7 @@ name: kratos
|
|
|
3
3
|
description: "Supports Go-Kratos microservices, proto/buf APIs, service/biz/data layers, middleware, auth, config, and troubleshooting. Not for generic Go style alone."
|
|
4
4
|
when_to_use: "kratos, Go-Kratos, proto, buf, service layer, biz layer, data layer, middleware, auth, config, Kratos 微服务"
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.2.
|
|
6
|
+
version: "0.2.7"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Kratos
|
|
@@ -3,7 +3,7 @@ name: plan
|
|
|
3
3
|
description: "Creates bite-sized implementation plans from approved requirements, clarify output, or design specs with exact files, tests, commands, expected output, and execution handoff. Not for unresolved requirements, design decisions, PRD generation, or code changes."
|
|
4
4
|
when_to_use: "plan, implementation plan, execution plan, task breakdown, approved requirements, approved design spec, docs/loopx/design, 实施计划, 执行计划, 任务拆分"
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.2.
|
|
6
|
+
version: "0.2.7"
|
|
7
7
|
argument-hint: "<design spec path or feature name>"
|
|
8
8
|
---
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ name: refactor-plan
|
|
|
3
3
|
description: "Creates a behavior-preserving refactor plan with user interview, repo evidence, tiny commits, scope boundaries, and testing decisions. Not for feature changes or immediate implementation."
|
|
4
4
|
when_to_use: "refactor-plan, refactor request, refactoring RFC, tiny commits, behavior-preserving cleanup, architecture cleanup, 重构计划"
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.2.
|
|
6
|
+
version: "0.2.7"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
This skill will be invoked when the user wants to create a refactor request. You should go through the steps below. You may skip steps if you don't consider them necessary.
|
|
@@ -3,7 +3,7 @@ name: review
|
|
|
3
3
|
description: "Dispatches a loopx code reviewer subagent against a concrete git range and requirements. Not for implementation, planning, or unresolved review scope."
|
|
4
4
|
when_to_use: "request code review, completed task review, major feature review, pre-merge review, subagent code quality check"
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.2.
|
|
6
|
+
version: "0.2.7"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Review
|
|
@@ -3,7 +3,7 @@ name: spec
|
|
|
3
3
|
description: "Writes software design specs from already-clarified requirements, including solution approach, architecture outline, detailed design, tradeoffs, verification design, and handoff context. Not for unresolved requirements, PRD generation, implementation task planning, or code changes."
|
|
4
4
|
when_to_use: "spec, design spec, technical design, design proposal, detailed design, architecture design, 设计方案, 概要设计, 详细设计, 技术方案"
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.2.
|
|
6
|
+
version: "0.2.7"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# loopx Spec
|
|
@@ -3,7 +3,7 @@ name: subagent-exec
|
|
|
3
3
|
description: "Executes approved loopx implementation plans with fresh subagents per independent task and staged review. Not for planning, unclear requirements, or tightly coupled edits."
|
|
4
4
|
when_to_use: "approved implementation plan, independent tasks, subagent execution, staged spec review, code quality review, parallel-capable execution"
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.2.
|
|
6
|
+
version: "0.2.7"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Subagent Exec
|
|
@@ -63,11 +63,13 @@ digraph process {
|
|
|
63
63
|
"Mark task complete in update_plan" [shape=box];
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
"Record finish baseline with loopx finish-start <slug> --source <plan-path>" [shape=box];
|
|
66
67
|
"Read plan, extract all tasks with full text, note context, create update_plan" [shape=box];
|
|
67
68
|
"More tasks remain?" [shape=diamond];
|
|
68
69
|
"Use loopx:final-review for entire implementation" [shape=box];
|
|
69
70
|
"Use loopx:finish" [shape=box style=filled fillcolor=lightgreen];
|
|
70
71
|
|
|
72
|
+
"Record finish baseline with loopx finish-start <slug> --source <plan-path>" -> "Read plan, extract all tasks with full text, note context, create update_plan";
|
|
71
73
|
"Read plan, extract all tasks with full text, note context, create update_plan" -> "Dispatch implementer subagent (./implementer-prompt.md)";
|
|
72
74
|
"Dispatch implementer subagent (./implementer-prompt.md)" -> "Implementer subagent asks questions?";
|
|
73
75
|
"Implementer subagent asks questions?" -> "Answer questions, provide context" [label="yes"];
|
|
@@ -89,6 +91,16 @@ digraph process {
|
|
|
89
91
|
}
|
|
90
92
|
```
|
|
91
93
|
|
|
94
|
+
### Step 0: Record Finish Baseline
|
|
95
|
+
|
|
96
|
+
Before dispatching the first implementer, run:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
loopx finish-start <slug> --source <plan-path>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Use the plan filename slug when no workflow slug is available. This preserves the starting `HEAD` so `finish-audit` can inspect `baseline..HEAD` even after implementers commit their work and the current `git diff` is empty.
|
|
103
|
+
|
|
92
104
|
## Model Selection
|
|
93
105
|
|
|
94
106
|
Use the least powerful model that can handle each role to conserve cost and increase speed.
|
|
@@ -3,7 +3,7 @@ name: tdd
|
|
|
3
3
|
description: "Guides feature and bugfix implementation through a failing test before production code and red-green-refactor discipline. Not for generated files or throwaway prototypes."
|
|
4
4
|
when_to_use: "tdd, failing test first, feature implementation, bugfix, regression test, red green refactor, 测试先行"
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.2.
|
|
6
|
+
version: "0.2.7"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Test-Driven Development (TDD)
|
|
@@ -3,7 +3,7 @@ name: verify
|
|
|
3
3
|
description: "Requires fresh verification evidence before claiming work is complete, fixed, passing, review-ready, or ready to commit. Not for speculative confidence or stale results."
|
|
4
4
|
when_to_use: "verify, completion claim, fixed claim, tests pass, review-ready, commit, fresh evidence, 验证, 完成前检查"
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.2.
|
|
6
|
+
version: "0.2.7"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Verification Before Completion
|
|
@@ -52,10 +52,59 @@ function findNearestLoopxRuntimeRoot(startCwd) {
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
function archiveNextActionReplacement(state) {
|
|
56
|
+
const approvedReviewAction = approvedReviewNextAction(state);
|
|
57
|
+
if (approvedReviewAction) {
|
|
58
|
+
return approvedReviewAction;
|
|
59
|
+
}
|
|
60
|
+
if (state.current_stage === 'done' || state.current_stage === 'archive' || state.completion_confirmed === true) {
|
|
61
|
+
return '$finish';
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function approvedReviewNextAction(state) {
|
|
67
|
+
if (state.current_stage === 'review' && state.review_verdict === 'approve' && state.slug) {
|
|
68
|
+
return `loopx approve ${state.slug} --from review --to done`;
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function persistedNextAction(state) {
|
|
74
|
+
const action = typeof state?.recommended_next_action === 'string'
|
|
75
|
+
? state.recommended_next_action.trim()
|
|
76
|
+
: '';
|
|
77
|
+
if (!action) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
if (/\bloopx\s+archive\b|\$archive\b/i.test(action)) {
|
|
81
|
+
return archiveNextActionReplacement(state);
|
|
82
|
+
}
|
|
83
|
+
return action;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function staleArchiveNextAction(state) {
|
|
87
|
+
const action = typeof state?.recommended_next_action === 'string'
|
|
88
|
+
? state.recommended_next_action.trim()
|
|
89
|
+
: '';
|
|
90
|
+
if (!action || !/\bloopx\s+archive\b|\$archive\b/i.test(action)) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
return archiveNextActionReplacement(state);
|
|
94
|
+
}
|
|
95
|
+
|
|
55
96
|
function nextSkill(state) {
|
|
56
97
|
if (!state?.slug) {
|
|
57
98
|
return null;
|
|
58
99
|
}
|
|
100
|
+
const staleArchiveAction = staleArchiveNextAction(state);
|
|
101
|
+
if (staleArchiveAction) {
|
|
102
|
+
return staleArchiveAction;
|
|
103
|
+
}
|
|
104
|
+
const approvedReviewAction = approvedReviewNextAction(state);
|
|
105
|
+
if (approvedReviewAction) {
|
|
106
|
+
return approvedReviewAction;
|
|
107
|
+
}
|
|
59
108
|
if (state.current_stage === 'clarify') {
|
|
60
109
|
return 'Use loopx:clarify until material questions are resolved, then route to loopx:spec or loopx:plan.';
|
|
61
110
|
}
|
|
@@ -68,7 +117,7 @@ function nextSkill(state) {
|
|
|
68
117
|
if (state.current_stage === 'review') {
|
|
69
118
|
return 'Legacy runtime review detected. New v1 code review should use loopx:review.';
|
|
70
119
|
}
|
|
71
|
-
return state
|
|
120
|
+
return persistedNextAction(state);
|
|
72
121
|
}
|
|
73
122
|
|
|
74
123
|
try {
|
|
@@ -35,16 +35,8 @@ function nextSkill(state) {
|
|
|
35
35
|
return `$plan ${state.slug}`;
|
|
36
36
|
}
|
|
37
37
|
if (state.current_stage === 'done'
|
|
38
|
-
&& state.completion_confirmed === true
|
|
39
|
-
|
|
40
|
-
return `$archive ${state.slug}`;
|
|
41
|
-
}
|
|
42
|
-
if (state.current_stage === 'review'
|
|
43
|
-
&& state.review_verdict === 'approve'
|
|
44
|
-
&& state.pending_user_decision === 'review->done'
|
|
45
|
-
&& ['requested', 'approved'].includes(state.approval?.complete)
|
|
46
|
-
&& state.archive_status !== 'archived') {
|
|
47
|
-
return `$archive ${state.slug}`;
|
|
38
|
+
&& state.completion_confirmed === true) {
|
|
39
|
+
return '$finish';
|
|
48
40
|
}
|
|
49
41
|
if (state.stage_status === 'awaiting-approval'
|
|
50
42
|
&& state.current_stage === 'plan'
|
|
@@ -103,6 +95,12 @@ function nextCli(state) {
|
|
|
103
95
|
&& state.plan_blockers.length === 0) {
|
|
104
96
|
return `loopx build .loopx/plans/requirements-snapshot-${state.slug}.md`;
|
|
105
97
|
}
|
|
98
|
+
if (state.current_stage === 'review'
|
|
99
|
+
&& state.review_verdict === 'approve'
|
|
100
|
+
&& state.pending_user_decision === 'review->done'
|
|
101
|
+
&& ['requested', 'approved'].includes(state.approval?.complete)) {
|
|
102
|
+
return `loopx approve ${state.slug} --from review --to done`;
|
|
103
|
+
}
|
|
106
104
|
if (state.current_stage === 'review'
|
|
107
105
|
&& state.review_verdict === 'request-changes'
|
|
108
106
|
&& state.rollback_target === 'build'
|
|
@@ -123,6 +121,29 @@ function nextCli(state) {
|
|
|
123
121
|
return null;
|
|
124
122
|
}
|
|
125
123
|
|
|
124
|
+
function archiveNextActionReplacement(state) {
|
|
125
|
+
if (state.current_stage === 'review' && state.review_verdict === 'approve' && state.slug) {
|
|
126
|
+
return `loopx approve ${state.slug} --from review --to done`;
|
|
127
|
+
}
|
|
128
|
+
if (state.current_stage === 'done' || state.current_stage === 'archive' || state.completion_confirmed === true) {
|
|
129
|
+
return '$finish';
|
|
130
|
+
}
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function persistedNextAction(state) {
|
|
135
|
+
const action = typeof state?.recommended_next_action === 'string'
|
|
136
|
+
? state.recommended_next_action.trim()
|
|
137
|
+
: '';
|
|
138
|
+
if (!action) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
if (/\bloopx\s+archive\b|\$archive\b/i.test(action)) {
|
|
142
|
+
return archiveNextActionReplacement(state);
|
|
143
|
+
}
|
|
144
|
+
return action;
|
|
145
|
+
}
|
|
146
|
+
|
|
126
147
|
function blockers(state) {
|
|
127
148
|
const values = [
|
|
128
149
|
...(Array.isArray(state.plan_blockers) ? state.plan_blockers : []),
|
|
@@ -161,9 +182,9 @@ function nextActionLine(state, workflow) {
|
|
|
161
182
|
return `loopx migrate, then $plan ${state.slug || workflow}`;
|
|
162
183
|
}
|
|
163
184
|
if (isClarifyReadyForPlan(state) && state.approval?.plan !== 'approved') {
|
|
164
|
-
return `
|
|
185
|
+
return `finish clarification, then $plan ${state.slug || workflow}`;
|
|
165
186
|
}
|
|
166
|
-
return nextSkill(state) || nextCli(state) || state
|
|
187
|
+
return nextSkill(state) || nextCli(state) || persistedNextAction(state) || 'none';
|
|
167
188
|
}
|
|
168
189
|
|
|
169
190
|
function implementationGateLines(state) {
|
|
@@ -2,17 +2,72 @@
|
|
|
2
2
|
|
|
3
3
|
import { installSkillsForTargets, verifyInstallTargets } from '../src/install-discovery.mjs';
|
|
4
4
|
|
|
5
|
+
function shouldSkipPostinstall(env = process.env) {
|
|
6
|
+
return env.LOOPX_SKIP_POSTINSTALL === '1' || env.LOOPX_POSTINSTALL === '0';
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function skipPostinstallEnv(env = process.env) {
|
|
10
|
+
if (env.LOOPX_SKIP_POSTINSTALL === '1') {
|
|
11
|
+
return 'LOOPX_SKIP_POSTINSTALL';
|
|
12
|
+
}
|
|
13
|
+
if (env.LOOPX_POSTINSTALL === '0') {
|
|
14
|
+
return 'LOOPX_POSTINSTALL';
|
|
15
|
+
}
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function targetNames(result) {
|
|
20
|
+
return Array.isArray(result.targets) && result.targets.length > 0 ? result.targets : Object.keys(result.results || {});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function count(result, key) {
|
|
24
|
+
return Object.values(result.results || {})
|
|
25
|
+
.reduce((sum, target) => sum + (Array.isArray(target?.[key]) ? target[key].length : 0), 0);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function printSummary(result, { checkOnly = false } = {}) {
|
|
29
|
+
console.log(`loopx ${checkOnly ? 'install check' : 'postinstall'}: ${result.ok === false ? 'attention needed' : 'ok'}`);
|
|
30
|
+
console.log(`targets: ${targetNames(result).join(', ')}`);
|
|
31
|
+
if (!checkOnly) {
|
|
32
|
+
console.log(`installed skills: ${count(result, 'installed')}`);
|
|
33
|
+
}
|
|
34
|
+
console.log(`conflicts: ${count(result, 'conflicts')}`);
|
|
35
|
+
console.log(`skipped user-modified: ${count(result, 'skipped')}`);
|
|
36
|
+
console.log('repair: loopx repair-install');
|
|
37
|
+
console.log('opt out: LOOPX_SKIP_POSTINSTALL=1');
|
|
38
|
+
console.log('disable hooks for one process: LOOPX_HOOKS=0');
|
|
39
|
+
console.log('details: node scripts/install-skills.mjs --json');
|
|
40
|
+
}
|
|
41
|
+
|
|
5
42
|
async function main() {
|
|
43
|
+
const json = process.argv.includes('--json');
|
|
44
|
+
if (shouldSkipPostinstall()) {
|
|
45
|
+
if (json) {
|
|
46
|
+
console.log(JSON.stringify({
|
|
47
|
+
ok: true,
|
|
48
|
+
skipped: true,
|
|
49
|
+
reason: 'postinstall_disabled',
|
|
50
|
+
env: skipPostinstallEnv(),
|
|
51
|
+
}, null, 2));
|
|
52
|
+
} else {
|
|
53
|
+
console.log('loopx postinstall skipped: LOOPX_SKIP_POSTINSTALL=1 or LOOPX_POSTINSTALL=0');
|
|
54
|
+
}
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
6
58
|
const checkOnly = process.argv.includes('--check');
|
|
7
59
|
const result = checkOnly ? await verifyInstallTargets(process.env) : await installSkillsForTargets(process.env);
|
|
8
60
|
const ok = checkOnly ? result.ok : result.ok !== false;
|
|
9
61
|
const payload = checkOnly ? result : { ok, targets: result.targets, results: result.results };
|
|
62
|
+
if (json) {
|
|
63
|
+
const stream = ok ? process.stdout : process.stderr;
|
|
64
|
+
stream.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
65
|
+
} else {
|
|
66
|
+
printSummary(payload, { checkOnly });
|
|
67
|
+
}
|
|
10
68
|
if (!ok) {
|
|
11
|
-
console.error(JSON.stringify(payload, null, 2));
|
|
12
69
|
process.exitCode = 1;
|
|
13
|
-
return;
|
|
14
70
|
}
|
|
15
|
-
console.log(JSON.stringify(payload, null, 2));
|
|
16
71
|
}
|
|
17
72
|
|
|
18
73
|
await main();
|