@tienne/gestalt 0.83.2 → 0.84.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 (142) hide show
  1. package/CLAUDE.md +2 -2
  2. package/README.ko.md +3 -1
  3. package/README.md +3 -1
  4. package/dist/package.json +1 -1
  5. package/dist/plugin/review-agents/harness-reviewer/AGENT.md +211 -0
  6. package/dist/plugin/role-agents/_shared/references/comment-rules.md +1 -1
  7. package/dist/plugin/role-agents/suggestion-verifier/AGENT.md +7 -1
  8. package/dist/plugin/skills/_shared/proactive-routing.md +1 -0
  9. package/dist/plugin/skills/_shared/rule-sources.md +1 -1
  10. package/dist/plugin/skills/agent/SKILL.md +2 -0
  11. package/dist/plugin/skills/review/SKILL.md +343 -7
  12. package/dist/plugin/skills/review-loop/SKILL.md +124 -2
  13. package/dist/plugin/skills/ship/SKILL.md +40 -1
  14. package/dist/schemas/gestalt.schema.json +12 -0
  15. package/dist/src/cli/commands/approve-gate.d.ts +24 -0
  16. package/dist/src/cli/commands/approve-gate.d.ts.map +1 -0
  17. package/dist/src/cli/commands/approve-gate.js +90 -0
  18. package/dist/src/cli/commands/approve-gate.js.map +1 -0
  19. package/dist/src/cli/commands/harness-refs-cross-pr.d.ts +218 -0
  20. package/dist/src/cli/commands/harness-refs-cross-pr.d.ts.map +1 -0
  21. package/dist/src/cli/commands/harness-refs-cross-pr.js +934 -0
  22. package/dist/src/cli/commands/harness-refs-cross-pr.js.map +1 -0
  23. package/dist/src/cli/commands/harness-refs.d.ts +19 -0
  24. package/dist/src/cli/commands/harness-refs.d.ts.map +1 -0
  25. package/dist/src/cli/commands/harness-refs.js +51 -0
  26. package/dist/src/cli/commands/harness-refs.js.map +1 -0
  27. package/dist/src/cli/index.d.ts.map +1 -1
  28. package/dist/src/cli/index.js +97 -0
  29. package/dist/src/cli/index.js.map +1 -1
  30. package/dist/src/core/config.d.ts +3 -0
  31. package/dist/src/core/config.d.ts.map +1 -1
  32. package/dist/src/core/config.js +23 -0
  33. package/dist/src/core/config.js.map +1 -1
  34. package/dist/src/core/types.d.ts +2 -0
  35. package/dist/src/core/types.d.ts.map +1 -1
  36. package/dist/src/harness-review/approve-gate.d.ts +53 -0
  37. package/dist/src/harness-review/approve-gate.d.ts.map +1 -0
  38. package/dist/src/harness-review/approve-gate.js +148 -0
  39. package/dist/src/harness-review/approve-gate.js.map +1 -0
  40. package/dist/src/harness-review/backward-search.d.ts +50 -0
  41. package/dist/src/harness-review/backward-search.d.ts.map +1 -0
  42. package/dist/src/harness-review/backward-search.js +183 -0
  43. package/dist/src/harness-review/backward-search.js.map +1 -0
  44. package/dist/src/harness-review/collect.d.ts +75 -0
  45. package/dist/src/harness-review/collect.d.ts.map +1 -0
  46. package/dist/src/harness-review/collect.js +253 -0
  47. package/dist/src/harness-review/collect.js.map +1 -0
  48. package/dist/src/harness-review/copy-drift.d.ts +83 -0
  49. package/dist/src/harness-review/copy-drift.d.ts.map +1 -0
  50. package/dist/src/harness-review/copy-drift.js +477 -0
  51. package/dist/src/harness-review/copy-drift.js.map +1 -0
  52. package/dist/src/harness-review/follow-up-marker.d.ts +29 -0
  53. package/dist/src/harness-review/follow-up-marker.d.ts.map +1 -0
  54. package/dist/src/harness-review/follow-up-marker.js +143 -0
  55. package/dist/src/harness-review/follow-up-marker.js.map +1 -0
  56. package/dist/src/harness-review/forward-search.d.ts +30 -0
  57. package/dist/src/harness-review/forward-search.d.ts.map +1 -0
  58. package/dist/src/harness-review/forward-search.js +381 -0
  59. package/dist/src/harness-review/forward-search.js.map +1 -0
  60. package/dist/src/harness-review/github-backend.d.ts +42 -0
  61. package/dist/src/harness-review/github-backend.d.ts.map +1 -0
  62. package/dist/src/harness-review/github-backend.js +130 -0
  63. package/dist/src/harness-review/github-backend.js.map +1 -0
  64. package/dist/src/harness-review/github-code-search.d.ts +46 -0
  65. package/dist/src/harness-review/github-code-search.d.ts.map +1 -0
  66. package/dist/src/harness-review/github-code-search.js +94 -0
  67. package/dist/src/harness-review/github-code-search.js.map +1 -0
  68. package/dist/src/harness-review/identifiers.d.ts +75 -0
  69. package/dist/src/harness-review/identifiers.d.ts.map +1 -0
  70. package/dist/src/harness-review/identifiers.js +678 -0
  71. package/dist/src/harness-review/identifiers.js.map +1 -0
  72. package/dist/src/harness-review/placeholders.d.ts +44 -0
  73. package/dist/src/harness-review/placeholders.d.ts.map +1 -0
  74. package/dist/src/harness-review/placeholders.js +138 -0
  75. package/dist/src/harness-review/placeholders.js.map +1 -0
  76. package/dist/src/harness-review/related-pr.d.ts +133 -0
  77. package/dist/src/harness-review/related-pr.d.ts.map +1 -0
  78. package/dist/src/harness-review/related-pr.js +553 -0
  79. package/dist/src/harness-review/related-pr.js.map +1 -0
  80. package/dist/src/harness-review/related-repos.d.ts +69 -0
  81. package/dist/src/harness-review/related-repos.d.ts.map +1 -0
  82. package/dist/src/harness-review/related-repos.js +430 -0
  83. package/dist/src/harness-review/related-repos.js.map +1 -0
  84. package/dist/src/harness-review/remote-url.d.ts +8 -0
  85. package/dist/src/harness-review/remote-url.d.ts.map +1 -0
  86. package/dist/src/harness-review/remote-url.js +35 -0
  87. package/dist/src/harness-review/remote-url.js.map +1 -0
  88. package/dist/src/harness-review/replay.d.ts +163 -0
  89. package/dist/src/harness-review/replay.d.ts.map +1 -0
  90. package/dist/src/harness-review/replay.js +575 -0
  91. package/dist/src/harness-review/replay.js.map +1 -0
  92. package/dist/src/harness-review/rule-id-lists.d.ts +38 -0
  93. package/dist/src/harness-review/rule-id-lists.d.ts.map +1 -0
  94. package/dist/src/harness-review/rule-id-lists.js +189 -0
  95. package/dist/src/harness-review/rule-id-lists.js.map +1 -0
  96. package/dist/src/harness-review/search-backend.d.ts +59 -0
  97. package/dist/src/harness-review/search-backend.d.ts.map +1 -0
  98. package/dist/src/harness-review/search-backend.js +178 -0
  99. package/dist/src/harness-review/search-backend.js.map +1 -0
  100. package/dist/src/harness-review/self-contamination.d.ts +83 -0
  101. package/dist/src/harness-review/self-contamination.d.ts.map +1 -0
  102. package/dist/src/harness-review/self-contamination.js +560 -0
  103. package/dist/src/harness-review/self-contamination.js.map +1 -0
  104. package/dist/src/harness-review/self-references.d.ts +20 -0
  105. package/dist/src/harness-review/self-references.d.ts.map +1 -0
  106. package/dist/src/harness-review/self-references.js +173 -0
  107. package/dist/src/harness-review/self-references.js.map +1 -0
  108. package/dist/src/harness-review/three-state.d.ts +79 -0
  109. package/dist/src/harness-review/three-state.d.ts.map +1 -0
  110. package/dist/src/harness-review/three-state.js +238 -0
  111. package/dist/src/harness-review/three-state.js.map +1 -0
  112. package/dist/src/harness-review/types.d.ts +148 -0
  113. package/dist/src/harness-review/types.d.ts.map +1 -0
  114. package/dist/src/harness-review/types.js +74 -0
  115. package/dist/src/harness-review/types.js.map +1 -0
  116. package/dist/src/index.d.ts +1 -0
  117. package/dist/src/index.d.ts.map +1 -1
  118. package/dist/src/index.js +1 -0
  119. package/dist/src/index.js.map +1 -1
  120. package/dist/src/mcp/tools/review-passthrough.js +7 -1
  121. package/dist/src/mcp/tools/review-passthrough.js.map +1 -1
  122. package/dist/src/review/agent-matcher.d.ts +16 -1
  123. package/dist/src/review/agent-matcher.d.ts.map +1 -1
  124. package/dist/src/review/agent-matcher.js +31 -4
  125. package/dist/src/review/agent-matcher.js.map +1 -1
  126. package/dist/src/review/passthrough-engine.d.ts.map +1 -1
  127. package/dist/src/review/passthrough-engine.js +40 -2
  128. package/dist/src/review/passthrough-engine.js.map +1 -1
  129. package/package.json +1 -1
  130. package/plugin/.codex-plugin/plugin.json +1 -1
  131. package/plugin/.mcp.json +1 -1
  132. package/plugin/mcp.json +1 -1
  133. package/plugin/review-agents/harness-reviewer/AGENT.md +211 -0
  134. package/plugin/role-agents/_shared/references/comment-rules.md +1 -1
  135. package/plugin/role-agents/suggestion-verifier/AGENT.md +7 -1
  136. package/plugin/skills/_shared/proactive-routing.md +1 -0
  137. package/plugin/skills/_shared/rule-sources.md +1 -1
  138. package/plugin/skills/agent/SKILL.md +2 -0
  139. package/plugin/skills/review/SKILL.md +343 -7
  140. package/plugin/skills/review-loop/SKILL.md +124 -2
  141. package/plugin/skills/ship/SKILL.md +40 -1
  142. package/schemas/gestalt.schema.json +12 -0
