makdoong2-team 2.1.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -3
- package/agents/makdoong2-team-leader.md +42 -1
- package/agents/makdoong2-verifier.md +1 -1
- package/bin/cli.js +0 -1
- package/bin/cli.ts +0 -1
- package/dist/opencode-plugin.js +69 -28
- package/dist/poll-sub-session.d.ts +1 -0
- package/dist/poll-sub-session.js +101 -13
- package/dist/verifier-verdict.d.ts +62 -0
- package/dist/verifier-verdict.js +110 -0
- package/package.json +6 -6
- package/postinstall.mjs +0 -2
- package/references/pr-template.md +2 -1
- package/scripts/install-lib.mjs +0 -2
- package/scripts/install-lib.mts +0 -2
- package/scripts/model-policy.mjs +0 -2
- package/scripts/model-policy.mts +0 -2
- package/scripts/run-tests.mts +3 -4
- package/scripts/smoke-test.mts +0 -1
- package/scripts/test-postinstall.mts +0 -1
- package/stages/08-pr.md +27 -0
- package/scripts/run-tests.mjs +0 -155
- package/scripts/smoke-test.mjs +0 -178
- package/scripts/test-postinstall.mjs +0 -144
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// scripts/test-postinstall.mts — integration test for npm install -g postinstall hook
|
|
3
|
-
//
|
|
4
|
-
// 산출물은 같은 자리의 scripts/test-postinstall.mjs 다 (`npm run build:entry`).
|
|
5
|
-
//
|
|
6
|
-
// Simulates global install in isolated HOME directory:
|
|
7
|
-
// 1) npm pack → produces tarball
|
|
8
|
-
// 2) npm install -g <tarball> with isolated HOME
|
|
9
|
-
// 3) Verify deployment artifacts
|
|
10
|
-
// 4) Verify idempotency (re-install doesn't create duplicate backups)
|
|
11
|
-
// 5) Verify secrets.env preservation
|
|
12
|
-
import { mkdtempSync, rmSync, existsSync, writeFileSync, readFileSync, readdirSync } from "node:fs";
|
|
13
|
-
import { tmpdir, platform } from "node:os";
|
|
14
|
-
import { join, dirname } from "node:path";
|
|
15
|
-
import { fileURLToPath } from "node:url";
|
|
16
|
-
import { spawnSync } from "node:child_process";
|
|
17
|
-
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
18
|
-
const PKG_ROOT = join(HERE, "..");
|
|
19
|
-
function run(cmd, args, opts = {}) {
|
|
20
|
-
const result = spawnSync(cmd, args, { ...opts, stdio: "pipe", encoding: "utf8" });
|
|
21
|
-
if (result.error)
|
|
22
|
-
throw result.error;
|
|
23
|
-
return result;
|
|
24
|
-
}
|
|
25
|
-
function assert(cond, msg) {
|
|
26
|
-
if (!cond) {
|
|
27
|
-
console.error(`✗ FAIL: ${msg}`);
|
|
28
|
-
process.exit(1);
|
|
29
|
-
}
|
|
30
|
-
console.log(`✓ ${msg}`);
|
|
31
|
-
}
|
|
32
|
-
console.log("[test-postinstall] Starting npm install -g smoke test");
|
|
33
|
-
// 1) npm pack
|
|
34
|
-
console.log("\n[1/6] Running npm pack...");
|
|
35
|
-
const packResult = run("npm", ["pack"], { cwd: PKG_ROOT });
|
|
36
|
-
if (packResult.status !== 0) {
|
|
37
|
-
console.error("npm pack failed:", packResult.stderr);
|
|
38
|
-
process.exit(1);
|
|
39
|
-
}
|
|
40
|
-
const tarballLine = packResult.stdout.trim().split("\n").pop();
|
|
41
|
-
if (!tarballLine) {
|
|
42
|
-
console.error("npm pack produced no tarball name on stdout");
|
|
43
|
-
process.exit(1);
|
|
44
|
-
}
|
|
45
|
-
const tarball = join(PKG_ROOT, tarballLine);
|
|
46
|
-
assert(existsSync(tarball), `tarball created: ${tarball}`);
|
|
47
|
-
try {
|
|
48
|
-
// 2) Create isolated HOME
|
|
49
|
-
console.log("\n[2/6] Setting up isolated HOME...");
|
|
50
|
-
const tmpHome = mkdtempSync(join(tmpdir(), "mkd2-postinstall-"));
|
|
51
|
-
const npmPrefix = join(tmpHome, "npm");
|
|
52
|
-
const configDir = join(tmpHome, ".config", "opencode");
|
|
53
|
-
console.log(` tmpHome: ${tmpHome}`);
|
|
54
|
-
console.log(` npmPrefix: ${npmPrefix}`);
|
|
55
|
-
console.log(` configDir: ${configDir}`);
|
|
56
|
-
// 3) npm install -g with isolated env
|
|
57
|
-
console.log("\n[3/6] Running npm install -g (first install)...");
|
|
58
|
-
// 격리는 HOME 만으로 부족하다. resolveConfigDir() 은 XDG_CONFIG_HOME 을 HOME
|
|
59
|
-
// 보다 **먼저** 보고, seedOpencodeCache() 는 XDG_CACHE_HOME 을 본다. `npm test`
|
|
60
|
-
// 가 두 변수를 임시 디렉토리로 고정하므로, 상속하면 배포가 tmpHome 이 아니라
|
|
61
|
-
// 그 임시 디렉토리로 가서 "npm install -g 는 성공했는데 configDir 이 비어 있다"
|
|
62
|
-
// 가 된다 — 단독 실행(`npm run test:postinstall`)에서는 두 변수가 없어 통과하고
|
|
63
|
-
// 스위트 안에서만 실패하는 형태라 원인을 찾기 어렵다.
|
|
64
|
-
const installEnv = {
|
|
65
|
-
...process.env,
|
|
66
|
-
HOME: tmpHome,
|
|
67
|
-
XDG_CONFIG_HOME: join(tmpHome, ".config"),
|
|
68
|
-
XDG_CACHE_HOME: join(tmpHome, ".cache"),
|
|
69
|
-
npm_config_prefix: npmPrefix,
|
|
70
|
-
npm_config_global: "true",
|
|
71
|
-
CI: undefined,
|
|
72
|
-
CONTINUOUS_INTEGRATION: undefined,
|
|
73
|
-
};
|
|
74
|
-
const installResult = run("npm", ["install", "-g", tarball], { env: installEnv });
|
|
75
|
-
if (installResult.status !== 0) {
|
|
76
|
-
console.error("npm install -g failed:", installResult.stderr);
|
|
77
|
-
process.exit(1);
|
|
78
|
-
}
|
|
79
|
-
console.log(" npm install -g completed");
|
|
80
|
-
// 4) Verify deployment artifacts
|
|
81
|
-
console.log("\n[4/6] Verifying deployment artifacts...");
|
|
82
|
-
// Binary shim
|
|
83
|
-
const isWin = platform() === "win32";
|
|
84
|
-
const binName = isWin ? "makdoong2-team.cmd" : "makdoong2-team";
|
|
85
|
-
const binPath = join(npmPrefix, "bin", binName);
|
|
86
|
-
assert(existsSync(binPath), `binary shim exists: ${binPath}`);
|
|
87
|
-
// Agents in configDir
|
|
88
|
-
const agentPath = join(configDir, "agents", "makdoong2-team-leader.md");
|
|
89
|
-
assert(existsSync(agentPath), `agent deployed to configDir: ${agentPath}`);
|
|
90
|
-
// Skills in configDir
|
|
91
|
-
const skillPath = join(configDir, "skills", "jira-research", "SKILL.md");
|
|
92
|
-
assert(existsSync(skillPath), `skill deployed to configDir: ${skillPath}`);
|
|
93
|
-
// opencode.json plugin ref (relative path to npm module)
|
|
94
|
-
const ocPath = join(configDir, "opencode.json");
|
|
95
|
-
assert(existsSync(ocPath), `opencode.json created: ${ocPath}`);
|
|
96
|
-
const oc = JSON.parse(readFileSync(ocPath, "utf8"));
|
|
97
|
-
// 플러그인 ref 는 **npm 패키지 이름**이다. 예전에는 src/opencode-plugin.ts 를
|
|
98
|
-
// 가리키는 절대 경로였고 이 단언도 그 시절 형태로 남아 있었다 — 즉 이 테스트는
|
|
99
|
-
// 지금 돌리면 실패한다. STEPS 에 등록돼 있지 않아 아무도 몰랐다.
|
|
100
|
-
// (install-lib 의 pluginRef() / isLegacyPluginEntry() 가 계약의 출처다.)
|
|
101
|
-
const PKG_NAME = "makdoong2-team";
|
|
102
|
-
const matchesRef = (v) => typeof v === "string" && (v === PKG_NAME || v.startsWith(`${PKG_NAME}@`));
|
|
103
|
-
assert(Array.isArray(oc.plugin) && oc.plugin.some((p) => matchesRef(p) || (Array.isArray(p) && matchesRef(p[0]))), `opencode.json has plugin ref (${PKG_NAME})`);
|
|
104
|
-
assert(!JSON.stringify(oc.plugin).includes("opencode-plugin.ts"), "opencode.json has no legacy path-based plugin ref");
|
|
105
|
-
assert(oc.tools?.verify_stage === true, "opencode.json has tools");
|
|
106
|
-
// makdoong2-team doctor
|
|
107
|
-
console.log("\n[5/6] Running makdoong2-team doctor...");
|
|
108
|
-
const doctorResult = run(binPath, ["doctor"], { env: installEnv });
|
|
109
|
-
assert(doctorResult.status === 0, "makdoong2-team doctor exits 0");
|
|
110
|
-
// 5) Re-install (idempotency test)
|
|
111
|
-
console.log("\n[6/6] Re-installing (idempotency check)...");
|
|
112
|
-
const beforeOcBackups = readdirSync(configDir).filter((f) => f.startsWith("opencode.json.bak."));
|
|
113
|
-
const reinstallResult = run("npm", ["install", "-g", tarball], { env: installEnv });
|
|
114
|
-
assert(reinstallResult.status === 0, "re-install succeeds");
|
|
115
|
-
const afterOcBackups = readdirSync(configDir).filter((f) => f.startsWith("opencode.json.bak."));
|
|
116
|
-
assert(afterOcBackups.length === beforeOcBackups.length, `no new opencode.json backups on re-install (idempotent): ${beforeOcBackups.length} → ${afterOcBackups.length}`);
|
|
117
|
-
// 6) legacy secrets.env cleanup
|
|
118
|
-
//
|
|
119
|
-
// 종전 이 블록은 "secrets.env 가 보존된다" 를 단언했다. 현행 install() 은 정반대로
|
|
120
|
-
// 동작한다 — 자격증명은 makdoong2-team.json .secrets.* 하나로 옮겨졌고, 남아 있는
|
|
121
|
-
// 레거시 파일은 백업 후 **삭제**하는 것이 계약이다 (install-lib 의
|
|
122
|
-
// cleanupLegacySecretsEnv). 규약이 뒤집혔는데 테스트가 따라오지 않았다.
|
|
123
|
-
console.log("\n[Bonus] Testing legacy secrets.env cleanup...");
|
|
124
|
-
const secretsPath = join(configDir, "skills", "jira-research", "secrets.env");
|
|
125
|
-
writeFileSync(secretsPath, "JIRA_TOKEN=test123");
|
|
126
|
-
const reinstall2Result = run("npm", ["install", "-g", tarball], { env: installEnv });
|
|
127
|
-
assert(reinstall2Result.status === 0, "third install succeeds");
|
|
128
|
-
assert(!existsSync(secretsPath), "legacy secrets.env removed on re-install");
|
|
129
|
-
const backups = readdirSync(join(configDir, "skills", "jira-research"))
|
|
130
|
-
.filter((f) => f.startsWith("secrets.env.bak."));
|
|
131
|
-
assert(backups.length >= 1, "legacy secrets.env backed up before removal");
|
|
132
|
-
// 자격증명의 새 자리가 실제로 만들어져 있어야 한다.
|
|
133
|
-
const cfg = JSON.parse(readFileSync(join(configDir, "makdoong2-team.json"), "utf8"));
|
|
134
|
-
assert(cfg.secrets && typeof cfg.secrets === "object", "makdoong2-team.json has .secrets scaffolding");
|
|
135
|
-
assert("JIRA_API_TOKEN" in cfg.secrets, "makdoong2-team.json .secrets has JIRA_API_TOKEN key");
|
|
136
|
-
console.log("\n✅ [test-postinstall] All checks passed!");
|
|
137
|
-
// Cleanup
|
|
138
|
-
rmSync(tmpHome, { recursive: true, force: true });
|
|
139
|
-
}
|
|
140
|
-
finally {
|
|
141
|
-
// Cleanup tarball
|
|
142
|
-
if (existsSync(tarball))
|
|
143
|
-
rmSync(tarball);
|
|
144
|
-
}
|