@tienne/gestalt 0.77.0 → 0.77.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/CLAUDE.md +1 -0
- package/dist/package.json +4 -4
- package/dist/plugin/role-agents/_shared/references/README.md +13 -1
- package/dist/plugin/skills/review/SKILL.md +14 -1
- package/dist/src/mcp/input-guard.d.ts +90 -0
- package/dist/src/mcp/input-guard.d.ts.map +1 -0
- package/dist/src/mcp/input-guard.js +531 -0
- package/dist/src/mcp/input-guard.js.map +1 -0
- package/dist/src/mcp/schemas.d.ts +50 -50
- package/dist/src/mcp/schemas.d.ts.map +1 -1
- package/dist/src/mcp/schemas.js +31 -22
- package/dist/src/mcp/schemas.js.map +1 -1
- package/dist/src/mcp/server.d.ts.map +1 -1
- package/dist/src/mcp/server.js +25 -16
- package/dist/src/mcp/server.js.map +1 -1
- package/package.json +4 -4
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/.mcp.json +1 -1
- package/plugin/mcp.json +1 -1
- package/plugin/role-agents/_shared/references/README.md +13 -1
- package/plugin/skills/review/SKILL.md +14 -1
package/CLAUDE.md
CHANGED
|
@@ -34,6 +34,7 @@ pnpm tsx bin/gestalt.ts spec <session-id>
|
|
|
34
34
|
pnpm tsx bin/gestalt.ts status
|
|
35
35
|
pnpm tsx bin/gestalt.ts init # gestalt.json + code graph + post-commit hook
|
|
36
36
|
pnpm verify:rules # 룰북과 에이전트 문서의 룰 ID·심각도 정합 검사
|
|
37
|
+
pnpm verify:output-style # 룰 ID 정합과 HOIST 조각 검사 (postbuild에도 걸려 있다)
|
|
37
38
|
pnpm build:output-style # 룰북 → ~/.claude/output-styles/tienne-voice.md 생성
|
|
38
39
|
pnpm tsx bin/gestalt.ts humanize-scan --file a.md --register chat # 걸린 룰만 추린다
|
|
39
40
|
pnpm tsx bin/gestalt.ts humanize-check --before a.md --after b.md --register report
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tienne/gestalt",
|
|
3
|
-
"version": "0.77.
|
|
3
|
+
"version": "0.77.2",
|
|
4
4
|
"description": "TypeScript AI Development Harness - Gestalt psychology-driven requirement clarification",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
],
|
|
28
28
|
"scripts": {
|
|
29
29
|
"dev": "tsx bin/gestalt.ts",
|
|
30
|
-
"build": "tsc",
|
|
30
|
+
"build": "tsc -p tsconfig.build.json",
|
|
31
31
|
"postbuild": "rm -rf dist/plugin && mkdir -p dist/plugin && cp -r plugin/agents plugin/role-agents plugin/review-agents plugin/personas plugin/skills dist/plugin/ && cp -r schemas dist/ && cp package.json dist/ && chmod +x dist/bin/gestalt.js && pnpm run verify:plugin && pnpm run verify:rules && pnpm run verify:output-style",
|
|
32
32
|
"verify:plugin": "tsx scripts/verify-plugin-assets.ts",
|
|
33
33
|
"prepublishOnly": "pnpm build",
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
"resolution-bench": "tsx benchmarks/run-resolution-benchmark.ts",
|
|
39
39
|
"lint": "eslint .",
|
|
40
40
|
"typecheck": "tsc --noEmit",
|
|
41
|
-
"format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"",
|
|
42
|
-
"format:check": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"",
|
|
41
|
+
"format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\" \"scripts/**/*.ts\"",
|
|
42
|
+
"format:check": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\" \"scripts/**/*.ts\"",
|
|
43
43
|
"version:sync": "tsx scripts/sync-version.ts",
|
|
44
44
|
"postversion": "pnpm run version:sync && pnpm run build:output-style",
|
|
45
45
|
"verify:rules": "tsx scripts/verify-rule-refs.ts",
|
|
@@ -20,13 +20,25 @@
|
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
22
|
pnpm verify:rules
|
|
23
|
+
pnpm verify:output-style
|
|
24
|
+
pnpm build:output-style
|
|
23
25
|
```
|
|
24
26
|
|
|
25
|
-
에이전트 문서 14곳이 룰 ID와 금지 어휘를 손으로 옮겨 적고 있어서 룰북에서 ID를 지우거나
|
|
27
|
+
**첫째 줄은 룰 ID 사본을 본다.** 에이전트 문서 14곳이 룰 ID와 금지 어휘를 손으로 옮겨 적고 있어서 룰북에서 ID를 지우거나
|
|
26
28
|
심각도를 바꾸면 그 사본들이 조용히 어긋난다. 이 검사가 네 가지를 본다 — 없는 ID를 인용하는
|
|
27
29
|
문서, 자체검증 목록에서 빠진 S1, 표와 목록의 심각도 불일치, 룰 문서 본문의 금지어 사용.
|
|
28
30
|
`pnpm test`와 `pnpm build`에도 걸려 있다.
|
|
29
31
|
|
|
32
|
+
**둘째 줄은 output style 생성기가 보는 것이다.** 두 가지를 본다 — 금지 목록과 자가점검이
|
|
33
|
+
인용한 룰 ID가 룰북에 살아있고 대화 기준 S1인지, 그리고 `scripts/build-output-style.ts`의
|
|
34
|
+
`HOIST`가 조각 문자열로 가리키는 처방 문장이 그대로인지. `verify:rules`는 둘 다 모른다.
|
|
35
|
+
`HOIST`에 적힌 룰마다 그 조각을 본다. 이것도 `pnpm test`와 `pnpm build`(postbuild)에
|
|
36
|
+
걸려 있다. `pnpm gate`를 돌리면 따로 부를 일이 없다.
|
|
37
|
+
|
|
38
|
+
**셋째 줄은 홈의 산출 파일을 다시 뽑는다.** 룰 문구나 심각도를 고쳐도
|
|
39
|
+
`~/.claude/output-styles/tienne-voice.md`는 저절로 안 바뀐다. 위 둘은 그 파일을 안 보므로
|
|
40
|
+
이걸 안 돌리면 룰북과 실제로 켜져 있는 어투 지시가 갈라진 채로 남는다.
|
|
41
|
+
|
|
30
42
|
- **룰을 추가하면 그 문서가 스스로 그 룰을 지키는지 먼저 확인한다.** 룰 문서가 금지 어휘를
|
|
31
43
|
본문에 쓰면 산출물로 샌다. 금지어를 넣었으면 같은 문서를 grep한다.
|
|
32
44
|
- 어투 규칙은 **S1으로 올려야 실제로 강제된다.** S2는 모델이 우선순위를 알아서 정하면서 빠져나간다.
|
|
@@ -517,7 +517,18 @@ ges_execute {
|
|
|
517
517
|
action: "review_consensus",
|
|
518
518
|
reviewSessionId: "<reviewSessionId>",
|
|
519
519
|
reviewConsensus: {
|
|
520
|
-
mergedIssues: [
|
|
520
|
+
mergedIssues: [
|
|
521
|
+
{
|
|
522
|
+
id: "...",
|
|
523
|
+
severity: "critical" | "high" | "warning",
|
|
524
|
+
category: "...",
|
|
525
|
+
file: "...",
|
|
526
|
+
line: 12, // 선택 — 파일 전반이면 생략
|
|
527
|
+
message: "...",
|
|
528
|
+
suggestion: "...",
|
|
529
|
+
reportedBy: "quality-reviewer" // 필수. 문자열 하나다
|
|
530
|
+
}
|
|
531
|
+
],
|
|
521
532
|
approvedBy: [...],
|
|
522
533
|
blockedBy: [...],
|
|
523
534
|
summary: "...",
|
|
@@ -527,6 +538,8 @@ ges_execute {
|
|
|
527
538
|
}
|
|
528
539
|
```
|
|
529
540
|
|
|
541
|
+
`line`만 선택이고 나머지는 전부 필수입니다. **`reportedBy`는 배열이 아니라 에이전트 이름 문자열 하나**입니다 — 여러 에이전트가 같은 걸 짚었으면 대표 하나만 적습니다.
|
|
542
|
+
|
|
530
543
|
엔진이 두 심급을 합쳐 판정합니다 — **결함(critical/high)이 없고 `coherent: true`여야 통과**입니다. `continuityVerdict`를 생략하면 결함 심급만으로 판정하는 기존 동작 그대로입니다.
|
|
531
544
|
|
|
532
545
|
응답 해석:
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP 도구 입력 검증을 부르는 쪽이 고칠 수 있는 형태로 돌려주는 자리.
|
|
3
|
+
*
|
|
4
|
+
* MCP SDK는 도구를 부르기 전에 등록된 zod 스키마로 인자를 검증한다. 실패하면
|
|
5
|
+
* 첫 이슈의 message 한 줄만 뽑아 `Invalid arguments for tool ...`로 던진다. 우리
|
|
6
|
+
* 핸들러는 그 전에 못 끼어든다. 그래서 고칠 수 있는 자리는 스키마 자체다.
|
|
7
|
+
*
|
|
8
|
+
* 심는 방어는 이렇다.
|
|
9
|
+
* - 객체나 배열을 기대하는 파라미터에 문자열이 오면 `JSON.parse`를 먼저 시도한다.
|
|
10
|
+
* 호스트가 JSON 문자열을 못 풀고 원본을 그대로 넘기는 일이 있는데, 그때 나오는
|
|
11
|
+
* `Expected object, received string`은 진짜 원인(문자열이 깨졌다)을 덮어버린다.
|
|
12
|
+
* - 파싱이 실패하면 파서의 원본 에러와 깨진 지점 주변을 함께 싣는다. 수만 자짜리
|
|
13
|
+
* 페이로드에서 위치 숫자만으론 어디가 깨졌는지 못 찾는다.
|
|
14
|
+
* - 타입이 어긋나면 실제로 받은 값의 샘플과 경로를 메시지에 붙인다. SDK가 첫 이슈
|
|
15
|
+
* message만 꺼내가므로 경로까지 message 안에 넣어야 살아남는다.
|
|
16
|
+
*
|
|
17
|
+
* **JSON 문자열 관용은 도구 파라미터(최상위 키)에만 걸린다.** `guardShape`가 shape의
|
|
18
|
+
* 키만 돌기 때문이다. `reviewConsensus`는 문자열로 보내도 풀리지만 그 안의
|
|
19
|
+
* `mergedIssues`를 문자열로 보내면 여전히 타입 에러로 떨어진다 — 대신 경로와 받은
|
|
20
|
+
* 값이 붙어 원인은 읽힌다. 중첩까지 넓히려면 배열 요소 스키마를 재구성해야 하는데,
|
|
21
|
+
* 실제로 문자열이 오는 자리는 최상위 파라미터라 거기까지 가지 않았다.
|
|
22
|
+
*
|
|
23
|
+
* **이 파일은 zod v3 내부 구조(`_def`)에 기댄다.** semver 보장 대상이 아니라 마이너
|
|
24
|
+
* 업그레이드에도 깨질 수 있다. 깨지면 예외 없이 조용히 안 걸린다 — 에러 메시지만 예전으로
|
|
25
|
+
* 돌아가고 아무도 모른다. 그래서 `tests/unit/mcp/input-guard.test.ts`가 컨테이너 종류마다
|
|
26
|
+
* 잎을 심어 순회가 그 잎에 닿는지 본다. zod 버전을 올리면 그 테스트를 반드시 다시 돌린다.
|
|
27
|
+
*/
|
|
28
|
+
import { z } from 'zod';
|
|
29
|
+
/** 규칙 표를 테스트가 확인할 수 있게 내보낸다. 런타임 경로는 이 함수를 안 쓴다. */
|
|
30
|
+
export declare function tokenRulesForTest(): ReadonlyArray<readonly [string, number]>;
|
|
31
|
+
/** 패턴 계약을 테스트가 확인할 수 있게 내보낸다. 런타임 경로는 이 함수를 안 쓴다. */
|
|
32
|
+
export declare function secretPatternsForTest(): RegExp[];
|
|
33
|
+
/** 실제로 받은 값을 에러 메시지에 실을 수 있게 줄여 찍는다. */
|
|
34
|
+
export declare function formatReceived(value: unknown): string;
|
|
35
|
+
/**
|
|
36
|
+
* 깨진 지점 주변만 잘라 보여준다.
|
|
37
|
+
*
|
|
38
|
+
* 가리기를 먼저 하고 자른다. 순서를 뒤집으면 윈도우가 접두어를 잘라낸 조각에서 패턴이
|
|
39
|
+
* 안 걸린다 — 따옴표를 안 닫은 JSON 이 그 자리다. V8 이 보고하는 위치가 문자열 끝이라
|
|
40
|
+
* 접두어가 윈도우 앞으로 밀려난다.
|
|
41
|
+
*
|
|
42
|
+
* 깨진 지점이 자격증명 안이면 그 자리가 별표로 덮여 원인이 안 보인다. 드문 경우이고
|
|
43
|
+
* 파서 사유와 line, column 은 그대로 남는다 — 노출을 막는 쪽을 택했다.
|
|
44
|
+
*/
|
|
45
|
+
export declare function snippetAround(text: string, position: number, radius?: number): string;
|
|
46
|
+
/** JSON 파싱 실패를 부르는 쪽이 바로 고칠 수 있는 한 줄로 만든다. */
|
|
47
|
+
export declare function describeJsonParseFailure(label: string, raw: string, error: unknown): string;
|
|
48
|
+
/**
|
|
49
|
+
* 타입이 어긋났을 때 무엇이 왔는지까지 말해주는 errorMap.
|
|
50
|
+
*
|
|
51
|
+
* SDK가 첫 이슈의 message만 꺼내 쓰므로 경로(`a.b[0].c`)도 여기 넣는다. 안 넣으면
|
|
52
|
+
* 어느 필드가 틀렸는지가 통째로 사라진다.
|
|
53
|
+
*/
|
|
54
|
+
export declare const verboseErrorMap: z.ZodErrorMap;
|
|
55
|
+
/**
|
|
56
|
+
* 스키마 트리 전체에 errorMap을 심는다.
|
|
57
|
+
*
|
|
58
|
+
* 제자리에서 고친다. 중첩 배열 요소까지 닿아야 `mergedIssues[0].reportedBy` 같은
|
|
59
|
+
* 자리의 에러에도 경로와 샘플이 붙는다.
|
|
60
|
+
*
|
|
61
|
+
* 가드가 둘이고 하는 일이 다르다.
|
|
62
|
+
* - `seen`에 있는 스키마 인스턴스는 **노드 전체를 건너뛴다** (자식 순회까지 중단).
|
|
63
|
+
* 순환 참조와 공유 참조 대비다.
|
|
64
|
+
* - errorMap이 이미 있는 스키마는 **값 재할당만 건너뛰고** 자식 순회는 계속한다.
|
|
65
|
+
* 같은 shape에 두 번 걸려도 안쪽이 빠짐없이 덮인다.
|
|
66
|
+
*/
|
|
67
|
+
export declare function attachErrorMap<S extends z.ZodTypeAny>(schema: S, seen?: WeakSet<object>): S;
|
|
68
|
+
/**
|
|
69
|
+
* 객체나 배열 파라미터에 JSON 문자열을 허용한다.
|
|
70
|
+
*
|
|
71
|
+
* 껍질(optional/default)은 벗겼다가 그대로 다시 씌운다. `preprocess`를 바깥에 두면
|
|
72
|
+
* SDK가 필수 파라미터로 잘못 노출하고 `describe()`도 날아간다.
|
|
73
|
+
*/
|
|
74
|
+
export declare function tolerateJsonString<S extends z.ZodTypeAny>(schema: S, label: string): z.ZodTypeAny;
|
|
75
|
+
/**
|
|
76
|
+
* 도구 등록에 넘길 raw shape에 방어를 입힌다.
|
|
77
|
+
*
|
|
78
|
+
* 두 번 지나도 결과가 같다. 다만 구조가 그대로 남는다는 뜻은 아니다. `attachErrorMap`은
|
|
79
|
+
* 값이 비었을 때만 대입하므로 손대는 게 없지만 `tolerateJsonString`은 두 번째 통과에서
|
|
80
|
+
* `preprocess`를 한 겹 더 씌운다. 바깥 겹이 문자열을 풀면 안쪽 겹에는 문자열이 아닌 값이
|
|
81
|
+
* 와서 그대로 지나간다. 상한 검사와 파싱 실패 문구도 한 번만 실린다.
|
|
82
|
+
*
|
|
83
|
+
* `schemas.ts`에서 `guardObject`를 지난 스키마가 `server.ts`의 `guardedTool`에서 한 번
|
|
84
|
+
* 더 지나는 게 그 경로다. 등록 채널을 하나로 남기는 것이 이 설계의 전제라, 레이어를
|
|
85
|
+
* 갈라 그 채널을 다시 여는 쪽으로는 안 간다.
|
|
86
|
+
*/
|
|
87
|
+
export declare function guardShape<S extends z.ZodRawShape>(shape: S): S;
|
|
88
|
+
/** 핸들러가 직접 `.parse()`하는 스키마에도 같은 방어를 입힌다. */
|
|
89
|
+
export declare function guardObject<S extends z.AnyZodObject>(schema: S): S;
|
|
90
|
+
//# sourceMappingURL=input-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-guard.d.ts","sourceRoot":"","sources":["../../../src/mcp/input-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAwKxB,oDAAoD;AACpD,wBAAgB,iBAAiB,IAAI,aAAa,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAE5E;AAED,qDAAqD;AACrD,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAEhD;AA8CD,wCAAwC;AACxC,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAarD;AAUD;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,SAAiB,GAAG,MAAM,CAQ7F;AAED,8CAA8C;AAC9C,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAe3F;AAED;;;;;GAKG;AACH,eAAO,MAAM,eAAe,EAAE,CAAC,CAAC,WA0B/B,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EACnD,MAAM,EAAE,CAAC,EACT,IAAI,GAAE,OAAO,CAAC,MAAM,CAAiB,GACpC,CAAC,CA4EH;AAiDD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC,CAAC,UAAU,CAwCjG;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAM/D;AAED,6CAA6C;AAC7C,wBAAgB,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC,YAAY,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAElE"}
|