@holmes-lab/holmes-kit 0.1.0 → 0.1.2
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/dist/.build-id
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
a81c431-msxg7g28
|
package/dist/holmes/cli/index.js
CHANGED
|
@@ -327,10 +327,12 @@ async function main(argv) {
|
|
|
327
327
|
process.stderr.write(`--specs-dir ${specsDir} must be a plain relative path inside the target (no '..', no '~', no quotes or shell metacharacters)\n\n${USAGE}`);
|
|
328
328
|
return 2;
|
|
329
329
|
}
|
|
330
|
-
// @implements A-SPEC-193
|
|
331
|
-
//
|
|
330
|
+
// @implements A-SPEC-193
|
|
331
|
+
// @implements A-SPEC-200 — World Top-Tier interactive TTY prompt & additive harness selection
|
|
332
332
|
const { AGENTS } = require('./agents');
|
|
333
|
+
const { promptAgentSelection } = require('./interactive-prompt');
|
|
333
334
|
let agents = [];
|
|
335
|
+
let isAdditive = false;
|
|
334
336
|
if (typeof flags.agent === 'string' && flags.agent !== '') {
|
|
335
337
|
const asked = flags.agent.split(',').map((s) => s.trim()).filter((s) => s !== '');
|
|
336
338
|
const wanted = asked.includes('all') ? [...AGENTS] : asked;
|
|
@@ -340,9 +342,20 @@ async function main(argv) {
|
|
|
340
342
|
return 2;
|
|
341
343
|
}
|
|
342
344
|
agents = wanted;
|
|
345
|
+
isAdditive = true;
|
|
346
|
+
}
|
|
347
|
+
else if (process.stdin.isTTY && process.stdout.isTTY && flags['dry-run'] !== true && flags.remove !== true) {
|
|
348
|
+
agents = await promptAgentSelection(AGENTS, ['claude', 'antigravity']);
|
|
349
|
+
isAdditive = true;
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
// Default to both primary AI harnesses (Claude Code & Antigravity) for seamless out-of-the-box UX
|
|
353
|
+
agents = ['claude', 'antigravity'];
|
|
354
|
+
isAdditive = true;
|
|
343
355
|
}
|
|
344
356
|
const opts = {
|
|
345
357
|
agents,
|
|
358
|
+
allowAdditive: isAdditive,
|
|
346
359
|
target: path.resolve(typeof flags.target === 'string' ? flags.target : process.cwd()),
|
|
347
360
|
packageRoot: packageRoot(),
|
|
348
361
|
mode,
|
package/dist/holmes/cli/init.js
CHANGED
|
@@ -237,7 +237,7 @@ function runInit(opts) {
|
|
|
237
237
|
// way to take governance off. A session must not be able to unwire the gate that governs it,
|
|
238
238
|
// whichever flag it reaches for. Wiring is asked of BOTH settings files.
|
|
239
239
|
const wiredAnywhere = ['local', 'project'].some((which) => alreadyWired(readJson((0, exports.settingsPathOf)(opts.target, which)).value));
|
|
240
|
-
if (!opts.remove && wiredAnywhere && !opts.force) {
|
|
240
|
+
if (!opts.remove && wiredAnywhere && !opts.force && !opts.allowAdditive) {
|
|
241
241
|
return { ok: false, exitCode: 2, changes, messages: [
|
|
242
242
|
'This target already has holmes-kit wiring. Re-run with --force to change it.',
|
|
243
243
|
] };
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.parseAgentList = parseAgentList;
|
|
37
|
+
exports.promptAgentSelection = promptAgentSelection;
|
|
38
|
+
// @implements A-SPEC-200
|
|
39
|
+
const readline = __importStar(require("node:readline"));
|
|
40
|
+
const agents_1 = require("./agents");
|
|
41
|
+
/**
|
|
42
|
+
* Parses user input or CLI flag string into normalized Agent array.
|
|
43
|
+
*/
|
|
44
|
+
function parseAgentList(input) {
|
|
45
|
+
const asked = input.split(',').map((s) => s.trim()).filter((s) => s !== '');
|
|
46
|
+
if (asked.includes('all')) {
|
|
47
|
+
return [...agents_1.AGENTS];
|
|
48
|
+
}
|
|
49
|
+
const known = agents_1.AGENTS;
|
|
50
|
+
return asked.filter((a) => known.includes(a));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Renders an interactive TTY checkbox selection menu using standard readline & ANSI codes.
|
|
54
|
+
*/
|
|
55
|
+
async function promptAgentSelection(availableAgents = agents_1.AGENTS, currentWired = ['claude']) {
|
|
56
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
57
|
+
return ['claude', 'antigravity']; // Fallback for non-TTY
|
|
58
|
+
}
|
|
59
|
+
return new Promise((resolve) => {
|
|
60
|
+
const selected = new Set(currentWired.length ? currentWired : ['claude', 'antigravity']);
|
|
61
|
+
let cursor = 0;
|
|
62
|
+
const items = [...availableAgents, 'all'];
|
|
63
|
+
const rl = readline.createInterface({
|
|
64
|
+
input: process.stdin,
|
|
65
|
+
output: process.stdout,
|
|
66
|
+
});
|
|
67
|
+
readline.emitKeypressEvents(process.stdin, rl);
|
|
68
|
+
if (process.stdin.isTTY) {
|
|
69
|
+
process.stdin.setRawMode(true);
|
|
70
|
+
}
|
|
71
|
+
const render = () => {
|
|
72
|
+
process.stdout.write('\x1B[2J\x1B[0;0H'); // Clear screen
|
|
73
|
+
process.stdout.write('\n 🔮 Holmes-Kit Governance Harness Setup\n\n');
|
|
74
|
+
process.stdout.write(' ? Select the AI Agent harnesses to wire into this project:\n\n');
|
|
75
|
+
items.forEach((item, idx) => {
|
|
76
|
+
const isCurrent = idx === cursor;
|
|
77
|
+
const prefix = isCurrent ? '❯ ' : ' ';
|
|
78
|
+
let label = '';
|
|
79
|
+
let isChecked = false;
|
|
80
|
+
if (item === 'all') {
|
|
81
|
+
isChecked = selected.size === availableAgents.length;
|
|
82
|
+
label = '🌟 Select All (Recommended)';
|
|
83
|
+
}
|
|
84
|
+
else if (item === 'claude') {
|
|
85
|
+
isChecked = selected.has('claude');
|
|
86
|
+
label = '🤖 Claude Code (.claude/settings.local.json, .mcp.json)';
|
|
87
|
+
}
|
|
88
|
+
else if (item === 'antigravity') {
|
|
89
|
+
isChecked = selected.has('antigravity');
|
|
90
|
+
label = '🚀 Antigravity CLI (AGY) (.agents/mcp_config.json, hooks.json, skills)';
|
|
91
|
+
}
|
|
92
|
+
else if (item === 'codex') {
|
|
93
|
+
isChecked = selected.has('codex');
|
|
94
|
+
label = '💻 Codex CLI (.codex/mcp_config.json)';
|
|
95
|
+
}
|
|
96
|
+
const box = isChecked ? '[X]' : '[ ]';
|
|
97
|
+
const line = `${prefix}${box} ${label}\n`;
|
|
98
|
+
process.stdout.write(isCurrent ? `\x1B[36m${line}\x1B[0m` : line);
|
|
99
|
+
});
|
|
100
|
+
process.stdout.write('\n Press <space> to toggle, <up/down> to navigate, <enter> to confirm\n');
|
|
101
|
+
};
|
|
102
|
+
const cleanup = () => {
|
|
103
|
+
if (process.stdin.isTTY) {
|
|
104
|
+
process.stdin.setRawMode(false);
|
|
105
|
+
}
|
|
106
|
+
rl.close();
|
|
107
|
+
};
|
|
108
|
+
const onKeypress = (_str, key) => {
|
|
109
|
+
if (key.name === 'up') {
|
|
110
|
+
cursor = (cursor - 1 + items.length) % items.length;
|
|
111
|
+
render();
|
|
112
|
+
}
|
|
113
|
+
else if (key.name === 'down') {
|
|
114
|
+
cursor = (cursor + 1) % items.length;
|
|
115
|
+
render();
|
|
116
|
+
}
|
|
117
|
+
else if (key.name === 'space') {
|
|
118
|
+
const target = items[cursor];
|
|
119
|
+
if (target === 'all') {
|
|
120
|
+
if (selected.size === availableAgents.length) {
|
|
121
|
+
selected.clear();
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
availableAgents.forEach((a) => selected.add(a));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
const agent = target;
|
|
129
|
+
if (selected.has(agent)) {
|
|
130
|
+
selected.delete(agent);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
selected.add(agent);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
render();
|
|
137
|
+
}
|
|
138
|
+
else if (key.name === 'return' || key.name === 'enter') {
|
|
139
|
+
cleanup();
|
|
140
|
+
process.stdout.write('\n');
|
|
141
|
+
resolve(Array.from(selected));
|
|
142
|
+
}
|
|
143
|
+
else if (key.ctrl && key.name === 'c') {
|
|
144
|
+
cleanup();
|
|
145
|
+
process.exit(0);
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
process.stdin.on('keypress', onKeypress);
|
|
149
|
+
render();
|
|
150
|
+
});
|
|
151
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@holmes-lab/holmes-kit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Holmes-Kit — deterministic Agentic Software Engineering (ASE) harness with causal traceability (spec chain + D-CPG + RTM + phase guardrail)",
|
|
5
5
|
"main": "dist/holmes/mcp/server.js",
|
|
6
6
|
"bin": {
|
|
@@ -72,5 +72,8 @@
|
|
|
72
72
|
"homepage": "https://github.com/snpark-io/holmes-kit#readme",
|
|
73
73
|
"bugs": {
|
|
74
74
|
"url": "https://github.com/snpark-io/holmes-kit/issues"
|
|
75
|
+
},
|
|
76
|
+
"publishConfig": {
|
|
77
|
+
"access": "public"
|
|
75
78
|
}
|
|
76
79
|
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: holmes-publish
|
|
3
|
+
description: >-
|
|
4
|
+
Use when asked to publish holmes-kit to NPM registry or run release workflow governed by
|
|
5
|
+
"HOLMES_APPROVAL", "hard-hitl", or "A-SPEC-133" with mandatory Human-In-The-Loop (HITL)
|
|
6
|
+
authorization by 박성남 그룹장님.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# holmes-publish — NPM 서버 배포 및 HITL 승인 절차
|
|
10
|
+
|
|
11
|
+
이 플레이북은 `@holmes-lab/holmes-kit` 패키지를 NPM Registry에 안전하게 배포하기 위한 **5단계 규정 절차**를 정의합니다.
|
|
12
|
+
배포 직전에는 반드시 **박성남 그룹장님**의 명시적 대역외 승인(HITL — Human-In-The-Loop)을 거쳐야만 실제 배포 명령어가 실행됩니다.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 배포 5단계 절차 (5-Step Release Workflow)
|
|
17
|
+
|
|
18
|
+
### 1단계: 사전 품질 감사 (Pre-flight Quality Audit)
|
|
19
|
+
배포를 시작하기 전 코드베이스의 무결성과 타입 안전성을 검증합니다:
|
|
20
|
+
1. `npm run typecheck` 실행 (타입 오류 0건 검증)
|
|
21
|
+
2. `npm test` 실행 (전체 145+ 테스트 수트 100% PASS 검증)
|
|
22
|
+
3. `npm run build` 실행 (`dist/` 최신 빌드 및 `.build-id` 생성)
|
|
23
|
+
|
|
24
|
+
> [!IMPORTANT]
|
|
25
|
+
> 단 하나의 테스트라도 실패하거나 타입 오류가 발생하면 즉시 배포 절차를 중단(Abort)합니다.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
### 2단계: 패키지 타르볼 시뮬레이션 및 검수 (Tarball Inspection)
|
|
30
|
+
NPM에 게시될 패키지 구성 요소를 사전 시뮬레이션하여 검수합니다:
|
|
31
|
+
- `npm publish --dry-run` 실행
|
|
32
|
+
- 출력된 타르볼 패키지 목록 검수:
|
|
33
|
+
- `package.json` (`@holmes-lab/holmes-kit` 명칭 및 버전 확인)
|
|
34
|
+
- `bin/` (`holmes-kit.js`, `holmes-mcp.js`, `holmes-hook-antigravity.js` 등)
|
|
35
|
+
- `dist/` (전체 컴파일 산출물)
|
|
36
|
+
- `playbooks/` (`adopt`, `author-slice`, `promote-slice`, `publish`)
|
|
37
|
+
- `CHANGELOG.md`, `README.md`
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
### 3단계: 필수 사람 승인 (Mandatory HITL Approval) — 보안 게이트
|
|
42
|
+
**가장 중요한 보안 지점입니다.** AI Agent는 독단적으로 `npm publish`를 실행할 수 없으며, 반드시 **박성남 그룹장님**께 배포 요약을 보고하고 명시적 승인을 받아야 합니다.
|
|
43
|
+
|
|
44
|
+
**[보고 양식]**:
|
|
45
|
+
- **배포 패키지**: `@holmes-lab/holmes-kit`
|
|
46
|
+
- **대상 버전**: `vX.Y.Z`
|
|
47
|
+
- **테스트 결과**: PASS (100%)
|
|
48
|
+
- **타르볼 파일 수 및 용량**: N개 / XXX kB
|
|
49
|
+
|
|
50
|
+
> [!CAUTION]
|
|
51
|
+
> **박성남 그룹장님**께서 승인을 내리지 않거나 거부 의사를 밝힌 경우, 즉시 배포 동작을 중단합니다.
|
|
52
|
+
> 승인은 채팅을 통한 명시적 확인 또는 `HOLMES_APPROVAL` 환경변수를 통해 전달됩니다.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
### 4단계: NPM 게시 실행 (NPM Publishing Execution)
|
|
57
|
+
승인이 완료된 경우에만 실제 게시 명령을 수행합니다:
|
|
58
|
+
```bash
|
|
59
|
+
npm publish --access public
|
|
60
|
+
```
|
|
61
|
+
- 2FA / Web OTP 인증이 필요한 경우 터미널 인증 URL을 사용자에게 제공하고 대기합니다.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
### 5단계: 배포 후 검증 및 Git 태깅 (Post-Release Verification)
|
|
66
|
+
게시가 완료된 후 등록 상태를 최종 검증합니다:
|
|
67
|
+
1. `npm view @holmes-lab/holmes-kit version` 실행하여 NPM Registry에 반영되었는지 확인
|
|
68
|
+
2. Git 커밋 및 태그 생성:
|
|
69
|
+
```bash
|
|
70
|
+
git add package.json
|
|
71
|
+
git commit -m "chore: release vX.Y.Z"
|
|
72
|
+
git tag -a vX.Y.Z -m "vX.Y.Z Release"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## 플레이북 트리거 조건
|
|
78
|
+
다음 요청 시 자동 트리거됩니다:
|
|
79
|
+
- "npm publish"
|
|
80
|
+
- "release to npm"
|
|
81
|
+
- "HOLMES_APPROVAL"
|
|
82
|
+
- "hard-hitl"
|
|
83
|
+
- "A-SPEC-133"
|
|
84
|
+
- "holmes-kit 배포해줘"
|