@tienne/gestalt 0.88.0 → 0.90.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/CLAUDE.md +7 -2
- package/README.ko.md +2 -1
- package/README.md +3 -1
- package/dist/package.json +7 -4
- package/dist/plugin/skills/_shared/proactive-routing.md +29 -12
- package/dist/plugin/skills/architecture/SKILL.md +944 -0
- package/dist/plugin/skills/brief/SKILL.md +2 -1
- package/dist/plugin/skills/dispatch/SKILL.md +2 -0
- package/dist/plugin/skills/explain/SKILL.md +4 -2
- package/dist/plugin/skills/jira-create/SKILL.md +2 -0
- package/dist/plugin/skills/pr/SKILL.md +2 -0
- package/dist/plugin/skills/presentation/SKILL.md +2 -0
- package/dist/plugin/skills/review/SKILL.md +1 -0
- package/dist/plugin/skills/review-loop/SKILL.md +3 -1
- package/dist/plugin/skills/review-reply/SKILL.md +2 -0
- package/dist/plugin/skills/ship/SKILL.md +2 -2
- package/dist/plugin/skills/slack-send/SKILL.md +2 -0
- package/dist/schemas/architecture-ir.schema.json +596 -0
- package/dist/src/architecture/canvas-geometry.d.ts +40 -0
- package/dist/src/architecture/canvas-geometry.d.ts.map +1 -0
- package/dist/src/architecture/canvas-geometry.js +212 -0
- package/dist/src/architecture/canvas-geometry.js.map +1 -0
- package/dist/src/architecture/codeowners.d.ts +16 -0
- package/dist/src/architecture/codeowners.d.ts.map +1 -0
- package/dist/src/architecture/codeowners.js +58 -0
- package/dist/src/architecture/codeowners.js.map +1 -0
- package/dist/src/architecture/compare-layout.d.ts +27 -0
- package/dist/src/architecture/compare-layout.d.ts.map +1 -0
- package/dist/src/architecture/compare-layout.js +72 -0
- package/dist/src/architecture/compare-layout.js.map +1 -0
- package/dist/src/architecture/dataflow-layout.d.ts +29 -0
- package/dist/src/architecture/dataflow-layout.d.ts.map +1 -0
- package/dist/src/architecture/dataflow-layout.js +229 -0
- package/dist/src/architecture/dataflow-layout.js.map +1 -0
- package/dist/src/architecture/doc-fresh.d.ts +31 -0
- package/dist/src/architecture/doc-fresh.d.ts.map +1 -0
- package/dist/src/architecture/doc-fresh.js +84 -0
- package/dist/src/architecture/doc-fresh.js.map +1 -0
- package/dist/src/architecture/doc-link.d.ts +84 -0
- package/dist/src/architecture/doc-link.d.ts.map +1 -0
- package/dist/src/architecture/doc-link.js +396 -0
- package/dist/src/architecture/doc-link.js.map +1 -0
- package/dist/src/architecture/doc-routes.d.ts +39 -0
- package/dist/src/architecture/doc-routes.d.ts.map +1 -0
- package/dist/src/architecture/doc-routes.js +123 -0
- package/dist/src/architecture/doc-routes.js.map +1 -0
- package/dist/src/architecture/doc-scan.d.ts +107 -0
- package/dist/src/architecture/doc-scan.d.ts.map +1 -0
- package/dist/src/architecture/doc-scan.js +617 -0
- package/dist/src/architecture/doc-scan.js.map +1 -0
- package/dist/src/architecture/doc-stale.d.ts +32 -0
- package/dist/src/architecture/doc-stale.d.ts.map +1 -0
- package/dist/src/architecture/doc-stale.js +60 -0
- package/dist/src/architecture/doc-stale.js.map +1 -0
- package/dist/src/architecture/drilldown.d.ts +51 -0
- package/dist/src/architecture/drilldown.d.ts.map +1 -0
- package/dist/src/architecture/drilldown.js +1160 -0
- package/dist/src/architecture/drilldown.js.map +1 -0
- package/dist/src/architecture/endpoint-match.d.ts +43 -0
- package/dist/src/architecture/endpoint-match.d.ts.map +1 -0
- package/dist/src/architecture/endpoint-match.js +133 -0
- package/dist/src/architecture/endpoint-match.js.map +1 -0
- package/dist/src/architecture/flow-layout.d.ts +79 -0
- package/dist/src/architecture/flow-layout.d.ts.map +1 -0
- package/dist/src/architecture/flow-layout.js +519 -0
- package/dist/src/architecture/flow-layout.js.map +1 -0
- package/dist/src/architecture/focus.d.ts +14 -0
- package/dist/src/architecture/focus.d.ts.map +1 -0
- package/dist/src/architecture/focus.js +107 -0
- package/dist/src/architecture/focus.js.map +1 -0
- package/dist/src/architecture/global-context.d.ts +23 -0
- package/dist/src/architecture/global-context.d.ts.map +1 -0
- package/dist/src/architecture/global-context.js +67 -0
- package/dist/src/architecture/global-context.js.map +1 -0
- package/dist/src/architecture/html-client.d.ts +35 -0
- package/dist/src/architecture/html-client.d.ts.map +1 -0
- package/dist/src/architecture/html-client.js +1852 -0
- package/dist/src/architecture/html-client.js.map +1 -0
- package/dist/src/architecture/html-renderer.d.ts +22 -0
- package/dist/src/architecture/html-renderer.d.ts.map +1 -0
- package/dist/src/architecture/html-renderer.js +1290 -0
- package/dist/src/architecture/html-renderer.js.map +1 -0
- package/dist/src/architecture/html-theme.d.ts +25 -0
- package/dist/src/architecture/html-theme.d.ts.map +1 -0
- package/dist/src/architecture/html-theme.js +681 -0
- package/dist/src/architecture/html-theme.js.map +1 -0
- package/dist/src/architecture/index.d.ts +9 -0
- package/dist/src/architecture/index.d.ts.map +1 -0
- package/dist/src/architecture/index.js +9 -0
- package/dist/src/architecture/index.js.map +1 -0
- package/dist/src/architecture/ir-schema.d.ts +1832 -0
- package/dist/src/architecture/ir-schema.d.ts.map +1 -0
- package/dist/src/architecture/ir-schema.js +343 -0
- package/dist/src/architecture/ir-schema.js.map +1 -0
- package/dist/src/architecture/kind-text.d.ts +21 -0
- package/dist/src/architecture/kind-text.d.ts.map +1 -0
- package/dist/src/architecture/kind-text.js +42 -0
- package/dist/src/architecture/kind-text.js.map +1 -0
- package/dist/src/architecture/layout.d.ts +227 -0
- package/dist/src/architecture/layout.d.ts.map +1 -0
- package/dist/src/architecture/layout.js +627 -0
- package/dist/src/architecture/layout.js.map +1 -0
- package/dist/src/architecture/mcp-tool-match.d.ts +49 -0
- package/dist/src/architecture/mcp-tool-match.d.ts.map +1 -0
- package/dist/src/architecture/mcp-tool-match.js +53 -0
- package/dist/src/architecture/mcp-tool-match.js.map +1 -0
- package/dist/src/architecture/merge.d.ts +54 -0
- package/dist/src/architecture/merge.d.ts.map +1 -0
- package/dist/src/architecture/merge.js +681 -0
- package/dist/src/architecture/merge.js.map +1 -0
- package/dist/src/architecture/micro-app.d.ts +20 -0
- package/dist/src/architecture/micro-app.d.ts.map +1 -0
- package/dist/src/architecture/micro-app.js +41 -0
- package/dist/src/architecture/micro-app.js.map +1 -0
- package/dist/src/architecture/name-ref-match.d.ts +43 -0
- package/dist/src/architecture/name-ref-match.d.ts.map +1 -0
- package/dist/src/architecture/name-ref-match.js +127 -0
- package/dist/src/architecture/name-ref-match.js.map +1 -0
- package/dist/src/architecture/packs/data.d.ts +109 -0
- package/dist/src/architecture/packs/data.d.ts.map +1 -0
- package/dist/src/architecture/packs/data.js +64 -0
- package/dist/src/architecture/packs/data.js.map +1 -0
- package/dist/src/architecture/packs/generic.d.ts +47 -0
- package/dist/src/architecture/packs/generic.d.ts.map +1 -0
- package/dist/src/architecture/packs/generic.js +35 -0
- package/dist/src/architecture/packs/generic.js.map +1 -0
- package/dist/src/architecture/packs/harness.d.ts +96 -0
- package/dist/src/architecture/packs/harness.d.ts.map +1 -0
- package/dist/src/architecture/packs/harness.js +66 -0
- package/dist/src/architecture/packs/harness.js.map +1 -0
- package/dist/src/architecture/packs/index.d.ts +840 -0
- package/dist/src/architecture/packs/index.d.ts.map +1 -0
- package/dist/src/architecture/packs/index.js +87 -0
- package/dist/src/architecture/packs/index.js.map +1 -0
- package/dist/src/architecture/packs/infra.d.ts +91 -0
- package/dist/src/architecture/packs/infra.d.ts.map +1 -0
- package/dist/src/architecture/packs/infra.js +57 -0
- package/dist/src/architecture/packs/infra.js.map +1 -0
- package/dist/src/architecture/packs/knowledge.d.ts +72 -0
- package/dist/src/architecture/packs/knowledge.d.ts.map +1 -0
- package/dist/src/architecture/packs/knowledge.js +58 -0
- package/dist/src/architecture/packs/knowledge.js.map +1 -0
- package/dist/src/architecture/packs/process.d.ts +87 -0
- package/dist/src/architecture/packs/process.d.ts.map +1 -0
- package/dist/src/architecture/packs/process.js +52 -0
- package/dist/src/architecture/packs/process.js.map +1 -0
- package/dist/src/architecture/packs/render-classes.d.ts +11 -0
- package/dist/src/architecture/packs/render-classes.d.ts.map +1 -0
- package/dist/src/architecture/packs/render-classes.js +92 -0
- package/dist/src/architecture/packs/render-classes.js.map +1 -0
- package/dist/src/architecture/packs/types.d.ts +66 -0
- package/dist/src/architecture/packs/types.d.ts.map +1 -0
- package/dist/src/architecture/packs/types.js +18 -0
- package/dist/src/architecture/packs/types.js.map +1 -0
- package/dist/src/architecture/packs/web-product.d.ts +348 -0
- package/dist/src/architecture/packs/web-product.d.ts.map +1 -0
- package/dist/src/architecture/packs/web-product.js +226 -0
- package/dist/src/architecture/packs/web-product.js.map +1 -0
- package/dist/src/architecture/sequence-layout.d.ts +50 -0
- package/dist/src/architecture/sequence-layout.d.ts.map +1 -0
- package/dist/src/architecture/sequence-layout.js +140 -0
- package/dist/src/architecture/sequence-layout.js.map +1 -0
- package/dist/src/architecture/service-facts.d.ts +30 -0
- package/dist/src/architecture/service-facts.d.ts.map +1 -0
- package/dist/src/architecture/service-facts.js +88 -0
- package/dist/src/architecture/service-facts.js.map +1 -0
- package/dist/src/architecture/store.d.ts +50 -0
- package/dist/src/architecture/store.d.ts.map +1 -0
- package/dist/src/architecture/store.js +320 -0
- package/dist/src/architecture/store.js.map +1 -0
- package/dist/src/architecture/types.d.ts +400 -0
- package/dist/src/architecture/types.d.ts.map +1 -0
- package/dist/src/architecture/types.js +75 -0
- package/dist/src/architecture/types.js.map +1 -0
- package/dist/src/architecture/validator.d.ts +65 -0
- package/dist/src/architecture/validator.d.ts.map +1 -0
- package/dist/src/architecture/validator.js +1249 -0
- package/dist/src/architecture/validator.js.map +1 -0
- package/dist/src/core/errors.d.ts +4 -0
- package/dist/src/core/errors.d.ts.map +1 -1
- package/dist/src/core/errors.js +8 -0
- package/dist/src/core/errors.js.map +1 -1
- package/dist/src/core/types.d.ts +4 -0
- package/dist/src/core/types.d.ts.map +1 -1
- package/dist/src/mcp/schemas.d.ts +317 -0
- package/dist/src/mcp/schemas.d.ts.map +1 -1
- package/dist/src/mcp/schemas.js +151 -0
- 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 +7 -1
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/mcp/tools/architecture-passthrough.d.ts +9 -0
- package/dist/src/mcp/tools/architecture-passthrough.d.ts.map +1 -0
- package/dist/src/mcp/tools/architecture-passthrough.js +587 -0
- package/dist/src/mcp/tools/architecture-passthrough.js.map +1 -0
- package/dist/src/skills/parser.d.ts.map +1 -1
- package/dist/src/skills/parser.js +1 -0
- package/dist/src/skills/parser.js.map +1 -1
- package/dist/src/skills/types.d.ts +4 -0
- package/dist/src/skills/types.d.ts.map +1 -1
- package/dist/src/utils/claude-projects.d.ts +19 -0
- package/dist/src/utils/claude-projects.d.ts.map +1 -0
- package/dist/src/utils/claude-projects.js +157 -0
- package/dist/src/utils/claude-projects.js.map +1 -0
- package/dist/src/utils/read-only-tools.d.ts +19 -0
- package/dist/src/utils/read-only-tools.d.ts.map +1 -0
- package/dist/src/utils/read-only-tools.js +132 -0
- package/dist/src/utils/read-only-tools.js.map +1 -0
- package/package.json +7 -4
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/.mcp.json +1 -1
- package/plugin/mcp.json +1 -1
- package/plugin/skills/_shared/proactive-routing.md +29 -12
- package/plugin/skills/architecture/SKILL.md +944 -0
- package/plugin/skills/brief/SKILL.md +2 -1
- package/plugin/skills/dispatch/SKILL.md +2 -0
- package/plugin/skills/explain/SKILL.md +4 -2
- package/plugin/skills/jira-create/SKILL.md +2 -0
- package/plugin/skills/pr/SKILL.md +2 -0
- package/plugin/skills/presentation/SKILL.md +2 -0
- package/plugin/skills/review/SKILL.md +1 -0
- package/plugin/skills/review-loop/SKILL.md +3 -1
- package/plugin/skills/review-reply/SKILL.md +2 -0
- package/plugin/skills/ship/SKILL.md +2 -2
- package/plugin/skills/slack-send/SKILL.md +2 -0
- package/schemas/architecture-ir.schema.json +596 -0
|
@@ -5,6 +5,10 @@ export interface SkillFrontmatter {
|
|
|
5
5
|
triggers: string[];
|
|
6
6
|
inputs: Record<string, SkillInputDef>;
|
|
7
7
|
outputs: string[];
|
|
8
|
+
/** 있으면 proactive-routing.md 스킬 표에 triggers와 함께 실린다 */
|
|
9
|
+
routing?: {
|
|
10
|
+
note?: string;
|
|
11
|
+
};
|
|
8
12
|
}
|
|
9
13
|
export interface SkillInputDef {
|
|
10
14
|
type: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/skills/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACtC,OAAO,EAAE,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/skills/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACtC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,sDAAsD;IACtD,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7B;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,gBAAgB,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type ExecGit = (cwd: string, args: string[]) => string;
|
|
2
|
+
export interface FindClaudeProjectMemoryDirsOptions {
|
|
3
|
+
repoRoot: string;
|
|
4
|
+
/** 기본값은 ~/.claude/projects. 테스트에서 주입한다. */
|
|
5
|
+
projectsRoot?: string;
|
|
6
|
+
/** 워크트리 밖에서 같은 레포를 열었던 경로. */
|
|
7
|
+
extraRoots?: string[];
|
|
8
|
+
execGit?: ExecGit;
|
|
9
|
+
}
|
|
10
|
+
export interface ClaudeProjectMemoryMatch {
|
|
11
|
+
remoteKey: string | null;
|
|
12
|
+
matchedPaths: string[];
|
|
13
|
+
memoryDirs: string[];
|
|
14
|
+
}
|
|
15
|
+
export declare function encodeClaudeProjectDir(absPath: string): string;
|
|
16
|
+
export declare function normalizeRemoteUrl(url: string): string;
|
|
17
|
+
export declare function listWorktreePaths(repoRoot: string, execGit?: ExecGit): string[];
|
|
18
|
+
export declare function findClaudeProjectMemoryDirs(opts: FindClaudeProjectMemoryDirsOptions): ClaudeProjectMemoryMatch;
|
|
19
|
+
//# sourceMappingURL=claude-projects.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-projects.d.ts","sourceRoot":"","sources":["../../../src/utils/claude-projects.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,OAAO,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,MAAM,CAAC;AAE9D,MAAM,WAAW,kCAAkC;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8BAA8B;IAC9B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAUD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAatD;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,OAAwB,GAAG,MAAM,EAAE,CAW/F;AA+DD,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,kCAAkC,GACvC,wBAAwB,CAmD1B"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import { existsSync, readdirSync, statSync } from 'node:fs';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
const defaultExecGit = (cwd, args) => execFileSync('git', args, {
|
|
6
|
+
cwd,
|
|
7
|
+
encoding: 'utf-8',
|
|
8
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
9
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
10
|
+
});
|
|
11
|
+
export function encodeClaudeProjectDir(absPath) {
|
|
12
|
+
return absPath.replace(/[^A-Za-z0-9-]/g, '-');
|
|
13
|
+
}
|
|
14
|
+
export function normalizeRemoteUrl(url) {
|
|
15
|
+
let rest = url.trim();
|
|
16
|
+
rest = rest.replace(/^[a-z][a-z0-9+.-]*:\/\//i, '');
|
|
17
|
+
rest = rest.replace(/^[^@/]*@/, '');
|
|
18
|
+
// scp 꼴(host:org/repo)은 첫 콜론이 구분자이고 URL 꼴의 host:port는 포트를 버린다.
|
|
19
|
+
rest = rest.replace(/^([^/:]+):(\d+)\//, '$1/').replace(/^([^/:]+):/, '$1/');
|
|
20
|
+
rest = rest
|
|
21
|
+
.replace(/\/+$/, '')
|
|
22
|
+
.replace(/\.git$/, '')
|
|
23
|
+
.replace(/\/+$/, '');
|
|
24
|
+
const slash = rest.indexOf('/');
|
|
25
|
+
if (slash < 0)
|
|
26
|
+
return rest.toLowerCase();
|
|
27
|
+
return rest.slice(0, slash).toLowerCase() + rest.slice(slash);
|
|
28
|
+
}
|
|
29
|
+
export function listWorktreePaths(repoRoot, execGit = defaultExecGit) {
|
|
30
|
+
try {
|
|
31
|
+
const out = execGit(repoRoot, ['worktree', 'list', '--porcelain']);
|
|
32
|
+
return out
|
|
33
|
+
.split('\n')
|
|
34
|
+
.filter((l) => l.startsWith('worktree '))
|
|
35
|
+
.map((l) => l.slice('worktree '.length).trim())
|
|
36
|
+
.filter(Boolean);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function remoteKeyOf(dir, execGit) {
|
|
43
|
+
try {
|
|
44
|
+
const url = execGit(dir, ['remote', 'get-url', 'origin']).trim();
|
|
45
|
+
return url ? normalizeRemoteUrl(url) : null;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function isDir(p) {
|
|
52
|
+
try {
|
|
53
|
+
return statSync(p).isDirectory();
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* 인코딩은 손실이 있어(`/`, `.`, `-`가 모두 `-`) 디렉토리 이름만으론 원래 경로를 못 얻는다.
|
|
61
|
+
* 조각 사이 구분자를 실제 파일시스템에 대어 보며 존재하는 경로로 복원한다.
|
|
62
|
+
*/
|
|
63
|
+
function restorePath(encoded) {
|
|
64
|
+
if (!encoded.startsWith('-'))
|
|
65
|
+
return null;
|
|
66
|
+
const pieces = encoded.slice(1).split('-');
|
|
67
|
+
const listCache = new Map();
|
|
68
|
+
const list = (dir) => {
|
|
69
|
+
let v = listCache.get(dir);
|
|
70
|
+
if (!v) {
|
|
71
|
+
try {
|
|
72
|
+
v = readdirSync(dir);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
v = [];
|
|
76
|
+
}
|
|
77
|
+
listCache.set(dir, v);
|
|
78
|
+
}
|
|
79
|
+
return v;
|
|
80
|
+
};
|
|
81
|
+
const join2 = (dir, seg) => (dir === '/' ? `/${seg}` : `${dir}/${seg}`);
|
|
82
|
+
const walk = (i, dir, seg) => {
|
|
83
|
+
// 지금까지의 조각이 dir 아래 어떤 항목의 접두어도 아니면 더 이어 봐야 헛걸음이다.
|
|
84
|
+
if (!list(dir).some((n) => n.startsWith(seg)))
|
|
85
|
+
return null;
|
|
86
|
+
if (i === pieces.length) {
|
|
87
|
+
const full = join2(dir, seg);
|
|
88
|
+
return seg && existsSync(full) ? full : null;
|
|
89
|
+
}
|
|
90
|
+
const next = pieces[i];
|
|
91
|
+
if (seg && isDir(join2(dir, seg))) {
|
|
92
|
+
const r = walk(i + 1, join2(dir, seg), next);
|
|
93
|
+
if (r)
|
|
94
|
+
return r;
|
|
95
|
+
}
|
|
96
|
+
for (const sep of ['-', '.']) {
|
|
97
|
+
const r = walk(i + 1, dir, seg + sep + next);
|
|
98
|
+
if (r)
|
|
99
|
+
return r;
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
};
|
|
103
|
+
return walk(1, '/', pieces[0]);
|
|
104
|
+
}
|
|
105
|
+
export function findClaudeProjectMemoryDirs(opts) {
|
|
106
|
+
const execGit = opts.execGit ?? defaultExecGit;
|
|
107
|
+
const projectsRoot = opts.projectsRoot ?? join(homedir(), '.claude', 'projects');
|
|
108
|
+
const remoteKey = remoteKeyOf(opts.repoRoot, execGit);
|
|
109
|
+
const memoryDirs = new Set();
|
|
110
|
+
const matchedPaths = new Set();
|
|
111
|
+
const seenEncoded = new Set();
|
|
112
|
+
const tryPath = (absPath) => {
|
|
113
|
+
const encoded = encodeClaudeProjectDir(absPath);
|
|
114
|
+
seenEncoded.add(encoded);
|
|
115
|
+
const mem = join(projectsRoot, encoded, 'memory');
|
|
116
|
+
if (isDir(mem)) {
|
|
117
|
+
memoryDirs.add(mem);
|
|
118
|
+
matchedPaths.add(absPath);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
const firstPass = new Set([
|
|
122
|
+
opts.repoRoot,
|
|
123
|
+
...listWorktreePaths(opts.repoRoot, execGit),
|
|
124
|
+
...(opts.extraRoots ?? []),
|
|
125
|
+
]);
|
|
126
|
+
for (const p of firstPass)
|
|
127
|
+
tryPath(p);
|
|
128
|
+
if (remoteKey && isDir(projectsRoot)) {
|
|
129
|
+
let entries;
|
|
130
|
+
try {
|
|
131
|
+
entries = readdirSync(projectsRoot);
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
entries = [];
|
|
135
|
+
}
|
|
136
|
+
for (const entry of entries) {
|
|
137
|
+
if (seenEncoded.has(entry))
|
|
138
|
+
continue;
|
|
139
|
+
const mem = join(projectsRoot, entry, 'memory');
|
|
140
|
+
if (!isDir(mem))
|
|
141
|
+
continue;
|
|
142
|
+
const restored = restorePath(entry);
|
|
143
|
+
if (!restored || !isDir(restored))
|
|
144
|
+
continue;
|
|
145
|
+
if (remoteKeyOf(restored, execGit) === remoteKey) {
|
|
146
|
+
memoryDirs.add(mem);
|
|
147
|
+
matchedPaths.add(restored);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return {
|
|
152
|
+
remoteKey,
|
|
153
|
+
matchedPaths: [...matchedPaths].sort(),
|
|
154
|
+
memoryDirs: [...memoryDirs].sort(),
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=claude-projects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-projects.js","sourceRoot":"","sources":["../../../src/utils/claude-projects.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const READ_ONLY_ALLOW_WORDS: readonly ["search", "get", "read", "list", "query", "fetch"];
|
|
2
|
+
export declare const READ_ONLY_DENY_WORDS: readonly ["send", "create", "update", "delete", "post", "put", "patch", "dml", "ddl"];
|
|
3
|
+
type Classification = 'allow' | 'deny' | 'ambiguous';
|
|
4
|
+
export declare function classifyToolName(name: string): Classification;
|
|
5
|
+
export interface FilteredTools {
|
|
6
|
+
allowed: string[];
|
|
7
|
+
denied: string[];
|
|
8
|
+
ambiguous: string[];
|
|
9
|
+
}
|
|
10
|
+
export declare function filterReadOnlyTools(names: string[]): FilteredTools;
|
|
11
|
+
/** CLI 하위 명령이 이 동사로 시작해야 읽기 전용으로 본다. 도구 이름 규칙과 같은 원리다 */
|
|
12
|
+
export declare const READ_ONLY_CLI_VERBS: readonly ["list", "get", "describe"];
|
|
13
|
+
/**
|
|
14
|
+
* 셸 명령 한 줄이 읽기 전용 클라우드 조회인지 본다. 지금은 aws CLI와 aws-vault list만 판정하고 나머지는 ambiguous다.
|
|
15
|
+
* 하위 명령이 list, get, describe로 시작해야 allow이고 비밀값이나 자격증명을 내주는 동작은 이름이 get이어도 deny다.
|
|
16
|
+
*/
|
|
17
|
+
export declare function classifyCliCommand(command: string): Classification;
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=read-only-tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-only-tools.d.ts","sourceRoot":"","sources":["../../../src/utils/read-only-tools.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB,8DAA+D,CAAC;AAElG,eAAO,MAAM,oBAAoB,uFAUvB,CAAC;AAEX,KAAK,cAAc,GAAG,OAAO,GAAG,MAAM,GAAG,WAAW,CAAC;AAcrD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAuB7D;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,aAAa,CAiBlE;AAED,yDAAyD;AACzD,eAAO,MAAM,mBAAmB,sCAAuC,CAAC;AA2CxE;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CAalE"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
export const READ_ONLY_ALLOW_WORDS = ['search', 'get', 'read', 'list', 'query', 'fetch'];
|
|
2
|
+
export const READ_ONLY_DENY_WORDS = [
|
|
3
|
+
'send',
|
|
4
|
+
'create',
|
|
5
|
+
'update',
|
|
6
|
+
'delete',
|
|
7
|
+
'post',
|
|
8
|
+
'put',
|
|
9
|
+
'patch',
|
|
10
|
+
'dml',
|
|
11
|
+
'ddl',
|
|
12
|
+
];
|
|
13
|
+
function tokenize(name) {
|
|
14
|
+
if (!name)
|
|
15
|
+
return [];
|
|
16
|
+
// camelCase 경계 분리: 대문자 앞에 공백 삽입
|
|
17
|
+
const withSpaces = name.replace(/([a-z])([A-Z])/g, '$1 $2');
|
|
18
|
+
// _ - . : / 로 분리
|
|
19
|
+
const tokens = withSpaces.split(/[\s_\-.:/]+/);
|
|
20
|
+
return tokens.filter((t) => t.length > 0).map((t) => t.toLowerCase());
|
|
21
|
+
}
|
|
22
|
+
export function classifyToolName(name) {
|
|
23
|
+
const tokens = tokenize(name);
|
|
24
|
+
if (tokens.length === 0)
|
|
25
|
+
return 'ambiguous';
|
|
26
|
+
const allowWords = new Set(READ_ONLY_ALLOW_WORDS);
|
|
27
|
+
const denyWords = new Set(READ_ONLY_DENY_WORDS);
|
|
28
|
+
let hasAllow = false;
|
|
29
|
+
let hasDeny = false;
|
|
30
|
+
for (const token of tokens) {
|
|
31
|
+
if (denyWords.has(token)) {
|
|
32
|
+
hasDeny = true;
|
|
33
|
+
}
|
|
34
|
+
if (allowWords.has(token)) {
|
|
35
|
+
hasAllow = true;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (hasDeny)
|
|
39
|
+
return 'deny';
|
|
40
|
+
if (hasAllow)
|
|
41
|
+
return 'allow';
|
|
42
|
+
return 'ambiguous';
|
|
43
|
+
}
|
|
44
|
+
export function filterReadOnlyTools(names) {
|
|
45
|
+
const allowed = [];
|
|
46
|
+
const denied = [];
|
|
47
|
+
const ambiguous = [];
|
|
48
|
+
for (const name of names) {
|
|
49
|
+
const classification = classifyToolName(name);
|
|
50
|
+
if (classification === 'allow') {
|
|
51
|
+
allowed.push(name);
|
|
52
|
+
}
|
|
53
|
+
else if (classification === 'deny') {
|
|
54
|
+
denied.push(name);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
ambiguous.push(name);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return { allowed, denied, ambiguous };
|
|
61
|
+
}
|
|
62
|
+
/** CLI 하위 명령이 이 동사로 시작해야 읽기 전용으로 본다. 도구 이름 규칙과 같은 원리다 */
|
|
63
|
+
export const READ_ONLY_CLI_VERBS = ['list', 'get', 'describe'];
|
|
64
|
+
// 이름은 읽기지만 비밀값이나 임시 자격증명을 내주거나 로컬에 파일을 쓰는 동작이다
|
|
65
|
+
const CLI_SENSITIVE_WORDS = ['secret', 'password', 'token', 'credential', 'credentials'];
|
|
66
|
+
const CLI_DENY_OPERATIONS = new Set(['get-object', 'get-object-torrent']);
|
|
67
|
+
const CLI_DENY_FLAGS = new Set(['--with-decryption']);
|
|
68
|
+
// 셸 연결이나 치환, 리다이렉션이 섞이면 뒤에 무엇이 붙었는지 이 함수로는 알 수 없다
|
|
69
|
+
const SHELL_META_RE = /[;&|`<>\n\r]|\$\(/;
|
|
70
|
+
// aws 전역 옵션 중 값을 받지 않는 것. 나머지 --옵션은 다음 토큰을 값으로 먹는다
|
|
71
|
+
const AWS_FLAG_ONLY_OPTIONS = new Set([
|
|
72
|
+
'--debug',
|
|
73
|
+
'--no-verify-ssl',
|
|
74
|
+
'--no-paginate',
|
|
75
|
+
'--no-sign-request',
|
|
76
|
+
'--no-cli-pager',
|
|
77
|
+
'--cli-auto-prompt',
|
|
78
|
+
'--no-cli-auto-prompt',
|
|
79
|
+
]);
|
|
80
|
+
function awsPositionals(args) {
|
|
81
|
+
const out = [];
|
|
82
|
+
for (let i = 0; i < args.length; i++) {
|
|
83
|
+
const a = args[i];
|
|
84
|
+
if (a.startsWith('--')) {
|
|
85
|
+
if (!a.includes('=') && !AWS_FLAG_ONLY_OPTIONS.has(a))
|
|
86
|
+
i += 1;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
out.push(a);
|
|
90
|
+
if (out.length === 2)
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
return out;
|
|
94
|
+
}
|
|
95
|
+
function classifyAwsOperation(service, operation) {
|
|
96
|
+
if (service === 'configure')
|
|
97
|
+
return operation === 'list-profiles' ? 'allow' : 'deny';
|
|
98
|
+
if (CLI_DENY_OPERATIONS.has(operation))
|
|
99
|
+
return 'deny';
|
|
100
|
+
const words = operation.split('-');
|
|
101
|
+
if (words.some((w) => CLI_SENSITIVE_WORDS.includes(w)))
|
|
102
|
+
return 'deny';
|
|
103
|
+
const verb = words[0];
|
|
104
|
+
if (READ_ONLY_CLI_VERBS.includes(verb))
|
|
105
|
+
return 'allow';
|
|
106
|
+
return 'deny';
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* 셸 명령 한 줄이 읽기 전용 클라우드 조회인지 본다. 지금은 aws CLI와 aws-vault list만 판정하고 나머지는 ambiguous다.
|
|
110
|
+
* 하위 명령이 list, get, describe로 시작해야 allow이고 비밀값이나 자격증명을 내주는 동작은 이름이 get이어도 deny다.
|
|
111
|
+
*/
|
|
112
|
+
export function classifyCliCommand(command) {
|
|
113
|
+
const trimmed = command.trim();
|
|
114
|
+
if (trimmed === '')
|
|
115
|
+
return 'ambiguous';
|
|
116
|
+
if (SHELL_META_RE.test(trimmed))
|
|
117
|
+
return 'deny';
|
|
118
|
+
const tokens = trimmed.split(/\s+/);
|
|
119
|
+
const program = tokens[0];
|
|
120
|
+
const args = tokens.slice(1);
|
|
121
|
+
if (args.some((a) => CLI_DENY_FLAGS.has(a.split('=')[0])))
|
|
122
|
+
return 'deny';
|
|
123
|
+
if (program === 'aws-vault')
|
|
124
|
+
return args[0] === 'list' ? 'allow' : 'deny';
|
|
125
|
+
if (program !== 'aws')
|
|
126
|
+
return 'ambiguous';
|
|
127
|
+
const [service, operation] = awsPositionals(args);
|
|
128
|
+
if (service === undefined || operation === undefined)
|
|
129
|
+
return 'ambiguous';
|
|
130
|
+
return classifyAwsOperation(service, operation);
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=read-only-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-only-tools.js","sourceRoot":"","sources":["../../../src/utils/read-only-tools.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tienne/gestalt",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.90.0",
|
|
4
4
|
"description": "TypeScript AI Development Harness - Gestalt psychology-driven requirement clarification",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"scripts": {
|
|
30
30
|
"dev": "tsx bin/gestalt.ts",
|
|
31
31
|
"build": "tsc -p tsconfig.build.json",
|
|
32
|
-
"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 dist/bin/gestalt-hook.js && pnpm run verify:plugin && pnpm run verify:rules && pnpm run verify:rule-overlap && pnpm run verify:output-style",
|
|
32
|
+
"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 dist/bin/gestalt-hook.js && pnpm run verify:plugin && pnpm run verify:rules && pnpm run verify:rule-overlap && pnpm run verify:output-style && pnpm run verify:routing",
|
|
33
33
|
"verify:plugin": "tsx scripts/verify-plugin-assets.ts",
|
|
34
34
|
"prepublishOnly": "pnpm build",
|
|
35
35
|
"test": "vitest run",
|
|
@@ -45,10 +45,12 @@
|
|
|
45
45
|
"postversion": "pnpm run version:sync && pnpm run build:output-style",
|
|
46
46
|
"verify:rules": "tsx scripts/verify-rule-refs.ts",
|
|
47
47
|
"verify:rule-overlap": "tsx scripts/verify-rule-overlap.ts",
|
|
48
|
-
"gate": "pnpm typecheck && pnpm verify:rules && pnpm verify:rule-overlap && pnpm lint && pnpm format:check && pnpm build && pnpm test",
|
|
48
|
+
"gate": "pnpm typecheck && pnpm verify:rules && pnpm verify:rule-overlap && pnpm verify:routing && pnpm lint && pnpm format:check && pnpm build && pnpm test",
|
|
49
49
|
"humanize:baseline": "tsx scripts/humanize-baseline.ts",
|
|
50
50
|
"build:output-style": "tsx scripts/build-output-style.ts",
|
|
51
|
-
"verify:output-style": "tsx scripts/build-output-style.ts --dry-run"
|
|
51
|
+
"verify:output-style": "tsx scripts/build-output-style.ts --dry-run",
|
|
52
|
+
"build:routing": "tsx scripts/build-skill-routing.ts",
|
|
53
|
+
"verify:routing": "tsx scripts/build-skill-routing.ts --check"
|
|
52
54
|
},
|
|
53
55
|
"dependencies": {
|
|
54
56
|
"@anthropic-ai/sdk": "^0.39.0",
|
|
@@ -58,6 +60,7 @@
|
|
|
58
60
|
"chokidar": "^4.0.3",
|
|
59
61
|
"commander": "^13.1.0",
|
|
60
62
|
"dotenv": "^17.3.1",
|
|
63
|
+
"elkjs": "^0.12.0",
|
|
61
64
|
"gray-matter": "^4.0.3",
|
|
62
65
|
"node-notifier": "^10.0.1",
|
|
63
66
|
"node-pty": "^1.1.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gestalt",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.90.0",
|
|
4
4
|
"description": "Gestalt psychology-driven AI development harness. Transforms scattered requirements into structured, validated specifications through interactive interviews.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "tienne"
|
package/plugin/.mcp.json
CHANGED
package/plugin/mcp.json
CHANGED
|
@@ -47,19 +47,15 @@
|
|
|
47
47
|
| README, API 문서, 가이드, 개발자 문서 작성 | `technical-writer` |
|
|
48
48
|
| 발표 슬라이드 콘텐츠·문구·데이터 요약·발표 노트 작성 | `presentation-writer` |
|
|
49
49
|
| 슬라이드 Reveal.js 구조·템플릿·비주얼 디자인 자문 | `presentation-designer` |
|
|
50
|
-
| 발표자료·슬라이드·프레젠테이션 제작 요청 ("발표자료 만들어줘", "슬라이드 만들어줘", "피치덱") | `presentation` 스킬 사용 (presentation-writer 콘텐츠 → 승인 단계 → presentation-designer 디자인 → Reveal.js HTML) |
|
|
51
50
|
| 시스템 설계, 아키텍처 리뷰, 설계 패턴 | `architect` |
|
|
52
51
|
| 보안 취약점, 인증/인가, 시크릿 노출 검토 | `security-reviewer` |
|
|
53
52
|
| 성능 병목, N+1, 메모리 누수 분석 | `performance-reviewer` |
|
|
54
53
|
| 코드 가독성, SOLID, 에러 처리 리뷰 | `quality-reviewer` |
|
|
55
54
|
| 테스트 케이스, 엣지 케이스, QA | `qa-engineer` |
|
|
56
55
|
| UX 문구 작성·교정, 버튼 텍스트, 에러 메시지, 토스트, 온보딩 카피 | `ux-writer` |
|
|
57
|
-
| 대상 지정해서 설명 요청 ("기획팀한테 설명해줘", "쉽게 풀어줘", "ELI5", "이 에러 뭐야") | `explain` 스킬 사용 (소스 확보 → 대상 확정 → explainer 위임 → explain-check → 재시도) |
|
|
58
56
|
| 설명 문장만 빠르게 필요할 때 | `explainer` 에이전트 |
|
|
59
57
|
| 슬랙·메신저 메시지 작성 또는 딱딱한/AI스러운 초안을 본인 말투로 다듬기 | `slack-messenger` |
|
|
60
|
-
| 슬랙 메시지 전송·예약 발송 요청 ("~라고 보내줘", "공지해줘", "예약 발송해줘") | `slack-send` 스킬 사용 (내부적으로 slack-messenger 다듬기 → 승인 단계 → 전송) |
|
|
61
58
|
| 지라 티켓 본문 작성·구조화 (제목, 설명, 완료 조건, 이슈타입 추천) | `jira-writer` |
|
|
62
|
-
| 지라 티켓 생성 요청 ("티켓 만들어줘", "이슈 생성해줘", "지라에 올려줘") | `jira-create` 스킬 사용 (내부적으로 jira-writer 구조화 → 프로젝트·필드 확정 → 승인 단계 → createJiraIssue) |
|
|
63
59
|
| UI, React, 접근성, 컴포넌트 설계 | `frontend-developer` — 단 레포가 이 범위를 `delegate`로 선언했으면 그쪽이 이긴다 (위 절) |
|
|
64
60
|
| UI·React 코드 리뷰, 접근성·번들 최적화 검토 | `frontend-reviewer` — 단 레포가 이 범위를 `delegate`로 선언했으면 그쪽이 이긴다 (위 절) |
|
|
65
61
|
| 주석 검토 ("주석 좀 봐줘", 불필요한 주석·죽은 코드·티켓 없는 TODO 확인) | `comment-reviewer` |
|
|
@@ -69,21 +65,42 @@
|
|
|
69
65
|
| 요구사항 정리, 로드맵, 유저 스토리 | `product-planner` |
|
|
70
66
|
| 성과 분석·KPI 해석·분기 성과 보고·회고 리포트 | `impact-writer` |
|
|
71
67
|
| 제안서, RFC, 의사결정 메모 등 설득·합의용 기획 산문 | `impact-writer` |
|
|
72
|
-
| 성과 보고서·제안서·RFC·회고 작성 요청 ("성과 보고서 써줘", "제안서 작성", "RFC 써줘") | `brief` 스킬 사용 |
|
|
73
68
|
| 기술 분석, 벤치마크, 사례 조사 | `researcher` |
|
|
74
69
|
| 내 PR에 달린 리뷰 코멘트 답변 본문 작성 (반영·대안·보류·질문) | `code-review-responder` |
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
70
|
+
|
|
71
|
+
## 스킬 트리거
|
|
72
|
+
|
|
73
|
+
요청 문구가 아래 표에 걸리면 그 스킬을 쓴다. 에이전트 표와 둘 다 걸리면 스킬이 먼저다 — 스킬은 에이전트를 부르기 전에 승인 단계나 게시 같은 절차를 붙인다.
|
|
74
|
+
|
|
75
|
+
<!-- skill-routing:start -->
|
|
76
|
+
<!-- 생성물이다. 각 SKILL.md의 triggers와 routing.note를 고치고 pnpm build:routing 으로 다시 뽑는다 -->
|
|
77
|
+
|
|
78
|
+
| 요청 문구 | 스킬 | 비고 |
|
|
79
|
+
|-----------|------|------|
|
|
80
|
+
| "architecture", "아키텍처 그려줘", "아키텍처 뷰", "화면에서 DB까지", "이 화면이 어떤 API를 부르는지 그려줘", "배포 경로 그려줘", "CI/CD 경로 그려줘", "서빙 인프라 그려줘", "하네스 구조 그려줘", "스킬이랑 MCP 도구 관계 그려줘", "시퀀스 그려줘", "호출 순서 그려줘", "데이터 흐름 그려줘", "데이터 리니지 그려줘", "업무 흐름 그려줘", "결재 절차 그려줘", "둘 구조 비교해서 그려줘", "네트워크 구성도 그려줘", "인프라 구성도 그려줘", "조직도 그려줘", "업무 시스템 관계 그려줘", "문서 지도 그려줘", "KB 레포 그려줘", "문서 구멍 찾아줘", "오래된 문서 찾아줘", "이 PR로 손봐야 할 문서 찾아줘", "코드 바뀐 걸로 낡은 문서 골라줘", "아키텍처 그림 합쳐줘" | `architecture` 스킬 사용 | 맥락 소스 찾기 → 읽기 전용 걸러내기 → 탐색 → IR validate → 미해결 질문 → render. 문서 레포는 scan_docs → link_docs → render. 설계 리뷰나 자문이면 `architect` |
|
|
81
|
+
| "성과 보고서", "성과 분석", "분기 리포트", "분기 보고", "KPI 리포트", "제안서 작성", "제안서 써줘", "RFC 써줘", "RFC 작성", "의사결정 메모", "회고 정리", "회고 써줘", "경영진 보고 자료", "성과 문서", "이 문서 다시 써줘", "보고서 보완" | `brief` 스킬 사용 | |
|
|
82
|
+
| "orca로 실행", "orca로 병렬", "워커로 뿌려", "터미널로 뿌려", "병렬 디스패치", "다른 에이전트로 실행", "codex로 실행", "워커 띄워서 실행" | `dispatch` 스킬 사용 | 런타임 감지 → 같은 워크트리에 터미널 → worker_done 대기 → ready 재계산. 런타임 없으면 execute의 기본 병렬 경로 |
|
|
83
|
+
| "설명해줘", "쉽게 풀어줘", "풀어서 설명", "이해하기 쉽게", "쉽게 말하면", "이거 뭐야", "이 에러 뭐야", "무슨 뜻이야", "ELI5", "한테 설명해줘", "에게 설명해줘", "기획팀한테", "비개발자한테", "경영진 보고용으로 설명" | `explain` 스킬 사용 | 소스 확보 → 대상 확정 → explainer 위임 → explain-check → 재시도. 설명 문장만 빠르게 필요하면 `explainer` 에이전트 |
|
|
84
|
+
| "지라 티켓", "지라 이슈", "티켓 만들어", "티켓 생성", "이슈 만들어", "이슈 생성", "지라에 올려", "지라에 등록", "백로그에 추가", "jira 티켓", "jira 이슈", "create jira" | `jira-create` 스킬 사용 | 내부적으로 jira-writer 구조화 → 프로젝트·필드 확정 → 승인 단계 → createJiraIssue |
|
|
85
|
+
| "PR 작성", "PR 만들어", "PR 써줘", "PR 올려", "풀리퀘", "풀 리퀘스트", "pull request", "create PR" | `pr` 스킬 사용 | 다른 레포의 PR 스킬과 이름이 겹치면 `gestalt:pr`로 부른다 |
|
|
86
|
+
| "발표자료 만들", "발표 자료 만들", "슬라이드 만들", "프레젠테이션 만들", "프레젠테이션 제작", "덱 만들", "피치덱", "피치 덱", "발표 슬라이드", "슬라이드 제작", "reveal 슬라이드" | `presentation` 스킬 사용 | presentation-writer 콘텐츠 → 승인 단계 → presentation-designer 디자인 → Reveal.js HTML |
|
|
87
|
+
| "PR 리뷰", "브랜치 리뷰", "코드 리뷰", "diff 리뷰", "review PR", "review branch", "이 브랜치 리뷰", "변경사항 리뷰", "PR에 코멘트 남겨줘", "리뷰 코멘트 달아줘", "PR에 인라인 코멘트", "리뷰 결과 PR에 게시", "주니어한테 설명하듯 리뷰", "신입이 읽을 리뷰" | `review` 스킬 사용 | |
|
|
88
|
+
| "리뷰 루프", "review loop", "리뷰하고 지켜봐줘", "리뷰 대응 모니터링", "대응하면 재리뷰", "리젝하고 지켜봐줘", "변경 요청 남겨줘", "approve 날 때까지", "리뷰어로 끝까지", "재리뷰 반복", "PR 계속 지켜봐줘" | `review-loop` 스킬 사용 | 리뷰 → 인라인 코멘트 → 판정 게시 → 대응 확인 → 재리뷰. **한 번 부르면 한 번 본다** — 이어 보려면 사람이 다시 부른다. 리뷰 한 번만이면 `review`, 내 PR을 밀어 올리는 쪽은 `ship` |
|
|
89
|
+
| "리뷰 반영", "리뷰 코멘트 답", "리뷰 답변", "리뷰 답글", "받은 리뷰 처리", "리뷰 피드백 반영", "PR 코멘트 처리", "리뷰 코멘트 처리", "코멘트에 답해줘", "reply to review", "리뷰어 의견 반영" | `review-reply` 스킬 사용 | 스레드 수집 → 유형 분류 승인 → 수정·커밋 → 답글 승인 → 게시 |
|
|
90
|
+
| "출하", "ship", "PR 올릴 때까지", "리뷰 통과할 때까지", "코파일럿 리뷰까지", "copilot 리뷰 받아줘", "draft PR 올리고 리뷰" | `ship` 스킬 사용 | 로컬 PR → 리뷰 수렴 루프 → 승인 → draft PR → Copilot 수렴 루프 → ready. 리뷰 한 번만이면 `review` |
|
|
91
|
+
| "슬랙 보내", "슬랙으로 보내", "메시지 보내", "메세지 보내", "전달해줘", "공지해줘", "공지 올려줘", "슬랙에 올려줘", "슬랙 메시지 전송", "예약 발송", "예약메세지", "예약 메시지", "이따 보내", "내일 아침에 보내", "9시에 보내" | `slack-send` 스킬 사용 | 내부적으로 slack-messenger 다듬기 → 승인 단계 → 전송 |
|
|
92
|
+
|
|
93
|
+
<!-- skill-routing:end -->
|
|
81
94
|
|
|
82
95
|
## 표를 늘릴 때
|
|
83
96
|
|
|
84
|
-
여기 한 줄 추가하면 끝이다. `CLAUDE.md`와 `agent/SKILL.md`를 따라가서 고칠 필요가 없다 — 둘 다
|
|
97
|
+
에이전트 줄은 여기 한 줄 추가하면 끝이다. `CLAUDE.md`와 `agent/SKILL.md`를 따라가서 고칠 필요가 없다 — 둘 다
|
|
85
98
|
이 파일을 가리키기만 하기 때문이다.
|
|
86
99
|
|
|
100
|
+
스킬 줄은 여기서 고치지 않는다. 그 스킬 SKILL.md의 `triggers`를 고친다. 표에 처음 올리는 스킬이면
|
|
101
|
+
frontmatter에 `routing`도 둔다 (비고가 없으면 `routing: {}`). 그다음 `pnpm build:routing`으로 다시
|
|
102
|
+
뽑는다. 손으로 고치면 `pnpm gate`의 `verify:routing`에서 걸린다.
|
|
103
|
+
|
|
87
104
|
**특정 레포에서만 다른 데로 보내고 싶은 거라면 표를 고치지 않는다.** 그 레포 `gestalt.json`에
|
|
88
105
|
`delegate` 소스를 선언한다. 이 표는 게슈탈트가 설치된 모든 레포가 보는 자리라, 한 조직에서만
|
|
89
106
|
쓰는 스킬 이름이 들어가면 나머지 레포는 없는 데로 가라는 지시를 읽게 된다.
|