@vordsec/cli 0.1.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.
Files changed (75) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +33 -0
  3. package/dist/bin.d.ts +3 -0
  4. package/dist/bin.d.ts.map +1 -0
  5. package/dist/bin.js +86 -0
  6. package/dist/bin.js.map +1 -0
  7. package/dist/commands/explain.d.ts +20 -0
  8. package/dist/commands/explain.d.ts.map +1 -0
  9. package/dist/commands/explain.js +61 -0
  10. package/dist/commands/explain.js.map +1 -0
  11. package/dist/commands/guard.d.ts +41 -0
  12. package/dist/commands/guard.d.ts.map +1 -0
  13. package/dist/commands/guard.js +106 -0
  14. package/dist/commands/guard.js.map +1 -0
  15. package/dist/commands/hook.d.ts +66 -0
  16. package/dist/commands/hook.d.ts.map +1 -0
  17. package/dist/commands/hook.js +127 -0
  18. package/dist/commands/hook.js.map +1 -0
  19. package/dist/commands/ignore.d.ts +40 -0
  20. package/dist/commands/ignore.d.ts.map +1 -0
  21. package/dist/commands/ignore.js +159 -0
  22. package/dist/commands/ignore.js.map +1 -0
  23. package/dist/commands/init.d.ts +14 -0
  24. package/dist/commands/init.d.ts.map +1 -0
  25. package/dist/commands/init.js +75 -0
  26. package/dist/commands/init.js.map +1 -0
  27. package/dist/commands/install-gate.d.ts +19 -0
  28. package/dist/commands/install-gate.d.ts.map +1 -0
  29. package/dist/commands/install-gate.js +118 -0
  30. package/dist/commands/install-gate.js.map +1 -0
  31. package/dist/commands/mcp.d.ts +53 -0
  32. package/dist/commands/mcp.d.ts.map +1 -0
  33. package/dist/commands/mcp.js +155 -0
  34. package/dist/commands/mcp.js.map +1 -0
  35. package/dist/commands/scan.d.ts +21 -0
  36. package/dist/commands/scan.d.ts.map +1 -0
  37. package/dist/commands/scan.js +77 -0
  38. package/dist/commands/scan.js.map +1 -0
  39. package/dist/exit-codes.d.ts +38 -0
  40. package/dist/exit-codes.d.ts.map +1 -0
  41. package/dist/exit-codes.js +40 -0
  42. package/dist/exit-codes.js.map +1 -0
  43. package/dist/index.d.ts +33 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +20 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/report/gate.d.ts +41 -0
  48. package/dist/report/gate.d.ts.map +1 -0
  49. package/dist/report/gate.js +111 -0
  50. package/dist/report/gate.js.map +1 -0
  51. package/dist/report/scan.d.ts +34 -0
  52. package/dist/report/scan.d.ts.map +1 -0
  53. package/dist/report/scan.js +170 -0
  54. package/dist/report/scan.js.map +1 -0
  55. package/dist/shim/artifacts.d.ts +54 -0
  56. package/dist/shim/artifacts.d.ts.map +1 -0
  57. package/dist/shim/artifacts.js +114 -0
  58. package/dist/shim/artifacts.js.map +1 -0
  59. package/dist/shim/decide.d.ts +68 -0
  60. package/dist/shim/decide.d.ts.map +1 -0
  61. package/dist/shim/decide.js +62 -0
  62. package/dist/shim/decide.js.map +1 -0
  63. package/dist/shim/install.d.ts +76 -0
  64. package/dist/shim/install.d.ts.map +1 -0
  65. package/dist/shim/install.js +174 -0
  66. package/dist/shim/install.js.map +1 -0
  67. package/dist/shim/log.d.ts +52 -0
  68. package/dist/shim/log.d.ts.map +1 -0
  69. package/dist/shim/log.js +78 -0
  70. package/dist/shim/log.js.map +1 -0
  71. package/dist/shim/run.d.ts +37 -0
  72. package/dist/shim/run.d.ts.map +1 -0
  73. package/dist/shim/run.js +100 -0
  74. package/dist/shim/run.js.map +1 -0
  75. package/package.json +44 -0
