@kaydash9999/banker-plugins 0.23.3 → 0.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +56 -0
- package/README.md +14 -6
- package/codex/manifest.json +6 -2
- package/codex/skills/teamwork/scripts/teamwork.mjs +3 -3
- package/codex/transform-matrix.md +6 -2
- package/package.json +1 -1
- package/skills/build-testbox/SKILL.md +213 -0
- package/skills/build-testbox/scripts/args.mjs +156 -0
- package/skills/build-testbox/scripts/browser-cell.mjs +181 -0
- package/skills/build-testbox/scripts/browsers.mjs +164 -0
- package/skills/build-testbox/scripts/containers.mjs +237 -0
- package/skills/build-testbox/scripts/detect.mjs +166 -0
- package/skills/build-testbox/scripts/proc.mjs +91 -0
- package/skills/build-testbox/scripts/report.mjs +109 -0
- package/skills/build-testbox/scripts/setup.mjs +144 -0
- package/skills/build-testbox/scripts/testbox.mjs +148 -0
- package/skills/git-init/SKILL.md +152 -0
- package/skills/git-init/scripts/git-init.mjs +440 -0
- package/skills/git-init/scripts/marker-block.mjs +321 -0
- package/skills/git-init/scripts/payload-scan.mjs +186 -0
- package/skills/init-dir/SKILL.md +172 -0
- package/skills/init-dir/scripts/init-dir.mjs +308 -0
- package/skills/init-dir/scripts/marker-block.mjs +321 -0
- package/skills/init-dir/scripts/templates.mjs +100 -0
- package/skills/init-dir/templates/KB/README.md +15 -0
- package/skills/init-dir/templates/docs/README.md +14 -0
- package/skills/init-dir/templates/logs/README.md +14 -0
- package/skills/init-dir/templates/logs/gitignore +3 -0
- package/skills/init-dir/templates/mockup/README.md +7 -0
- package/skills/init-dir/templates/scripts/README.md +39 -0
- package/skills/init-dir/templates/scripts/lib/service.mjs +596 -0
- package/skills/init-dir/templates/scripts/restart.cmd +13 -0
- package/skills/init-dir/templates/scripts/restart.sh +10 -0
- package/skills/init-dir/templates/scripts/service.conf +5 -0
- package/skills/init-dir/templates/scripts/start.cmd +13 -0
- package/skills/init-dir/templates/scripts/start.sh +10 -0
- package/skills/init-dir/templates/scripts/status.cmd +13 -0
- package/skills/init-dir/templates/scripts/status.sh +10 -0
- package/skills/init-dir/templates/scripts/stop.cmd +13 -0
- package/skills/init-dir/templates/scripts/stop.sh +10 -0
- package/skills/init-dir/templates/tests/README.md +15 -0
- package/skills/init-dir/templates/tests/run.cmd +13 -0
- package/skills/init-dir/templates/tests/run.mjs +160 -0
- package/skills/init-dir/templates/tests/run.sh +10 -0
- package/skills/init-dir/templates/tests/tests.conf +7 -0
- package/skills/init-dir/templates/work/README.md +8 -0
- package/skills/progress-mon/README.md +11 -8
- package/skills/progress-mon/SKILL.md +53 -16
- package/skills/progress-mon/assets/fixture/README.md +1 -1
- package/skills/progress-mon/assets/fixture/adr.json +35 -0
- package/skills/progress-mon/assets/fixture/arch.json +1 -1
- package/skills/progress-mon/assets/fixture/flow.json +2 -2
- package/skills/progress-mon/assets/fixture/variants/arch-auto/arch.json +1 -1
- package/skills/progress-mon/assets/fixture/variants/legacy-init/rules.json +6 -0
- package/skills/progress-mon/assets/fixture/variants/legacy-init/state.json +5 -0
- package/skills/progress-mon/references/adr.md +184 -0
- package/skills/progress-mon/references/authoring.md +13 -5
- package/skills/progress-mon/scripts/pm-adr-view.mjs +101 -0
- package/skills/progress-mon/scripts/pm-adr.mjs +515 -0
- package/skills/progress-mon/scripts/pm-check.mjs +59 -22
- package/skills/progress-mon/scripts/pm-data.mjs +1 -1
- package/skills/progress-mon/scripts/pm-html.mjs +1 -0
- package/skills/progress-mon/scripts/pm-memory.mjs +113 -28
- package/skills/progress-mon/scripts/pm-render.mjs +6 -4
- package/skills/progress-mon/scripts/pm-server.mjs +2 -1
- package/skills/progress-mon/scripts/pm-sources.mjs +10 -0
- package/skills/progress-mon/scripts/progress-mon.mjs +3 -2
- package/skills/tune-tmux/SKILL.md +235 -0
- package/skills/tune-tmux/scripts/app-notes.mjs +38 -0
- package/skills/tune-tmux/scripts/marker-block.mjs +321 -0
- package/skills/tune-tmux/scripts/psmux-caps.json +71 -0
- package/skills/tune-tmux/scripts/tmux-config.mjs +251 -0
- package/skills/tune-tmux/scripts/tune-tmux.mjs +284 -0
- package/skills/ultra-chain/SKILL.md +52 -22
- package/skills/ultra-chain/references/chain-ledger.mjs +93 -11
- package/skills/ultra-chain/references/chain-report.mjs +13 -2
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
@echo off
|
|
2
|
+
rem scripts\stop.cmd: Windows form of ./scripts/stop.sh (banker init-dir)
|
|
3
|
+
rem Exit: 0 done, 1 failed, 2 no settings, 3 Node 18 or later not found
|
|
4
|
+
setlocal
|
|
5
|
+
set "NODE_BIN=%NODE%"
|
|
6
|
+
if "%NODE_BIN%"=="" set "NODE_BIN=node"
|
|
7
|
+
"%NODE_BIN%" -e "process.exit(Number(process.versions.node.split('.')[0]) >= 18 ? 0 : 1)" >nul 2>&1
|
|
8
|
+
if errorlevel 1 (
|
|
9
|
+
echo Node 18 or later is required: %NODE_BIN% 1>&2
|
|
10
|
+
exit /b 3
|
|
11
|
+
)
|
|
12
|
+
"%NODE_BIN%" "%~dp0lib\service.mjs" stop %*
|
|
13
|
+
exit /b %ERRORLEVEL%
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# ./scripts/stop.sh: 서비스와 감독 프로세스를 멈춤 (banker init-dir)
|
|
3
|
+
# 종료 코드: 0 성공, 1 실패, 2 설정 없음, 3 Node 18 이상 없음
|
|
4
|
+
dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) || exit 1
|
|
5
|
+
node_bin=${NODE:-node}
|
|
6
|
+
if ! "$node_bin" -e 'process.exit(Number(process.versions.node.split(".")[0]) >= 18 ? 0 : 1)' >/dev/null 2>&1; then
|
|
7
|
+
echo "Node 18 이상 필요: $node_bin" >&2
|
|
8
|
+
exit 3
|
|
9
|
+
fi
|
|
10
|
+
exec "$node_bin" "$dir/lib/service.mjs" stop "$@"
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# tests
|
|
2
|
+
|
|
3
|
+
단위 시험과 통합 시험 폴더. banker init-dir 이 만든 틀이다.
|
|
4
|
+
|
|
5
|
+
| 폴더 | 둘 것 |
|
|
6
|
+
|---|---|
|
|
7
|
+
| `tests/unit/` | 단위 시험. 외부 서비스 없이 빠르게 끝나는 것 |
|
|
8
|
+
| `tests/integration/` | 통합 시험. 실제 서비스, 파일, 네트워크를 쓰는 것 |
|
|
9
|
+
|
|
10
|
+
- 실행: `./tests/run.sh`(Windows `tests\run.cmd`). 스위트 이름을 주면 그것만(`./tests/run.sh unit`)
|
|
11
|
+
- 스위트 설정: `tests.conf` 에 `<스위트>=<명령>`. 프로젝트 폴더에서 셸로 실행
|
|
12
|
+
- 출력: 스위트마다 한 줄(`PASS unit (1.2s)`, `FAIL integration (0.3s, 종료 1)`). 실패하면 그 출력의 마지막 20줄, 끝에 요약 한 줄
|
|
13
|
+
- 시간 한도: 스위트마다 600초. `tests.conf` 의 `timeout=<초>` 나 환경 변수 `TESTS_TIMEOUT_SECONDS`(우선)로 바꿈. 넘으면 `FAIL <스위트> (600.0s, timeout 600초)` 와 그 스위트의 프로세스 트리 종료. 그래서 `timeout` 은 스위트 이름으로 못 씀
|
|
14
|
+
- 종료 코드: 0 모두 통과, 1 실패 있음, 2 설정 없음(실행할 명령 없음 포함), 3 Node 18 이상 없음
|
|
15
|
+
- 시험은 결과를 간결하게 출력하도록 쓴다. 통과는 조용히, 실패는 무엇이 왜 틀렸는지 한두 줄로
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
@echo off
|
|
2
|
+
rem tests\run.cmd: Windows form of ./tests/run.sh (banker init-dir)
|
|
3
|
+
rem Exit: 0 all passed, 1 a suite failed, 2 no settings, 3 Node 18 or later not found
|
|
4
|
+
setlocal
|
|
5
|
+
set "NODE_BIN=%NODE%"
|
|
6
|
+
if "%NODE_BIN%"=="" set "NODE_BIN=node"
|
|
7
|
+
"%NODE_BIN%" -e "process.exit(Number(process.versions.node.split('.')[0]) >= 18 ? 0 : 1)" >nul 2>&1
|
|
8
|
+
if errorlevel 1 (
|
|
9
|
+
echo Node 18 or later is required: %NODE_BIN% 1>&2
|
|
10
|
+
exit /b 3
|
|
11
|
+
)
|
|
12
|
+
"%NODE_BIN%" "%~dp0run.mjs" %*
|
|
13
|
+
exit /b %ERRORLEVEL%
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* tests/run.mjs: runs the test suites in tests/tests.conf and prints one short line per suite (made by banker
|
|
4
|
+
* init-dir).
|
|
5
|
+
*
|
|
6
|
+
* ./tests/run.sh [suite ...] (Windows: tests\run.cmd)
|
|
7
|
+
*
|
|
8
|
+
* tests.conf lines are `<suite>=<command>`; the command runs through the shell in the project folder. A suite
|
|
9
|
+
* with no command is SKIP. Each run prints `PASS <suite> (1.2s)` or `FAIL <suite> (0.3s, 종료 1)` with the last
|
|
10
|
+
* lines of its output, then one summary line.
|
|
11
|
+
*
|
|
12
|
+
* Each suite has a time limit, 600 seconds unless `timeout=<seconds>` in tests.conf or the environment variable
|
|
13
|
+
* TESTS_TIMEOUT_SECONDS (which wins) says otherwise. A suite past it is `FAIL <suite> (600.0s, timeout 600초)` and
|
|
14
|
+
* its whole process tree is killed (its process group on POSIX, taskkill /T /F on Windows). `timeout` is therefore
|
|
15
|
+
* not a suite name.
|
|
16
|
+
*
|
|
17
|
+
* Exit status: 0 every suite run passed, 1 a suite failed, 2 no settings (no tests.conf, no command to run, an
|
|
18
|
+
* unknown suite name), 3 environment (the wrappers did not find Node 18 or later).
|
|
19
|
+
*/
|
|
20
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
21
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
22
|
+
import { dirname, join } from "node:path";
|
|
23
|
+
import { fileURLToPath } from "node:url";
|
|
24
|
+
|
|
25
|
+
const TESTS = dirname(fileURLToPath(import.meta.url));
|
|
26
|
+
const ROOT = dirname(TESTS);
|
|
27
|
+
const CONF = join(TESTS, "tests.conf");
|
|
28
|
+
const TAIL_LINES = 20;
|
|
29
|
+
const KEEP_BYTES = 1024 * 1024;
|
|
30
|
+
const WIN = process.platform === "win32";
|
|
31
|
+
const DEFAULT_TIMEOUT_S = 600;
|
|
32
|
+
|
|
33
|
+
// The suites and the time limit in seconds: { suites, timeout }. `timeout=` sets the limit, every other key is a suite.
|
|
34
|
+
function readConf() {
|
|
35
|
+
const suites = [];
|
|
36
|
+
let timeout = DEFAULT_TIMEOUT_S;
|
|
37
|
+
for (const raw of readFileSync(CONF, "utf8").split(/\r?\n/)) {
|
|
38
|
+
const line = raw.trim();
|
|
39
|
+
const eq = line.indexOf("=");
|
|
40
|
+
if (line.startsWith("#") || eq <= 0) continue;
|
|
41
|
+
const [key, value] = [line.slice(0, eq).trim(), line.slice(eq + 1).trim()];
|
|
42
|
+
if (key === "timeout") timeout = seconds(value) ?? timeout;
|
|
43
|
+
else suites.push({ name: key, command: value });
|
|
44
|
+
}
|
|
45
|
+
return { suites, timeout: seconds(process.env.TESTS_TIMEOUT_SECONDS) ?? timeout };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function seconds(text) {
|
|
49
|
+
const n = Number(text);
|
|
50
|
+
return text && Number.isFinite(n) && n > 0 ? n : null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// The suite's whole tree: its process group on POSIX (it runs detached), taskkill /T /F on Windows.
|
|
54
|
+
function killTree(child) {
|
|
55
|
+
// The shell may be gone while what it started still holds the output pipes, so the group is killed regardless.
|
|
56
|
+
if (!child.pid) return;
|
|
57
|
+
if (WIN) spawnSync("taskkill", ["/T", "/F", "/PID", String(child.pid)], { stdio: "ignore", windowsHide: true });
|
|
58
|
+
else {
|
|
59
|
+
try {
|
|
60
|
+
process.kill(-child.pid, "SIGKILL");
|
|
61
|
+
} catch {
|
|
62
|
+
// the group is gone already
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Output kept for the failure tail: the last KEEP_BYTES of stdout and stderr together.
|
|
68
|
+
function collector() {
|
|
69
|
+
let text = "";
|
|
70
|
+
const add = (chunk) => {
|
|
71
|
+
text = (text + chunk).slice(-KEEP_BYTES);
|
|
72
|
+
};
|
|
73
|
+
return { add, lines: () => text.split(/\r?\n/).filter((l) => l.trim() !== "") };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
let current = null;
|
|
77
|
+
|
|
78
|
+
// Runs one suite: { code, signal, error, timedOut, output }.
|
|
79
|
+
function spawnSuite(suite, limitS) {
|
|
80
|
+
return new Promise((done) => {
|
|
81
|
+
const out = collector();
|
|
82
|
+
const child = spawn(suite.command, { shell: true, cwd: ROOT, detached: !WIN, stdio: ["ignore", "pipe", "pipe"], windowsHide: true });
|
|
83
|
+
current = child;
|
|
84
|
+
let timedOut = false;
|
|
85
|
+
let error = null;
|
|
86
|
+
const timer = setTimeout(() => {
|
|
87
|
+
timedOut = true;
|
|
88
|
+
killTree(child);
|
|
89
|
+
}, limitS * 1000);
|
|
90
|
+
for (const stream of [child.stdout, child.stderr]) {
|
|
91
|
+
stream.setEncoding("utf8");
|
|
92
|
+
stream.on("data", out.add);
|
|
93
|
+
}
|
|
94
|
+
child.on("error", (e) => {
|
|
95
|
+
error = e;
|
|
96
|
+
});
|
|
97
|
+
child.on("close", (code, signal) => {
|
|
98
|
+
clearTimeout(timer);
|
|
99
|
+
current = null;
|
|
100
|
+
done({ code, signal, error, timedOut, output: out.lines() });
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function runSuite(suite, limitS) {
|
|
106
|
+
const began = Date.now();
|
|
107
|
+
const r = await spawnSuite(suite, limitS);
|
|
108
|
+
const took = ((Date.now() - began) / 1000).toFixed(1);
|
|
109
|
+
if (r.code === 0 && !r.timedOut) return { pass: true, line: `PASS ${suite.name} (${took}s)` };
|
|
110
|
+
const why = r.timedOut ? `timeout ${limitS}초` : r.error ? r.error.message : r.code === null ? `신호 ${r.signal}` : `종료 ${r.code}`;
|
|
111
|
+
return { pass: false, line: `FAIL ${suite.name} (${took}s, ${why})`, tail: r.output.slice(-TAIL_LINES) };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function choose(suites, names) {
|
|
115
|
+
if (names.length === 0) return { chosen: suites };
|
|
116
|
+
const unknown = names.filter((n) => !suites.some((s) => s.name === n));
|
|
117
|
+
if (unknown.length > 0) return { error: `tests.conf 에 없는 스위트: ${unknown.join(", ")}` };
|
|
118
|
+
return { chosen: suites.filter((s) => names.includes(s.name)) };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async function runAll(chosen, limitS) {
|
|
122
|
+
const count = { pass: 0, fail: 0, skip: 0 };
|
|
123
|
+
for (const suite of chosen) {
|
|
124
|
+
if (suite.command === "") {
|
|
125
|
+
count.skip++;
|
|
126
|
+
console.log(`SKIP ${suite.name} (명령 없음)`);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const r = await runSuite(suite, limitS);
|
|
130
|
+
count[r.pass ? "pass" : "fail"]++;
|
|
131
|
+
console.log(r.line);
|
|
132
|
+
for (const line of r.tail ?? []) console.log(` ${line}`);
|
|
133
|
+
}
|
|
134
|
+
console.log(`결과: 통과 ${count.pass}, 실패 ${count.fail}, 건너뜀 ${count.skip}`);
|
|
135
|
+
return count.fail > 0 ? 1 : 0;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function usageError(text) {
|
|
139
|
+
console.error(text);
|
|
140
|
+
return 2;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async function main(names) {
|
|
144
|
+
if (!existsSync(CONF)) return usageError(`설정 파일 없음: ${CONF}`);
|
|
145
|
+
const conf = readConf();
|
|
146
|
+
const { chosen, error } = choose(conf.suites, names);
|
|
147
|
+
if (error) return usageError(error);
|
|
148
|
+
if (!chosen.some((s) => s.command !== "")) return usageError(`실행할 명령 없음: ${CONF} 의 unit=, integration= 을 채우세요`);
|
|
149
|
+
return runAll(chosen, conf.timeout);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// A suite runs in its own process group, so Ctrl+C or a stop of run.mjs does not reach it by itself: pass it on.
|
|
153
|
+
for (const [signal, code] of [["SIGINT", 130], ["SIGTERM", 143], ["SIGHUP", 129]]) {
|
|
154
|
+
process.on(signal, () => {
|
|
155
|
+
if (current) killTree(current);
|
|
156
|
+
process.exit(code);
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
process.exitCode = await main(process.argv.slice(2));
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# ./tests/run.sh: tests/tests.conf 의 스위트를 돌리고 스위트마다 한 줄로 결과를 보고 (banker init-dir)
|
|
3
|
+
# 종료 코드: 0 모두 통과, 1 실패 있음, 2 설정 없음, 3 Node 18 이상 없음
|
|
4
|
+
dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) || exit 1
|
|
5
|
+
node_bin=${NODE:-node}
|
|
6
|
+
if ! "$node_bin" -e 'process.exit(Number(process.versions.node.split(".")[0]) >= 18 ? 0 : 1)' >/dev/null 2>&1; then
|
|
7
|
+
echo "Node 18 이상 필요: $node_bin" >&2
|
|
8
|
+
exit 3
|
|
9
|
+
fi
|
|
10
|
+
exec "$node_bin" "$dir/run.mjs" "$@"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# progress-mon
|
|
2
2
|
|
|
3
|
-
프로젝트 진척도를
|
|
3
|
+
프로젝트 진척도를 5탭 웹 화면(진척도, 구현요건, workflow, 구성도, ADR)으로 보이는 스킬. 사용 절차는 `SKILL.md`.
|
|
4
4
|
이 폴더 하나를 banker 의 `skills/progress-mon/` 으로 그대로 옮긴다.
|
|
5
5
|
|
|
6
6
|
## 구조
|
|
@@ -13,15 +13,17 @@
|
|
|
13
13
|
| `scripts/pm-config.mjs` | 프로젝트 루트와 자료 폴더 결정, `config.json` 읽기, 기본값, 형식 검사, 원자적 쓰기(임시 파일과 rename, Windows 재시도) |
|
|
14
14
|
| `scripts/pm-sources.mjs` | events.jsonl, git log, 워크플로 journal, `items.json` 읽기. 스토리와 라벨 판정 함수, 시각 해석, 읽기 캐시 |
|
|
15
15
|
| `scripts/pm-html.mjs` | escape, 색 검사, 유한 수 검사, 글 폭 추정, 줄바꿈, 공통 CSS, 탭 머리 |
|
|
16
|
-
| `scripts/pm-render.mjs` |
|
|
16
|
+
| `scripts/pm-render.mjs` | 5탭, 단일 HTML 스냅숏(`export`), workflow 배치, 구성도 자동 배치 |
|
|
17
|
+
| `scripts/pm-adr.mjs` | ADR 탭 검사: `adr.json` 두 층 스키마 검사, 참조 확인과 정리(`check --adr-cleanup`), `docs/adr/` 갈라짐 경고, 밀도, 집계, check 대조 기록(`adr-check.json`) |
|
|
18
|
+
| `scripts/pm-adr-view.mjs` | ADR 탭 렌더: 화면 본문과 check 대조 배지 |
|
|
17
19
|
| `scripts/pm-server.mjs` | `serve`, `start`, `stop`, `status`. 바인드, Host 검사, 신원 경로, 상태 파일, 포트 선택, 로그 |
|
|
18
20
|
| `scripts/pm-data.mjs` | `init`, `item`, `note`, `stage`, `story`(`items.json` 잠금과 낡은 잠금 정리) |
|
|
19
|
-
| `scripts/pm-memory.mjs` | 메모리 규칙 등록, 규칙 로드 한도 측정 |
|
|
21
|
+
| `scripts/pm-memory.mjs` | 메모리 규칙 등록, 옛 판 규칙 줄의 제자리 교체(첫 원본 `.progress-mon.bak`), 규칙 로드 한도 측정 |
|
|
20
22
|
| `scripts/pm-check.mjs` | 자료 형식, 상호 참조, 구성도와 workflow 기하, 밀도 검사 |
|
|
21
23
|
| `scripts/index.js` | `node --test <폴더>/` 진입 로더. 모든 `*.test.mjs` 적재, 마지막 시험 `all <n> test files loaded` |
|
|
22
24
|
| `scripts/*.test.mjs` | 모듈별 시험. 시험마다 `timeout: 60000` |
|
|
23
|
-
| `references/` | `config.md`, `items.md`, `req-spec.md`, `reqs.md`, `flow.md`, `arch.md`(스키마와 판정 규칙), `authoring.md`(init 작성 지침, 밀도 기준), `inventory.md` |
|
|
24
|
-
| `assets/fixture/` | 형식 시험용 최소 자료와 변형(`variants/`). 화면 수준의 견본이 아님 |
|
|
25
|
+
| `references/` | `config.md`, `items.md`, `req-spec.md`, `reqs.md`, `flow.md`, `arch.md`, `adr.md`(스키마와 판정 규칙), `authoring.md`(init 작성 지침, 밀도 기준), `inventory.md` |
|
|
26
|
+
| `assets/fixture/` | 형식 시험용 최소 자료와 변형(`variants/`, 옛 판 규칙 줄 `variants/legacy-init/`). 화면 수준의 견본이 아님 |
|
|
25
27
|
|
|
26
28
|
- 의존성: Node 18 이상 내장 모듈만. npm 의존 0
|
|
27
29
|
- 인코딩: UTF-8, BOM 없음, LF. 숨은 문자는 escape(`\u{...}`)로만
|
|
@@ -40,6 +42,7 @@
|
|
|
40
42
|
- 시험은 임시 HOME, 임시 프로젝트, OS 가 고른 빈 포트에서 돈다. 포트 30000, 3456, 3458 은 쓰지 않는다
|
|
41
43
|
- 시험은 PATH 의 `git` 으로 임시 저장소를 만든다. git 이 없는 PC 에서는 그 시험 10개가 실패한다(2026-10-30, PATH 에 node 와 mkfifo 만 두고 실측). 스킬 자체는 git 이 없으면 커밋 기록 없이 동작
|
|
42
44
|
- FIFO 와 `/dev/zero` 시험은 POSIX 만. Windows 에서는 이유를 밝히고 건너뛴다
|
|
45
|
+
- ADR 화면 e2e 는 Playwright Chromium 으로 `export` 한 HTML 을 연다. Playwright 는 `BUILD_TESTBOX_PLAYWRIGHT_DIR`(테스트박스 도구 폴더, `node_modules` 를 담은 폴더)이 있으면 그곳, 없으면 `npm root -g` 에서 찾는다. Playwright 가 없거나 Chromium 을 띄우지 못하면 사유를 밝히고 건너뛴다. `PM_ADR_SHOT=<png 경로>` 를 주면 스크린숏을 그 경로에 남긴다
|
|
43
46
|
|
|
44
47
|
## 개발
|
|
45
48
|
|
|
@@ -88,7 +91,7 @@ override 에 banker 블록이나 이 스킬 블록만 있으면 `init`, `status`
|
|
|
88
91
|
| 항목 | `/banker:progress` | `/banker:progress-mon` |
|
|
89
92
|
|---|---|---|
|
|
90
93
|
| 종류 | 명령(`commands/progress.md`)과 훅 | 스킬 |
|
|
91
|
-
| 보이는 곳 | Claude Mods 패널(세션 작업 목록) | 브라우저(로컬 포트 서버,
|
|
94
|
+
| 보이는 곳 | Claude Mods 패널(세션 작업 목록) | 브라우저(로컬 포트 서버, 5탭) |
|
|
92
95
|
| 런타임 | mod 를 지원하는 Claude Code 만 | Claude Code 와 Codex |
|
|
93
96
|
| 서버 | 없음 | 있음(127.0.0.1 기본) |
|
|
94
97
|
|
|
@@ -100,8 +103,8 @@ override 에 banker 블록이나 이 스킬 블록만 있으면 `init`, `status`
|
|
|
100
103
|
|
|
101
104
|
```json
|
|
102
105
|
{ "name": "progress-mon", "type": "skill", "target": "both",
|
|
103
|
-
"reason": "project progress web screen with
|
|
104
|
-
"supportingFiles": ["README.md", "references/arch.md", "references/authoring.md", "references/config.md", "references/flow.md", "references/inventory.md", "references/items.md", "references/req-spec.md", "references/reqs.md", "scripts/index.js", "scripts/pm-check.mjs", "scripts/pm-config.mjs", "scripts/pm-data.mjs", "scripts/pm-html.mjs", "scripts/pm-memory.mjs", "scripts/pm-render.mjs", "scripts/pm-server.mjs", "scripts/pm-sources.mjs", "scripts/progress-mon.mjs", "assets/fixture/README.md", "assets/fixture/config.json", "assets/fixture/events.jsonl", "assets/fixture/items.json", "assets/fixture/commits.json", "assets/fixture/req-spec.json", "assets/fixture/reqs.json", "assets/fixture/flow.json", "assets/fixture/arch.json", "assets/fixture/workflows/wf_ex1/journal.jsonl", "assets/fixture/workflows/wf_ex1/agent-a01.jsonl", "assets/fixture/workflows/wf_ex1/agent-a02.jsonl", "assets/fixture/workflows/wf_ex1/agent-a03.jsonl", "assets/fixture/workflows/wf_ex1/agent-a04.jsonl", "assets/fixture/variants/arch-auto/arch.json", "assets/fixture/variants/check-auto/arch.json", "assets/fixture/variants/check-overlap/arch.json", "assets/fixture/variants/history-manual/config.json", "assets/fixture/variants/history-manual/items.json", "assets/fixture/variants/workflow-wide/flow.json"],
|
|
106
|
+
"reason": "project progress web screen with five tabs (progress, requirements, workflow, architecture, ADR) on a local server; init reads the code and writes the tab data, registers a one-line update rule in project memory; item, note, stage, story keep it current; pure Node, no deps",
|
|
107
|
+
"supportingFiles": ["README.md", "references/adr.md", "references/arch.md", "references/authoring.md", "references/config.md", "references/flow.md", "references/inventory.md", "references/items.md", "references/req-spec.md", "references/reqs.md", "scripts/index.js", "scripts/pm-adr.mjs", "scripts/pm-adr-view.mjs", "scripts/pm-check.mjs", "scripts/pm-config.mjs", "scripts/pm-data.mjs", "scripts/pm-html.mjs", "scripts/pm-memory.mjs", "scripts/pm-render.mjs", "scripts/pm-server.mjs", "scripts/pm-sources.mjs", "scripts/progress-mon.mjs", "assets/fixture/README.md", "assets/fixture/config.json", "assets/fixture/events.jsonl", "assets/fixture/items.json", "assets/fixture/commits.json", "assets/fixture/req-spec.json", "assets/fixture/reqs.json", "assets/fixture/flow.json", "assets/fixture/arch.json", "assets/fixture/adr.json", "assets/fixture/workflows/wf_ex1/journal.jsonl", "assets/fixture/workflows/wf_ex1/agent-a01.jsonl", "assets/fixture/workflows/wf_ex1/agent-a02.jsonl", "assets/fixture/workflows/wf_ex1/agent-a03.jsonl", "assets/fixture/workflows/wf_ex1/agent-a04.jsonl", "assets/fixture/variants/arch-auto/arch.json", "assets/fixture/variants/check-auto/arch.json", "assets/fixture/variants/check-overlap/arch.json", "assets/fixture/variants/history-manual/config.json", "assets/fixture/variants/history-manual/items.json", "assets/fixture/variants/workflow-wide/flow.json", "assets/fixture/variants/legacy-init/rules.json", "assets/fixture/variants/legacy-init/state.json"],
|
|
105
108
|
"caveat": "needs Node 18 or later (above the package engines floor); binds 127.0.0.1 only by default, --host takes a private IPv4 with a warning; data lives in .omc/progress-mon/ (Codex .omx/progress-mon/); on Codex start, stop, status and init each ask for sandbox_permissions require_escalated, and a long-lived screen runs from the user's terminal (serve) since closing the session may stop the server" }
|
|
106
109
|
```
|
|
107
110
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: progress-mon
|
|
3
|
-
description: "프로젝트 진척도를
|
|
3
|
+
description: "프로젝트 진척도를 5탭 웹 화면(진척도, 구현요건, workflow, 구성도, ADR)으로 로컬 서버(기본 127.0.0.1:30000)에 띄움. ADR 탭은 결정마다 최적화 로직, 확장 대응, 포기와 얻은 것과 프로젝트의 검증, 흐름, 증거를 확인 가능한 참조와 함께 보임. 인자 없이 부르면 자료 폴더가 없을 때 init(코드를 읽어 5탭 자료를 쓰고 갱신 규칙 등록), 서버가 꺼져 있으면 start, 켜져 있으면 URL 보고. ADR 자료가 없는 옛 자료 폴더는 확인 뒤 ADR 단계를 먼저 함. 하위 명령 init, start, stop, status, export, item, note, stage, story, check. 'progress-mon'/'진척도 화면'/'진척도 서버'/'진행 현황 웹 화면' 시 사용. 세션 작업 목록 패널은 이 스킬 대신 progress(Claude Code `/banker:progress`, Codex `$banker-progress`)."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# progress-mon: 프로젝트 진척도 웹 화면
|
|
7
7
|
|
|
8
|
-
프로젝트의 진척도를
|
|
8
|
+
프로젝트의 진척도를 5탭 웹 화면으로 보인다. 서버는 Node 내장 모듈만 쓰고 기본으로 127.0.0.1 에만 바인드한다.
|
|
9
9
|
답변은 한글.
|
|
10
10
|
|
|
11
11
|
progress-mon skill body marker v1
|
|
@@ -16,13 +16,16 @@ progress-mon skill body marker v1
|
|
|
16
16
|
| 구현요건 | 요구 원문, 기능 명세, 근거 AC, 담당 스토리, 구현 여부 | `req-spec.json`, `reqs.json` |
|
|
17
17
|
| workflow | 실행 흐름 그림, 분기, 외부 구성요소, 장면 대본 | `flow.json` |
|
|
18
18
|
| 구성도 | 영역, 구성요소, 연결, 범례, 장면 대본 | `arch.json` |
|
|
19
|
+
| ADR | 프로젝트 요약(검증, 흐름, 증거)과 결정마다 맥락, 선택지, 결론, 최적화 로직, 확장 대응, 포기와 얻은 것. 참조는 위치 글만 | `adr.json` |
|
|
19
20
|
|
|
20
21
|
- 없는 출처는 건너뛴다. 자료가 없는 탭은 "자료 없음" 과 스키마 문서 경로를 보인다
|
|
21
22
|
- 진척도, 구현요건 탭은 30초마다 자동 갱신(meta refresh). 다른 갱신 연결은 없다
|
|
23
|
+
- ADR 탭은 서버가 `adr.json` 만 읽는다. 프로젝트의 `docs/adr/`, `docs/evidence/` 는 에이전트가 init 과 갱신 때 근거 출처로 읽고 참조로 가리킨다
|
|
22
24
|
|
|
23
25
|
## 언제 쓰나
|
|
24
26
|
|
|
25
|
-
- 다른 프로젝트에서도 같은
|
|
27
|
+
- 다른 프로젝트에서도 같은 5탭 진척도 화면을 띄우고 싶을 때
|
|
28
|
+
- 결정의 근거와 검증 증거를 타인이 확인할 수 있게 한 화면에 모으고 싶을 때(ADR 탭)
|
|
26
29
|
- 단계, 스토리, 그 밖 작업의 진행을 에이전트가 세션마다 기록하게 하고 싶을 때
|
|
27
30
|
- 화면을 서버 없이 한 파일로 넘겨야 할 때(`export`)
|
|
28
31
|
|
|
@@ -70,11 +73,30 @@ progress-mon skill body marker v1
|
|
|
70
73
|
| 종료 3, `꺼짐(자료 폴더 없음: ...)` | 아래 "init 절차" 를 끝까지. 마지막 단계가 `start` 와 URL 보고 |
|
|
71
74
|
| 종료 3, `꺼짐(자료 폴더: ...)` | `start` 를 실행하고 출력의 URL 을 보고 |
|
|
72
75
|
| 종료 0, `실행 중: <URL> (PID n)` | URL 과 `탭 자료:` 줄을 보고 |
|
|
76
|
+
| 자료 폴더가 있고 `탭 자료:` 줄이 `ADR 없음` | 위 행의 일을 하기 전에 아래 "기존 프로젝트의 ADR 단계" 를 한다. `ADR 깨짐` 이면 하지 않고 깨짐을 보고(`check` 로 위치 확인) |
|
|
73
77
|
| 종료 1 또는 2 | 오류 줄을 그대로 보고하고 멈춤 |
|
|
74
78
|
|
|
75
79
|
3. `status` 의 표준 오류에 경고 줄(규칙 로드 한도, override 가려짐, `workflowDirs`)이 있으면 그대로 전한다
|
|
76
80
|
- `WARN workflowDirs auto: 찾은 폴더 0` 은 이 프로젝트에서 Claude Code 워크플로를 돌린 적이 없으면 정상이다. 끄려면 `config.json` 의 `sources.workflowDirs` 를 `[]`(`references/config.md`)
|
|
77
81
|
|
|
82
|
+
### 기존 프로젝트의 ADR 단계
|
|
83
|
+
|
|
84
|
+
ADR 탭이 생기기 전 판으로 init 한 프로젝트는 `adr.json` 이 없고 메모리의 규칙 줄도 옛 판이다. 다음 인자 없는 호출에서 한 번 채운다.
|
|
85
|
+
|
|
86
|
+
1. 진행 전에 한 번 묻는다: "ADR 탭 자료가 없습니다. 코드와 문서를 읽어 `adr.json` 을 쓰고 메모리의 progress-mon 규칙 줄을 새 판으로 바꿀까요?"
|
|
87
|
+
- Claude Code 는 AskUserQuestion, Codex 는 request_user_input 으로 묻는다(선택지: 진행, 이번에는 건너뜀)
|
|
88
|
+
- 사용자가 `--auto` 를 붙여 불렀거나(예 `/progress-mon --auto`, 스크립트에는 넘기지 않음) 다른 스킬이 자동 진행으로 불렀으면 묻지 않는다
|
|
89
|
+
- 건너뜀이면 원래 표의 일만 한다
|
|
90
|
+
2. `<data>/state.json` 의 `memory`(`{kind, path}`)를 읽어 `init` 을 다시 실행한다. 다른 자료 파일은 이미 있으면 그대로 둔다
|
|
91
|
+
- `auto-memory`: `init --runtime <rt> --memory auto-memory --memory-dir "<path 의 폴더>"`(`--memory-dir` 필수. `path` 는 `MEMORY.md` 경로라 그 폴더를 넘긴다)
|
|
92
|
+
- `claude-md`, `agents-md`, `none`: `init --runtime <rt> --memory <kind>`
|
|
93
|
+
- Codex 는 init 처럼 `sandbox_permissions: "require_escalated"` 로 승인 요청
|
|
94
|
+
3. 출력의 `규칙 줄 교체(백업 <경로>): <파일>` 줄을 사용자에게 알린다. 표식 줄(우리가 쓴 규칙 줄과 색인 줄)만 새 판으로 바꾸고 첫 원본을 그 백업에 남긴다. 사용자가 손으로 고친 표식 줄도 덮으므로 백업 경로를 함께 알린다
|
|
95
|
+
4. 아래 "init 절차" 의 8(ADR 단계), 9~11(check 반복과 정리 단계)만 한다
|
|
96
|
+
5. 원래 표의 일(`start` 와 URL 보고, 또는 URL 과 `탭 자료:` 보고)로 돌아간다
|
|
97
|
+
|
|
98
|
+
- `--memory none` 으로 init 한 프로젝트는 바꿀 규칙 줄이 없어 1, 4, 5 만 한다
|
|
99
|
+
|
|
78
100
|
- `start` 출력: `시작함: <URL>`, 이미 떠 있으면 `이미 실행 중(재사용): <URL>`. 포트가 차 있으면 다음 빈 포트를 쓰고 알림 줄을 낸다
|
|
79
101
|
- `--port 0`(OS 선택)은 받지 않는다. 특정 포트를 피해야 하면 OS 가 고른 빈 포트를 먼저 얻어 `--port` 로 넘긴다(`references/config.md` 의 "포트와 주소")
|
|
80
102
|
- 인자가 있는 호출(`/progress-mon status` 등)은 그 하위 명령을 `--runtime <rt>` 와 함께 그대로 실행하고 출력을 보고한다. `init` 만은 아래 절차를 따른다
|
|
@@ -86,19 +108,19 @@ progress-mon skill body marker v1
|
|
|
86
108
|
| `init` | `--memory claude-md\|agents-md\|auto-memory\|none` `[--memory-dir <dir>] [--title <t>]` | 자료 폴더, `config.json`(있으면 그대로), 빈 `items.json`, `state.json` 생성. git 제외 목록에 자료 폴더 한 줄. 메모리 규칙 등록. `auto-memory` 는 `--memory-dir` 필수 |
|
|
87
109
|
| `start` | `[--port <n>] [--port-strict] [--host <사설 IPv4>]` | 서버를 분리 실행하고 URL 출력. 같은 프로젝트 서버가 떠 있으면 재사용. 동시에 부른 start 는 차례로 돌아 서버 하나를 같이 씀. `<n>` 은 1024~65535 |
|
|
88
110
|
| `stop` | 없음 | 상태 파일 PID 가 이 서버일 때만 끔 |
|
|
89
|
-
| `status` | 없음 | 실행 여부, URL, PID, 자료 폴더, 탭별 자료 유무(깨진 JSON 은 깨짐), 시작 시각, 요청 수, 마지막 오류 시각. 서버를 띄운 뒤 `config.json` 의 `port`, `portStrict`, `hosts` 가 바뀌었으면 경고(그 셋만 `stop` 뒤 `start` 해야 적용, 나머지는 다음 응답에 반영) |
|
|
90
|
-
| `export` | `<file> [--now <ISO>]` |
|
|
111
|
+
| `status` | 없음 | 실행 여부, URL, PID, 자료 폴더, 탭별 자료 유무(`탭 자료:` 줄, 꺼져 있어도 자료 폴더가 있으면 보임. 깨진 JSON 은 깨짐), 시작 시각, 요청 수, 마지막 오류 시각. 서버를 띄운 뒤 `config.json` 의 `port`, `portStrict`, `hosts` 가 바뀌었으면 경고(그 셋만 `stop` 뒤 `start` 해야 적용, 나머지는 다음 응답에 반영) |
|
|
112
|
+
| `export` | `<file> [--now <ISO>]` | 5탭을 한 HTML 파일로. 외부 자원 없음, `file://` 에서 탭 전환. 사용자가 지시할 때만 만든다 |
|
|
91
113
|
| `item` | `--key <k> --status todo\|doing\|done --text <t> [--note <t>] [--issue <t>] [--at <ISO>] [--commit <hash>]` | 기타 항목. 같은 key 는 대체하고 시작 시각 유지(시작 시각은 `doing` 으로 기록할 때만). `--at` 은 지금 대신 그 시각으로 기록(시간대 필수). `--commit` 은 4~40자 16진 해시(commit Hash 칸에 앞 7자리). 빼면 있던 해시 유지 |
|
|
92
114
|
| `note` | `--key <k> [--note <t>] [--issue <t>]` | 단계(`stage:<id>`)나 스토리 행의 비고, 문제점. 빈 값은 그 칸을 지움 |
|
|
93
115
|
| `stage` | `--id <id> --status started\|done\|skipped\|failed\|stopped [--label <t>]` | 단계 상태 기록. 설정에 없는 id 는 새 단계 행 |
|
|
94
116
|
| `story` | `--id <id> (--status todo\|doing\|done \| --commit <hash>) [--name <t>]` | 스토리 상태나 완료 커밋 기록. 설정에 없는 id 는 새 스토리 행 |
|
|
95
|
-
| `check` |
|
|
117
|
+
| `check` | `[--adr-cleanup]` | 자료 파일 검사. `FAIL <파일> <json 경로> <이유>`, `WARN ...` 한 줄씩, 끝에 `check: FAIL n, WARN m` 과 밀도 요약 `density <탭> ok\|low`, 마지막 줄 `adr 근거 없음 n칸, 미검증 n, 구현 못 함 n, 참조 없는 서술 n`(늘. 참조 없는 서술은 `refs` 에 확인된 참조가 0개인 `optimization`, `scaling` 칸 수로 규칙은 WARN 이지만 0 이 아니면 화면 배지가 빨강). 밀도 미달 줄 `WARN density <탭> <항목> <값>/<하한>[: <못 채운 대상>]`. `--adr-cleanup` 은 먼저 init 정리 단계를 `adr.json` 에 적용(참조 FAIL 은 `gap`, 스키마 FAIL 이 남으면 같은 폴더의 `adr.json.rejected-<YYYYMMDD-HHMMSS>` 로 옮김. 이름이 있으면 `-2` 부터 번호)하고 `정리:` 줄(옮긴 경로 포함)을 낸 뒤 검사. 끝에 화면 대조용 `adr-check.json`(check 집계와 `adr.json` sha256)을 쓴다(`references/adr.md`) |
|
|
96
118
|
|
|
97
119
|
- 공통 인자: `--runtime claude|codex`, `--project <dir>`, `--data <dir>`(자료 폴더 직접 지정)
|
|
98
120
|
- 종료 코드: 0 성공(이미 그 상태 포함), 1 거부나 사용법 오류나 `check` FAIL, 2 예기치 못한 오류, 3 `status` 꺼짐
|
|
99
121
|
- 자료 폴더가 없으면 `start`, `item`, `note`, `stage`, `story` 는 종료 1("init 먼저"). `status`, `check`, `export` 는 폴더를 만들지 않는다
|
|
100
122
|
- 내부용 `serve`: `start` 와 같은 인자로 서버를 앞에서 실행. Codex 사용자 터미널 안내와 디버그에만 쓴다
|
|
101
|
-
- 스키마와 규칙: `references/config.md`, `references/items.md`
|
|
123
|
+
- 스키마와 규칙: `references/config.md`, `references/items.md`, `references/adr.md`
|
|
102
124
|
|
|
103
125
|
## init 절차
|
|
104
126
|
|
|
@@ -108,20 +130,33 @@ progress-mon skill body marker v1
|
|
|
108
130
|
- 쓴 파일과 줄 수: 자동 메모리는 파일 2개(`progress-mon.md`, `MEMORY.md` 색인 1줄), `CLAUDE.md` 는 1줄, Codex 는 3줄 블록
|
|
109
131
|
- `--memory claude-md` 는 프로젝트 루트 `CLAUDE.md` 를 만들거나 고친다. 새로 만들었으면 `git status` 에 추적하지 않는 파일로 보인다. 커밋할지는 사용자가 정한다고 알린다
|
|
110
132
|
- 출력에 `경고:` 줄(규칙 로드 한도, override 가려짐)이 있으면 그대로 전한다. Claude 면 `--memory claude-md` 로 다시 등록할지 묻고, Codex 면 프로젝트 지시 파일 정리(banker `cleansing-memory`)나 `config.toml` 의 `project_doc_max_bytes` 확인을 제안한다
|
|
111
|
-
- 출력 끝 `다음 할 일` 3줄은 요약이다. 그 목록이 아니라 이 절차 4~
|
|
133
|
+
- 출력 끝 `다음 할 일` 3줄은 요약이다. 그 목록이 아니라 이 절차 4~14 를 모두 따른다(`inventory.json`, `config.json` 의 `title`, `shortName`, `stories`, 진척도 기록은 요약에 없어도 한다)
|
|
112
134
|
4. `<S>/references/authoring.md` 를 읽는다. 밀도 기준 표, 읽기 예산, 좋은 예가 거기 있다
|
|
113
135
|
5. 읽기 예산 안에서 코드를 읽고 `<data>/inventory.json` 을 쓴다(`references/inventory.md`)
|
|
114
136
|
6. `<data>/config.json` 의 `title`, `shortName`, `stories` 를 채운다. `shortName` 은 브라우저 탭 제목과 구성도 그림 이름에 쓰는 짧은 이름(기본은 폴더 이름). 스토리가 없으면 빈 목록(`references/config.md`)
|
|
115
137
|
7. `<data>/req-spec.json`, `reqs.json`, `flow.json`, `arch.json` 을 쓴다. 구조만 쓰고 좌표는 쓰지 않는다(자동 배치). 스토리가 없으면 명세마다 `state` 와 `note`(`references/req-spec.md`, `reqs.md`, `flow.md`, `arch.md`)
|
|
116
|
-
8. `
|
|
117
|
-
|
|
118
|
-
|
|
138
|
+
8. ADR 단계: `<data>/adr.json` 을 쓴다(`references/adr.md`). 두 층(프로젝트의 검증, 흐름, 증거와 결정마다 최적화 로직, 확장 대응, 포기와 얻은 것). 근거 출처를 이 순서로 읽는다
|
|
139
|
+
1. 프로젝트의 `docs/adr/`(init-dir 규칙), `docs/evidence/`
|
|
140
|
+
2. `.omc/plans/*.md`(Codex `.omx/plans/`)의 ADR 절과 RALPLAN-DR
|
|
141
|
+
3. ultra-chain 실행 기록(`events.jsonl` 의 판정과 시험 기록)
|
|
142
|
+
4. 커밋 기록(`git log`)과 시험 파일
|
|
143
|
+
|
|
144
|
+
- 시험 결과는 실제로 돌린 명령의 출력만 참조한다. 출력 파일이 없으면 `cmd` 참조에 `output` 없이 두어 WARN 으로 드러낸다
|
|
145
|
+
- 근거가 없는 항목은 지어내지 않는다. 결정의 3칸과 흐름은 `{ "gap": "<사유>" }`, 증거 없는 모듈은 `status: "unverified"` 와 `why`, 증명 없는 기능은 `notImplemented`(구현됨, 검증됨 주장에 증거가 없으면 FAIL)
|
|
146
|
+
- `docs/adr/*.md` 가 있으면 결정마다 그 문서를 `sources` 로 가리킨다(가리키지 않는 문서는 WARN)
|
|
147
|
+
9. `check` 를 실행한다. FAIL 이 있으면 고쳐 7, 8 과 9 를 다시. 9 의 `check` 는 FAIL 0 이 될 때까지 최대 3회
|
|
148
|
+
10. FAIL 0 이 된 뒤 `WARN density ...` 가 남으면 읽기 예산 안에서 한 번 보충하고 `check` 를 한 번 더 실행한다
|
|
149
|
+
- 이 보충과 `check` 는 9 의 3회에 세지 않는다. 보충은 한 번만
|
|
119
150
|
- 보충 뒤 새 FAIL 이 나오면 그 보충 부분을 고치거나 되돌려 FAIL 0 으로 둔다
|
|
120
151
|
- 그래도 남은 `WARN density` 줄은 그대로 사용자에게 보고한다(실패 아님). 줄 끝의 대상 이름이 고칠 곳이다(`references/authoring.md`)
|
|
121
152
|
- 자동 배치 WARN(`이름표 덮음`, `이름표가 그림 밖`)은 배치 조언이다. 자동 배치 선은 상자와 영역 제목을 돌아가므로 `선이 상자 지남` 은 보통 없다. 연결을 하한 아래로 지우지 않는다(`references/arch.md` 의 "자동 배치 WARN 줄이기")
|
|
122
153
|
- `자기 연결` WARN 은 그 연결의 `from` 이나 `to` 를 실제 상대로 고친다
|
|
123
|
-
|
|
124
|
-
|
|
154
|
+
11. 정리 단계. 9 의 3회 뒤에도 FAIL 이 남으면
|
|
155
|
+
- 탭 파일(`req-spec.json`, `reqs.json`, `flow.json`, `arch.json`)은 FAIL 이 난 그 파일만 지워 "자료 없음" 으로 둔다
|
|
156
|
+
- `adr.json` 은 `check --adr-cleanup` 을 실행한다. 스키마 FAIL 이 남으면 지우지 않고 `adr.json.rejected-<YYYYMMDD-HHMMSS>` 로 옮겨 "자료 없음" 으로 두고(옮긴 경로를 보고), 참조 FAIL(`참조:` 가 붙은 줄)만 있으면 그 참조를 `{ "gap": "참조 확인 실패: <이유>" }` 로 바꾸고 다시 검사한다
|
|
157
|
+
- 정리 뒤 `증거 없음` FAIL(`정리: 증거가 남지 않은 주장 n건` 줄)이 남으면 스크립트는 옮기지 않는다. 증거를 지어내지 말고 그 모듈을 `status: "unverified"` 와 `why` 로, 그 기능을 `notImplemented` 로 옮긴 뒤 `check` 를 다시 돌린다(`references/adr.md` 의 "주장에는 증거")
|
|
158
|
+
- 남은 FAIL 과 정리 결과(`정리:` 줄)를 보고한다
|
|
159
|
+
12. 진척도 탭: 아는 단계와 작업을 적는다. 명령마다 `--note`(근거 커밋, 결과)를 쓴다. 문제점이 있으면 `--issue` 도 쓰고, 없으면 `--issue` 를 빼서 칸을 빈칸으로 둔다
|
|
125
160
|
|
|
126
161
|
| 프로젝트 | 쓸 명령 |
|
|
127
162
|
|---|---|
|
|
@@ -131,11 +166,12 @@ progress-mon skill body marker v1
|
|
|
131
166
|
|
|
132
167
|
- 스토리가 없는 프로젝트에서 `story` 를 쓰지 않는다. 설정에 없는 id 는 새 스토리 행이 되어 진척률이 켜진다. 단계도 같다(`stage` 는 새 단계 행)
|
|
133
168
|
- 지난 커밋은 커밋 시각과 해시로 기록한다. `git log -n <수> --format="%h %cI %s"` 의 `%cI` 를 `--at`, `%h` 를 `--commit` 에 넘긴다(예 `item --key c-1a2b3c4 --status done --text "<제목>" --at 2026-10-20T12:34:56+09:00 --commit 1a2b3c4`). `--at` 이 없으면 모든 항목이 기록한 지금 시각으로 보인다. `--commit` 이 없으면 commit Hash 칸이 빈다
|
|
134
|
-
|
|
135
|
-
|
|
169
|
+
13. `check` 를 다시 실행한다. 12 의 기록으로 `history 비고` 같은 밀도 줄이 바뀐다. 새 FAIL 이 있으면 고친다. 남은 `WARN` 은 보고한다
|
|
170
|
+
14. `start` 를 실행하고 URL 을 보고한다
|
|
136
171
|
|
|
137
172
|
- 자료가 없는 탭을 만들 수 없을 때(문서와 코드에 근거 없음)는 그 파일을 쓰지 않는다. 화면은 "자료 없음" 과 만드는 법을 보인다
|
|
138
|
-
- 사용자 문서는 덧붙이기만 한다. 표식 `<!-- progress-mon:rule -->` 이 이미 있으면 다시
|
|
173
|
+
- 사용자 문서는 덧붙이기만 한다. 표식 `<!-- progress-mon:rule -->` 이 이미 있으면 다시 덧붙이지 않는다
|
|
174
|
+
- 예외: 표식이 붙은 우리 줄(줄 앞머리가 `진척도 화면(progress-mon):` 인 규칙 줄과 `- [진척도 화면 갱신 규칙](progress-mon.md)` 인 색인 줄)이 지금 판과 다르면 그 줄만 제자리에서 바꾼다. 규칙 줄의 런타임은 줄에 `--runtime codex` 가 있으면 Codex 판. 줄 끝(CRLF, LF), BOM, 나머지 줄은 그대로이고, 첫 원본은 `<파일>.progress-mon.bak`(이미 있으면 덮지 않음). 앞머리가 다른 표식 줄은 손대지 않는다
|
|
139
175
|
|
|
140
176
|
## 갱신 규칙(init 뒤 세션)
|
|
141
177
|
|
|
@@ -151,6 +187,7 @@ progress-mon skill body marker v1
|
|
|
151
187
|
| 스토리 진행, 완료 | `story --id <id> --status doing`, 완료 커밋은 `story --id <id> --commit <hash>` |
|
|
152
188
|
| 그 밖 작업 | `item --key <k> --status doing\|done --text "<내용>" --note "<근거>" [--issue "<문제점>"]` |
|
|
153
189
|
| 단계, 스토리 행의 비고 | `note --key stage:<id> --note "<근거>"`, `note --key <스토리 id> --issue "<문제점>"` |
|
|
190
|
+
| 결정이 생기거나 스토리가 끝남 | `<data>/adr.json` 을 고치고(`references/adr.md`) `check`. 참조 FAIL 은 FAIL 줄의 json 경로를 고침 |
|
|
154
191
|
|
|
155
192
|
- Codex 는 모든 명령에 `--runtime codex` 를 붙인다. 세션을 닫아도 화면을 두려면 사용자 터미널의 `serve` 를 안내한다
|
|
156
193
|
- 스토리 상태 우선순위: 커밋(제목 판정 또는 `story --commit`) 있으면 완료, 없으면 `story --status`, 없으면 진행 중 에이전트가 있으면 진행 중, 그 밖 예정
|
|
@@ -1 +1 @@
|
|
|
1
|
-
형식 시험용 최소 자료(시험 픽스처와 형식 시험 보기 fixture-*). 화면 수준의 견본이 아님.
|
|
1
|
+
형식 시험용 최소 자료(시험 픽스처와 형식 시험 보기 fixture-*). 화면 수준의 견본이 아님. `adr.json` 의 참조는 시험이 임시 프로젝트에 만드는 파일(`src/app.mjs`, `test/app.test.mjs`, `docs/evidence/test-run.md`, `docs/adr/0001-data-file.md`)을 가리킴. `variants/legacy-init/` 은 옛 판 init 의 규칙 줄(`rules.json`)과 `state.json`(`<memory-dir>` 자리는 시험이 바꿈).
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"project": {
|
|
3
|
+
"verification": [
|
|
4
|
+
{ "id": "M-1", "module": "설정 읽기", "result": "시험 3개 통과", "evidence": [{ "kind": "test", "path": "test/app.test.mjs", "name": "설정 읽기" }, { "kind": "cmd", "cmd": "node --test test/", "output": "docs/evidence/test-run.md" }] },
|
|
5
|
+
{ "id": "M-2", "module": "화면 렌더", "result": "고정 자료로 HTML 확인", "evidence": [{ "kind": "file", "path": "src/app.mjs", "line": 3, "note": "render 함수" }] }
|
|
6
|
+
],
|
|
7
|
+
"flow": { "input": "config.json 과 자료 파일", "logic": "설정을 읽어 검사한 뒤 탭마다 HTML 로 렌더", "output": "로컬 서버 화면과 단일 HTML", "refs": [{ "kind": "file", "path": "src/app.mjs", "line": 1 }] },
|
|
8
|
+
"proof": {
|
|
9
|
+
"implemented": [{ "feature": "설정 읽기와 화면", "modules": ["M-1", "M-2"], "proofs": [{ "kind": "test", "path": "test/app.test.mjs", "name": "설정 읽기" }, { "kind": "commit", "hash": "1a2b3c4" }] }],
|
|
10
|
+
"notImplemented": [{ "feature": "알림", "why": "범위 밖으로 미룸" }]
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"decisions": [
|
|
14
|
+
{
|
|
15
|
+
"id": "ADR-1", "title": "자료는 JSON 파일", "status": "accepted", "date": "2026-10-20",
|
|
16
|
+
"context": "의존성 없이 자료를 저장해야 함",
|
|
17
|
+
"options": [{ "name": "JSON 파일", "pros": "내장 모듈만", "cons": "동시 쓰기 잠금 필요" }, { "name": "SQLite", "pros": "질의", "cons": "의존성 추가" }],
|
|
18
|
+
"decision": "JSON 파일", "why": "의존성 0 원칙과 자료 크기가 작음",
|
|
19
|
+
"optimization": { "process": "자료 크기 1 MB 미만에서 읽기 시간을 재어 파일 하나 읽기가 충분함을 확인", "modules": ["M-1"], "refs": [{ "kind": "cmd", "cmd": "node --test test/", "output": "docs/evidence/test-run.md" }] },
|
|
20
|
+
"scaling": { "argument": "탭마다 파일을 나눠 한 파일이 커지지 않음. 바뀐 파일만 다시 읽음", "limits": "파일 하나가 32 MB 를 넘으면 읽지 않음", "refs": [{ "kind": "file", "path": "src/app.mjs", "line": 2 }] },
|
|
21
|
+
"tradeoffs": { "gaveUp": [{ "what": "질의 기능", "why": "의존성 0" }], "gained": [{ "what": "설치 없는 실행", "purpose": "어느 PC 에서나 바로 실행" }] },
|
|
22
|
+
"sources": [{ "kind": "file", "path": "docs/adr/0001-data-file.md" }]
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "ADR-2", "title": "서버는 127.0.0.1 만", "status": "proposed",
|
|
26
|
+
"context": "화면을 로컬에서만 보이게 함",
|
|
27
|
+
"options": [{ "name": "127.0.0.1", "pros": "밖에서 못 봄", "cons": "다른 PC 에서 못 봄" }],
|
|
28
|
+
"rejected": "0.0.0.0 은 공개 노출 위험",
|
|
29
|
+
"decision": "127.0.0.1 바인드", "why": "보안 원칙",
|
|
30
|
+
"optimization": { "process": "바인드 주소별 접근 시험", "modules": ["M-2"], "refs": [{ "kind": "test", "path": "test/app.test.mjs", "name": "바인드" }] },
|
|
31
|
+
"scaling": { "gap": "규모 확장 근거를 아직 재지 않음" },
|
|
32
|
+
"tradeoffs": { "gaveUp": [{ "what": "원격 보기", "why": "노출 위험" }], "gained": [{ "what": "기본 안전", "purpose": "설정 실수로 밖에 열리지 않게" }] }
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
}
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
{ "id": "browser", "zone": "user", "label": "브라우저", "x": 40, "y": 90, "w": 160, "h": 64, "kind": "사람", "detail": "탭을 고름" },
|
|
14
14
|
{ "id": "cli", "zone": "user", "label": "CLI", "x": 40, "y": 250, "w": 160, "h": 64, "kind": "명령", "detail": "시작, 정지, 기록" },
|
|
15
15
|
{ "id": "server", "zone": "app", "label": "서버", "x": 340, "y": 90, "w": 130, "h": 64, "kind": "프로세스", "detail": "Host 검사" },
|
|
16
|
-
{ "id": "render", "zone": "app", "label": "렌더", "x": 530, "y": 90, "w": 130, "h": 64, "kind": "모듈", "detail": "
|
|
16
|
+
{ "id": "render", "zone": "app", "label": "렌더", "x": 530, "y": 90, "w": 130, "h": 64, "kind": "모듈", "detail": "다섯 탭 HTML" },
|
|
17
17
|
{ "id": "files", "zone": "store", "label": "자료 파일", "x": 800, "y": 90, "w": 160, "h": 64, "kind": "파일", "detail": "JSON 네 개" },
|
|
18
18
|
{ "id": "git", "zone": "store", "label": "git 저장소", "x": 800, "y": 250, "w": 160, "h": 64, "kind": "저장소", "detail": "커밋 제목" }
|
|
19
19
|
],
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"color": "#2e7d32",
|
|
30
30
|
"steps": [
|
|
31
31
|
{ "id": "e1", "label": "인자 검사", "detail": "출력 파일 경로 확인", "actor": "cli.mjs", "refs": ["cli.mjs:80"], "planned": false },
|
|
32
|
-
{ "id": "e2", "label": "
|
|
32
|
+
{ "id": "e2", "label": "다섯 탭 렌더", "detail": "다섯 탭을 한 파일에 담음", "actor": "render.mjs", "refs": ["render.mjs:200"], "planned": false },
|
|
33
33
|
{ "id": "e3", "label": "파일 쓰기", "detail": "임시 파일에 쓰고 이름 바꿈", "actor": "cli.mjs", "refs": [], "planned": true }
|
|
34
34
|
],
|
|
35
35
|
"branches": [],
|
|
@@ -39,6 +39,6 @@
|
|
|
39
39
|
"scenes": [
|
|
40
40
|
{ "n": 1, "sec": 2, "lane": "main", "focus": ["p1", "p2"], "caption": "인자와 설정을 읽음" },
|
|
41
41
|
{ "n": 2, "sec": 3, "lane": "main", "focus": ["p4", "p5"], "caption": "상태를 판정해 화면을 그림" },
|
|
42
|
-
{ "n": 3, "sec": 2, "lane": "export", "focus": ["e2"], "caption": "
|
|
42
|
+
{ "n": 3, "sec": 2, "lane": "export", "focus": ["e2"], "caption": "다섯 탭을 한 파일로" }
|
|
43
43
|
]
|
|
44
44
|
}
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
{ "id": "browser", "zone": "user", "label": "브라우저", "x": 40, "y": 90, "w": 160, "h": 64, "kind": "사람", "detail": "탭을 고름" },
|
|
21
21
|
{ "id": "cli", "zone": "user", "label": "CLI", "x": 40, "y": 250, "w": 160, "h": 64, "kind": "명령", "detail": "시작, 정지, 기록" },
|
|
22
22
|
{ "id": "server", "zone": "app", "label": "서버", "x": 340, "y": 90, "w": 130, "h": 64, "kind": "프로세스", "detail": "Host 검사" },
|
|
23
|
-
{ "id": "render", "zone": "app", "label": "렌더", "x": 530, "y": 90, "w": 130, "h": 64, "kind": "모듈", "detail": "
|
|
23
|
+
{ "id": "render", "zone": "app", "label": "렌더", "x": 530, "y": 90, "w": 130, "h": 64, "kind": "모듈", "detail": "다섯 탭 HTML" },
|
|
24
24
|
{ "id": "files", "zone": "store", "label": "자료 파일", "x": 800, "y": 90, "w": 160, "h": 64, "kind": "파일", "detail": "JSON 네 개" },
|
|
25
25
|
{ "id": "git", "zone": "store", "label": "git 저장소", "x": 800, "y": 250, "w": 160, "h": 64, "kind": "저장소", "detail": "커밋 제목" }
|
|
26
26
|
],
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"note": "옛 판(브랜치 bd4d7cd) init 이 쓴 규칙 줄. 규칙 줄 교체 시험이 이 줄로 메모리 파일을 만든다",
|
|
3
|
+
"claude": "진척도 화면(progress-mon): 단계는 stage, 스토리는 story, 그 밖 작업은 item 으로 갱신. .omc/progress-mon/state.json 의 skillDir 아래 scripts/progress-mon.mjs 를 node 로 직접 실행하고, 실패하면 progress-mon 스킬로 호출. 세션 시작 때 status, 꺼져 있으면 start. <!-- progress-mon:rule -->",
|
|
4
|
+
"codex": "진척도 화면(progress-mon): 모든 명령에 --runtime codex 를 붙임. 단계는 stage, 스토리는 story, 그 밖 작업은 item 으로 갱신. .omx/progress-mon/state.json 의 skillDir 아래 scripts/progress-mon.mjs 를 node 로 직접 실행하고, 실패하면 banker-progress-mon 스킬(플러그인 설치는 banker:progress-mon)로 호출. 세션 시작 때 status, 꺼져 있으면 start. start, stop, status 는 sandbox_permissions \"require_escalated\" 로 승인 요청. 세션을 닫아도 화면을 두려면 사용자 터미널에서 serve 실행을 안내. <!-- progress-mon:rule -->",
|
|
5
|
+
"index": "- [진척도 화면 갱신 규칙](progress-mon.md) - stage, story, item 으로 progress-mon 갱신 <!-- progress-mon:rule -->"
|
|
6
|
+
}
|