cairn-ai 0.1.2 → 0.1.4
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/.agents/workflows/cairn-doctor.md +1 -1
- package/.agents/workflows/cairn-install.md +1 -1
- package/.agents/workflows/cairn-plan.md +2 -2
- package/.agents/workflows/cairn-toolcheck.md +2 -2
- package/.agents/workflows/cairn-uninstall.md +1 -1
- package/.agents/workflows/cairn-upgrade.md +1 -1
- package/.agents/workflows/cairn-work.md +1 -1
- package/.claude/commands/cairn-doctor.md +1 -1
- package/.claude/commands/cairn-install.md +1 -1
- package/.claude/commands/cairn-toolcheck.md +2 -2
- package/.claude/commands/cairn-uninstall.md +1 -1
- package/.claude/commands/cairn-upgrade.md +1 -1
- package/commands/cairn-doctor.md +1 -1
- package/commands/cairn-install.md +1 -1
- package/commands/cairn-memory.md +1 -1
- package/commands/cairn-plan.md +3 -3
- package/commands/cairn-review.md +1 -1
- package/commands/cairn-toolcheck.md +2 -2
- package/commands/cairn-uninstall.md +1 -1
- package/commands/cairn-upgrade.md +1 -1
- package/commands/cairn-work.md +2 -2
- package/hooks/hooks.json +5 -5
- package/package.json +4 -4
- package/scripts/cairn +1 -102
- package/scripts/cairn-lifecycle.mjs +12 -6
- package/scripts/cairn-state.mjs +103 -0
- package/scripts/cairn-toolcheck.mjs +54 -14
- package/scripts/cairn.mjs +115 -0
- package/skills/cairn-memory/SKILL.md +1 -1
- package/skills/cairn-plan/SKILL.md +3 -3
- package/skills/cairn-work/SKILL.md +2 -2
|
@@ -8,8 +8,8 @@ Procedure:
|
|
|
8
8
|
|
|
9
9
|
1. Read `MEMORY.md` and relevant `docs/memory/*.md`.
|
|
10
10
|
2. If the active or assigned model is Claude-family, read `docs/model-guidance/claude.md`; if Codex-family, read `docs/model-guidance/codex.md`.
|
|
11
|
-
3. Run `scripts/cairn toolcheck` when available.
|
|
12
|
-
4. If required LSP/check tools are missing, run `scripts/cairn toolcheck --install` or a repository-native install command before accepting a fallback.
|
|
11
|
+
3. Run `node scripts/cairn.mjs toolcheck` when available.
|
|
12
|
+
4. If required LSP/check tools are missing, run `node scripts/cairn.mjs toolcheck --install` or a repository-native install command before accepting a fallback.
|
|
13
13
|
5. Explore before asking the user.
|
|
14
14
|
6. Run complexity triage before applying agent, plugin, or delegated workflow guidance.
|
|
15
15
|
7. Use Light Path by default unless a Heavy Path condition clearly applies.
|
|
@@ -5,13 +5,13 @@ Goal: detect repository stacks and check required LSP, typecheck, lint, dry-run,
|
|
|
5
5
|
Run the local command first:
|
|
6
6
|
|
|
7
7
|
```sh
|
|
8
|
-
scripts/cairn toolcheck
|
|
8
|
+
node scripts/cairn.mjs toolcheck
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
If required tools are missing, attempt repository-native installation:
|
|
12
12
|
|
|
13
13
|
```sh
|
|
14
|
-
scripts/cairn toolcheck --install
|
|
14
|
+
node scripts/cairn.mjs toolcheck --install
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
Record detected stacks, missing tools, install attempts, and blockers in the related `docs/plan/<topic>.md`.
|
|
@@ -11,7 +11,7 @@ bunx cairn-ai@latest uninstall
|
|
|
11
11
|
When running from local source:
|
|
12
12
|
|
|
13
13
|
```sh
|
|
14
|
-
scripts/cairn uninstall
|
|
14
|
+
node scripts/cairn.mjs uninstall
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
The source work folder and user-created `MEMORY.md`, `PLAN.md`, `docs/memory`, and `docs/plan` files are not deleted.
|
|
@@ -9,7 +9,7 @@ Procedure:
|
|
|
9
9
|
1. Read `PLAN.md`, the detailed plan, `MEMORY.md`, and relevant memory notes.
|
|
10
10
|
2. Read the Codex or Claude model guidance recorded in the plan.
|
|
11
11
|
3. Select one small module slice.
|
|
12
|
-
4. Confirm required tool readiness. If a required LSP/check tool is missing, run `scripts/cairn toolcheck --install` or a repository-native install command before accepting a fallback.
|
|
12
|
+
4. Confirm required tool readiness. If a required LSP/check tool is missing, run `node scripts/cairn.mjs toolcheck --install` or a repository-native install command before accepting a fallback.
|
|
13
13
|
5. Confirm the complexity triage and selected Light/Heavy Path recorded in the plan.
|
|
14
14
|
6. For Light Path, implement directly or use one bounded `worker`, then run focused verification.
|
|
15
15
|
7. For Heavy Path, follow the plan's staged implementation and review gates without role-mapping shortcuts.
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
Detect repository stacks and check required LSP, typecheck, lint, dry-run, and verification tools.
|
|
4
4
|
|
|
5
5
|
```sh
|
|
6
|
-
scripts/cairn toolcheck
|
|
7
|
-
scripts/cairn toolcheck --install
|
|
6
|
+
node scripts/cairn.mjs toolcheck
|
|
7
|
+
node scripts/cairn.mjs toolcheck --install
|
|
8
8
|
```
|
|
9
9
|
|
|
10
10
|
Use `--install` before accepting a missing required tool as unavailable.
|
package/commands/cairn-doctor.md
CHANGED
package/commands/cairn-memory.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Use the `cairn-memory` skill.
|
|
4
4
|
|
|
5
|
-
Prerequisite: if `scripts/cairn doctor` fails, restore installation with `scripts/cairn install` or `scripts/cairn upgrade`.
|
|
5
|
+
Prerequisite: if `node scripts/cairn.mjs doctor` fails, restore installation with `node scripts/cairn.mjs install` or `node scripts/cairn.mjs upgrade`.
|
|
6
6
|
|
|
7
7
|
Goal: create or update repository memory without asking the user for discoverable facts.
|
|
8
8
|
|
package/commands/cairn-plan.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Use the `cairn-plan` skill.
|
|
4
4
|
|
|
5
|
-
Prerequisite: if `scripts/cairn doctor` fails, restore installation with `scripts/cairn install` or `scripts/cairn upgrade`.
|
|
5
|
+
Prerequisite: if `node scripts/cairn.mjs doctor` fails, restore installation with `node scripts/cairn.mjs install` or `node scripts/cairn.mjs upgrade`.
|
|
6
6
|
|
|
7
7
|
Goal: leave a decision-complete plan for the current task in files.
|
|
8
8
|
|
|
@@ -10,8 +10,8 @@ Procedure:
|
|
|
10
10
|
|
|
11
11
|
1. Read `MEMORY.md` and relevant `docs/memory/*.md`.
|
|
12
12
|
2. If the active or assigned model is Claude-family, read `docs/model-guidance/claude.md`; if Codex-family, read `docs/model-guidance/codex.md`.
|
|
13
|
-
3. Run `scripts/cairn toolcheck` when available.
|
|
14
|
-
4. If required LSP/check tools are missing, run `scripts/cairn toolcheck --install` or a repository-native install command before accepting a fallback.
|
|
13
|
+
3. Run `node scripts/cairn.mjs toolcheck` when available.
|
|
14
|
+
4. If required LSP/check tools are missing, run `node scripts/cairn.mjs toolcheck --install` or a repository-native install command before accepting a fallback.
|
|
15
15
|
5. Explore before asking the user.
|
|
16
16
|
6. Run complexity triage before applying agent, plugin, or delegated workflow guidance.
|
|
17
17
|
7. Use Light Path by default unless a Heavy Path condition clearly applies.
|
package/commands/cairn-review.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Use the `cairn-review` skill.
|
|
4
4
|
|
|
5
|
-
Prerequisite: if `scripts/cairn doctor` fails, restore installation with `scripts/cairn install` or `scripts/cairn upgrade`.
|
|
5
|
+
Prerequisite: if `node scripts/cairn.mjs doctor` fails, restore installation with `node scripts/cairn.mjs install` or `node scripts/cairn.mjs upgrade`.
|
|
6
6
|
|
|
7
7
|
Goal: review completed work against plan, memory, policy, and evidence.
|
|
8
8
|
|
|
@@ -12,8 +12,8 @@ bunx cairn-ai@latest toolcheck --install
|
|
|
12
12
|
From this repository:
|
|
13
13
|
|
|
14
14
|
```sh
|
|
15
|
-
scripts/cairn toolcheck
|
|
16
|
-
scripts/cairn toolcheck --install
|
|
15
|
+
node scripts/cairn.mjs toolcheck
|
|
16
|
+
node scripts/cairn.mjs toolcheck --install
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
Use `--install` when a required tool is missing. Record detected stacks, missing tools, install attempts, and blockers in the related `docs/plan/<topic>.md`.
|
package/commands/cairn-work.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Use the `cairn-work` skill.
|
|
4
4
|
|
|
5
|
-
Prerequisite: if `scripts/cairn doctor` fails, restore installation with `scripts/cairn install` or `scripts/cairn upgrade`.
|
|
5
|
+
Prerequisite: if `node scripts/cairn.mjs doctor` fails, restore installation with `node scripts/cairn.mjs install` or `node scripts/cairn.mjs upgrade`.
|
|
6
6
|
|
|
7
7
|
Goal: execute the next incomplete module slice in `PLAN.md`.
|
|
8
8
|
|
|
@@ -11,7 +11,7 @@ Procedure:
|
|
|
11
11
|
1. Read `PLAN.md`, the detailed plan, `MEMORY.md`, and relevant memory notes.
|
|
12
12
|
2. Read the Codex or Claude model guidance recorded in the plan.
|
|
13
13
|
3. Select one small module slice.
|
|
14
|
-
4. Confirm required tool readiness. If a required LSP/check tool is missing, run `scripts/cairn toolcheck --install` or a repository-native install command before accepting a fallback.
|
|
14
|
+
4. Confirm required tool readiness. If a required LSP/check tool is missing, run `node scripts/cairn.mjs toolcheck --install` or a repository-native install command before accepting a fallback.
|
|
15
15
|
5. Confirm the complexity triage and selected Light/Heavy Path recorded in the plan.
|
|
16
16
|
6. For Light Path, implement directly or use one bounded `worker`, then run focused verification.
|
|
17
17
|
7. For Heavy Path, follow the plan's staged implementation and review gates without role-mapping shortcuts.
|
package/hooks/hooks.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"hooks": [
|
|
6
6
|
{
|
|
7
7
|
"type": "command",
|
|
8
|
-
"command": "
|
|
8
|
+
"command": "node \"${PLUGIN_ROOT}/scripts/cairn-state.mjs\" session-start",
|
|
9
9
|
"timeout": 10,
|
|
10
10
|
"statusMessage": "Cairn: preparing repository memory and plan indexes"
|
|
11
11
|
}
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"hooks": [
|
|
18
18
|
{
|
|
19
19
|
"type": "command",
|
|
20
|
-
"command": "
|
|
20
|
+
"command": "node \"${PLUGIN_ROOT}/scripts/cairn-state.mjs\" user-prompt-submit",
|
|
21
21
|
"timeout": 10,
|
|
22
22
|
"statusMessage": "Cairn: loading compact work context"
|
|
23
23
|
}
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"hooks": [
|
|
31
31
|
{
|
|
32
32
|
"type": "command",
|
|
33
|
-
"command": "
|
|
33
|
+
"command": "node \"${PLUGIN_ROOT}/scripts/cairn-state.mjs\" post-tool-use",
|
|
34
34
|
"timeout": 10,
|
|
35
35
|
"statusMessage": "Cairn: checking memory and plan indexes"
|
|
36
36
|
}
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"hooks": [
|
|
43
43
|
{
|
|
44
44
|
"type": "command",
|
|
45
|
-
"command": "
|
|
45
|
+
"command": "node \"${PLUGIN_ROOT}/scripts/cairn-state.mjs\" stop",
|
|
46
46
|
"timeout": 10,
|
|
47
47
|
"statusMessage": "Cairn: checking two-gate evidence requirements"
|
|
48
48
|
}
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"hooks": [
|
|
55
55
|
{
|
|
56
56
|
"type": "command",
|
|
57
|
-
"command": "
|
|
57
|
+
"command": "node \"${PLUGIN_ROOT}/scripts/cairn-state.mjs\" subagent-stop",
|
|
58
58
|
"timeout": 10,
|
|
59
59
|
"statusMessage": "Cairn: checking subagent handoff evidence"
|
|
60
60
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cairn-ai",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Token-efficient agent harness with tool readiness for Codex, Claude Code, and Antigravity",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
"workflow"
|
|
22
22
|
],
|
|
23
23
|
"bin": {
|
|
24
|
-
"cairn": "scripts/cairn",
|
|
25
|
-
"cairn-ai": "scripts/cairn"
|
|
24
|
+
"cairn": "scripts/cairn.mjs",
|
|
25
|
+
"cairn-ai": "scripts/cairn.mjs"
|
|
26
26
|
},
|
|
27
27
|
"files": [
|
|
28
28
|
".agents/",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"README.*.md"
|
|
40
40
|
],
|
|
41
41
|
"scripts": {
|
|
42
|
-
"check": "node --check scripts/cairn-lifecycle.mjs && node --check scripts/cairn-toolcheck.mjs && node -e \"JSON.parse(require('node:fs').readFileSync('package.json','utf8')); JSON.parse(require('node:fs').readFileSync('.codex-plugin/plugin.json','utf8')); JSON.parse(require('node:fs').readFileSync('hooks/hooks.json','utf8'))\" && npm test",
|
|
42
|
+
"check": "node --check scripts/cairn.mjs && node --check scripts/cairn-state.mjs && node --check scripts/cairn-lifecycle.mjs && node --check scripts/cairn-toolcheck.mjs && node -e \"JSON.parse(require('node:fs').readFileSync('package.json','utf8')); JSON.parse(require('node:fs').readFileSync('.codex-plugin/plugin.json','utf8')); JSON.parse(require('node:fs').readFileSync('hooks/hooks.json','utf8'))\" && npm test",
|
|
43
43
|
"test": "node --test",
|
|
44
44
|
"prepack": "npm run check"
|
|
45
45
|
},
|
package/scripts/cairn
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
set -eu
|
|
3
3
|
|
|
4
|
-
cmd="${1:-help}"
|
|
5
|
-
shift || true
|
|
6
|
-
locale="${LC_ALL:-${LC_MESSAGES:-${LANG:-en}}}"
|
|
7
|
-
|
|
8
4
|
script_path="$0"
|
|
9
5
|
link_target="$(readlink "$script_path" 2>/dev/null || true)"
|
|
10
6
|
if [ -n "$link_target" ]; then
|
|
@@ -15,101 +11,4 @@ if [ -n "$link_target" ]; then
|
|
|
15
11
|
fi
|
|
16
12
|
script_dir="$(cd "$(dirname "$script_path")" && pwd)"
|
|
17
13
|
|
|
18
|
-
|
|
19
|
-
case "$locale" in
|
|
20
|
-
ko*|KO*) printf '%s\n' ko ;;
|
|
21
|
-
ja*|JA*) printf '%s\n' ja ;;
|
|
22
|
-
zh*|ZH*) printf '%s\n' zh ;;
|
|
23
|
-
es*|ES*) printf '%s\n' es ;;
|
|
24
|
-
fr*|FR*) printf '%s\n' fr ;;
|
|
25
|
-
de*|DE*) printf '%s\n' de ;;
|
|
26
|
-
pt*|PT*) printf '%s\n' pt ;;
|
|
27
|
-
*) printf '%s\n' en ;;
|
|
28
|
-
esac
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
say() {
|
|
32
|
-
key="$1"
|
|
33
|
-
family="$(locale_family)"
|
|
34
|
-
case "$family:$key" in
|
|
35
|
-
ko:memory) printf '%s\n' "cairn-memory 스킬을 사용하세요. MEMORY.md는 짧은 색인으로, 상세 내용은 docs/memory/<domain>.md에 기록합니다." ;;
|
|
36
|
-
ko:plan) printf '%s\n' "cairn-plan 스킬을 사용하세요. PLAN.md는 색인으로, 상세 계획은 docs/plan/<topic>.md에 기록합니다." ;;
|
|
37
|
-
ko:work) printf '%s\n' "cairn-work 스킬을 사용하세요. 하나의 모듈 조각을 실행하고 모듈 증거와 표면 증거를 확보합니다." ;;
|
|
38
|
-
ko:review) printf '%s\n' "cairn-review 스킬을 사용하세요. PLAN.md와 MEMORY.md 기준으로 증거를 비교합니다." ;;
|
|
39
|
-
ko:toolcheck) printf '%s\n' "저장소 도구를 점검하려면 cairn toolcheck 를 실행하세요. 누락 도구 설치까지 시도하려면 cairn toolcheck --install 을 사용합니다." ;;
|
|
40
|
-
ko:usage) printf '%s\n' "사용법: cairn install|upgrade|doctor|uninstall|init|memory|plan|work|review|toolcheck" ;;
|
|
41
|
-
ja:memory) printf '%s\n' "cairn-memory スキルを使用してください。MEMORY.md は短い索引にし、詳細は docs/memory/<domain>.md に記録します。" ;;
|
|
42
|
-
ja:plan) printf '%s\n' "cairn-plan スキルを使用してください。PLAN.md は索引にし、詳細計画は docs/plan/<topic>.md に記録します。" ;;
|
|
43
|
-
ja:work) printf '%s\n' "cairn-work スキルを使用してください。1つのモジュールスライスを実行し、モジュール証拠と表面証拠を取得します。" ;;
|
|
44
|
-
ja:review) printf '%s\n' "cairn-review スキルを使用してください。PLAN.md と MEMORY.md に照らして証拠を比較します。" ;;
|
|
45
|
-
ja:toolcheck) printf '%s\n' "リポジトリツールを確認するには cairn toolcheck を実行してください。不足ツールのインストールも試すには cairn toolcheck --install を使用します。" ;;
|
|
46
|
-
ja:usage) printf '%s\n' "使い方: cairn install|upgrade|doctor|uninstall|init|memory|plan|work|review|toolcheck" ;;
|
|
47
|
-
zh:memory) printf '%s\n' "使用 cairn-memory skill。将 MEMORY.md 保持为简短索引,并将详细内容写入 docs/memory/<domain>.md。" ;;
|
|
48
|
-
zh:plan) printf '%s\n' "使用 cairn-plan skill。将 PLAN.md 保持为索引,并将详细计划写入 docs/plan/<topic>.md。" ;;
|
|
49
|
-
zh:work) printf '%s\n' "使用 cairn-work skill。执行一个模块切片,并收集模块证据和表面证据。" ;;
|
|
50
|
-
zh:review) printf '%s\n' "使用 cairn-review skill。根据 PLAN.md 和 MEMORY.md 对比证据。" ;;
|
|
51
|
-
zh:toolcheck) printf '%s\n' "运行 cairn toolcheck 检查仓库工具。使用 cairn toolcheck --install 尝试安装缺失工具。" ;;
|
|
52
|
-
zh:usage) printf '%s\n' "用法: cairn install|upgrade|doctor|uninstall|init|memory|plan|work|review|toolcheck" ;;
|
|
53
|
-
es:memory) printf '%s\n' "Usa la skill cairn-memory. Mantén MEMORY.md como un índice breve y escribe los detalles en docs/memory/<domain>.md." ;;
|
|
54
|
-
es:plan) printf '%s\n' "Usa la skill cairn-plan. Mantén PLAN.md como índice y escribe los planes detallados en docs/plan/<topic>.md." ;;
|
|
55
|
-
es:work) printf '%s\n' "Usa la skill cairn-work. Ejecuta un solo segmento de módulo y captura evidencia de módulo y de superficie." ;;
|
|
56
|
-
es:review) printf '%s\n' "Usa la skill cairn-review. Compara la evidencia con PLAN.md y MEMORY.md." ;;
|
|
57
|
-
es:toolcheck) printf '%s\n' "Ejecuta cairn toolcheck para revisar herramientas del repositorio. Usa cairn toolcheck --install para intentar instalar herramientas faltantes." ;;
|
|
58
|
-
es:usage) printf '%s\n' "Uso: cairn install|upgrade|doctor|uninstall|init|memory|plan|work|review|toolcheck" ;;
|
|
59
|
-
fr:memory) printf '%s\n' "Utilisez la skill cairn-memory. Gardez MEMORY.md comme index court et écrivez les détails dans docs/memory/<domain>.md." ;;
|
|
60
|
-
fr:plan) printf '%s\n' "Utilisez la skill cairn-plan. Gardez PLAN.md comme index et écrivez les plans détaillés dans docs/plan/<topic>.md." ;;
|
|
61
|
-
fr:work) printf '%s\n' "Utilisez la skill cairn-work. Exécutez une tranche de module et capturez les preuves de module et de surface." ;;
|
|
62
|
-
fr:review) printf '%s\n' "Utilisez la skill cairn-review. Comparez les preuves avec PLAN.md et MEMORY.md." ;;
|
|
63
|
-
fr:toolcheck) printf '%s\n' "Exécutez cairn toolcheck pour vérifier les outils du dépôt. Utilisez cairn toolcheck --install pour tenter d'installer les outils manquants." ;;
|
|
64
|
-
fr:usage) printf '%s\n' "Utilisation: cairn install|upgrade|doctor|uninstall|init|memory|plan|work|review|toolcheck" ;;
|
|
65
|
-
de:memory) printf '%s\n' "Verwenden Sie die Skill cairn-memory. Halten Sie MEMORY.md als kurzen Index und schreiben Sie Details nach docs/memory/<domain>.md." ;;
|
|
66
|
-
de:plan) printf '%s\n' "Verwenden Sie die Skill cairn-plan. Halten Sie PLAN.md als Index und schreiben Sie Detailpläne nach docs/plan/<topic>.md." ;;
|
|
67
|
-
de:work) printf '%s\n' "Verwenden Sie die Skill cairn-work. Führen Sie einen Modulabschnitt aus und erfassen Sie Modul- und Oberflächenbelege." ;;
|
|
68
|
-
de:review) printf '%s\n' "Verwenden Sie die Skill cairn-review. Vergleichen Sie Belege mit PLAN.md und MEMORY.md." ;;
|
|
69
|
-
de:toolcheck) printf '%s\n' "Führen Sie cairn toolcheck aus, um Repository-Tools zu prüfen. Verwenden Sie cairn toolcheck --install, um fehlende Tools zu installieren." ;;
|
|
70
|
-
de:usage) printf '%s\n' "Verwendung: cairn install|upgrade|doctor|uninstall|init|memory|plan|work|review|toolcheck" ;;
|
|
71
|
-
pt:memory) printf '%s\n' "Use a skill cairn-memory. Mantenha MEMORY.md como um índice curto e escreva detalhes em docs/memory/<domain>.md." ;;
|
|
72
|
-
pt:plan) printf '%s\n' "Use a skill cairn-plan. Mantenha PLAN.md como índice e escreva planos detalhados em docs/plan/<topic>.md." ;;
|
|
73
|
-
pt:work) printf '%s\n' "Use a skill cairn-work. Execute uma fatia de módulo e capture evidências de módulo e de superfície." ;;
|
|
74
|
-
pt:review) printf '%s\n' "Use a skill cairn-review. Compare evidências com PLAN.md e MEMORY.md." ;;
|
|
75
|
-
pt:toolcheck) printf '%s\n' "Execute cairn toolcheck para verificar ferramentas do repositório. Use cairn toolcheck --install para tentar instalar ferramentas ausentes." ;;
|
|
76
|
-
pt:usage) printf '%s\n' "Uso: cairn install|upgrade|doctor|uninstall|init|memory|plan|work|review|toolcheck" ;;
|
|
77
|
-
*)
|
|
78
|
-
case "$key" in
|
|
79
|
-
memory) printf '%s\n' "Use the cairn-memory skill. Keep MEMORY.md as a short index and write details to docs/memory/<domain>.md." ;;
|
|
80
|
-
plan) printf '%s\n' "Use the cairn-plan skill. Keep PLAN.md as an index and write detailed plans to docs/plan/<topic>.md." ;;
|
|
81
|
-
work) printf '%s\n' "Use the cairn-work skill. Execute one module slice and capture module and surface evidence." ;;
|
|
82
|
-
review) printf '%s\n' "Use the cairn-review skill. Compare evidence against PLAN.md and MEMORY.md." ;;
|
|
83
|
-
toolcheck) printf '%s\n' "Run cairn toolcheck to inspect repository tools. Use cairn toolcheck --install to attempt missing tool installation." ;;
|
|
84
|
-
usage) printf '%s\n' "Usage: cairn install|upgrade|doctor|uninstall|init|memory|plan|work|review|toolcheck" ;;
|
|
85
|
-
esac
|
|
86
|
-
;;
|
|
87
|
-
esac
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
case "$cmd" in
|
|
91
|
-
install|upgrade|doctor|uninstall)
|
|
92
|
-
node "$script_dir/cairn-lifecycle.mjs" "$cmd" "$@"
|
|
93
|
-
;;
|
|
94
|
-
init)
|
|
95
|
-
sh "$script_dir/cairn-state.sh" manual
|
|
96
|
-
;;
|
|
97
|
-
memory)
|
|
98
|
-
say memory
|
|
99
|
-
;;
|
|
100
|
-
plan)
|
|
101
|
-
say plan
|
|
102
|
-
;;
|
|
103
|
-
work)
|
|
104
|
-
say work
|
|
105
|
-
;;
|
|
106
|
-
review)
|
|
107
|
-
say review
|
|
108
|
-
;;
|
|
109
|
-
toolcheck)
|
|
110
|
-
node "$script_dir/cairn-toolcheck.mjs" "$@"
|
|
111
|
-
;;
|
|
112
|
-
*)
|
|
113
|
-
say usage
|
|
114
|
-
;;
|
|
115
|
-
esac
|
|
14
|
+
exec node "$script_dir/cairn.mjs" "$@"
|
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
3
|
import { realpathSync } from "node:fs";
|
|
4
4
|
import { cp, mkdir, readFile, rm, stat, writeFile } from "node:fs/promises";
|
|
5
|
-
import {
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
import { dirname, join, relative, resolve } from "node:path";
|
|
6
7
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
7
8
|
|
|
8
9
|
const pluginRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
10
|
+
const homeRoot = process.env.HOME ?? process.env.USERPROFILE ?? homedir() ?? ".";
|
|
11
|
+
const codexHome = resolve(process.env.CODEX_HOME ?? join(homeRoot, ".codex"));
|
|
12
|
+
const claudeHome = resolve(process.env.CLAUDE_HOME ?? join(homeRoot, ".claude"));
|
|
13
|
+
const antigravityHome = resolve(process.env.ANTIGRAVITY_HOME ?? join(homeRoot, ".agents"));
|
|
14
|
+
const antigravityCliHome = resolve(process.env.ANTIGRAVITY_CLI_HOME ?? join(homeRoot, ".gemini", "antigravity-cli"));
|
|
13
15
|
const configPath = process.env.CODEX_CONFIG_PATH ?? join(codexHome, "config.toml");
|
|
14
16
|
const marketplaceName = "cairn";
|
|
15
17
|
const pluginName = "cairn";
|
|
@@ -87,7 +89,7 @@ async function copyPlugin() {
|
|
|
87
89
|
await mkdir(dirname(installedPluginRoot), { recursive: true });
|
|
88
90
|
await cp(pluginRoot, installedPluginRoot, {
|
|
89
91
|
recursive: true,
|
|
90
|
-
filter: (source) => !source.
|
|
92
|
+
filter: (source) => !pathHasSegment(relative(pluginRoot, source), ".git") && !pathHasSegment(relative(pluginRoot, source), "node_modules"),
|
|
91
93
|
});
|
|
92
94
|
const manifestPath = join(installedPluginRoot, ".codex-plugin", "plugin.json");
|
|
93
95
|
const manifest = JSON.parse(await readFile(manifestPath, "utf8"));
|
|
@@ -257,6 +259,10 @@ function append(config, block) {
|
|
|
257
259
|
return `${config.trimEnd()}${config.trimEnd().length === 0 ? "" : "\n\n"}${block.trimEnd()}\n`;
|
|
258
260
|
}
|
|
259
261
|
|
|
262
|
+
export function pathHasSegment(path, segment) {
|
|
263
|
+
return path.split(/[\\/]+/).includes(segment);
|
|
264
|
+
}
|
|
265
|
+
|
|
260
266
|
export function commandNames() {
|
|
261
267
|
return ["install", "upgrade", "doctor", "uninstall", "memory", "plan", "work", "review", "toolcheck"];
|
|
262
268
|
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
5
|
+
|
|
6
|
+
const memoryTemplate = `# MEMORY
|
|
7
|
+
|
|
8
|
+
This file is a short index of persistent repository knowledge.
|
|
9
|
+
|
|
10
|
+
## Domain Knowledge
|
|
11
|
+
|
|
12
|
+
- Link detailed notes under \`docs/memory/\`.
|
|
13
|
+
|
|
14
|
+
## Policy
|
|
15
|
+
|
|
16
|
+
- Prefer precise repository exploration before implementation.
|
|
17
|
+
- Preserve proper nouns, file names, variable names, service names, alert names, MCP tool names, and agent names exactly as written.
|
|
18
|
+
- Read only the detailed memory files needed for the current task.
|
|
19
|
+
- Write user-visible responses and artifacts in the OS locale unless the user asks for another language.
|
|
20
|
+
|
|
21
|
+
## Update Rules
|
|
22
|
+
|
|
23
|
+
- Keep root files short.
|
|
24
|
+
- Move detailed domain knowledge to \`docs/memory/<domain>.md\`.
|
|
25
|
+
- Record facts with source paths, commands, and observed behavior.
|
|
26
|
+
`;
|
|
27
|
+
|
|
28
|
+
const planTemplate = `# PLAN
|
|
29
|
+
|
|
30
|
+
This file is a short index of active and completed work plans.
|
|
31
|
+
|
|
32
|
+
## Active Plans
|
|
33
|
+
|
|
34
|
+
- Link detailed plans under \`docs/plan/\`.
|
|
35
|
+
|
|
36
|
+
## Completed Plans
|
|
37
|
+
|
|
38
|
+
- Move completed topics here with evidence links.
|
|
39
|
+
|
|
40
|
+
## Planning Rules
|
|
41
|
+
|
|
42
|
+
- Plans must be decision-complete before implementation.
|
|
43
|
+
- Split implementation into small module slices.
|
|
44
|
+
- Detect repository stack and required LSP/check tools before implementation.
|
|
45
|
+
- Install or bootstrap missing required tools before declaring them unavailable.
|
|
46
|
+
- Each slice normally passes exactly two gates.
|
|
47
|
+
- Module acceptance verification.
|
|
48
|
+
- Surface integration verification.
|
|
49
|
+
- Run dry-run or check mode before external-state mutation when available.
|
|
50
|
+
- Use at most two verification passes per slice by default.
|
|
51
|
+
- If a gate fails, diagnose once, shrink or split the slice, and rerun both gates.
|
|
52
|
+
- After two failed passes, record the blocker in \`docs/plan/<topic>.md\`.
|
|
53
|
+
`;
|
|
54
|
+
|
|
55
|
+
if (isCliEntry()) {
|
|
56
|
+
const event = process.argv[2] ?? "manual";
|
|
57
|
+
console.log(await runState(event));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export async function runState(event = "manual", { root = process.env.HARNESS_REPO_ROOT ?? process.cwd(), locale = localeValue() } = {}) {
|
|
61
|
+
const resolvedRoot = resolve(root);
|
|
62
|
+
await mkdir(join(resolvedRoot, "docs", "memory"), { recursive: true });
|
|
63
|
+
await mkdir(join(resolvedRoot, "docs", "plan"), { recursive: true });
|
|
64
|
+
await writeIfMissing(join(resolvedRoot, "MEMORY.md"), memoryTemplate);
|
|
65
|
+
await writeIfMissing(join(resolvedRoot, "PLAN.md"), planTemplate);
|
|
66
|
+
|
|
67
|
+
const ko = locale.toLowerCase().startsWith("ko");
|
|
68
|
+
if (event === "session-start" || event === "user-prompt-submit") {
|
|
69
|
+
return ko
|
|
70
|
+
? "Cairn 컨텍스트: 먼저 MEMORY.md와 PLAN.md를 읽고, 필요한 경우 toolcheck로 LSP/check 도구 준비 상태를 확인하세요."
|
|
71
|
+
: "Cairn context: read MEMORY.md and PLAN.md first, then run toolcheck when LSP/check tool readiness is needed.";
|
|
72
|
+
}
|
|
73
|
+
if (event === "post-tool-use") {
|
|
74
|
+
return ko
|
|
75
|
+
? "Cairn 점검: 외부 상태 변경에는 dry-run/check 증거가 필요하고, 동작이 바뀌었다면 docs/plan 증거를 갱신하세요."
|
|
76
|
+
: "Cairn check: external-state changes need dry-run/check evidence; if behavior changed, update docs/plan evidence.";
|
|
77
|
+
}
|
|
78
|
+
if (event === "stop" || event === "subagent-stop") {
|
|
79
|
+
return ko
|
|
80
|
+
? "Cairn 종료 게이트: 완료에는 docs/plan의 dry-run/check, 모듈 수용, 표면 통합 증거가 필요합니다."
|
|
81
|
+
: "Cairn stop gate: completion requires dry-run/check, module acceptance, and surface integration evidence in docs/plan.";
|
|
82
|
+
}
|
|
83
|
+
return ko
|
|
84
|
+
? "Cairn이 MEMORY.md, PLAN.md, docs/memory, docs/plan을 초기화했습니다."
|
|
85
|
+
: "Cairn initialized MEMORY.md, PLAN.md, docs/memory, and docs/plan.";
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async function writeIfMissing(path, content) {
|
|
89
|
+
try {
|
|
90
|
+
await readFile(path, "utf8");
|
|
91
|
+
} catch {
|
|
92
|
+
await writeFile(path, content);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function localeValue() {
|
|
97
|
+
return [process.env.LC_ALL, process.env.LC_MESSAGES, process.env.LANG]
|
|
98
|
+
.find((value) => typeof value === "string" && value.length > 0) ?? Intl.DateTimeFormat().resolvedOptions().locale;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function isCliEntry() {
|
|
102
|
+
return process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href;
|
|
103
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { readdir, stat } from "node:fs/promises";
|
|
3
|
-
import { join } from "node:path";
|
|
3
|
+
import { join, relative, sep } from "node:path";
|
|
4
4
|
import { spawnSync } from "node:child_process";
|
|
5
5
|
import { pathToFileURL } from "node:url";
|
|
6
6
|
|
|
@@ -60,7 +60,7 @@ export async function collectEntries(base) {
|
|
|
60
60
|
for (const entry of await readdir(dir)) {
|
|
61
61
|
if ([".git", ".cairn", "node_modules", "vendor", "target", ".venv", "__pycache__"].includes(entry)) continue;
|
|
62
62
|
const path = join(dir, entry);
|
|
63
|
-
const relativePath =
|
|
63
|
+
const relativePath = normalizePath(relative(base, path));
|
|
64
64
|
if (relativePath === "test/fixtures" || relativePath.startsWith("test/fixtures/")) continue;
|
|
65
65
|
const info = await stat(path);
|
|
66
66
|
if (info.isDirectory()) await walk(path);
|
|
@@ -85,7 +85,7 @@ export function detectStacks(paths) {
|
|
|
85
85
|
return [...stacks];
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
export function buildRequirements(stacks, entries = [], commandAvailable = commandOk) {
|
|
88
|
+
export function buildRequirements(stacks, entries = [], commandAvailable = commandOk, platform = process.platform) {
|
|
89
89
|
const requirements = [];
|
|
90
90
|
if (stacks.includes("javascript")) {
|
|
91
91
|
requirements.push(req("node", ["--version"], "JavaScript runtime for package scripts and CLI checks"));
|
|
@@ -98,8 +98,8 @@ export function buildRequirements(stacks, entries = [], commandAvailable = comma
|
|
|
98
98
|
if (stacks.includes("python")) {
|
|
99
99
|
const uv = commandAvailable("uv", ["--version"]);
|
|
100
100
|
const project = entries.includes("pyproject.toml");
|
|
101
|
-
const basedpyrightInstall = pythonInstall(uv, project, "basedpyright");
|
|
102
|
-
const ruffInstall = pythonInstall(uv, project, "ruff");
|
|
101
|
+
const basedpyrightInstall = pythonInstall(uv, project, "basedpyright", platform);
|
|
102
|
+
const ruffInstall = pythonInstall(uv, project, "ruff", platform);
|
|
103
103
|
requirements.push(req("basedpyright", ["--version"], "Python LSP/type checker", basedpyrightInstall));
|
|
104
104
|
requirements.push(req("ruff", ["--version"], "Python lint and format checker", ruffInstall));
|
|
105
105
|
}
|
|
@@ -114,7 +114,7 @@ export function buildRequirements(stacks, entries = [], commandAvailable = comma
|
|
|
114
114
|
}
|
|
115
115
|
if (stacks.includes("java")) {
|
|
116
116
|
addJvmRequirements(requirements);
|
|
117
|
-
requirements.push(req("jdtls", ["--version"], "Java LSP server",
|
|
117
|
+
requirements.push(req("jdtls", ["--version"], "Java LSP server", jdtlsInstall(platform)));
|
|
118
118
|
addJvmBuildToolRequirements(requirements, entries);
|
|
119
119
|
}
|
|
120
120
|
if (stacks.includes("kotlin")) {
|
|
@@ -151,9 +151,12 @@ export function addJvmRequirements(requirements) {
|
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
export function addJvmBuildToolRequirements(requirements, entries = []) {
|
|
154
|
-
if (entries.includes("gradlew")) pushUnique(requirements, req("
|
|
154
|
+
if (entries.includes("gradlew.bat")) pushUnique(requirements, req("gradlew.bat", ["--version"], "Gradle wrapper availability"));
|
|
155
|
+
else if (entries.includes("gradlew")) pushUnique(requirements, req("./gradlew", ["--version"], "Gradle wrapper availability"));
|
|
155
156
|
else if (entries.includes("build.gradle") || entries.includes("build.gradle.kts")) pushUnique(requirements, req("gradle", ["--version"], "Gradle availability"));
|
|
156
|
-
if (entries.includes("mvnw")) pushUnique(requirements, req("
|
|
157
|
+
if (entries.includes("mvnw.cmd")) pushUnique(requirements, req("mvnw.cmd", ["--version"], "Maven wrapper availability"));
|
|
158
|
+
else if (entries.includes("mvnw.bat")) pushUnique(requirements, req("mvnw.bat", ["--version"], "Maven wrapper availability"));
|
|
159
|
+
else if (entries.includes("mvnw")) pushUnique(requirements, req("./mvnw", ["--version"], "Maven wrapper availability"));
|
|
157
160
|
else if (entries.includes("pom.xml")) pushUnique(requirements, req("mvn", ["--version"], "Maven availability"));
|
|
158
161
|
}
|
|
159
162
|
|
|
@@ -165,12 +168,24 @@ export function composerInstall(packages) {
|
|
|
165
168
|
return { command: "composer", args: ["require", "--dev", ...packages] };
|
|
166
169
|
}
|
|
167
170
|
|
|
168
|
-
export function pythonInstall(uv, project, tool) {
|
|
171
|
+
export function pythonInstall(uv, project, tool, platform = process.platform) {
|
|
169
172
|
if (uv && project) return { command: "uv", args: ["add", "--dev", tool] };
|
|
170
173
|
if (uv) return { command: "uv", args: ["tool", "install", tool] };
|
|
174
|
+
if (platform === "win32") return { command: "py", args: ["-3", "-m", "pip", "install", "--user", tool] };
|
|
171
175
|
return { command: "python3", args: ["-m", "pip", "install", "--user", tool] };
|
|
172
176
|
}
|
|
173
177
|
|
|
178
|
+
export function jdtlsInstall(platform = process.platform) {
|
|
179
|
+
const url = "https://download.eclipse.org/jdtls/milestones/latest/jdt-language-server-latest.tar.gz";
|
|
180
|
+
if (platform === "win32") {
|
|
181
|
+
return {
|
|
182
|
+
command: "powershell",
|
|
183
|
+
args: ["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", `New-Item -ItemType Directory -Force .cairn/tools | Out-Null; Invoke-WebRequest -Uri ${url} -OutFile .cairn/tools/jdtls.tar.gz; tar -xzf .cairn/tools/jdtls.tar.gz -C .cairn/tools`],
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
return { command: "bash", args: ["-lc", `mkdir -p .cairn/tools && curl -L ${url} | tar -xz -C .cairn/tools`] };
|
|
187
|
+
}
|
|
188
|
+
|
|
174
189
|
export function req(command, args, reason, installCommand = null) {
|
|
175
190
|
return { name: command, command, args, reason, install: installCommand };
|
|
176
191
|
}
|
|
@@ -190,16 +205,41 @@ export function installDev(pm, packages) {
|
|
|
190
205
|
}
|
|
191
206
|
|
|
192
207
|
export function commandOk(command, args, root = process.cwd(), runner = run) {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
208
|
+
return commandCandidates(command, root).some((candidate) => runner(candidate, args).status === 0);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export function commandCandidates(command, root = process.cwd(), platform = process.platform) {
|
|
212
|
+
const candidates = [
|
|
213
|
+
command,
|
|
214
|
+
join(root, "node_modules", ".bin", command),
|
|
215
|
+
join(root, "vendor", "bin", command),
|
|
216
|
+
join(root, ".cairn", "tools", "bin", command),
|
|
217
|
+
];
|
|
218
|
+
if (platform !== "win32") return candidates;
|
|
219
|
+
const extensions = [".cmd", ".bat", ".exe"];
|
|
220
|
+
return candidates.flatMap((candidate) => hasWindowsExecutableExtension(candidate) ? [candidate] : [candidate, ...extensions.map((extension) => `${candidate}${extension}`)]);
|
|
197
221
|
}
|
|
198
222
|
|
|
199
223
|
export function run(command, args) {
|
|
200
|
-
return spawnSync(command, args, {
|
|
224
|
+
return spawnSync(command, args, {
|
|
225
|
+
stdio: "ignore",
|
|
226
|
+
encoding: "utf8",
|
|
227
|
+
shell: shouldUseShell(command),
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export function shouldUseShell(command, platform = process.platform) {
|
|
232
|
+
return platform === "win32" && /\.(cmd|bat)$/i.test(command);
|
|
201
233
|
}
|
|
202
234
|
|
|
203
235
|
function isCliEntry() {
|
|
204
236
|
return process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href;
|
|
205
237
|
}
|
|
238
|
+
|
|
239
|
+
function normalizePath(path) {
|
|
240
|
+
return path.split(sep).join("/");
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function hasWindowsExecutableExtension(command) {
|
|
244
|
+
return /\.(cmd|bat|exe)$/i.test(command);
|
|
245
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
4
|
+
import { spawnSync } from "node:child_process";
|
|
5
|
+
import { runState } from "./cairn-state.mjs";
|
|
6
|
+
|
|
7
|
+
const scriptDir = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
|
|
9
|
+
export async function main(command = "help", args = [], { runner = spawnSync } = {}) {
|
|
10
|
+
if (["install", "upgrade", "doctor", "uninstall"].includes(command)) {
|
|
11
|
+
const result = runner(process.execPath, [join(scriptDir, "cairn-lifecycle.mjs"), command, ...args], { stdio: "inherit" });
|
|
12
|
+
process.exitCode = result.status ?? 1;
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (command === "init") {
|
|
16
|
+
console.log(await runState("manual"));
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (command === "toolcheck") {
|
|
20
|
+
const result = runner(process.execPath, [join(scriptDir, "cairn-toolcheck.mjs"), ...args], { stdio: "inherit" });
|
|
21
|
+
process.exitCode = result.status ?? 1;
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (["memory", "plan", "work", "review"].includes(command)) {
|
|
25
|
+
console.log(message(command));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
console.log(message("usage"));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function message(key, locale = localeValue()) {
|
|
32
|
+
const family = localeFamily(locale);
|
|
33
|
+
return messages[family]?.[key] ?? messages.en[key];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function localeFamily(locale = localeValue()) {
|
|
37
|
+
const normalized = locale.toLowerCase();
|
|
38
|
+
for (const family of ["ko", "ja", "zh", "es", "fr", "de", "pt"]) {
|
|
39
|
+
if (normalized.startsWith(family)) return family;
|
|
40
|
+
}
|
|
41
|
+
return "en";
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function localeValue() {
|
|
45
|
+
return [process.env.LC_ALL, process.env.LC_MESSAGES, process.env.LANG]
|
|
46
|
+
.find((value) => typeof value === "string" && value.length > 0) ?? Intl.DateTimeFormat().resolvedOptions().locale;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function isCliEntry() {
|
|
50
|
+
return process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const messages = {
|
|
54
|
+
en: {
|
|
55
|
+
memory: "Use the cairn-memory skill. Keep MEMORY.md as a short index and write details to docs/memory/<domain>.md.",
|
|
56
|
+
plan: "Use the cairn-plan skill. Keep PLAN.md as an index and write detailed plans to docs/plan/<topic>.md.",
|
|
57
|
+
work: "Use the cairn-work skill. Execute one module slice and capture module and surface evidence.",
|
|
58
|
+
review: "Use the cairn-review skill. Compare evidence against PLAN.md and MEMORY.md.",
|
|
59
|
+
usage: "Usage: cairn install|upgrade|doctor|uninstall|init|memory|plan|work|review|toolcheck",
|
|
60
|
+
},
|
|
61
|
+
ko: {
|
|
62
|
+
memory: "cairn-memory 스킬을 사용하세요. MEMORY.md는 짧은 색인으로, 상세 내용은 docs/memory/<domain>.md에 기록합니다.",
|
|
63
|
+
plan: "cairn-plan 스킬을 사용하세요. PLAN.md는 색인으로, 상세 계획은 docs/plan/<topic>.md에 기록합니다.",
|
|
64
|
+
work: "cairn-work 스킬을 사용하세요. 하나의 모듈 조각을 실행하고 모듈 증거와 표면 증거를 확보합니다.",
|
|
65
|
+
review: "cairn-review 스킬을 사용하세요. PLAN.md와 MEMORY.md 기준으로 증거를 비교합니다.",
|
|
66
|
+
usage: "사용법: cairn install|upgrade|doctor|uninstall|init|memory|plan|work|review|toolcheck",
|
|
67
|
+
},
|
|
68
|
+
ja: {
|
|
69
|
+
memory: "cairn-memory スキルを使用してください。MEMORY.md は短い索引にし、詳細は docs/memory/<domain>.md に記録します。",
|
|
70
|
+
plan: "cairn-plan スキルを使用してください。PLAN.md は索引にし、詳細計画は docs/plan/<topic>.md に記録します。",
|
|
71
|
+
work: "cairn-work スキルを使用してください。1つのモジュールスライスを実行し、モジュール証拠と表面証拠を取得します。",
|
|
72
|
+
review: "cairn-review スキルを使用してください。PLAN.md と MEMORY.md に照らして証拠を比較します。",
|
|
73
|
+
usage: "使い方: cairn install|upgrade|doctor|uninstall|init|memory|plan|work|review|toolcheck",
|
|
74
|
+
},
|
|
75
|
+
zh: {
|
|
76
|
+
memory: "使用 cairn-memory skill。将 MEMORY.md 保持为简短索引,并将详细内容写入 docs/memory/<domain>.md。",
|
|
77
|
+
plan: "使用 cairn-plan skill。将 PLAN.md 保持为索引,并将详细计划写入 docs/plan/<topic>.md。",
|
|
78
|
+
work: "使用 cairn-work skill。执行一个模块切片,并收集模块证据。",
|
|
79
|
+
review: "使用 cairn-review skill。根据 PLAN.md 和 MEMORY.md 对比证据。",
|
|
80
|
+
usage: "用法: cairn install|upgrade|doctor|uninstall|init|memory|plan|work|review|toolcheck",
|
|
81
|
+
},
|
|
82
|
+
es: {
|
|
83
|
+
memory: "Usa la skill cairn-memory. Mantén MEMORY.md como un índice breve y escribe los detalles en docs/memory/<domain>.md.",
|
|
84
|
+
plan: "Usa la skill cairn-plan. Mantén PLAN.md como índice y escribe los planes detallados en docs/plan/<topic>.md.",
|
|
85
|
+
work: "Usa la skill cairn-work. Ejecuta un solo segmento de módulo y captura evidencia de módulo y de superficie.",
|
|
86
|
+
review: "Usa la skill cairn-review. Compara la evidencia con PLAN.md y MEMORY.md.",
|
|
87
|
+
usage: "Uso: cairn install|upgrade|doctor|uninstall|init|memory|plan|work|review|toolcheck",
|
|
88
|
+
},
|
|
89
|
+
fr: {
|
|
90
|
+
memory: "Utilisez la skill cairn-memory. Gardez MEMORY.md comme index court et écrivez les détails dans docs/memory/<domain>.md.",
|
|
91
|
+
plan: "Utilisez la skill cairn-plan. Gardez MEMORY.md comme index et écrivez les plans détaillés dans docs/plan/<topic>.md.",
|
|
92
|
+
work: "Utilisez la skill cairn-work. Exécutez une tranche de module et capturez les preuves de module et de surface.",
|
|
93
|
+
review: "Utilisez la skill cairn-review. Comparez les preuves avec PLAN.md et MEMORY.md.",
|
|
94
|
+
usage: "Utilisation: cairn install|upgrade|doctor|uninstall|init|memory|plan|work|review|toolcheck",
|
|
95
|
+
},
|
|
96
|
+
de: {
|
|
97
|
+
memory: "Verwenden Sie die Skill cairn-memory. Halten Sie MEMORY.md als kurzen Index und schreiben Sie Details nach docs/memory/<domain>.md.",
|
|
98
|
+
plan: "Verwenden Sie die Skill cairn-plan. Halten Sie MEMORY.md als Index und schreiben Sie Detailpläne nach docs/plan/<topic>.md.",
|
|
99
|
+
work: "Verwenden Sie die Skill cairn-work. Führen Sie einen Modulabschnitt aus und erfassen Sie Modul- und Oberflächenbelege.",
|
|
100
|
+
review: "Verwenden Sie die Skill cairn-review. Vergleichen Sie Belege mit PLAN.md und MEMORY.md.",
|
|
101
|
+
usage: "Verwendung: cairn install|upgrade|doctor|uninstall|init|memory|plan|work|review|toolcheck",
|
|
102
|
+
},
|
|
103
|
+
pt: {
|
|
104
|
+
memory: "Use a skill cairn-memory. Mantenha MEMORY.md como um índice curto e escreva detalhes em docs/memory/<domain>.md.",
|
|
105
|
+
plan: "Use a skill cairn-plan. Mantenha MEMORY.md como índice e escreva planos detalhados em docs/plan/<topic>.md.",
|
|
106
|
+
work: "Use a skill cairn-work. Execute uma fatia de módulo e capture evidências de módulo e de superfície.",
|
|
107
|
+
review: "Use a skill cairn-review. Compare evidências com PLAN.md e MEMORY.md.",
|
|
108
|
+
usage: "Uso: cairn install|upgrade|doctor|uninstall|init|memory|plan|work|review|toolcheck",
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
if (isCliEntry()) {
|
|
113
|
+
const [command = "help", ...args] = process.argv.slice(2);
|
|
114
|
+
await main(command, args);
|
|
115
|
+
}
|
|
@@ -13,7 +13,7 @@ The root `MEMORY.md` is an index, not detailed knowledge. Record details in `doc
|
|
|
13
13
|
|
|
14
14
|
## Procedure
|
|
15
15
|
|
|
16
|
-
1. Run `scripts/cairn-state.
|
|
16
|
+
1. Run `node scripts/cairn-state.mjs manual` if it exists. Otherwise ensure `MEMORY.md`, `PLAN.md`, `docs/memory`, and `docs/plan` directly.
|
|
17
17
|
2. Explore the repository before asking the user.
|
|
18
18
|
3. Delegate when it materially improves speed or quality instead of asking the user.
|
|
19
19
|
- `explorer`: read-only domain discovery, boundaries, invariants, policies, contradictions, and stale facts when available.
|
|
@@ -13,11 +13,11 @@ Plans must reduce execution tokens. Do not leave long plans only in chat. Store
|
|
|
13
13
|
|
|
14
14
|
## Procedure
|
|
15
15
|
|
|
16
|
-
1. Run `scripts/cairn-state.
|
|
16
|
+
1. Run `node scripts/cairn-state.mjs manual` if it exists. Otherwise ensure `MEMORY.md`, `PLAN.md`, `docs/memory`, and `docs/plan` directly.
|
|
17
17
|
2. Read only `MEMORY.md` and relevant `docs/memory/*.md` files.
|
|
18
18
|
3. Based on the active or assigned model, read `docs/model-guidance/README.md` and only the relevant model guidance.
|
|
19
|
-
4. Run `scripts/cairn toolcheck` when available, or `scripts/cairn-toolcheck.mjs` directly, to identify repository stacks and required tools.
|
|
20
|
-
5. If LSP, typecheck, lint, dry-run, or verification tools are missing, run `scripts/cairn toolcheck --install` or the closest repository-native install command before treating the tool as unavailable.
|
|
19
|
+
4. Run `node scripts/cairn.mjs toolcheck` when available, or `scripts/cairn-toolcheck.mjs` directly, to identify repository stacks and required tools.
|
|
20
|
+
5. If LSP, typecheck, lint, dry-run, or verification tools are missing, run `node scripts/cairn.mjs toolcheck --install` or the closest repository-native install command before treating the tool as unavailable.
|
|
21
21
|
6. Explore the repository with focused search and LSP/symbol tools after tool readiness is confirmed.
|
|
22
22
|
7. Identify the closest available dry-run or check mode for every slice that can mutate external state.
|
|
23
23
|
8. Run complexity triage before applying workflow guidance from agents, plugins, or delegated roles.
|
|
@@ -17,7 +17,7 @@ Execute only one module slice at a time. Instead of a repeated red-green loop, p
|
|
|
17
17
|
2. Read the `docs/model-guidance/*.md` inputs recorded in the plan.
|
|
18
18
|
3. Select the first incomplete module slice.
|
|
19
19
|
4. Confirm that required LSP, typecheck, lint, dry-run, and verification tools are available from the plan's tool readiness section.
|
|
20
|
-
5. If a required tool is missing, run `scripts/cairn toolcheck --install` or the closest repository-native install command, then rerun the tool before continuing.
|
|
20
|
+
5. If a required tool is missing, run `node scripts/cairn.mjs toolcheck --install` or the closest repository-native install command, then rerun the tool before continuing.
|
|
21
21
|
6. Confirm the selected Light Path or Heavy Path in the plan.
|
|
22
22
|
7. For Light Path, implement directly or delegate to one bounded `worker`; keep the verification gate.
|
|
23
23
|
8. For Heavy Path, follow the full planning and review pipeline recorded in the plan. Run pre-implementation review before mutation and read-only review after evidence exists.
|
|
@@ -43,7 +43,7 @@ CONTEXT: docs/plan/<topic>.md slice, relevant docs/memory notes, applied model g
|
|
|
43
43
|
## Tool Readiness Policy
|
|
44
44
|
|
|
45
45
|
- Run the repository tool readiness command recorded in the plan before implementation.
|
|
46
|
-
- If no command is recorded, run `scripts/cairn toolcheck` when available.
|
|
46
|
+
- If no command is recorded, run `node scripts/cairn.mjs toolcheck` when available.
|
|
47
47
|
- Missing LSP, typecheck, lint, dry-run, or verification tools must trigger a project-local or repository-native install attempt.
|
|
48
48
|
- After installation, rerun the exact tool command and record evidence.
|
|
49
49
|
- If installation fails, stop the slice and record the blocker rather than silently falling back to less precise exploration.
|