@@ -0,0 +1,159 @@
1
+ /**
2
+ * `vord ignore` — 오탐을 사용자가 무시 처리한다 (Layer 1, 로컬 파일).
3
+ *
4
+ * ## 왜 파일인가
5
+ *
6
+ * 무시는 **레포에 남아야 한다.** 사람이 "이건 오탐이다" 라고 판단한 근거가 레포 밖에 있으면
7
+ * 다음 사람이 같은 판단을 처음부터 다시 한다. 그래서 커밋되는 텍스트 파일에 둔다.
8
+ *
9
+ * ## 규율 셋
10
+ *
11
+ * 1. **사유를 요구한다.** 사유 없는 무시는 6개월 뒤에 아무도 왜 껐는지 모른다
12
+ * 2. **조용히 지우지 않는다.** 무시된 항목은 리포트가 건수로 계속 센다
13
+ * 3. **룰을 통째로 끄는 것을 쉽게 만들지 않는다** — 경로를 반드시 적게 한다.
14
+ * `*` 를 쓸 수는 있지만 그건 사용자가 명시적으로 쓴 것이다
15
+ *
16
+ * 형식 (`.vordignore`):
17
+ * ```
18
+ * # 왜 껐는지 적는다
19
+ * SEC-003 src/widgets/zendesk.ts # 공개 전제 위젯 키
20
+ * ```
21
+ */
22
+ import fs from 'node:fs';
23
+ import path from 'node:path';
24
+ import { EXIT } from '../exit-codes.js';
25
+ export const IGNORE_FILE = '.vordignore';
26
+ /** 한 줄 파싱. 주석·빈 줄은 `undefined` */
27
+ export function parseIgnoreLine(raw, line) {
28
+ const body = raw.trim();
29
+ if (body === '' || body.startsWith('#'))
30
+ return undefined;
31
+ const hash = body.indexOf('#');
32
+ const head = (hash < 0 ? body : body.slice(0, hash)).trim();
33
+ const reason = hash < 0 ? undefined : body.slice(hash + 1).trim();
34
+ const m = /^(SEC-\d{3})\s+(\S+)$/.exec(head);
35
+ if (m === null)
36
+ return undefined;
37
+ return {
38
+ rule: m[1],
39
+ pattern: m[2],
40
+ ...(reason === undefined || reason === '' ? {} : { reason }),
41
+ line,
42
+ };
43
+ }
44
+ export function parseIgnoreFile(text) {
45
+ return text.split(/\r?\n/)
46
+ .map((l, i) => parseIgnoreLine(l, i + 1))
47
+ .filter((e) => e !== undefined);
48
+ }
49
+ export function readIgnoreFile(root) {
50
+ try {
51
+ return parseIgnoreFile(fs.readFileSync(path.join(root, IGNORE_FILE), 'utf8'));
52
+ }
53
+ catch {
54
+ return [];
55
+ }
56
+ }
57
+ /** `*` 는 한 조각, `**` 는 여러 조각. 나머지는 글자 그대로 */
58
+ export function matchesPattern(pattern, filePath) {
59
+ if (pattern === '*' || pattern === '**')
60
+ return true;
61
+ let re = '';
62
+ for (let i = 0; i < pattern.length; i++) {
63
+ const c = pattern[i];
64
+ if (c === '*') {
65
+ if (pattern[i + 1] === '*') {
66
+ re += '.*';
67
+ i++;
68
+ }
69
+ else
70
+ re += '[^/]*';
71
+ }
72
+ else if ('.+^${}()|[]\\?'.includes(c)) {
73
+ re += `\\${c}`;
74
+ }
75
+ else {
76
+ re += c;
77
+ }
78
+ }
79
+ return new RegExp(`^${re}$`).test(filePath);
80
+ }
81
+ /**
82
+ * 무시 규칙을 적용한다. **거른 것을 버리지 않고 돌려준다** — 리포터가 건수를 센다.
83
+ *
84
+ * ## 교차 항목도 같이 꺼진다 (ADR-024)
85
+ *
86
+ * 교차 항목은 **출처 룰의 파급**이고 `rule`·`location` 이 출처와 같다.
87
+ * 사용자가 그 출처를 오탐이라고 판단했으면 *"그래서 SEC-001 판정이 무효다"* 도 성립하지 않는다.
88
+ * 남겨 두면 **끈 적 없는 경고가 계속 뜨고**, 그건 무시 기능이 없는 것과 같다.
89
+ *
90
+ * 반대 방향은 자연히 막힌다 — 대상 룰(`SEC-001`)을 끄는 규칙은 교차 항목의 `rule`
91
+ * (출처인 `SEC-003`)과 안 맞아서 걸리지 않는다.
92
+ */
93
+ export function applyIgnores(findings, entries) {
94
+ const kept = [];
95
+ const suppressed = [];
96
+ for (const f of findings) {
97
+ const hit = entries.some((e) => e.rule === f.rule && matchesPattern(e.pattern, f.location.path));
98
+ (hit ? suppressed : kept).push(f);
99
+ }
100
+ return { kept, suppressed };
101
+ }
102
+ const USAGE = [
103
+ 'vord ignore — 오탐을 무시 처리한다 (로컬 `.vordignore`)',
104
+ '',
105
+ ' vord ignore add SEC-003 <경로> --reason "<왜>" 무시 규칙을 추가한다',
106
+ ' vord ignore list 지금 걸린 규칙을 본다',
107
+ '',
108
+ '경로에는 `*`(한 조각) 과 `**`(여러 조각) 을 쓸 수 있다.',
109
+ '**사유는 필수다** — 사유 없는 무시는 6개월 뒤에 아무도 왜 껐는지 모른다.',
110
+ ];
111
+ export function runIgnore(argv, cwd) {
112
+ const [sub, ...rest] = argv;
113
+ if (sub === 'list') {
114
+ const entries = readIgnoreFile(cwd);
115
+ if (entries.length === 0)
116
+ return { lines: [`무시 규칙이 없다 (${IGNORE_FILE} 없음)`], exitCode: EXIT.OK };
117
+ return {
118
+ lines: [
119
+ `${IGNORE_FILE} — ${entries.length}건`,
120
+ ...entries.map((e) => ` ${e.rule} ${e.pattern}${e.reason === undefined ? ' (사유 없음)' : ` # ${e.reason}`}`),
121
+ ],
122
+ exitCode: EXIT.OK,
123
+ };
124
+ }
125
+ if (sub === 'add') {
126
+ const reasonAt = rest.findIndex((a) => a === '--reason');
127
+ const positional = (reasonAt < 0 ? rest : rest.slice(0, reasonAt)).filter((a) => !a.startsWith('-'));
128
+ const reason = reasonAt < 0 ? undefined : rest[reasonAt + 1];
129
+ const [rule, target] = positional;
130
+ if (rule === undefined || !/^SEC-\d{3}$/.test(rule) || target === undefined) {
131
+ return { lines: ['룰 ID 와 경로가 필요하다 — `vord ignore add SEC-003 src/x.ts --reason "..."`', ...USAGE], exitCode: EXIT.USAGE };
132
+ }
133
+ if (reason === undefined || reason.trim() === '') {
134
+ return {
135
+ lines: [
136
+ '`--reason` 이 필요하다. **사유 없는 무시는 다음 사람에게 아무것도 남기지 않는다.**',
137
+ ' 예: vord ignore add SEC-003 src/widgets/zendesk.ts --reason "공개 전제 위젯 키"',
138
+ ],
139
+ exitCode: EXIT.USAGE,
140
+ };
141
+ }
142
+ const file = path.join(cwd, IGNORE_FILE);
143
+ const existing = readIgnoreFile(cwd);
144
+ if (existing.some((e) => e.rule === rule && e.pattern === target)) {
145
+ return { lines: [`이미 있다 — ${rule} ${target}`], exitCode: EXIT.OK };
146
+ }
147
+ const header = fs.existsSync(file) ? '' : `# vord 무시 규칙. 사유를 꼭 적는다.\n`;
148
+ fs.appendFileSync(file, `${header}${rule} ${target} # ${reason.trim()}\n`, 'utf8');
149
+ return {
150
+ lines: [
151
+ `${IGNORE_FILE} 에 추가했다 — ${rule} ${target}`,
152
+ ' 이 파일은 **커밋한다.** 무시한 근거가 레포에 남아야 다음 사람이 다시 판단하지 않는다.',
153
+ ],
154
+ exitCode: EXIT.OK,
155
+ };
156
+ }
157
+ return { lines: USAGE, exitCode: sub === undefined ? EXIT.OK : EXIT.USAGE };
158
+ }
159
+ //# sourceMappingURL=ignore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ignore.js","sourceRoot":"","sources":["../../src/commands/ignore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export declare const CACHE_FILENAME = "registry-cache.json";
2
+ export declare function defaultCacheFile(home?: string): string;
3
+ export interface InitOptions {
4
+ readonly cwd?: string;
5
+ readonly cacheFile?: string;
6
+ readonly dryRun?: boolean;
7
+ }
8
+ export interface InitResult {
9
+ readonly lines: readonly string[];
10
+ readonly exitCode: number;
11
+ }
12
+ export declare function parseInitArgs(argv: readonly string[]): InitOptions;
13
+ export declare function runInit(opts?: InitOptions): Promise<InitResult>;
14
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,cAAc,wBAAwB,CAAC;AAEpD,wBAAgB,gBAAgB,CAAC,IAAI,GAAE,MAAqB,GAAG,MAAM,CAEpE;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,WAAW,CAKlE;AAED,wBAAsB,OAAO,CAAC,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,CAyDzE"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * `vord init` — 캐시 예열 (ADR-017 부수 결정).
3
+ *
4
+ * 프로젝트의 기존 의존성을 미리 조회해 캐시를 채운다.
5
+ * **fail-closed 의 마찰을 낮추는 가장 싼 수단이다** — 캐시가 차 있으면 네트워크를 안 타고,
6
+ * 네트워크를 안 타면 확인 불가가 안 뜬다.
7
+ */
8
+ import os from 'node:os';
9
+ import path from 'node:path';
10
+ import { buildWorkspaceContext, collectDeclaredDeps, fileCache, warmCache, } from '@vordsec/core';
11
+ export const CACHE_FILENAME = 'registry-cache.json';
12
+ export function defaultCacheFile(home = os.homedir()) {
13
+ return path.join(home, '.vord', 'cache', CACHE_FILENAME);
14
+ }
15
+ export function parseInitArgs(argv) {
16
+ const i = argv.indexOf('--cache-file');
17
+ const cacheFile = i >= 0 ? argv[i + 1] : undefined;
18
+ const dryRun = argv.includes('--dry-run');
19
+ return cacheFile === undefined ? { dryRun } : { cacheFile, dryRun };
20
+ }
21
+ export async function runInit(opts = {}) {
22
+ const cwd = opts.cwd ?? process.cwd();
23
+ const ws = buildWorkspaceContext(cwd);
24
+ const deps = collectDeclaredDeps(ws.root);
25
+ if (deps.length === 0) {
26
+ return {
27
+ lines: [
28
+ `프로젝트 루트: ${ws.root}`,
29
+ '선언된 의존성을 찾지 못했다 — 예열할 것이 없다.',
30
+ ],
31
+ exitCode: 0,
32
+ };
33
+ }
34
+ if (opts.dryRun === true) {
35
+ return {
36
+ lines: [
37
+ `프로젝트 루트: ${ws.root}`,
38
+ `선언된 의존성 ${deps.length}개를 찾았다. \`--dry-run\` 이라 조회하지 않는다.`,
39
+ ],
40
+ exitCode: 0,
41
+ };
42
+ }
43
+ const cacheFile = opts.cacheFile ?? defaultCacheFile();
44
+ const cache = fileCache(cacheFile);
45
+ const r = await warmCache(deps, { cache, workspace: ws });
46
+ return {
47
+ lines: [
48
+ `프로젝트 루트: ${ws.root}`,
49
+ `캐시: ${cacheFile}`,
50
+ '',
51
+ `선언된 의존성 ${r.total}개`,
52
+ ` 새로 조회 ${r.warmed} · 이미 캐시됨 ${r.alreadyCached}`,
53
+ ` 로컬 해결로 건너뜀 ${r.skippedLocal} (워크스페이스 패키지 — 조회 대상이 아니다)`,
54
+ ...(r.notFound.length > 0
55
+ ? [
56
+ '',
57
+ `⚠️ 레지스트리에 없는 것 ${r.notFound.length}개:`,
58
+ ...r.notFound.map((n) => ` ${n}`),
59
+ ' 워크스페이스 선언을 못 읽었거나, 실제로 없는 이름이다.',
60
+ ] : []),
61
+ ...(r.failed.length > 0
62
+ ? [
63
+ '',
64
+ `조회하지 못한 것 ${r.failed.length}개 — **이것들이 나중에 확인 불가로 뜬다.**`,
65
+ ...r.failed.slice(0, 20).map((n) => ` ${n}`),
66
+ ...(r.failed.length > 20 ? [` … 외 ${r.failed.length - 20}개`] : []),
67
+ ' 네트워크를 확인한 뒤 다시 실행하면 채워진다.',
68
+ ] : []),
69
+ '',
70
+ '캐시가 차 있으면 오프라인에서도 게이트가 판정할 수 있다 (ADR-017 장치 1).',
71
+ ],
72
+ exitCode: 0,
73
+ };
74
+ }
75
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { type Env } from '../shim/install.js';
2
+ export type InstallGateAction = 'install' | 'remove' | 'verify' | 'status' | 'help';
3
+ export interface InstallGateOptions {
4
+ readonly action: InstallGateAction;
5
+ readonly shimDir?: string;
6
+ /** `--shell` 이 없으면 아무것도 하지 않는다 */
7
+ readonly shell: boolean;
8
+ }
9
+ export declare function parseArgs(argv: readonly string[]): InstallGateOptions;
10
+ export interface CommandResult {
11
+ readonly lines: readonly string[];
12
+ readonly exitCode: number;
13
+ }
14
+ export declare function runInstallGate(argv: readonly string[], deps: {
15
+ readonly env: Env;
16
+ readonly cliRunPath: string;
17
+ readonly home?: string;
18
+ }): CommandResult;
19
+ //# sourceMappingURL=install-gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-gate.d.ts","sourceRoot":"","sources":["../../src/commands/install-gate.ts"],"names":[],"mappings":"AAQA,OAAO,EAA2C,KAAK,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAIvF,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEpF,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,kCAAkC;IAClC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,kBAAkB,CAarE;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAeD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,IAAI,EAAE;IAAE,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/E,aAAa,CAsFf"}
@@ -0,0 +1,118 @@
1
+ /**
2
+ * `vord install-gate --shell` — shim 설치 · 제거 · 확인 (ADR-026 결정 3).
3
+ *
4
+ * **opt-in 이다.** 사용자가 명시적으로 부를 때만 무언가를 만진다.
5
+ * 출력을 반환값으로 낸다 — 표준출력에 직접 쓰지 않아야 테스트가 붙는다.
6
+ */
7
+ import os from 'node:os';
8
+ import path from 'node:path';
9
+ import { defaultShimDir, install, remove, verify } from '../shim/install.js';
10
+ import { fileLogger, summarize } from '../shim/log.js';
11
+ import { CRASH_PASSES_THROUGH_PROVISIONAL } from '../shim/decide.js';
12
+ export function parseArgs(argv) {
13
+ const shell = argv.includes('--shell');
14
+ const dirIndex = argv.indexOf('--dir');
15
+ const shimDir = dirIndex >= 0 ? argv[dirIndex + 1] : undefined;
16
+ const action = argv.includes('--help') || argv.includes('-h') ? 'help'
17
+ : argv.includes('--remove') ? 'remove'
18
+ : argv.includes('--verify') ? 'verify'
19
+ : argv.includes('--status') ? 'status'
20
+ : shell ? 'install'
21
+ : 'help';
22
+ return shimDir === undefined ? { action, shell } : { action, shell, shimDir };
23
+ }
24
+ const HELP = [
25
+ 'vord install-gate --shell — 설치 경계 shim (opt-in)',
26
+ '',
27
+ ' --shell shim 을 설치한다 (npm · pnpm × 확장자 3종 = 6개)',
28
+ ' --shell --verify 설치 상태와 PATH 순서를 확인한다',
29
+ ' --shell --remove 우리가 만든 파일만 지운다',
30
+ ' --shell --status 기록을 요약한다 (차단 · 확인 불가 · 크래시)',
31
+ ' --dir <경로> shim 디렉터리를 지정한다 (기본 ~/.vord/shim)',
32
+ '',
33
+ 'shim 은 에이전트가 spawn 하는 설치를 잡는 유일한 방법이다.',
34
+ 'alias 와 셸 함수는 자식 프로세스에 상속되지 않아 걸리지 않는다 (ADR-026).',
35
+ ];
36
+ export function runInstallGate(argv, deps) {
37
+ const opts = parseArgs(argv);
38
+ if (opts.action === 'help' || !opts.shell) {
39
+ return { lines: HELP, exitCode: opts.shell ? 0 : 1 };
40
+ }
41
+ const home = deps.home ?? os.homedir();
42
+ const shimDir = opts.shimDir ?? defaultShimDir(home);
43
+ if (opts.action === 'remove') {
44
+ const r = remove(shimDir);
45
+ return {
46
+ lines: r.removed.length === 0
47
+ ? [`지울 것이 없다 (${shimDir}).`]
48
+ : [
49
+ `shim ${r.removed.length}개를 지웠다 — ${shimDir}`,
50
+ ...(r.remaining.length > 0
51
+ ? [`남은 파일 ${r.remaining.length}개는 우리가 만든 것이 아니라 두었다.`] : []),
52
+ 'PATH 에 넣어 둔 항목은 셸 설정에서 직접 빼야 한다.',
53
+ ],
54
+ exitCode: 0,
55
+ };
56
+ }
57
+ if (opts.action === 'status') {
58
+ const s = summarize(fileLogger(path.dirname(shimDir)).read());
59
+ const crashLines = Object.entries(s.crashDetails)
60
+ .sort((a, b) => b[1] - a[1])
61
+ .map(([k, n]) => ` ${n}회 ${k}`);
62
+ return {
63
+ lines: [
64
+ `기록 ${s.total}건`,
65
+ ` 통과 ${s.byOutcome.passed} · 대상 아님 ${s.byOutcome['not-applicable']}`,
66
+ ` 차단 ${s.byOutcome.blocked} · 확인 불가 ${s.byOutcome.unverifiable}`,
67
+ ` 게이트 크래시 ${s.byOutcome['gate-crash']} · shim 미가동 ${s.byOutcome['shim-unavailable']}`,
68
+ ...(crashLines.length > 0 ? [' 크래시 사유:', ...crashLines] : []),
69
+ '',
70
+ '차단과 확인 불가는 **다른 것이다** — 확인 불가는 판단하지 못한 것이지 위험한 것이 아니다.',
71
+ `크래시 시 현재 동작: ${CRASH_PASSES_THROUGH_PROVISIONAL ? '통과' : '차단'} (잠정 — 이 기록으로 정한다).`,
72
+ ],
73
+ exitCode: 0,
74
+ };
75
+ }
76
+ if (opts.action === 'verify') {
77
+ const v = verify(deps.env, shimDir);
78
+ return {
79
+ lines: [
80
+ `shim 디렉터리: ${v.shimDir}`,
81
+ ` 설치됨 ${v.installed.length}/6${v.missing.length > 0 ? ` — 없음: ${v.missing.join(', ')}` : ''}`,
82
+ ` 런타임: ${v.runtimePresent ? '있음' : '없음'}`,
83
+ ` PATH 앞쪽: ${v.onPath ? '예' : '아니오'}`,
84
+ '',
85
+ ...(v.healthy
86
+ ? ['정상이다.']
87
+ : [
88
+ '**게이트가 온전하지 않다.**',
89
+ ...(v.missing.length > 0
90
+ ? [` 없는 파일의 실행 경로는 조용히 통과한다 — 특히 \`.cmd\` 가 없으면
91
+ Node 의 execSync 가 그대로 지나간다.`] : []),
92
+ ...(v.onPath ? [] : [' PATH 앞쪽에 없으면 아무것도 걸리지 않는다.']),
93
+ ]),
94
+ ],
95
+ exitCode: v.healthy ? 0 : 1,
96
+ };
97
+ }
98
+ // ── 설치
99
+ const r = install(deps.env, { shimDir, cliRunPath: deps.cliRunPath });
100
+ return {
101
+ lines: [
102
+ `shim ${r.written.length}개를 설치했다 — ${r.shimDir}`,
103
+ ...(r.written.length > 0 ? [` ${r.written.join(', ')}`] : []),
104
+ ...(r.skipped.length > 0
105
+ ? [` 건너뜀(원본 없음): ${r.skipped.join(', ')}`] : []),
106
+ ...(r.silentGaps.length > 0
107
+ ? [
108
+ '',
109
+ `⚠️ **조용히 통과할 경로가 있다**: ${r.silentGaps.join(', ')}`,
110
+ ' 그 매니저는 설치돼 있는데 해당 확장자의 원본을 못 찾았다.',
111
+ ' 그 경로로 실행되는 설치는 게이트를 지나간다.',
112
+ ] : []),
113
+ ...(r.instructions.length > 0 ? ['', ...r.instructions] : ['', 'PATH 설정도 이미 돼 있다.']),
114
+ ],
115
+ exitCode: 0,
116
+ };
117
+ }
118
+ //# sourceMappingURL=install-gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-gate.js","sourceRoot":"","sources":["../../src/commands/install-gate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * `vord mcp` — MCP 서버 (stdio). ADR-012 유통 3경로의 셋째.
3
+ *
4
+ * **에이전트가 스스로 부르는 경로다.** 훅(`PreToolUse`)이 설치를 가로채는 자리라면,
5
+ * 이것은 에이전트가 설치 **전에 물어보는** 자리다. 판정은 같은 `guardCommand` 다.
6
+ *
7
+ * ## 지금은 Tier 0 만 노출한다
8
+ *
9
+ * ADR-012 는 MCP 의 역할을 "Tier 1 스캔 결과를 에이전트에게 되먹인다" 로 적었는데
10
+ * **Tier 1 이 아직 없다.** 그래서 지금 노출하는 것은 `guard` 하나뿐이고,
11
+ * Tier 1 이 생기면 도구가 늘어난다. 없는 것을 있는 것처럼 광고하지 않는다.
12
+ *
13
+ * ## 의존성 0 을 유지한다
14
+ *
15
+ * MCP SDK 를 넣지 않고 stdio JSON-RPC 를 직접 쓴다. 쓰는 것은 세 메서드뿐이다 —
16
+ * `initialize` · `tools/list` · `tools/call`. 프레임워크가 무게만 되는 자리다
17
+ * (masterplan §CLI 프레임워크 결정과 같은 논리).
18
+ *
19
+ * **네트워크를 쓰지 않는다.** stdin/stdout 만 쓴다 — HC-1 정적 층이 이 파일도 훑는다.
20
+ */
21
+ import { type GuardOptions } from '@vordsec/core';
22
+ /** 우리가 구현한 MCP 스펙 버전 */
23
+ export declare const MCP_PROTOCOL_VERSION = "2024-11-05";
24
+ export declare const TOOL_NAME = "vord_guard";
25
+ interface JsonRpcRequest {
26
+ readonly jsonrpc?: string;
27
+ readonly id?: string | number | null;
28
+ readonly method?: string;
29
+ readonly params?: Record<string, unknown>;
30
+ }
31
+ /**
32
+ * 요청 하나를 처리한다. **순수하게 유지한다** — stdin/stdout 은 호출부가 다룬다.
33
+ *
34
+ * 알림(`id` 가 없는 요청)에는 응답하지 않는다. 응답하면 규약 위반이다.
35
+ */
36
+ export declare function handleMcpRequest(req: JsonRpcRequest, deps?: {
37
+ readonly guardOptions?: GuardOptions;
38
+ }): Promise<string | undefined>;
39
+ /** 한 줄(JSON-RPC 메시지 하나)을 처리한다 */
40
+ export declare function handleMcpLine(line: string, deps?: {
41
+ readonly guardOptions?: GuardOptions;
42
+ }): Promise<string | undefined>;
43
+ /**
44
+ * stdio 루프. **줄 단위다** — MCP stdio 전송은 줄바꿈으로 구분된 JSON 이다.
45
+ *
46
+ * 응답은 **받은 순서대로** 낸다. 동시에 처리하면 순서가 섞이고,
47
+ * 게이트는 설치마다 한 번씩 불리는 것이라 병렬성이 이득이 되지 않는다.
48
+ */
49
+ export declare function runMcpServer(stdin: NodeJS.ReadableStream, write: (line: string) => void, deps?: {
50
+ readonly guardOptions?: GuardOptions;
51
+ }): Promise<void>;
52
+ export {};
53
+ //# sourceMappingURL=mcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAGhE,wBAAwB;AACxB,eAAO,MAAM,oBAAoB,eAAe,CAAC;AAEjD,eAAO,MAAM,SAAS,eAAe,CAAC;AAwBtC,UAAU,cAAc;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC3C;AAiBD;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,cAAc,EACnB,IAAI,GAAE;IAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,YAAY,CAAA;CAAO,GAClD,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA+C7B;AAED,iCAAiC;AACjC,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE;IAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,YAAY,CAAA;CAAO,GAClD,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAkB7B;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,MAAM,CAAC,cAAc,EAC5B,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,EAC7B,IAAI,GAAE;IAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,YAAY,CAAA;CAAO,GAClD,OAAO,CAAC,IAAI,CAAC,CAgBf"}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * `vord mcp` — MCP 서버 (stdio). ADR-012 유통 3경로의 셋째.
3
+ *
4
+ * **에이전트가 스스로 부르는 경로다.** 훅(`PreToolUse`)이 설치를 가로채는 자리라면,
5
+ * 이것은 에이전트가 설치 **전에 물어보는** 자리다. 판정은 같은 `guardCommand` 다.
6
+ *
7
+ * ## 지금은 Tier 0 만 노출한다
8
+ *
9
+ * ADR-012 는 MCP 의 역할을 "Tier 1 스캔 결과를 에이전트에게 되먹인다" 로 적었는데
10
+ * **Tier 1 이 아직 없다.** 그래서 지금 노출하는 것은 `guard` 하나뿐이고,
11
+ * Tier 1 이 생기면 도구가 늘어난다. 없는 것을 있는 것처럼 광고하지 않는다.
12
+ *
13
+ * ## 의존성 0 을 유지한다
14
+ *
15
+ * MCP SDK 를 넣지 않고 stdio JSON-RPC 를 직접 쓴다. 쓰는 것은 세 메서드뿐이다 —
16
+ * `initialize` · `tools/list` · `tools/call`. 프레임워크가 무게만 되는 자리다
17
+ * (masterplan §CLI 프레임워크 결정과 같은 논리).
18
+ *
19
+ * **네트워크를 쓰지 않는다.** stdin/stdout 만 쓴다 — HC-1 정적 층이 이 파일도 훑는다.
20
+ */
21
+ import { guardCommand } from '@vordsec/core';
22
+ import { renderJson } from '../report/gate.js';
23
+ /** 우리가 구현한 MCP 스펙 버전 */
24
+ export const MCP_PROTOCOL_VERSION = '2024-11-05';
25
+ export const TOOL_NAME = 'vord_guard';
26
+ const TOOL_DEF = {
27
+ name: TOOL_NAME,
28
+ description: '패키지 설치 명령이 안전한지 판정한다. **설치하기 전에 부른다.** '
29
+ + '존재하지 않는 패키지(슬롭스쿼팅) · 신생 저신뢰 패키지 · 설치 훅의 내용을 본다. '
30
+ + '판정만 하고 설치를 실행하지는 않는다.',
31
+ inputSchema: {
32
+ type: 'object',
33
+ properties: {
34
+ command: {
35
+ type: 'string',
36
+ description: '검사할 설치 명령 전체. 예: `npm install lodash` · `pip install requests`',
37
+ },
38
+ cwd: {
39
+ type: 'string',
40
+ description: '프로젝트 루트를 찾을 시작 경로. 생략하면 서버의 작업 디렉터리',
41
+ },
42
+ },
43
+ required: ['command'],
44
+ },
45
+ };
46
+ const ERR = { PARSE: -32700, INVALID: -32600, NO_METHOD: -32601, INTERNAL: -32603 };
47
+ function ok(id, result) {
48
+ return JSON.stringify({ jsonrpc: '2.0', id, result });
49
+ }
50
+ function fail(id, code, message) {
51
+ return JSON.stringify({ jsonrpc: '2.0', id, error: { code, message } });
52
+ }
53
+ /** 텍스트 한 덩이를 내는 도구 응답 */
54
+ function textResult(text, isError = false) {
55
+ return { content: [{ type: 'text', text }], isError };
56
+ }
57
+ /**
58
+ * 요청 하나를 처리한다. **순수하게 유지한다** — stdin/stdout 은 호출부가 다룬다.
59
+ *
60
+ * 알림(`id` 가 없는 요청)에는 응답하지 않는다. 응답하면 규약 위반이다.
61
+ */
62
+ export async function handleMcpRequest(req, deps = {}) {
63
+ const id = req.id ?? null;
64
+ const isNotification = req.id === undefined;
65
+ switch (req.method) {
66
+ case 'initialize':
67
+ return ok(id, {
68
+ protocolVersion: MCP_PROTOCOL_VERSION,
69
+ capabilities: { tools: {} },
70
+ serverInfo: { name: 'vord', version: '0.0.0' },
71
+ });
72
+ case 'notifications/initialized':
73
+ return undefined;
74
+ case 'tools/list':
75
+ return ok(id, { tools: [TOOL_DEF] });
76
+ case 'tools/call': {
77
+ const params = req.params ?? {};
78
+ if (params['name'] !== TOOL_NAME) {
79
+ return fail(id, ERR.NO_METHOD, `모르는 도구: ${String(params['name'])}`);
80
+ }
81
+ const args = (params['arguments'] ?? {});
82
+ const command = args['command'];
83
+ if (typeof command !== 'string' || command.trim() === '') {
84
+ // **도구 오류는 프로토콜 오류가 아니다.** 에이전트가 읽고 고칠 수 있게 낸다
85
+ return ok(id, textResult('`command` 가 필요하다. 예: `npm install lodash`', true));
86
+ }
87
+ const cwd = args['cwd'];
88
+ try {
89
+ const report = await guardCommand(command, {
90
+ ...(typeof cwd === 'string' ? { cwd } : {}),
91
+ ...deps.guardOptions,
92
+ });
93
+ // **JSON 으로 낸다** — 독자가 에이전트다. 사유 코드가 있어야 다음 행동을 정한다 (ADR-010 §2)
94
+ return ok(id, textResult(renderJson(report)));
95
+ }
96
+ catch (e) {
97
+ const why = e instanceof Error ? e.message : String(e);
98
+ return ok(id, textResult(`판정에 실패했다: ${why}. **이 명령은 검사되지 않았다.**`, true));
99
+ }
100
+ }
101
+ default:
102
+ if (isNotification)
103
+ return undefined;
104
+ return fail(id, ERR.NO_METHOD, `모르는 메서드: ${String(req.method)}`);
105
+ }
106
+ }
107
+ /** 한 줄(JSON-RPC 메시지 하나)을 처리한다 */
108
+ export async function handleMcpLine(line, deps = {}) {
109
+ const trimmed = line.trim();
110
+ if (trimmed === '')
111
+ return undefined;
112
+ let req;
113
+ try {
114
+ const v = JSON.parse(trimmed);
115
+ if (v === null || typeof v !== 'object' || Array.isArray(v)) {
116
+ return fail(null, ERR.INVALID, '객체가 아니다');
117
+ }
118
+ req = v;
119
+ }
120
+ catch {
121
+ return fail(null, ERR.PARSE, 'JSON 이 아니다');
122
+ }
123
+ try {
124
+ return await handleMcpRequest(req, deps);
125
+ }
126
+ catch (e) {
127
+ return fail(req.id ?? null, ERR.INTERNAL, e instanceof Error ? e.message : String(e));
128
+ }
129
+ }
130
+ /**
131
+ * stdio 루프. **줄 단위다** — MCP stdio 전송은 줄바꿈으로 구분된 JSON 이다.
132
+ *
133
+ * 응답은 **받은 순서대로** 낸다. 동시에 처리하면 순서가 섞이고,
134
+ * 게이트는 설치마다 한 번씩 불리는 것이라 병렬성이 이득이 되지 않는다.
135
+ */
136
+ export async function runMcpServer(stdin, write, deps = {}) {
137
+ let buffer = '';
138
+ for await (const chunk of stdin) {
139
+ buffer += Buffer.isBuffer(chunk) ? chunk.toString('utf8') : String(chunk);
140
+ let nl = buffer.indexOf('\n');
141
+ while (nl >= 0) {
142
+ const line = buffer.slice(0, nl);
143
+ buffer = buffer.slice(nl + 1);
144
+ const res = await handleMcpLine(line, deps);
145
+ if (res !== undefined)
146
+ write(res + '\n');
147
+ nl = buffer.indexOf('\n');
148
+ }
149
+ }
150
+ // 스트림이 줄바꿈 없이 끝난 경우
151
+ const rest = await handleMcpLine(buffer, deps);
152
+ if (rest !== undefined)
153
+ write(rest + '\n');
154
+ }
155
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"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"}