@@ -0,0 +1,130 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import { runGh } from '../review-loop/fetch.js';
3
+ import { resolveRemoteUrl } from './remote-url.js';
4
+ export const BLOCK_REASONS = [
5
+ 'notLoggedIn',
6
+ 'noPermission',
7
+ 'rateLimited',
8
+ 'noGitHubRemote',
9
+ ];
10
+ export const GH_SEARCH_LIMITATIONS = [
11
+ '기본 브랜치만 검색한다. 열린 PR이나 다른 브랜치의 변경은 안 보인다',
12
+ '푸시 직후 인덱싱이 늦을 수 있다. 방금 바뀐 파일은 결과에 없을 수 있다',
13
+ '아카이브된 레포와 포크는 인덱싱되지 않는다',
14
+ ];
15
+ export const GH_SEARCH_MAX_LIMIT = 100;
16
+ /**
17
+ * gh 실패 출력에서 막힘 종류를 가른다. 판정 못 하면 null이라 부르는 쪽이 일반 오류로 다룬다.
18
+ * 속도 제한을 권한 없음보다 먼저 본다 — 둘 다 403이라 메시지로만 갈린다.
19
+ */
20
+ export function classifyGhFailure(text) {
21
+ const t = text.toLowerCase();
22
+ if (/rate limit|secondary rate|abuse detection|retry-after/.test(t))
23
+ return 'rateLimited';
24
+ if (/gh auth login|not logged in|not logged into|authentication required|no oauth token|http 401|bad credentials/.test(t)) {
25
+ return 'notLoggedIn';
26
+ }
27
+ if (/http 404|not found|http 403|resource not accessible|forbidden|saml|must have push access|requires authentication/.test(t)) {
28
+ return 'noPermission';
29
+ }
30
+ return null;
31
+ }
32
+ function failureText(e) {
33
+ if (typeof e !== 'object' || e === null)
34
+ return String(e);
35
+ const { stderr, stdout, message } = e;
36
+ return [stderr, stdout, message]
37
+ .filter((v) => v !== undefined && v !== null)
38
+ .map(String)
39
+ .join('\n');
40
+ }
41
+ const defaultGit = (args) => execFileSync('git', [...args], { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] });
42
+ /** origin이 github.com을 가리키면 owner를, 아니면 null을 돌려준다 */
43
+ export function resolveGithubOwner(repoRoot, git = defaultGit) {
44
+ let url;
45
+ try {
46
+ url = git(['-C', repoRoot, 'remote', 'get-url', 'origin']).trim();
47
+ }
48
+ catch {
49
+ return null;
50
+ }
51
+ const m = /github\.com[:/]([^/\s]+)\/[^/\s]+?(?:\.git)?$/.exec(resolveRemoteUrl(url));
52
+ return m ? m[1] : null;
53
+ }
54
+ export function createGithubSearchBackend(gh = runGh) {
55
+ const backend = {
56
+ kind: 'githubSearch',
57
+ capabilities: {
58
+ defaultBranchOnly: true,
59
+ indexingDelay: true,
60
+ indexesArchivedAndForks: false,
61
+ limitations: GH_SEARCH_LIMITATIONS,
62
+ },
63
+ rateLimitState: {},
64
+ search(query, opts) {
65
+ const limitations = [...GH_SEARCH_LIMITATIONS];
66
+ if (opts.owner === null) {
67
+ return {
68
+ status: 'blocked',
69
+ reason: 'noGitHubRemote',
70
+ detail: 'GitHub 원격이 없다',
71
+ limitations,
72
+ };
73
+ }
74
+ const limit = Math.min(opts.limit ?? 30, GH_SEARCH_MAX_LIMIT);
75
+ const args = [
76
+ 'search',
77
+ 'code',
78
+ query,
79
+ '--owner',
80
+ opts.owner,
81
+ '--json',
82
+ 'path,repository,textMatches',
83
+ '--limit',
84
+ String(limit),
85
+ ];
86
+ let raw;
87
+ try {
88
+ raw = gh(args);
89
+ }
90
+ catch (e) {
91
+ const detail = failureText(e);
92
+ const reason = classifyGhFailure(detail);
93
+ if (reason === 'rateLimited')
94
+ backend.rateLimitState = { blockedAt: new Date().toISOString() };
95
+ if (reason === null) {
96
+ // 원인을 못 가른 실패도 죽이지 않고 막힘으로 올려 사용자에게 묻는다
97
+ return { status: 'blocked', reason: 'noPermission', detail, limitations };
98
+ }
99
+ return { status: 'blocked', reason, detail, limitations };
100
+ }
101
+ let parsed;
102
+ try {
103
+ const json = JSON.parse(raw);
104
+ if (!Array.isArray(json))
105
+ throw new Error('배열이 아니다');
106
+ parsed = json;
107
+ }
108
+ catch (e) {
109
+ return {
110
+ status: 'blocked',
111
+ reason: 'noPermission',
112
+ detail: `응답 파싱 실패: ${failureText(e)}`,
113
+ limitations,
114
+ };
115
+ }
116
+ const hits = parsed.flatMap((h) => h.path && h.repository?.nameWithOwner
117
+ ? [
118
+ {
119
+ repo: h.repository.nameWithOwner,
120
+ path: h.path,
121
+ fragments: (h.textMatches ?? []).flatMap((t) => (t.fragment ? [t.fragment] : [])),
122
+ },
123
+ ]
124
+ : []);
125
+ return { status: 'ok', hits, limitations };
126
+ },
127
+ };
128
+ return backend;
129
+ }
130
+ //# sourceMappingURL=github-backend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-backend.js","sourceRoot":"","sources":["../../../src/harness-review/github-backend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * GitHub 코드 검색을 역방향 검색 인터페이스(CodeSearchBackend)에 맞춘다.
3
+ *
4
+ * github-backend.ts는 조직 단위 질의 하나를 돌리고 막힘을 결과 값으로 알린다. 역방향 검색은
5
+ * 식별자와 레포 목록을 주고 hits와 skipped를 받는 꼴이라 둘을 이어 줄 자리가 필요하다.
6
+ * 조회가 한 번 막히면 뒤 질의는 gh를 부르지 않고 전부 skipped로 돌려준다. 속도 제한에 걸린 채
7
+ * 같은 호출을 수십 번 반복하면 제한이 풀리는 시점만 늦어진다.
8
+ */
9
+ import type { GhRunner } from '../review-loop/fetch.js';
10
+ import { type BlockReason, type GithubSearchBackend } from './github-backend.js';
11
+ import { type CodeSearchBackend, type SearchOptions, type SearchResult } from './search-backend.js';
12
+ export interface GithubLookupBlocked {
13
+ reason: BlockReason;
14
+ detail: string;
15
+ }
16
+ export interface GithubCodeSearchOptions {
17
+ /** 검색할 조직. null이면 GitHub 원격이 없는 레포라 첫 질의에서 바로 막힌다 */
18
+ owner: string | null;
19
+ /** 리뷰 중인 레포(owner/name). 조직 전체 검색에 섞여 나와도 버린다 */
20
+ selfRepo?: string;
21
+ /** 테스트에서 가짜 gh로 바꾼다. backend를 주면 쓰지 않는다 */
22
+ gh?: GhRunner;
23
+ backend?: GithubSearchBackend;
24
+ }
25
+ /** GitHub 결과에는 줄 번호가 없다. 이 값이면 줄을 모른다는 뜻이다 */
26
+ export declare const UNKNOWN_LINE = 0;
27
+ /**
28
+ * repos에 이 값을 넣으면 목록 밖 레포의 결과도 남긴다. 받기만 하는 레포는 관련 레포 목록이
29
+ * 비어 있어서 조직 전체를 찾지 않으면 자기를 부르는 레포를 영영 못 찾는다
30
+ */
31
+ export declare function orgWildcard(owner: string): string;
32
+ export declare class GithubCodeSearchAdapter implements CodeSearchBackend {
33
+ readonly kind: "githubSearch";
34
+ readonly capabilities: Record<string, unknown>;
35
+ /** 첫 막힘. 채워지면 이후 search는 gh를 부르지 않는다 */
36
+ blocked: GithubLookupBlocked | null;
37
+ readonly limitations: string[];
38
+ private readonly backend;
39
+ private readonly owner;
40
+ private readonly selfRepo;
41
+ constructor(opts: GithubCodeSearchOptions);
42
+ get rateLimitState(): Record<string, unknown> | undefined;
43
+ search(identifier: string, repos: string[], opts?: SearchOptions): Promise<SearchResult>;
44
+ private filterHits;
45
+ }
46
+ //# sourceMappingURL=github-code-search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-code-search.d.ts","sourceRoot":"","sources":["../../../src/harness-review/github-code-search.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAIL,KAAK,WAAW,EAChB,KAAK,mBAAmB,EAEzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAGL,KAAK,iBAAiB,EAEtB,KAAK,aAAa,EAClB,KAAK,YAAY,EAClB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,uBAAuB;IACtC,qDAAqD;IACrD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,iDAAiD;IACjD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,EAAE,CAAC,EAAE,QAAQ,CAAC;IACd,OAAO,CAAC,EAAE,mBAAmB,CAAC;CAC/B;AAED,8CAA8C;AAC9C,eAAO,MAAM,YAAY,IAAI,CAAC;AAE9B;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEjD;AAmBD,qBAAa,uBAAwB,YAAW,iBAAiB;IAC/D,QAAQ,CAAC,IAAI,EAAG,cAAc,CAAU;IACxC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/C,wCAAwC;IACxC,OAAO,EAAE,mBAAmB,GAAG,IAAI,CAAQ;IAC3C,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,CAAsD;IAEpF,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;gBAElC,IAAI,EAAE,uBAAuB;IAOzC,IAAI,cAAc,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAExD;IAEK,MAAM,CACV,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,GAAE,aAAkB,GACvB,OAAO,CAAC,YAAY,CAAC;IAsBxB,OAAO,CAAC,UAAU;CA6BnB"}
@@ -0,0 +1,94 @@
1
+ import { createGithubSearchBackend, GH_SEARCH_LIMITATIONS, GH_SEARCH_MAX_LIMIT, } from './github-backend.js';
2
+ import { DEFAULT_MAX_HITS_PER_REPO, MAX_HIT_TEXT_LENGTH, } from './search-backend.js';
3
+ /** GitHub 결과에는 줄 번호가 없다. 이 값이면 줄을 모른다는 뜻이다 */
4
+ export const UNKNOWN_LINE = 0;
5
+ /**
6
+ * repos에 이 값을 넣으면 목록 밖 레포의 결과도 남긴다. 받기만 하는 레포는 관련 레포 목록이
7
+ * 비어 있어서 조직 전체를 찾지 않으면 자기를 부르는 레포를 영영 못 찾는다
8
+ */
9
+ export function orgWildcard(owner) {
10
+ return `${owner}/*`;
11
+ }
12
+ function quoteQuery(identifier) {
13
+ return `"${identifier.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
14
+ }
15
+ function hitsFromGithub(hit, identifier) {
16
+ const lines = hit.fragments.flatMap((f) => f.split('\n')).map((l) => l.trimEnd());
17
+ const matched = [...new Set(lines.filter((l) => l.includes(identifier)))];
18
+ // 조각에 식별자가 안 보여도 GitHub이 파일을 돌려줬다면 매치는 있다. 줄만 모를 뿐이다
19
+ const texts = matched.length > 0 ? matched : [lines.find((l) => l.trim() !== '') ?? ''];
20
+ return texts.map((text) => ({
21
+ repo: hit.repo,
22
+ path: hit.path,
23
+ line: UNKNOWN_LINE,
24
+ text: text.slice(0, MAX_HIT_TEXT_LENGTH),
25
+ }));
26
+ }
27
+ export class GithubCodeSearchAdapter {
28
+ kind = 'githubSearch';
29
+ capabilities;
30
+ /** 첫 막힘. 채워지면 이후 search는 gh를 부르지 않는다 */
31
+ blocked = null;
32
+ limitations = [...GH_SEARCH_LIMITATIONS, 'GitHub 결과에는 줄 번호가 없다'];
33
+ backend;
34
+ owner;
35
+ selfRepo;
36
+ constructor(opts) {
37
+ this.backend = opts.backend ?? createGithubSearchBackend(opts.gh);
38
+ this.owner = opts.owner;
39
+ this.selfRepo = opts.selfRepo?.toLowerCase();
40
+ this.capabilities = { ...this.backend.capabilities, orgWide: true, lineNumbers: false };
41
+ }
42
+ get rateLimitState() {
43
+ return this.backend.rateLimitState;
44
+ }
45
+ async search(identifier, repos, opts = {}) {
46
+ const result = { hits: [], skipped: [] };
47
+ if (identifier === '' || repos.length === 0)
48
+ return result;
49
+ if (!this.blocked) {
50
+ const outcome = this.backend.search(quoteQuery(identifier), {
51
+ owner: this.owner,
52
+ limit: GH_SEARCH_MAX_LIMIT,
53
+ });
54
+ if (outcome.status === 'blocked') {
55
+ this.blocked = { reason: outcome.reason, detail: outcome.detail };
56
+ }
57
+ else {
58
+ result.hits = this.filterHits(outcome.hits, identifier, repos, opts);
59
+ return result;
60
+ }
61
+ }
62
+ const reason = `GitHub 조회 막힘 (${this.blocked.reason})`;
63
+ result.skipped = repos.map((repo) => ({ repo, reason }));
64
+ return result;
65
+ }
66
+ filterHits(hits, identifier, repos, opts) {
67
+ const wanted = new Set(repos.map((r) => r.toLowerCase()));
68
+ const orgWide = this.owner !== null && wanted.has(orgWildcard(this.owner).toLowerCase());
69
+ const max = opts.maxHitsPerRepo ?? DEFAULT_MAX_HITS_PER_REPO;
70
+ const perRepo = new Map();
71
+ const seen = new Set();
72
+ const out = [];
73
+ for (const hit of hits) {
74
+ const repo = hit.repo.toLowerCase();
75
+ if (repo === this.selfRepo)
76
+ continue;
77
+ if (!orgWide && !wanted.has(repo))
78
+ continue;
79
+ for (const h of hitsFromGithub(hit, identifier)) {
80
+ const key = `${h.repo}\u0000${h.path}\u0000${h.text}`;
81
+ if (seen.has(key))
82
+ continue;
83
+ const count = perRepo.get(repo) ?? 0;
84
+ if (count >= max)
85
+ break;
86
+ seen.add(key);
87
+ perRepo.set(repo, count + 1);
88
+ out.push(h);
89
+ }
90
+ }
91
+ return out;
92
+ }
93
+ }
94
+ //# sourceMappingURL=github-code-search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-code-search.js","sourceRoot":"","sources":["../../../src/harness-review/github-code-search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ import type { Identifier } from './types.js';
2
+ export type DiffFileStatus = 'added' | 'deleted' | 'modified' | 'renamed';
3
+ export interface DiffLine {
4
+ type: 'context' | 'removed' | 'added';
5
+ text: string;
6
+ /** removed와 context는 옛 파일 줄 번호, added는 새 파일 줄 번호 */
7
+ lineNumber: number;
8
+ }
9
+ export interface DiffHunk {
10
+ /** hunk 헤더의 옛 파일 시작 줄 */
11
+ oldStart: number;
12
+ /** hunk 헤더의 새 파일 시작 줄. 파일이 지워졌으면 0 */
13
+ newStart: number;
14
+ lines: DiffLine[];
15
+ }
16
+ export interface DiffFile {
17
+ oldPath: string | null;
18
+ newPath: string | null;
19
+ status: DiffFileStatus;
20
+ hunks: DiffHunk[];
21
+ }
22
+ /** `git diff` 출력(unified diff)을 파일 단위로 나눈다. */
23
+ export declare function parseUnifiedDiff(diff: string): DiffFile[];
24
+ /** 플러그인 매니페스트(plugin.json, marketplace.json)인가. */
25
+ export declare function isPluginManifestPath(path: string): boolean;
26
+ /**
27
+ * 다른 레포가 하네스로 읽는 경로인가. 역방향 검색 결과를 거르고 관련 레포 탐지가 읽을 문서를 고를 때 쓴다.
28
+ * SKILL.md, AGENT.md, CLAUDE.md, AGENTS.md, GEMINI.md, .mcp.json, 플러그인 매니페스트,
29
+ * .claude/, .agents/, .cursor/rules/, 플러그인 매니페스트 디렉토리 아래 파일,
30
+ * skills/와 plugins/ 아래 문서꼴 파일(md, mdc, json, toml, yaml, txt)이 해당한다.
31
+ */
32
+ export declare function isHarnessPath(path: string): boolean;
33
+ /**
34
+ * review 스킬 1단계가 이름만으로 ruleDocs에 넣는 경로인가.
35
+ * SKILL.md, AGENT.md, CLAUDE.md, AGENTS.md, GEMINI.md, .cursorrules, .windsurfrules,
36
+ * .claude/ 아래 .md, .cursor/rules/ 아래 파일.
37
+ */
38
+ export declare function isRuleDocPath(path: string): boolean;
39
+ export declare const MCP_SDK_PACKAGE = "@modelcontextprotocol/sdk";
40
+ /** private가 아니고 name이 있는 package.json인가. 다른 레포가 이 이름으로 설치하거나 부른다. */
41
+ export declare function isPublicPackageJson(path: string, content: string): boolean;
42
+ /** package.json이 MCP SDK에 의존하는가. */
43
+ export declare function dependsOnMcpSdk(packageJsonContent: string): boolean;
44
+ /** 파일 내용에 MCP 도구 등록부 꼴(server.tool, registerTool, ListTools 핸들러)이 있는가. */
45
+ export declare function isMcpToolRegistry(content: string): boolean;
46
+ /** 소스에서 패턴으로 잡히는 MCP 도구 이름을 전부 뽑는다. 등록부가 아니면 name: 필드는 안 본다. */
47
+ export declare function extractMcpToolNames(content: string): string[];
48
+ export type ReadFileFn = (relPath: string) => string | undefined;
49
+ export type HarnessTargetReason = 'ruleDoc' | 'mcpToolRegistry' | 'publicPackage';
50
+ /**
51
+ * 변경 파일이 하네스 대상인지 판정한다. ruleDocs 꼴 문서이거나, 다른 레포가 이름으로 부르는
52
+ * 코드(MCP SDK에 의존하는 도구 등록부, private 아닌 package.json)면 그 이유를 돌려준다.
53
+ * content는 판정할 파일의 내용이다. readFile을 주면 가장 가까운 package.json의 의존성도 본다.
54
+ */
55
+ export declare function classifyHarnessTarget(path: string, content?: string, readFile?: ReadFileFn): HarnessTargetReason | null;
56
+ export interface ExtractIdentifiersOptions {
57
+ /** base 쪽 트리의 파일 목록. 레포에 하나뿐인 파일 이름을 판정할 때 쓴다. 없으면 uniqueFileName을 안 뽑는다. */
58
+ baseFiles?: string[];
59
+ /** 파일 내용을 읽는다. head에 없으면 base 내용을 돌려줘도 된다. */
60
+ readFile?: ReadFileFn;
61
+ }
62
+ /** 룰 문서에서 룰을 정의하는 줄이면 그 ID를 돌려준다. 규칙을 언급만 하는 줄은 정의로 안 본다 */
63
+ export declare function ruleIdOfDefinitionLine(text: string): string | null;
64
+ /**
65
+ * diff에서 지워지거나 바뀐 식별자를 뽑는다. 역방향 검색이 이 값으로 관련 레포를 찾는다.
66
+ * 하네스 문서 PR이 아니어도 MCP 도구 정의나 패키지 이름이 바뀌면 그 식별자가 나온다.
67
+ * 패턴으로 도구 이름을 못 잡은 MCP 등록부 변경은 value에 파일 경로를 담고 extractedBy=llm으로 표시한다.
68
+ */
69
+ export declare function extractIdentifiers(diff: string, opts?: ExtractIdentifiersOptions): Identifier[];
70
+ /**
71
+ * git 레포의 두 ref 사이 diff에서 식별자를 뽑는다. base 트리 파일 목록으로 하나뿐인 파일 이름을 판정하고
72
+ * 파일 내용은 head에서 먼저 읽고 없으면 base에서 읽는다.
73
+ */
74
+ export declare function extractIdentifiersFromGit(repoRoot: string, baseRef: string, headRef: string): Identifier[];
75
+ //# sourceMappingURL=identifiers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identifiers.d.ts","sourceRoot":"","sources":["../../../src/harness-review/identifiers.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAA+B,UAAU,EAAkB,MAAM,YAAY,CAAC;AAI1F,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;AAE1E,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,oDAAoD;IACpD,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,QAAQ;IACvB,yBAAyB;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,cAAc,CAAC;IACvB,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB;AA+BD,+CAA+C;AAC/C,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,EAAE,CAoEzD;AAoBD,mDAAmD;AACnD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE1D;AAcD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAWnD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOnD;AAID,eAAO,MAAM,eAAe,8BAA8B,CAAC;AAW3D,qEAAqE;AACrE,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAI1E;AAED,oCAAoC;AACpC,wBAAgB,eAAe,CAAC,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAQnE;AAWD,0EAA0E;AAC1E,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE1D;AAYD,gEAAgE;AAChE,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAQ7D;AAED,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;AAkBjE,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,iBAAiB,GAAG,eAAe,CAAC;AAElF;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,UAAU,GACpB,mBAAmB,GAAG,IAAI,CAY5B;AAID,MAAM,WAAW,yBAAyB;IACxC,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,UAAU,CAAC;CACvB;AAsHD,4DAA4D;AAC5D,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIlE;AA6OD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,yBAA8B,GACnC,UAAU,EAAE,CAad;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,UAAU,EAAE,CAuBd"}