@aipper/aiws-spec 0.0.51 → 0.0.53
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/docs/pi-plugins-manifest.json +10 -9
- package/docs/pi-plugins-manifest.md +6 -6
- package/docs/skill-manifest.json +18 -0
- package/package.json +1 -1
- package/templates/workspace/.opencode/README.md +49 -0
- package/templates/workspace/.opencode/command/ws-frontend-design.md +17 -0
- package/templates/workspace/.opencode/commands/using-aiws.md +18 -7
- package/templates/workspace/.opencode/plugins/memory-autoload.js +185 -0
- package/templates/workspace/.opencode/skills/codebase-design/SKILL.md +114 -0
- package/templates/workspace/.opencode/skills/domain-modeling/SKILL.md +74 -0
- package/templates/workspace/.opencode/skills/grill-with-docs/SKILL.md +7 -0
- package/templates/workspace/.opencode/skills/tdd/SKILL.md +36 -0
- package/templates/workspace/.opencode/skills/using-aiws/SKILL.md +2 -1
- package/templates/workspace/.opencode/skills/ws-dev/SKILL.md +24 -3
- package/templates/workspace/.opencode/skills/ws-plan/SKILL.md +15 -1
- package/templates/workspace/.opencode/skills/ws-review/SKILL.md +22 -0
- package/templates/workspace/AGENTS.md +13 -0
- package/templates/workspace/manifest.json +9 -121
- package/templates/workspace/.opencode/command/p-aiws-change-archive.md +0 -27
- package/templates/workspace/.opencode/command/p-aiws-change-finish.md +0 -27
- package/templates/workspace/.opencode/command/p-aiws-change-list.md +0 -26
- package/templates/workspace/.opencode/command/p-aiws-change-new.md +0 -27
- package/templates/workspace/.opencode/command/p-aiws-change-next.md +0 -27
- package/templates/workspace/.opencode/command/p-aiws-change-start.md +0 -27
- package/templates/workspace/.opencode/command/p-aiws-change-status.md +0 -27
- package/templates/workspace/.opencode/command/p-aiws-change-sync.md +0 -27
- package/templates/workspace/.opencode/command/p-aiws-change-templates-init.md +0 -26
- package/templates/workspace/.opencode/command/p-aiws-change-templates-which.md +0 -26
- package/templates/workspace/.opencode/command/p-aiws-change-validate.md +0 -27
- package/templates/workspace/.opencode/command/p-aiws-hooks-install.md +0 -26
- package/templates/workspace/.opencode/command/p-aiws-hooks-status.md +0 -26
- package/templates/workspace/.opencode/command/p-aiws-init.md +0 -23
- package/templates/workspace/.opencode/command/p-aiws-rollback.md +0 -16
- package/templates/workspace/.opencode/command/p-aiws-update.md +0 -22
- package/templates/workspace/.opencode/command/p-aiws-validate.md +0 -17
- package/templates/workspace/.opencode/command/ws-analyze.md +0 -30
- package/templates/workspace/.opencode/command/ws-auto.md +0 -33
- package/templates/workspace/.opencode/command/ws-autonomy.md +0 -25
- package/templates/workspace/.opencode/command/ws-bugfix.md +0 -35
- package/templates/workspace/.opencode/command/ws-commit.md +0 -87
- package/templates/workspace/.opencode/command/ws-delegate.md +0 -33
- package/templates/workspace/.opencode/command/ws-deliver.md +0 -75
- package/templates/workspace/.opencode/command/ws-handoff.md +0 -43
- package/templates/workspace/.opencode/command/ws-intake.md +0 -22
- package/templates/workspace/.opencode/command/ws-migrate.md +0 -25
- package/templates/workspace/.opencode/command/ws-plan-verify.md +0 -28
- package/templates/workspace/.opencode/command/ws-preflight.md +0 -35
- package/templates/workspace/.opencode/command/ws-pull.md +0 -87
- package/templates/workspace/.opencode/command/ws-push.md +0 -93
- package/templates/workspace/.opencode/command/ws-quality-review.md +0 -30
- package/templates/workspace/.opencode/command/ws-req-change.md +0 -45
- package/templates/workspace/.opencode/command/ws-req-contract-sync.md +0 -21
- package/templates/workspace/.opencode/command/ws-req-contract-validate.md +0 -16
- package/templates/workspace/.opencode/command/ws-req-flow-sync.md +0 -23
- package/templates/workspace/.opencode/command/ws-req-review.md +0 -36
- package/templates/workspace/.opencode/command/ws-rule.md +0 -27
- package/templates/workspace/.opencode/command/ws-spec-review.md +0 -30
- package/templates/workspace/.opencode/command/ws-submodule-setup.md +0 -57
- package/templates/workspace/.opencode/command/ws-verify-before-complete.md +0 -27
- package/templates/workspace/.opencode/commands/p-aiws-change-archive.md +0 -27
- package/templates/workspace/.opencode/commands/p-aiws-change-finish.md +0 -27
- package/templates/workspace/.opencode/commands/p-aiws-change-list.md +0 -26
- package/templates/workspace/.opencode/commands/p-aiws-change-new.md +0 -27
- package/templates/workspace/.opencode/commands/p-aiws-change-next.md +0 -27
- package/templates/workspace/.opencode/commands/p-aiws-change-start.md +0 -27
- package/templates/workspace/.opencode/commands/p-aiws-change-status.md +0 -27
- package/templates/workspace/.opencode/commands/p-aiws-change-sync.md +0 -27
- package/templates/workspace/.opencode/commands/p-aiws-change-templates-init.md +0 -26
- package/templates/workspace/.opencode/commands/p-aiws-change-templates-which.md +0 -26
- package/templates/workspace/.opencode/commands/p-aiws-change-validate.md +0 -27
- package/templates/workspace/.opencode/commands/p-aiws-hooks-install.md +0 -26
- package/templates/workspace/.opencode/commands/p-aiws-hooks-status.md +0 -26
- package/templates/workspace/.opencode/commands/p-aiws-init.md +0 -23
- package/templates/workspace/.opencode/commands/p-aiws-rollback.md +0 -16
- package/templates/workspace/.opencode/commands/p-aiws-update.md +0 -22
- package/templates/workspace/.opencode/commands/p-aiws-validate.md +0 -17
- package/templates/workspace/.opencode/commands/ws-analyze.md +0 -30
- package/templates/workspace/.opencode/commands/ws-auto.md +0 -33
- package/templates/workspace/.opencode/commands/ws-autonomy.md +0 -25
- package/templates/workspace/.opencode/commands/ws-bugfix.md +0 -35
- package/templates/workspace/.opencode/commands/ws-commit.md +0 -18
- package/templates/workspace/.opencode/commands/ws-delegate.md +0 -33
- package/templates/workspace/.opencode/commands/ws-deliver.md +0 -18
- package/templates/workspace/.opencode/commands/ws-handoff.md +0 -18
- package/templates/workspace/.opencode/commands/ws-intake.md +0 -22
- package/templates/workspace/.opencode/commands/ws-migrate.md +0 -18
- package/templates/workspace/.opencode/commands/ws-plan-verify.md +0 -18
- package/templates/workspace/.opencode/commands/ws-preflight.md +0 -35
- package/templates/workspace/.opencode/commands/ws-pull.md +0 -18
- package/templates/workspace/.opencode/commands/ws-push.md +0 -18
- package/templates/workspace/.opencode/commands/ws-quality-review.md +0 -30
- package/templates/workspace/.opencode/commands/ws-req-change.md +0 -45
- package/templates/workspace/.opencode/commands/ws-req-contract-sync.md +0 -21
- package/templates/workspace/.opencode/commands/ws-req-contract-validate.md +0 -16
- package/templates/workspace/.opencode/commands/ws-req-flow-sync.md +0 -23
- package/templates/workspace/.opencode/commands/ws-req-review.md +0 -36
- package/templates/workspace/.opencode/commands/ws-rule.md +0 -27
- package/templates/workspace/.opencode/commands/ws-spec-review.md +0 -30
- package/templates/workspace/.opencode/commands/ws-submodule-setup.md +0 -18
- package/templates/workspace/.opencode/commands/ws-verify-before-complete.md +0 -18
- package/templates/workspace/.opencode/skills/ws-handoff/SKILL.md +0 -18
- package/templates/workspace/.opencode/skills/ws-intake/SKILL.md +0 -80
|
@@ -14,13 +14,13 @@
|
|
|
14
14
|
],
|
|
15
15
|
"recommended_a": [
|
|
16
16
|
{
|
|
17
|
-
"id": "pi-extension-settings",
|
|
18
|
-
"package": "pi-extension-settings",
|
|
17
|
+
"id": "@juanibiapina/pi-extension-settings",
|
|
18
|
+
"package": "@juanibiapina/pi-extension-settings",
|
|
19
19
|
"tier": "recommended_a"
|
|
20
20
|
},
|
|
21
21
|
{
|
|
22
|
-
"id": "pi-powerbar",
|
|
23
|
-
"package": "pi-powerbar",
|
|
22
|
+
"id": "@juanibiapina/pi-powerbar",
|
|
23
|
+
"package": "@juanibiapina/pi-powerbar",
|
|
24
24
|
"tier": "recommended_a"
|
|
25
25
|
},
|
|
26
26
|
{
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"tier": "recommended_a"
|
|
40
40
|
},
|
|
41
41
|
{
|
|
42
|
-
"id": "rpiv-ask-user-question",
|
|
43
|
-
"package": "rpiv-ask-user-question",
|
|
42
|
+
"id": "@juicesharp/rpiv-ask-user-question",
|
|
43
|
+
"package": "@juicesharp/rpiv-ask-user-question",
|
|
44
44
|
"tier": "recommended_a"
|
|
45
45
|
},
|
|
46
46
|
{
|
|
@@ -63,7 +63,8 @@
|
|
|
63
63
|
{
|
|
64
64
|
"id": "pi-mcp-adapter",
|
|
65
65
|
"package": "pi-mcp-adapter",
|
|
66
|
-
"tier": "recommended_b"
|
|
66
|
+
"tier": "recommended_b",
|
|
67
|
+
"reason": "MCP adapter; heavy deps \u2014 sequential install with timeout; may need manual retry"
|
|
67
68
|
},
|
|
68
69
|
{
|
|
69
70
|
"id": "pi-fff",
|
|
@@ -76,8 +77,8 @@
|
|
|
76
77
|
"tier": "recommended_b"
|
|
77
78
|
},
|
|
78
79
|
{
|
|
79
|
-
"id": "plan-mode",
|
|
80
|
-
"package": "plan-mode",
|
|
80
|
+
"id": "pi-plan-mode",
|
|
81
|
+
"package": "pi-plan-mode",
|
|
81
82
|
"tier": "recommended_b"
|
|
82
83
|
},
|
|
83
84
|
{
|
|
@@ -54,12 +54,12 @@ Low conflict with AIWS governance; useful quality-of-life.
|
|
|
54
54
|
|
|
55
55
|
| package | notes |
|
|
56
56
|
|---------|--------|
|
|
57
|
-
|
|
|
58
|
-
|
|
|
57
|
+
| `@juanibiapina/pi-extension-settings` | settings UX |
|
|
58
|
+
| `@juanibiapina/pi-powerbar` | status bar |
|
|
59
59
|
| `pi-lsp` | LSP |
|
|
60
60
|
| `pi-hashline-edit-pro` | edit helper (watch tool names vs force deny) |
|
|
61
61
|
| `rpiv-todo` | todos |
|
|
62
|
-
|
|
|
62
|
+
| `@juicesharp/rpiv-ask-user-question` | structured questions |
|
|
63
63
|
| `pi-btw` | asides |
|
|
64
64
|
| `pi-caffeinate` | keep awake |
|
|
65
65
|
| `pi-workspace-history` | history |
|
|
@@ -68,10 +68,10 @@ Low conflict with AIWS governance; useful quality-of-life.
|
|
|
68
68
|
|
|
69
69
|
| package | notes |
|
|
70
70
|
|---------|--------|
|
|
71
|
-
| `pi-mcp-adapter` | MCP |
|
|
71
|
+
| `pi-mcp-adapter` | MCP (heavy deps; install may hang — retry alone or skip) |
|
|
72
72
|
| `pi-fff` | file finder |
|
|
73
73
|
| `pi-slopchop` | slop cleanup |
|
|
74
|
-
| `plan-mode` | plan UX (AIWS keeps plan truth) |
|
|
74
|
+
| `pi-plan-mode` | plan UX (AIWS keeps plan truth) |
|
|
75
75
|
| `pi-cache-optimizer` | cache (truncation caution) |
|
|
76
76
|
| `pi-rtk-optimizer` | RTK |
|
|
77
77
|
| `pi-agent-browser-native` | browser |
|
|
@@ -102,7 +102,7 @@ Low conflict with AIWS governance; useful quality-of-life.
|
|
|
102
102
|
- Missing **required** → exit code ≠ 0
|
|
103
103
|
- Conflicts / forbidden installed → warn (exit ≠ 0 if any required missing or any conflict)
|
|
104
104
|
- `init --pi` / `update` (when `.pi/` exists or `--pi`): print same report as **warn**; do not fail init/update by default
|
|
105
|
-
- Optional `--install-pi-plugins`: install **
|
|
105
|
+
- Optional `--install-pi-plugins`: install **all declared installable** plugins (required + recommended A/B, user scope); never forbidden; default without flag remains detect+prompt only
|
|
106
106
|
|
|
107
107
|
## Related
|
|
108
108
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"description": "Default skills installed by `aiws skill add`",
|
|
4
|
+
"sources": [
|
|
5
|
+
{
|
|
6
|
+
"source": "https://gitea.aipper.de/github/taste-skill",
|
|
7
|
+
"description": "67K-star collection: anti-slop frontend design rules (Impeccable Design, Zero Emoji, Phosphor Icons, layout diversification, etc.)"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"source": "https://gitea.aipper.de/github/skills",
|
|
11
|
+
"description": "Engineering workflow pipeline: grill-with-docs → to-spec → to-tickets → implement → code-review + tdd, domain-modeling, handoff, research, prototype, grill-me"
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"notes": [
|
|
15
|
+
"Add more sources here as curated defaults.",
|
|
16
|
+
"aiws-built-in skills (grill-me, ws-*, p-aiws-*) are shipped via templates and do not need listing here."
|
|
17
|
+
]
|
|
18
|
+
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# OpenCode Skills — Two-Layer Architecture
|
|
2
|
+
|
|
3
|
+
This workspace uses a layered skill architecture:
|
|
4
|
+
|
|
5
|
+
## Layer 1: Engineering Pipeline (mattpocock/skills)
|
|
6
|
+
|
|
7
|
+
Default entry for daily engineering work. Skills auto-load by intent.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
/grill-with-docs → Design discussion with domain modeling + ADR
|
|
11
|
+
/to-spec → Synthesize conversation into a spec
|
|
12
|
+
/to-tickets → Break spec into executable tickets
|
|
13
|
+
/implement → Implement from spec/tickets (with TDD)
|
|
14
|
+
/code-review → Review against standards + spec
|
|
15
|
+
/handoff → Compact session for handoff to another agent
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Also available: `/tdd`, `/research`, `/prototype`, `/domain-modeling`, `/grill-me`, `/diagnosing-bugs`, `/resolving-merge-conflicts`, etc.
|
|
19
|
+
|
|
20
|
+
## Layer 2: aiws Governance (ws-*)
|
|
21
|
+
|
|
22
|
+
Supplemental skills for process, audit, and compliance. Use when the work needs:
|
|
23
|
+
- Traceable goal/change/contract tracking
|
|
24
|
+
- Completion gates and evidence
|
|
25
|
+
- Spec/quality review process
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
/ws-goal → Set auditable goal with dependency check
|
|
29
|
+
/ws-plan → Bind change with requirements contract
|
|
30
|
+
/ws-dev / ws-dev-lite → Develop under AIWS constraints
|
|
31
|
+
/ws-frontend-design → Apply frontend design rules
|
|
32
|
+
/ws-finish → Merge change + archive evidence
|
|
33
|
+
/ws-spec-review → Process completeness audit
|
|
34
|
+
/ws-quality-review → Implementation quality + test coverage
|
|
35
|
+
/ws-verify-before-complete → Pre-finish validation gate
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## When to Use Which
|
|
39
|
+
|
|
40
|
+
| You want to... | Use |
|
|
41
|
+
|---|---|
|
|
42
|
+
| Explore and refine an idea | `/grill-with-docs` |
|
|
43
|
+
| Create a spec from discussion | `/to-spec` |
|
|
44
|
+
| Implement a well-defined feature | `/implement` (or `/ws-dev` if aiws governance needed) |
|
|
45
|
+
| Fix a small bug quickly | `/ws-dev-lite` |
|
|
46
|
+
| Review a branch | `/code-review` |
|
|
47
|
+
| Audit process compliance | `/ws-spec-review` + `/ws-quality-review` |
|
|
48
|
+
| Merge and archive | `/ws-finish` |
|
|
49
|
+
| Design UI | `/ws-frontend-design` |
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: 前端设计:视觉优先的 UI/UX 实现,先信息层级与构图,再组件细节
|
|
3
|
+
---
|
|
4
|
+
<!-- AIWS_MANAGED_BEGIN:opencode:ws-frontend-design -->
|
|
5
|
+
# ws frontend design
|
|
6
|
+
|
|
7
|
+
用中文输出(命令/路径/代码标识符保持原样不翻译)。
|
|
8
|
+
|
|
9
|
+
目标:在 AIWS 约束下交付可运行、可验证、视觉方向明确的前端界面。先信息层级与构图,再组件细节。品牌页重视觉锚点,产品页重可操作性。
|
|
10
|
+
|
|
11
|
+
前置:
|
|
12
|
+
1) 运行 `$ws-preflight` 读取真值文件。
|
|
13
|
+
2) 判断任务类型:`landing`(品牌/营销)| `app-ui`(dashboard/工具)| `polish-only`(仅视觉提质)。
|
|
14
|
+
3) medium/complex 任务先用 `$ws-plan` 落盘计划。
|
|
15
|
+
|
|
16
|
+
详细设计指令见对应的 SKILL.md 文件:`skill(name="ws-frontend-design")`
|
|
17
|
+
<!-- AIWS_MANAGED_END:opencode:ws-frontend-design -->
|
|
@@ -15,13 +15,24 @@ description: 默认 workflow router:先判定阶段,再进入具体 ws-* 入
|
|
|
15
15
|
- 若未检测到:输出 `OpenCode mode: standard-opencode`
|
|
16
16
|
2) 若缺失任一真值文件:先 `/ws-preflight`,必要时运行 `aiws init .`,不要继续实现。
|
|
17
17
|
3) 若任务意图、归因或验证入口不明确:先提 1-3 个关键澄清问题并停止。
|
|
18
|
-
4)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
4) 两层架构:默认走 mattpocock/skills 工程流水线,需要 aiws 治理时叠加 ws-*。
|
|
19
|
+
- 工程入口(mattpocock):
|
|
20
|
+
- 需求澄清/设计探讨:`/grill-with-docs`(→ `/grilling` + `/domain-modeling`)
|
|
21
|
+
- 输出 spec:`/to-spec`
|
|
22
|
+
- 拆 tickets:`/to-tickets`
|
|
23
|
+
- 实现(含 TDD):`/implement`
|
|
24
|
+
- 代码审查:`/code-review`
|
|
25
|
+
- 交接:`/handoff`
|
|
26
|
+
- 治理叠加(aiws ws-*):
|
|
27
|
+
- 设定可审计目标:`/ws-goal`
|
|
28
|
+
- 绑定 change + contract:`/ws-plan`
|
|
29
|
+
- 小步实现(simple/local 单点修复):`/ws-dev-lite`
|
|
30
|
+
- 完整开发(AIWS 约束下):`/ws-dev`
|
|
31
|
+
- 前端设计规则:`/ws-frontend-design`
|
|
32
|
+
- aiws 规范/质量双审查:`/ws-spec-review` + `/ws-quality-review`
|
|
33
|
+
- 完成前验证:`/ws-verify-before-complete`
|
|
34
|
+
- 合并/推送/清理:`/ws-finish`
|
|
35
|
+
- 需求/验收/合同变更:`/ws-req-review`
|
|
25
36
|
5) 输出 `OpenCode mode:` / `Task intent:` / `Binding:` / `Route:` / `Why:` / `Next:`。
|
|
26
37
|
6) 若 `Route: ws-dev` 且任务属于 simple/local 单点修复:`Next` 可显式建议 `/ws-dev-lite`。
|
|
27
38
|
7) 除非用户只要路由判断,否则给出 route 后继续遵循对应入口的契约。
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Autoload Plugin
|
|
3
|
+
*
|
|
4
|
+
* Injects AIWS memory context at session start so each session
|
|
5
|
+
* has continuity without needing the nocturne_memory MCP server.
|
|
6
|
+
*
|
|
7
|
+
* What it does:
|
|
8
|
+
* 1. On the first user message of a new session, reads:
|
|
9
|
+
* - Active goal(s) from .aiws/goals/*.state.json
|
|
10
|
+
* - Recent decisions from .aiws/memory-bank/decision/ (last 3)
|
|
11
|
+
* - Project overview from .aiws/memory-bank/project/
|
|
12
|
+
* 2. Injects a <memory-context> block into the assistant's first response.
|
|
13
|
+
* 3. Deduplicates per session — injects once only.
|
|
14
|
+
*
|
|
15
|
+
* Disable: export MEMORY_AUTOLOAD_DISABLE=1
|
|
16
|
+
*
|
|
17
|
+
* @module memory-autoload
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { readFileSync, existsSync, readdirSync } from "node:fs";
|
|
21
|
+
import { join } from "node:path";
|
|
22
|
+
|
|
23
|
+
const MEMORY_BANK = ".aiws/memory-bank";
|
|
24
|
+
const GOALS_DIR = ".aiws/goals";
|
|
25
|
+
|
|
26
|
+
export const MemoryAutoloadPlugin = async ({ project, client, directory }) => {
|
|
27
|
+
const processed = new Set();
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
"chat.message": async (input, output) => {
|
|
31
|
+
const sid = input?.sessionID;
|
|
32
|
+
if (!sid || processed.has(sid)) return;
|
|
33
|
+
if (process.env.MEMORY_AUTOLOAD_DISABLE === "1") {
|
|
34
|
+
processed.add(sid);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const root = directory || process.cwd();
|
|
39
|
+
const bankDir = join(root, MEMORY_BANK);
|
|
40
|
+
if (!existsSync(bankDir)) {
|
|
41
|
+
processed.add(sid);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const blocks = [];
|
|
46
|
+
|
|
47
|
+
// ── 1. Active/paused goals (ADVISORY ONLY — not FSM authority) ─
|
|
48
|
+
// TOOLING-003D: authoritative goal-context + next_action come from
|
|
49
|
+
// session-start → buildSessionContext → getActiveGoal(s).
|
|
50
|
+
// memory-autoload must NOT become authority over goal state.
|
|
51
|
+
try {
|
|
52
|
+
const goalsDir = join(root, GOALS_DIR);
|
|
53
|
+
if (existsSync(goalsDir)) {
|
|
54
|
+
const files = readdirSync(goalsDir).filter((f) =>
|
|
55
|
+
f.endsWith(".state.json"),
|
|
56
|
+
);
|
|
57
|
+
const advisory = [];
|
|
58
|
+
for (const file of files.sort()) {
|
|
59
|
+
try {
|
|
60
|
+
const state = JSON.parse(
|
|
61
|
+
readFileSync(join(goalsDir, file), "utf-8"),
|
|
62
|
+
);
|
|
63
|
+
const st = state.status;
|
|
64
|
+
if (st === "active" || st === "paused") {
|
|
65
|
+
const phase = state.current_phase ?? "?";
|
|
66
|
+
const iter = state.iteration ?? "?";
|
|
67
|
+
advisory.push(
|
|
68
|
+
`- [${st}] ${state.goal_id || file} — phase=${phase}, iteration=${iter}`,
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
} catch {
|
|
72
|
+
/* skip malformed state file */
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (advisory.length) {
|
|
76
|
+
blocks.push(
|
|
77
|
+
"[Goals — advisory memory only; use session <goal-context> for next_action]",
|
|
78
|
+
);
|
|
79
|
+
blocks.push(...advisory);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
} catch {
|
|
83
|
+
/* goals dir missing */
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ── 2. Recent decisions (last 3, sorted by filename) ──────────
|
|
87
|
+
try {
|
|
88
|
+
const decDir = join(bankDir, "decision");
|
|
89
|
+
if (existsSync(decDir)) {
|
|
90
|
+
const files = readdirSync(decDir)
|
|
91
|
+
.filter((f) => f.endsWith(".md") && f !== "handoff-evidence.md")
|
|
92
|
+
.sort()
|
|
93
|
+
.reverse()
|
|
94
|
+
.slice(0, 3);
|
|
95
|
+
for (const file of files) {
|
|
96
|
+
try {
|
|
97
|
+
const content = readFileSync(join(decDir, file), "utf-8");
|
|
98
|
+
const title =
|
|
99
|
+
content
|
|
100
|
+
.split("\n")
|
|
101
|
+
.find((l) => l.startsWith("#"))
|
|
102
|
+
?.replace(/^#+\s*/, "") || file.replace(".md", "");
|
|
103
|
+
const summary = content
|
|
104
|
+
.split("\n")
|
|
105
|
+
.slice(1, 8)
|
|
106
|
+
.filter((l) => l.trim())
|
|
107
|
+
.join("\n")
|
|
108
|
+
.trim();
|
|
109
|
+
blocks.push(`\n[Decision] ${title}\n${summary}`);
|
|
110
|
+
} catch {
|
|
111
|
+
/* skip unreadable file */
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
} catch {
|
|
116
|
+
/* decision dir missing */
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ── 3. Project overview ────────────────────────────────────────
|
|
120
|
+
try {
|
|
121
|
+
const projDir = join(bankDir, "project");
|
|
122
|
+
if (existsSync(projDir)) {
|
|
123
|
+
const files = readdirSync(projDir).filter((f) => f.endsWith(".md"));
|
|
124
|
+
for (const file of files.slice(0, 2)) {
|
|
125
|
+
try {
|
|
126
|
+
const content = readFileSync(join(projDir, file), "utf-8");
|
|
127
|
+
const title =
|
|
128
|
+
content
|
|
129
|
+
.split("\n")
|
|
130
|
+
.find((l) => l.startsWith("#"))
|
|
131
|
+
?.replace(/^#+\s*/, "") || file.replace(".md", "");
|
|
132
|
+
const excerpt = content
|
|
133
|
+
.split("\n")
|
|
134
|
+
.slice(1, 12)
|
|
135
|
+
.filter((l) => l.trim())
|
|
136
|
+
.join("\n")
|
|
137
|
+
.trim();
|
|
138
|
+
blocks.push(`\n[Project: ${title}]\n${excerpt}`);
|
|
139
|
+
} catch {
|
|
140
|
+
/* skip */
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
} catch {
|
|
145
|
+
/* project dir missing */
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// ── 4. If aiws memory boot produces anything, append it ────────
|
|
149
|
+
// (skipped — avoids shell dependency; use --disclosure boot on
|
|
150
|
+
// `aiws memory write` and the injected goal/decision blocks
|
|
151
|
+
// above already provide sufficient context)
|
|
152
|
+
|
|
153
|
+
if (blocks.length === 0) {
|
|
154
|
+
processed.add(sid);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const context = `<memory-context>\n${blocks.join("\n")}\n</memory-context>`;
|
|
159
|
+
|
|
160
|
+
const parts = output?.parts || [];
|
|
161
|
+
const textIdx = parts.findIndex(
|
|
162
|
+
(p) => p.type === "text" && p.text !== undefined,
|
|
163
|
+
);
|
|
164
|
+
if (textIdx !== -1) {
|
|
165
|
+
parts[textIdx].text = `${context}\n\n${parts[textIdx].text}`;
|
|
166
|
+
} else {
|
|
167
|
+
parts.unshift({ type: "text", text: context });
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
await client.app.log({
|
|
172
|
+
body: {
|
|
173
|
+
service: "memory-autoload",
|
|
174
|
+
level: "info",
|
|
175
|
+
message: `Injected ${blocks.length} memory blocks for session ${sid.slice(0, 12)}`,
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
} catch {
|
|
179
|
+
/* logging optional */
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
processed.add(sid);
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: codebase-design
|
|
3
|
+
description: Shared vocabulary for designing deep modules. Use when the user wants to design or improve a module's interface, find deepening opportunities, decide where a seam goes, make code more testable or AI-navigable, or when another skill needs the deep-module vocabulary.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Codebase Design
|
|
7
|
+
|
|
8
|
+
Design **deep modules**: a lot of behaviour behind a small interface, placed at a clean seam, testable through that interface. Use this language and these principles wherever code is being designed or restructured. The aim is leverage for callers, locality for maintainers, and testability for everyone.
|
|
9
|
+
|
|
10
|
+
## Glossary
|
|
11
|
+
|
|
12
|
+
Use these terms exactly — don't substitute "component," "service," "API," or "boundary." Consistent language is the whole point.
|
|
13
|
+
|
|
14
|
+
**Module** — anything with an interface and an implementation. Deliberately scale-agnostic: a function, class, package, or tier-spanning slice. _Avoid_: unit, component, service.
|
|
15
|
+
|
|
16
|
+
**Interface** — everything a caller must know to use the module correctly: the type signature, but also invariants, ordering constraints, error modes, required configuration, and performance characteristics. _Avoid_: API, signature (too narrow — they refer only to the type-level surface).
|
|
17
|
+
|
|
18
|
+
**Implementation** — what's inside a module, its body of code. Distinct from **Adapter**: a thing can be a small adapter with a large implementation (a Postgres repo) or a large adapter with a small implementation (an in-memory fake). Reach for "adapter" when the seam is the topic; "implementation" otherwise.
|
|
19
|
+
|
|
20
|
+
**Depth** — leverage at the interface: the amount of behaviour a caller (or test) can exercise per unit of interface they have to learn. A module is **deep** when a large amount of behaviour sits behind a small interface, **shallow** when the interface is nearly as complex as the implementation.
|
|
21
|
+
|
|
22
|
+
**Seam** _(Michael Feathers)_ — a place where you can alter behaviour without editing in that place; the *location* at which a module's interface lives. Where to put the seam is its own design decision, distinct from what goes behind it. _Avoid_: boundary (overloaded with DDD's bounded context).
|
|
23
|
+
|
|
24
|
+
**Adapter** — a concrete thing that satisfies an interface at a seam. Describes *role* (what slot it fills), not substance (what's inside).
|
|
25
|
+
|
|
26
|
+
**Leverage** — what callers get from depth: more capability per unit of interface they learn. One implementation pays back across N call sites and M tests.
|
|
27
|
+
|
|
28
|
+
**Locality** — what maintainers get from depth: change, bugs, knowledge, and verification concentrate in one place rather than spreading across callers. Fix once, fixed everywhere.
|
|
29
|
+
|
|
30
|
+
## Deep vs shallow
|
|
31
|
+
|
|
32
|
+
**Deep module** = small interface + lots of implementation:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
┌─────────────────────┐
|
|
36
|
+
│ Small Interface │ ← Few methods, simple params
|
|
37
|
+
├─────────────────────┤
|
|
38
|
+
│ │
|
|
39
|
+
│ Deep Implementation│ ← Complex logic hidden
|
|
40
|
+
│ │
|
|
41
|
+
└─────────────────────┘
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Shallow module** = large interface + little implementation (avoid):
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
┌─────────────────────────────────┐
|
|
48
|
+
│ Large Interface │ ← Many methods, complex params
|
|
49
|
+
├─────────────────────────────────┤
|
|
50
|
+
│ Thin Implementation │ ← Just passes through
|
|
51
|
+
└─────────────────────────────────┘
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
When designing an interface, ask:
|
|
55
|
+
|
|
56
|
+
- Can I reduce the number of methods?
|
|
57
|
+
- Can I simplify the parameters?
|
|
58
|
+
- Can I hide more complexity inside?
|
|
59
|
+
|
|
60
|
+
## Principles
|
|
61
|
+
|
|
62
|
+
- **Depth is a property of the interface, not the implementation.** A deep module can be internally composed of small, mockable, swappable parts — they just aren't part of the interface. A module can have **internal seams** (private to its implementation, used by its own tests) as well as the **external seam** at its interface.
|
|
63
|
+
- **The deletion test.** Imagine deleting the module. If complexity vanishes, it was a pass-through. If complexity reappears across N callers, it was earning its keep.
|
|
64
|
+
- **The interface is the test surface.** Callers and tests cross the same seam. If you want to test *past* the interface, the module is probably the wrong shape.
|
|
65
|
+
- **One adapter means a hypothetical seam. Two adapters means a real one.** Don't introduce a seam unless something actually varies across it.
|
|
66
|
+
|
|
67
|
+
## Designing for testability
|
|
68
|
+
|
|
69
|
+
Good interfaces make testing natural:
|
|
70
|
+
|
|
71
|
+
1. **Accept dependencies, don't create them.**
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
// Testable
|
|
75
|
+
function processOrder(order, paymentGateway) {}
|
|
76
|
+
|
|
77
|
+
// Hard to test
|
|
78
|
+
function processOrder(order) {
|
|
79
|
+
const gateway = new StripeGateway();
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
2. **Return results, don't produce side effects.**
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
// Testable
|
|
87
|
+
function calculateDiscount(cart): Discount {}
|
|
88
|
+
|
|
89
|
+
// Hard to test
|
|
90
|
+
function applyDiscount(cart): void {
|
|
91
|
+
cart.total -= discount;
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
3. **Small surface area.** Fewer methods = fewer tests needed. Fewer params = simpler test setup.
|
|
96
|
+
|
|
97
|
+
## Relationships
|
|
98
|
+
|
|
99
|
+
- A **Module** has exactly one **Interface** (the surface it presents to callers and tests).
|
|
100
|
+
- **Depth** is a property of a **Module**, measured against its **Interface**.
|
|
101
|
+
- A **Seam** is where a **Module**'s **Interface** lives.
|
|
102
|
+
- An **Adapter** sits at a **Seam** and satisfies the **Interface**.
|
|
103
|
+
- **Depth** produces **Leverage** for callers and **Locality** for maintainers.
|
|
104
|
+
|
|
105
|
+
## Rejected framings
|
|
106
|
+
|
|
107
|
+
- **Depth as ratio of implementation-lines to interface-lines** (Ousterhout): rewards padding the implementation. We use depth-as-leverage instead.
|
|
108
|
+
- **"Interface" as the TypeScript `interface` keyword or a class's public methods**: too narrow — interface here includes every fact a caller must know.
|
|
109
|
+
- **"Boundary"**: overloaded with DDD's bounded context. Say **seam** or **interface**.
|
|
110
|
+
|
|
111
|
+
## Going deeper
|
|
112
|
+
|
|
113
|
+
- **Deepening a cluster given its dependencies** — see [DEEPENING.md](DEEPENING.md): dependency categories, seam discipline, and replace-don't-layer testing.
|
|
114
|
+
- **Exploring alternative interfaces** — see [DESIGN-IT-TWICE.md](DESIGN-IT-TWICE.md): spin up parallel sub-agents to design the interface several radically different ways, then compare on depth, locality, and seam placement.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: domain-modeling
|
|
3
|
+
description: Build and sharpen a project's domain model. Use when the user wants to pin down domain terminology or a ubiquitous language, record an architectural decision, or when another skill needs to maintain the domain model.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Domain Modeling
|
|
7
|
+
|
|
8
|
+
Actively build and sharpen the project's domain model as you design. This is the *active* discipline — challenging terms, inventing edge-case scenarios, and writing the glossary and decisions down the moment they crystallise. (Merely *reading* `CONTEXT.md` for vocabulary is not this skill — that's a one-line habit any skill can do. This skill is for when you're changing the model, not just consuming it.)
|
|
9
|
+
|
|
10
|
+
## File structure
|
|
11
|
+
|
|
12
|
+
Most repos have a single context:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
/
|
|
16
|
+
├── CONTEXT.md
|
|
17
|
+
├── docs/
|
|
18
|
+
│ └── adr/
|
|
19
|
+
│ ├── 0001-event-sourced-orders.md
|
|
20
|
+
│ └── 0002-postgres-for-write-model.md
|
|
21
|
+
└── src/
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
If a `CONTEXT-MAP.md` exists at the root, the repo has multiple contexts. The map points to where each one lives:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
/
|
|
28
|
+
├── CONTEXT-MAP.md
|
|
29
|
+
├── docs/
|
|
30
|
+
│ └── adr/ ← system-wide decisions
|
|
31
|
+
├── src/
|
|
32
|
+
│ ├── ordering/
|
|
33
|
+
│ │ ├── CONTEXT.md
|
|
34
|
+
│ │ └── docs/adr/ ← context-specific decisions
|
|
35
|
+
│ └── billing/
|
|
36
|
+
│ ├── CONTEXT.md
|
|
37
|
+
│ └── docs/adr/
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Create files lazily — only when you have something to write. If no `CONTEXT.md` exists, create one when the first term is resolved. If no `docs/adr/` exists, create it when the first ADR is needed.
|
|
41
|
+
|
|
42
|
+
## During the session
|
|
43
|
+
|
|
44
|
+
### Challenge against the glossary
|
|
45
|
+
|
|
46
|
+
When the user uses a term that conflicts with the existing language in `CONTEXT.md`, call it out immediately. "Your glossary defines 'cancellation' as X, but you seem to mean Y — which is it?"
|
|
47
|
+
|
|
48
|
+
### Sharpen fuzzy language
|
|
49
|
+
|
|
50
|
+
When the user uses vague or overloaded terms, propose a precise canonical term. "You're saying 'account' — do you mean the Customer or the User? Those are different things."
|
|
51
|
+
|
|
52
|
+
### Discuss concrete scenarios
|
|
53
|
+
|
|
54
|
+
When domain relationships are being discussed, stress-test them with specific scenarios. Invent scenarios that probe edge cases and force the user to be precise about the boundaries between concepts.
|
|
55
|
+
|
|
56
|
+
### Cross-reference with code
|
|
57
|
+
|
|
58
|
+
When the user states how something works, check whether the code agrees. If you find a contradiction, surface it: "Your code cancels entire Orders, but you just said partial cancellation is possible — which is right?"
|
|
59
|
+
|
|
60
|
+
### Update CONTEXT.md inline
|
|
61
|
+
|
|
62
|
+
When a term is resolved, update `CONTEXT.md` right there. Don't batch these up — capture them as they happen. Use the format in [CONTEXT-FORMAT.md](./CONTEXT-FORMAT.md).
|
|
63
|
+
|
|
64
|
+
`CONTEXT.md` should be totally devoid of implementation details. Do not treat `CONTEXT.md` as a spec, a scratch pad, or a repository for implementation decisions. It is a glossary and nothing else.
|
|
65
|
+
|
|
66
|
+
### Offer ADRs sparingly
|
|
67
|
+
|
|
68
|
+
Only offer to create an ADR when all three are true:
|
|
69
|
+
|
|
70
|
+
1. **Hard to reverse** — the cost of changing your mind later is meaningful
|
|
71
|
+
2. **Surprising without context** — a future reader will wonder "why did they do it this way?"
|
|
72
|
+
3. **The result of a real trade-off** — there were genuine alternatives and you picked one for specific reasons
|
|
73
|
+
|
|
74
|
+
If any of the three is missing, skip the ADR. Use the format in [ADR-FORMAT.md](./ADR-FORMAT.md).
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tdd
|
|
3
|
+
description: Test-driven development. Use when the user wants to build features or fix bugs test-first, mentions "red-green-refactor", or wants integration tests.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Test-Driven Development
|
|
7
|
+
|
|
8
|
+
TDD is the red → green loop. This skill is the reference that makes that loop produce tests worth keeping: what a good test is, where tests go, the anti-patterns, and the rules of the loop. Every section applies on every cycle — consult them before and during the loop, not after.
|
|
9
|
+
|
|
10
|
+
When exploring the codebase, read `CONTEXT.md` (if it exists) so test names and interface vocabulary match the project's domain language, and respect ADRs in the area you're touching.
|
|
11
|
+
|
|
12
|
+
## What a good test is
|
|
13
|
+
|
|
14
|
+
Tests verify behavior through public interfaces, not implementation details. Code can change entirely; tests shouldn't. A good test reads like a specification — "user can checkout with valid cart" tells you exactly what capability exists — and survives refactors because it doesn't care about internal structure.
|
|
15
|
+
|
|
16
|
+
See [tests.md](tests.md) for examples and [mocking.md](mocking.md) for mocking guidelines.
|
|
17
|
+
|
|
18
|
+
## Seams — where tests go
|
|
19
|
+
|
|
20
|
+
A **seam** is the public boundary you test at: the interface where you observe behavior without reaching inside. Tests live at seams, never against internals.
|
|
21
|
+
|
|
22
|
+
**Test only at pre-agreed seams.** Before writing any test, write down the seams under test and confirm them with the user. No test is written at an unconfirmed seam. You can't test everything — agreeing the seams up front is how testing effort lands on the critical paths and complex logic instead of every edge case.
|
|
23
|
+
|
|
24
|
+
Ask: "What's the public interface, and which seams should we test?"
|
|
25
|
+
|
|
26
|
+
## Anti-patterns
|
|
27
|
+
|
|
28
|
+
- **Implementation-coupled** — mocks internal collaborators, tests private methods, or verifies through a side channel (querying the database instead of using the interface). The tell: the test breaks when you refactor but behavior hasn't changed.
|
|
29
|
+
- **Tautological** — the assertion recomputes the expected value the way the code does (`expect(add(a, b)).toBe(a + b)`, a snapshot derived by hand the same way, a constant asserted equal to itself), so it passes by construction and can never disagree with the code. Expected values must come from an independent source of truth — a known-good literal, a worked example, the spec.
|
|
30
|
+
- **Horizontal slicing** — writing all tests first, then all implementation. Bulk tests verify _imagined_ behavior: you test the _shape_ of things rather than user-facing behavior, the tests go insensitive to real changes, and you commit to test structure before understanding the implementation. Work in **vertical slices** instead — one test → one implementation → repeat, each test a **tracer bullet** that responds to what the last cycle taught you.
|
|
31
|
+
|
|
32
|
+
## Rules of the loop
|
|
33
|
+
|
|
34
|
+
- **Red before green.** Write the failing test first, then only enough code to pass it. Don't anticipate future tests or add speculative features.
|
|
35
|
+
- **One slice at a time.** One seam, one test, one minimal implementation per cycle.
|
|
36
|
+
- **Refactoring is not part of the loop.** It belongs to the review stage (see the `code-review` skill), not the red → green implementation cycle.
|
|
@@ -68,7 +68,7 @@ description: 使用时机:新会话开始、不确定下一步做什么时。
|
|
|
68
68
|
|
|
69
69
|
只问 1-3 个关键问题(意图、Req_ID/Problem_ID、verify、change),然后停止。
|
|
70
70
|
|
|
71
|
-
### 4. Continuation Routing
|
|
71
|
+
### 4. Continuation Routing / 续跑决策表(新 session 恢复)
|
|
72
72
|
|
|
73
73
|
change 相位 + goal 叠加;goal 优先于冷启动 plan/dev 跳过:
|
|
74
74
|
|
|
@@ -98,3 +98,4 @@ Root: / Found: / OpenCode mode: / Task intent: / Binding: / Route: / Why: / Next
|
|
|
98
98
|
- subagent 不可用:单 agent,维护等价工件;不用 L4 程序化 skill invoke(agent 读规则后进入 skill)
|
|
99
99
|
|
|
100
100
|
> 运行时行为约束:`packages/spec/docs/run-behavior-guidelines.md`
|
|
101
|
+
> Subagent-first 规范:`packages/spec/docs/opencode-subagent-first.md`
|