@einja/dev-cli 0.1.7 → 0.1.9
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/README.md +4 -5
- package/dist/cli.js +4 -4
- package/dist/cli.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +4 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +16 -9
- package/dist/commands/sync.js.map +1 -1
- package/dist/commands/task-loop/index.d.ts +18 -0
- package/dist/commands/task-loop/index.d.ts.map +1 -0
- package/dist/commands/task-loop/index.js +343 -0
- package/dist/commands/task-loop/index.js.map +1 -0
- package/dist/commands/task-loop/lib/branch-manager.d.ts +66 -0
- package/dist/commands/task-loop/lib/branch-manager.d.ts.map +1 -0
- package/dist/commands/task-loop/lib/branch-manager.js +697 -0
- package/dist/commands/task-loop/lib/branch-manager.js.map +1 -0
- package/dist/commands/task-loop/lib/conflict-handler.d.ts +8 -0
- package/dist/commands/task-loop/lib/conflict-handler.d.ts.map +1 -0
- package/dist/commands/task-loop/lib/conflict-handler.js +68 -0
- package/dist/commands/task-loop/lib/conflict-handler.js.map +1 -0
- package/dist/commands/task-loop/lib/dependency-resolver.d.ts +45 -0
- package/dist/commands/task-loop/lib/dependency-resolver.d.ts.map +1 -0
- package/dist/commands/task-loop/lib/dependency-resolver.js +184 -0
- package/dist/commands/task-loop/lib/dependency-resolver.js.map +1 -0
- package/dist/commands/task-loop/lib/gh-setup.d.ts +15 -0
- package/dist/commands/task-loop/lib/gh-setup.d.ts.map +1 -0
- package/dist/commands/task-loop/lib/gh-setup.js +196 -0
- package/dist/commands/task-loop/lib/gh-setup.js.map +1 -0
- package/dist/commands/task-loop/lib/github-client.d.ts +27 -0
- package/dist/commands/task-loop/lib/github-client.d.ts.map +1 -0
- package/dist/commands/task-loop/lib/github-client.js +110 -0
- package/dist/commands/task-loop/lib/github-client.js.map +1 -0
- package/dist/commands/task-loop/lib/issue-parser.d.ts +27 -0
- package/dist/commands/task-loop/lib/issue-parser.d.ts.map +1 -0
- package/dist/commands/task-loop/lib/issue-parser.js +254 -0
- package/dist/commands/task-loop/lib/issue-parser.js.map +1 -0
- package/dist/commands/task-loop/lib/project-selector.d.ts +15 -0
- package/dist/commands/task-loop/lib/project-selector.d.ts.map +1 -0
- package/dist/commands/task-loop/lib/project-selector.js +187 -0
- package/dist/commands/task-loop/lib/project-selector.js.map +1 -0
- package/dist/commands/task-loop/lib/task-number-utils.d.ts +56 -0
- package/dist/commands/task-loop/lib/task-number-utils.d.ts.map +1 -0
- package/dist/commands/task-loop/lib/task-number-utils.js +114 -0
- package/dist/commands/task-loop/lib/task-number-utils.js.map +1 -0
- package/dist/commands/task-loop/lib/task-state-manager.d.ts +59 -0
- package/dist/commands/task-loop/lib/task-state-manager.d.ts.map +1 -0
- package/dist/commands/task-loop/lib/task-state-manager.js +184 -0
- package/dist/commands/task-loop/lib/task-state-manager.js.map +1 -0
- package/dist/commands/task-loop/lib/types.d.ts +93 -0
- package/dist/commands/task-loop/lib/types.d.ts.map +1 -0
- package/dist/commands/task-loop/lib/types.js +5 -0
- package/dist/commands/task-loop/lib/types.js.map +1 -0
- package/dist/commands/task-loop/lib/vibe-kanban-client.d.ts +82 -0
- package/dist/commands/task-loop/lib/vibe-kanban-client.d.ts.map +1 -0
- package/dist/commands/task-loop/lib/vibe-kanban-client.js +280 -0
- package/dist/commands/task-loop/lib/vibe-kanban-client.js.map +1 -0
- package/dist/commands/task-loop/lib/vibe-kanban-rest-client.d.ts +42 -0
- package/dist/commands/task-loop/lib/vibe-kanban-rest-client.d.ts.map +1 -0
- package/dist/commands/task-loop/lib/vibe-kanban-rest-client.js +122 -0
- package/dist/commands/task-loop/lib/vibe-kanban-rest-client.js.map +1 -0
- package/dist/lib/sync/batch-processor.test.js +1 -1
- package/dist/lib/sync/batch-processor.test.js.map +1 -1
- package/dist/lib/sync/diff-engine.js +1 -1
- package/dist/lib/sync/diff-engine.js.map +1 -1
- package/dist/lib/sync/hash-cache.d.ts +10 -4
- package/dist/lib/sync/hash-cache.d.ts.map +1 -1
- package/dist/lib/sync/hash-cache.js +28 -9
- package/dist/lib/sync/hash-cache.js.map +1 -1
- package/dist/lib/sync/hash-cache.test.js +69 -38
- package/dist/lib/sync/hash-cache.test.js.map +1 -1
- package/dist/lib/sync/metadata-manager.d.ts.map +1 -1
- package/dist/lib/sync/metadata-manager.js +3 -4
- package/dist/lib/sync/metadata-manager.js.map +1 -1
- package/dist/lib/sync/performance.test.js +4 -5
- package/dist/lib/sync/performance.test.js.map +1 -1
- package/package.json +2 -1
- package/presets/minimal/preset.yaml +0 -1
- package/scaffolds/CLAUDE.md.template +81 -13
- package/dist/commands/task-loop.d.ts +0 -11
- package/dist/commands/task-loop.d.ts.map +0 -1
- package/dist/commands/task-loop.js +0 -81
- package/dist/commands/task-loop.js.map +0 -1
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub Issue 操作(gh CLI wrapper)
|
|
3
|
+
*/
|
|
4
|
+
import { execSync } from "node:child_process";
|
|
5
|
+
/**
|
|
6
|
+
* GitHub Issue を取得
|
|
7
|
+
*/
|
|
8
|
+
export function getIssue(issueNumber) {
|
|
9
|
+
try {
|
|
10
|
+
const result = execSync(`gh issue view ${issueNumber} --json number,title,body,state`, {
|
|
11
|
+
encoding: "utf-8",
|
|
12
|
+
});
|
|
13
|
+
const data = JSON.parse(result);
|
|
14
|
+
return {
|
|
15
|
+
number: data.number,
|
|
16
|
+
title: data.title,
|
|
17
|
+
body: data.body,
|
|
18
|
+
state: data.state,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
throw new Error(`GitHub Issue #${issueNumber} の取得に失敗しました: ${error}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* GitHub Issue の本文を更新
|
|
27
|
+
*/
|
|
28
|
+
export function updateIssueBody(issueNumber, newBody) {
|
|
29
|
+
try {
|
|
30
|
+
// 本文をファイルに書き出してから gh コマンドで更新(長い本文対策)
|
|
31
|
+
const fs = require("node:fs");
|
|
32
|
+
const os = require("node:os");
|
|
33
|
+
const path = require("node:path");
|
|
34
|
+
const tempFile = path.join(os.tmpdir(), `issue-body-${issueNumber}.md`);
|
|
35
|
+
fs.writeFileSync(tempFile, newBody, "utf-8");
|
|
36
|
+
execSync(`gh issue edit ${issueNumber} --body-file "${tempFile}"`, {
|
|
37
|
+
encoding: "utf-8",
|
|
38
|
+
});
|
|
39
|
+
// 一時ファイルを削除
|
|
40
|
+
fs.unlinkSync(tempFile);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
throw new Error(`GitHub Issue #${issueNumber} の更新に失敗しました: ${error}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* GitHub Issue の状態を確認(Open/Closed)
|
|
48
|
+
*/
|
|
49
|
+
export function isIssueClosed(issueNumber) {
|
|
50
|
+
try {
|
|
51
|
+
const result = execSync(`gh issue view ${issueNumber} --json state`, {
|
|
52
|
+
encoding: "utf-8",
|
|
53
|
+
});
|
|
54
|
+
const data = JSON.parse(result);
|
|
55
|
+
return data.state === "CLOSED";
|
|
56
|
+
}
|
|
57
|
+
catch (_a) {
|
|
58
|
+
// Issue が見つからない場合は閉じられていないとみなす
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* リポジトリ情報を取得
|
|
64
|
+
*/
|
|
65
|
+
export function getRepoInfo() {
|
|
66
|
+
try {
|
|
67
|
+
const result = execSync("gh repo view --json owner,name,defaultBranchRef", {
|
|
68
|
+
encoding: "utf-8",
|
|
69
|
+
});
|
|
70
|
+
const data = JSON.parse(result);
|
|
71
|
+
return {
|
|
72
|
+
owner: data.owner.login,
|
|
73
|
+
name: data.name,
|
|
74
|
+
defaultBranch: data.defaultBranchRef.name,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
throw new Error(`リポジトリ情報の取得に失敗しました: ${error}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Issue 本文のタスクグループを完了マークに更新
|
|
83
|
+
* - [ ] **X.Y タスク名** → - [x] **X.Y タスク名**
|
|
84
|
+
* - [ ] X.Y タスク名 → - [x] X.Y タスク名
|
|
85
|
+
*/
|
|
86
|
+
export function markTaskGroupAsCompleted(issueBody, taskGroupId) {
|
|
87
|
+
// パターン1: ボールドあり - [ ] **X.Y タスク名**
|
|
88
|
+
const boldPattern = new RegExp(`^(\\s*)- \\[ \\] (\\*\\*${escapeRegex(taskGroupId)}\\s)(.*)$`, "gm");
|
|
89
|
+
// パターン2: ボールドなし - [ ] X.Y タスク名
|
|
90
|
+
const plainPattern = new RegExp(`^(\\s*)- \\[ \\] (${escapeRegex(taskGroupId)}\\s)(.*)$`, "gm");
|
|
91
|
+
let result = issueBody;
|
|
92
|
+
// ボールドありパターンを置換
|
|
93
|
+
result = result.replace(boldPattern, (_match, indent, prefix, rest) => {
|
|
94
|
+
const cleanedRest = rest.replace(/\s*<!--\s*🔄\s*着手中\s*-->\s*$/, "");
|
|
95
|
+
return `${indent}- [x] ${prefix}${cleanedRest}`;
|
|
96
|
+
});
|
|
97
|
+
// ボールドなしパターンを置換
|
|
98
|
+
result = result.replace(plainPattern, (_match, indent, prefix, rest) => {
|
|
99
|
+
const cleanedRest = rest.replace(/\s*<!--\s*🔄\s*着手中\s*-->\s*$/, "");
|
|
100
|
+
return `${indent}- [x] ${prefix}${cleanedRest}`;
|
|
101
|
+
});
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* 正規表現のエスケープ
|
|
106
|
+
*/
|
|
107
|
+
function escapeRegex(str) {
|
|
108
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=github-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-client.js","sourceRoot":"","sources":["../../../../src/commands/task-loop/lib/github-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub Issue Markdown パーサー
|
|
3
|
+
*
|
|
4
|
+
* Issue 本文からタスク構造を抽出
|
|
5
|
+
*/
|
|
6
|
+
import type { GitHubIssue, ParsedIssue, TaskGroup } from "./types.js";
|
|
7
|
+
/**
|
|
8
|
+
* Issue 本文を解析してタスク構造を抽出
|
|
9
|
+
*/
|
|
10
|
+
export declare function parseIssueBody(issue: GitHubIssue): ParsedIssue;
|
|
11
|
+
/**
|
|
12
|
+
* タスクグループ ID からタスクグループを取得
|
|
13
|
+
*/
|
|
14
|
+
export declare function findTaskGroupById(parsedIssue: ParsedIssue, taskGroupId: string): TaskGroup | null;
|
|
15
|
+
/**
|
|
16
|
+
* 全タスクグループをフラットなリストで取得
|
|
17
|
+
*/
|
|
18
|
+
export declare function getAllTaskGroups(parsedIssue: ParsedIssue): TaskGroup[];
|
|
19
|
+
/**
|
|
20
|
+
* 完了済みタスクグループの ID 一覧を取得
|
|
21
|
+
*/
|
|
22
|
+
export declare function getCompletedTaskGroupIds(parsedIssue: ParsedIssue): Set<string>;
|
|
23
|
+
/**
|
|
24
|
+
* 未着手タスクグループの一覧を取得
|
|
25
|
+
*/
|
|
26
|
+
export declare function getPendingTaskGroups(parsedIssue: ParsedIssue): TaskGroup[];
|
|
27
|
+
//# sourceMappingURL=issue-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"issue-parser.d.ts","sourceRoot":"","sources":["../../../../src/commands/task-loop/lib/issue-parser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAe,SAAS,EAAc,MAAM,YAAY,CAAC;AAE/F;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,WAAW,CAS9D;AAkOD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CASjG;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,WAAW,GAAG,SAAS,EAAE,CAMtE;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,CAU9E;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,WAAW,GAAG,SAAS,EAAE,CAU1E"}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub Issue Markdown パーサー
|
|
3
|
+
*
|
|
4
|
+
* Issue 本文からタスク構造を抽出
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Issue 本文を解析してタスク構造を抽出
|
|
8
|
+
*/
|
|
9
|
+
export function parseIssueBody(issue) {
|
|
10
|
+
const phases = extractPhases(issue.body);
|
|
11
|
+
return {
|
|
12
|
+
issueNumber: issue.number,
|
|
13
|
+
title: issue.title,
|
|
14
|
+
body: issue.body,
|
|
15
|
+
phases,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Phase 構造を抽出
|
|
20
|
+
*/
|
|
21
|
+
function extractPhases(body) {
|
|
22
|
+
const phases = [];
|
|
23
|
+
// "### Phase X:" または "### Phase X:" パターンを検索
|
|
24
|
+
const _phasePattern = /^###\s*Phase\s*(\d+):\s*(.*)$/gim;
|
|
25
|
+
const lines = body.split("\n");
|
|
26
|
+
let currentPhase = null;
|
|
27
|
+
let currentTaskGroupLines = [];
|
|
28
|
+
for (let i = 0; i < lines.length; i++) {
|
|
29
|
+
const line = lines[i];
|
|
30
|
+
const phaseMatch = line === null || line === void 0 ? void 0 : line.match(/^###\s*Phase\s*(\d+):\s*(.*)$/i);
|
|
31
|
+
if (phaseMatch) {
|
|
32
|
+
// 前の Phase を保存
|
|
33
|
+
if (currentPhase) {
|
|
34
|
+
currentPhase.taskGroups = extractTaskGroups(currentTaskGroupLines.join("\n"), currentPhase.number);
|
|
35
|
+
phases.push(currentPhase);
|
|
36
|
+
}
|
|
37
|
+
// 新しい Phase を開始
|
|
38
|
+
currentPhase = {
|
|
39
|
+
number: Number.parseInt(phaseMatch[1], 10),
|
|
40
|
+
name: phaseMatch[2].trim(),
|
|
41
|
+
taskGroups: [],
|
|
42
|
+
};
|
|
43
|
+
currentTaskGroupLines = [];
|
|
44
|
+
}
|
|
45
|
+
else if (currentPhase && line !== undefined) {
|
|
46
|
+
currentTaskGroupLines.push(line);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// 最後の Phase を保存
|
|
50
|
+
if (currentPhase) {
|
|
51
|
+
currentPhase.taskGroups = extractTaskGroups(currentTaskGroupLines.join("\n"), currentPhase.number);
|
|
52
|
+
phases.push(currentPhase);
|
|
53
|
+
}
|
|
54
|
+
return phases;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* タスクグループを抽出
|
|
58
|
+
*/
|
|
59
|
+
function extractTaskGroups(content, phaseNumber) {
|
|
60
|
+
var _a, _b, _c, _d;
|
|
61
|
+
const taskGroups = [];
|
|
62
|
+
// タスクグループパターン: - [ ] **X.Y タスク名** or - [x] **X.Y タスク名**
|
|
63
|
+
const lines = content.split("\n");
|
|
64
|
+
let currentTaskGroup = null;
|
|
65
|
+
let currentTaskGroupContent = [];
|
|
66
|
+
for (const line of lines) {
|
|
67
|
+
// タスクグループ行のマッチ
|
|
68
|
+
// ボールドあり: - [ ] **1.1 名前**
|
|
69
|
+
// ボールドなし: - [ ] 1.1 名前
|
|
70
|
+
const taskGroupMatch = line.match(/^(\s*)-\s*\[([ xX])\]\s*\*\*(\d+\.\d+)\s+(.+?)\*\*\s*$/) ||
|
|
71
|
+
line.match(/^(\s*)-\s*\[([ xX])\]\s*(\d+\.\d+)\s+(.+)$/);
|
|
72
|
+
if (taskGroupMatch) {
|
|
73
|
+
// 前のタスクグループを保存
|
|
74
|
+
if (currentTaskGroup === null || currentTaskGroup === void 0 ? void 0 : currentTaskGroup.id) {
|
|
75
|
+
const fullContent = currentTaskGroupContent.join("\n");
|
|
76
|
+
const metadata = parseMetadata(fullContent, currentTaskGroup.id);
|
|
77
|
+
const tasks = extractTasks(fullContent, currentTaskGroup.id);
|
|
78
|
+
taskGroups.push({
|
|
79
|
+
id: currentTaskGroup.id,
|
|
80
|
+
name: (_a = currentTaskGroup.name) !== null && _a !== void 0 ? _a : "",
|
|
81
|
+
phaseNumber,
|
|
82
|
+
status: (_b = currentTaskGroup.status) !== null && _b !== void 0 ? _b : "pending",
|
|
83
|
+
dependencies: metadata.dependencies,
|
|
84
|
+
completionCriteria: metadata.completionCriteria,
|
|
85
|
+
tasks,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
// 新しいタスクグループを開始
|
|
89
|
+
const checkboxStatus = taskGroupMatch[2];
|
|
90
|
+
const taskGroupId = taskGroupMatch[3];
|
|
91
|
+
const taskGroupName = taskGroupMatch[4];
|
|
92
|
+
// ステータスはチェックボックスのみで判定
|
|
93
|
+
// 着手中かどうかはVibe-Kanbanのタスク存在で判定する
|
|
94
|
+
const status = checkboxStatus.toLowerCase() === "x" ? "completed" : "pending";
|
|
95
|
+
currentTaskGroup = {
|
|
96
|
+
id: taskGroupId,
|
|
97
|
+
name: taskGroupName.trim(),
|
|
98
|
+
status,
|
|
99
|
+
};
|
|
100
|
+
currentTaskGroupContent = [line];
|
|
101
|
+
}
|
|
102
|
+
else if (currentTaskGroup) {
|
|
103
|
+
currentTaskGroupContent.push(line);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// 最後のタスクグループを保存
|
|
107
|
+
if (currentTaskGroup === null || currentTaskGroup === void 0 ? void 0 : currentTaskGroup.id) {
|
|
108
|
+
const fullContent = currentTaskGroupContent.join("\n");
|
|
109
|
+
const metadata = parseMetadata(fullContent, currentTaskGroup.id);
|
|
110
|
+
const tasks = extractTasks(fullContent, currentTaskGroup.id);
|
|
111
|
+
taskGroups.push({
|
|
112
|
+
id: currentTaskGroup.id,
|
|
113
|
+
name: (_c = currentTaskGroup.name) !== null && _c !== void 0 ? _c : "",
|
|
114
|
+
phaseNumber,
|
|
115
|
+
status: (_d = currentTaskGroup.status) !== null && _d !== void 0 ? _d : "pending",
|
|
116
|
+
dependencies: metadata.dependencies,
|
|
117
|
+
completionCriteria: metadata.completionCriteria,
|
|
118
|
+
tasks,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return taskGroups;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* 個別タスクを抽出
|
|
125
|
+
*/
|
|
126
|
+
function extractTasks(content, taskGroupId) {
|
|
127
|
+
const tasks = [];
|
|
128
|
+
const lines = content.split("\n");
|
|
129
|
+
// タスクパターン: - X.Y.Z タスク名 または X.Y.Z タスク名
|
|
130
|
+
const taskPattern = new RegExp(`^\\s*-?\\s*(${escapeRegex(taskGroupId)}\\.\\d+)\\s+(.+)$`);
|
|
131
|
+
for (const line of lines) {
|
|
132
|
+
const match = line.match(taskPattern);
|
|
133
|
+
if (match) {
|
|
134
|
+
tasks.push({
|
|
135
|
+
id: match[1],
|
|
136
|
+
name: match[2].trim(),
|
|
137
|
+
subtasks: [],
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return tasks;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* メタデータを抽出(依存関係、完了条件)
|
|
145
|
+
*
|
|
146
|
+
* 依存関係のパターン:
|
|
147
|
+
* - タスクグループ間: X.Y(例: 1.1, 2.3)
|
|
148
|
+
* - Phase間: Phase X完了
|
|
149
|
+
* - Issue間: #123
|
|
150
|
+
*
|
|
151
|
+
* サブタスク間の依存関係(X.Y.Z形式)はタスクグループID(X.Y)に変換する
|
|
152
|
+
* 自己参照(自分自身への依存)は除外する
|
|
153
|
+
*
|
|
154
|
+
* @param content タスクグループのコンテンツ
|
|
155
|
+
* @param taskGroupId 処理中のタスクグループID(自己参照除外用)
|
|
156
|
+
*/
|
|
157
|
+
function parseMetadata(content, taskGroupId) {
|
|
158
|
+
const dependencies = [];
|
|
159
|
+
let completionCriteria = "";
|
|
160
|
+
const lines = content.split("\n");
|
|
161
|
+
for (const line of lines) {
|
|
162
|
+
// 依存関係: **依存関係**: ...
|
|
163
|
+
const depMatch = line.match(/\*\*依存関係\*\*:\s*(.+)$/);
|
|
164
|
+
if (depMatch) {
|
|
165
|
+
const depText = depMatch[1].trim();
|
|
166
|
+
if (depText === "なし" || depText === "-" || depText === "") {
|
|
167
|
+
// 依存関係なし
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
// カンマ区切りまたは単一の依存関係
|
|
171
|
+
const deps = depText.split(/[,、]/).map((d) => d.trim());
|
|
172
|
+
// サブタスクID(X.Y.Z形式)をタスクグループID(X.Y)に変換
|
|
173
|
+
for (const dep of deps) {
|
|
174
|
+
let resolvedDep = dep;
|
|
175
|
+
const subtaskMatch = dep.match(/^(\d+\.\d+)\.\d+$/);
|
|
176
|
+
if (subtaskMatch) {
|
|
177
|
+
// サブタスクID(X.Y.Z)をタスクグループID(X.Y)に変換
|
|
178
|
+
resolvedDep = subtaskMatch[1];
|
|
179
|
+
}
|
|
180
|
+
// 自己参照を除外
|
|
181
|
+
if (resolvedDep !== taskGroupId) {
|
|
182
|
+
dependencies.push(resolvedDep);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// 完了条件: **完了条件**: ...
|
|
188
|
+
const criteriaMatch = line.match(/\*\*完了条件\*\*:\s*(.+)$/);
|
|
189
|
+
if (criteriaMatch) {
|
|
190
|
+
completionCriteria = criteriaMatch[1].trim();
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// 重複を除去
|
|
194
|
+
const uniqueDeps = [...new Set(dependencies)];
|
|
195
|
+
return { dependencies: uniqueDeps, completionCriteria };
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* 正規表現のエスケープ
|
|
199
|
+
*/
|
|
200
|
+
function escapeRegex(str) {
|
|
201
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* タスクグループ ID からタスクグループを取得
|
|
205
|
+
*/
|
|
206
|
+
export function findTaskGroupById(parsedIssue, taskGroupId) {
|
|
207
|
+
for (const phase of parsedIssue.phases) {
|
|
208
|
+
for (const taskGroup of phase.taskGroups) {
|
|
209
|
+
if (taskGroup.id === taskGroupId) {
|
|
210
|
+
return taskGroup;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* 全タスクグループをフラットなリストで取得
|
|
218
|
+
*/
|
|
219
|
+
export function getAllTaskGroups(parsedIssue) {
|
|
220
|
+
const taskGroups = [];
|
|
221
|
+
for (const phase of parsedIssue.phases) {
|
|
222
|
+
taskGroups.push(...phase.taskGroups);
|
|
223
|
+
}
|
|
224
|
+
return taskGroups;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* 完了済みタスクグループの ID 一覧を取得
|
|
228
|
+
*/
|
|
229
|
+
export function getCompletedTaskGroupIds(parsedIssue) {
|
|
230
|
+
const completedIds = new Set();
|
|
231
|
+
for (const phase of parsedIssue.phases) {
|
|
232
|
+
for (const taskGroup of phase.taskGroups) {
|
|
233
|
+
if (taskGroup.status === "completed") {
|
|
234
|
+
completedIds.add(taskGroup.id);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return completedIds;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* 未着手タスクグループの一覧を取得
|
|
242
|
+
*/
|
|
243
|
+
export function getPendingTaskGroups(parsedIssue) {
|
|
244
|
+
const pending = [];
|
|
245
|
+
for (const phase of parsedIssue.phases) {
|
|
246
|
+
for (const taskGroup of phase.taskGroups) {
|
|
247
|
+
if (taskGroup.status === "pending") {
|
|
248
|
+
pending.push(taskGroup);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return pending;
|
|
253
|
+
}
|
|
254
|
+
//# sourceMappingURL=issue-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"issue-parser.js","sourceRoot":"","sources":["../../../../src/commands/task-loop/lib/issue-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* プロジェクト選択モジュール
|
|
3
|
+
*
|
|
4
|
+
* Vibe-Kanban プロジェクトのインタラクティブ選択と設定ファイル管理
|
|
5
|
+
*/
|
|
6
|
+
import type { VibeKanbanClient } from "./vibe-kanban-client.js";
|
|
7
|
+
/**
|
|
8
|
+
* プロジェクトを選択またはプロジェクトが有効か確認
|
|
9
|
+
*
|
|
10
|
+
* @param vibeKanban Vibe-Kanban MCP クライアント
|
|
11
|
+
* @param issueNumber Issue 番号(ガイダンス表示用)
|
|
12
|
+
* @returns プロジェクト ID
|
|
13
|
+
*/
|
|
14
|
+
export declare function selectProject(vibeKanban: VibeKanbanClient, issueNumber?: number): Promise<string>;
|
|
15
|
+
//# sourceMappingURL=project-selector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-selector.d.ts","sourceRoot":"","sources":["../../../../src/commands/task-loop/lib/project-selector.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AA4EhE;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,UAAU,EAAE,gBAAgB,EAC5B,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,CAAC,CAsCjB"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* プロジェクト選択モジュール
|
|
3
|
+
*
|
|
4
|
+
* Vibe-Kanban プロジェクトのインタラクティブ選択と設定ファイル管理
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
7
|
+
import { basename, join } from "node:path";
|
|
8
|
+
import { createInterface } from "node:readline";
|
|
9
|
+
import { VibeKanbanRestClient } from "./vibe-kanban-rest-client.js";
|
|
10
|
+
/** 設定ファイル名 */
|
|
11
|
+
const CONFIG_FILE_NAME = ".vibe-kanban.json";
|
|
12
|
+
/**
|
|
13
|
+
* 設定ファイルのパスを取得
|
|
14
|
+
*/
|
|
15
|
+
function getConfigPath() {
|
|
16
|
+
return join(process.cwd(), CONFIG_FILE_NAME);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 設定ファイルを読み込む
|
|
20
|
+
*/
|
|
21
|
+
function loadConfig() {
|
|
22
|
+
const configPath = getConfigPath();
|
|
23
|
+
if (!existsSync(configPath)) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const content = readFileSync(configPath, "utf-8");
|
|
28
|
+
return JSON.parse(content);
|
|
29
|
+
}
|
|
30
|
+
catch (_a) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 設定ファイルを保存
|
|
36
|
+
*/
|
|
37
|
+
function saveConfig(projectId) {
|
|
38
|
+
const configPath = getConfigPath();
|
|
39
|
+
const config = { project_id: projectId };
|
|
40
|
+
writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* readline でユーザー入力を取得
|
|
44
|
+
*/
|
|
45
|
+
function askQuestion(rl, question) {
|
|
46
|
+
return new Promise((resolve) => {
|
|
47
|
+
rl.question(question, (answer) => {
|
|
48
|
+
resolve(answer.trim());
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* プロジェクト作成ガイダンスを表示
|
|
54
|
+
*/
|
|
55
|
+
function showCreateProjectGuidance(issueNumber) {
|
|
56
|
+
const issueArg = issueNumber ? ` ${issueNumber}` : " <issue-number>";
|
|
57
|
+
console.log(`
|
|
58
|
+
❌ Vibe-Kanban バックエンドに接続できません
|
|
59
|
+
|
|
60
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
61
|
+
Step 1: Vibe-Kanban を再起動
|
|
62
|
+
既に起動中の場合は一度終了してから再起動してください
|
|
63
|
+
(ポートファイルが古い可能性があります)
|
|
64
|
+
|
|
65
|
+
$ npx vibe-kanban
|
|
66
|
+
|
|
67
|
+
Step 2: 再度このコマンドを実行
|
|
68
|
+
$ pnpm task:loop${issueArg}
|
|
69
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
70
|
+
`);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* プロジェクトを選択またはプロジェクトが有効か確認
|
|
74
|
+
*
|
|
75
|
+
* @param vibeKanban Vibe-Kanban MCP クライアント
|
|
76
|
+
* @param issueNumber Issue 番号(ガイダンス表示用)
|
|
77
|
+
* @returns プロジェクト ID
|
|
78
|
+
*/
|
|
79
|
+
export async function selectProject(vibeKanban, issueNumber) {
|
|
80
|
+
// 1. プロジェクト一覧を取得(接続確認も兼ねる)
|
|
81
|
+
let projects;
|
|
82
|
+
try {
|
|
83
|
+
projects = await vibeKanban.listProjects();
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
// MCP経由でバックエンドに接続できない場合
|
|
87
|
+
showCreateProjectGuidance(issueNumber);
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
// 2. 設定ファイルがあれば使用
|
|
91
|
+
const config = loadConfig();
|
|
92
|
+
if (config === null || config === void 0 ? void 0 : config.project_id) {
|
|
93
|
+
// プロジェクトが存在するか確認
|
|
94
|
+
const project = projects.find((p) => p.id === config.project_id);
|
|
95
|
+
if (project) {
|
|
96
|
+
console.log(`📦 プロジェクト: ${project.name} (${config.project_id.substring(0, 8)}...)`);
|
|
97
|
+
return config.project_id;
|
|
98
|
+
}
|
|
99
|
+
console.log(`⚠️ 設定ファイルのプロジェクト ID が無効です: ${config.project_id}`);
|
|
100
|
+
console.log(" プロジェクトを再選択してください\n");
|
|
101
|
+
}
|
|
102
|
+
// 3. インタラクティブ選択
|
|
103
|
+
const rl = createInterface({
|
|
104
|
+
input: process.stdin,
|
|
105
|
+
output: process.stdout,
|
|
106
|
+
});
|
|
107
|
+
try {
|
|
108
|
+
const projectId = await interactiveSelectProject(rl, projects, issueNumber);
|
|
109
|
+
return projectId;
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
rl.close();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* インタラクティブにプロジェクトを選択
|
|
117
|
+
*/
|
|
118
|
+
async function interactiveSelectProject(rl, projects, issueNumber) {
|
|
119
|
+
console.log("\n📦 Vibe-Kanban プロジェクトを選択してください:\n");
|
|
120
|
+
// 選択肢を表示
|
|
121
|
+
for (let i = 0; i < projects.length; i++) {
|
|
122
|
+
console.log(` ${i + 1}. ${projects[i].name}`);
|
|
123
|
+
}
|
|
124
|
+
// 区切り線と新規作成オプション
|
|
125
|
+
console.log(" ─────────────────");
|
|
126
|
+
console.log(` ${projects.length + 1}. 新しいプロジェクトを作成`);
|
|
127
|
+
console.log("");
|
|
128
|
+
// 入力を受け付ける
|
|
129
|
+
while (true) {
|
|
130
|
+
const answer = await askQuestion(rl, `番号を入力 (1-${projects.length + 1}): `);
|
|
131
|
+
const num = Number.parseInt(answer, 10);
|
|
132
|
+
if (Number.isNaN(num) || num < 1 || num > projects.length + 1) {
|
|
133
|
+
console.log(`❌ 1〜${projects.length + 1} の数字を入力してください`);
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
// 既存プロジェクトを選択
|
|
137
|
+
if (num <= projects.length) {
|
|
138
|
+
const selected = projects[num - 1];
|
|
139
|
+
saveConfig(selected.id);
|
|
140
|
+
console.log("\n✅ .vibe-kanban.json を作成しました");
|
|
141
|
+
console.log(" 次回から自動的にこのプロジェクトが使用されます\n");
|
|
142
|
+
return selected.id;
|
|
143
|
+
}
|
|
144
|
+
// 新規プロジェクト作成
|
|
145
|
+
return await createNewProject(rl, issueNumber);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* 新規プロジェクトを作成
|
|
150
|
+
*/
|
|
151
|
+
async function createNewProject(rl, issueNumber) {
|
|
152
|
+
console.log("\n📝 新しいプロジェクトを作成します\n");
|
|
153
|
+
// ポート発見
|
|
154
|
+
const port = VibeKanbanRestClient.discoverPort();
|
|
155
|
+
if (!port) {
|
|
156
|
+
showCreateProjectGuidance(issueNumber);
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
// REST クライアント作成
|
|
160
|
+
const restClient = new VibeKanbanRestClient(port);
|
|
161
|
+
// 接続確認
|
|
162
|
+
const isAvailable = await restClient.isAvailable();
|
|
163
|
+
if (!isAvailable) {
|
|
164
|
+
showCreateProjectGuidance(issueNumber);
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
// プロジェクト名を入力
|
|
168
|
+
const defaultName = basename(process.cwd());
|
|
169
|
+
const answer = await askQuestion(rl, `プロジェクト名を入力 (default: ${defaultName}): `);
|
|
170
|
+
const projectName = answer || defaultName;
|
|
171
|
+
// プロジェクト作成
|
|
172
|
+
try {
|
|
173
|
+
const repoPath = process.cwd();
|
|
174
|
+
const projectId = await restClient.createProject(projectName, repoPath);
|
|
175
|
+
console.log(`\n✅ プロジェクト「${projectName}」を作成しました`);
|
|
176
|
+
// 設定ファイル保存
|
|
177
|
+
saveConfig(projectId);
|
|
178
|
+
console.log("✅ .vibe-kanban.json を作成しました");
|
|
179
|
+
console.log(" 次回から自動的にこのプロジェクトが使用されます\n");
|
|
180
|
+
return projectId;
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
console.error("\n❌ プロジェクト作成に失敗しました:", error);
|
|
184
|
+
process.exit(1);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=project-selector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-selector.js","sourceRoot":"","sources":["../../../../src/commands/task-loop/lib/project-selector.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAkB,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhE,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAEpE,cAAc;AACd,MAAM,gBAAgB,GAAG,mBAAmB,CAAC;AAO7C;;GAEG;AACH,SAAS,aAAa;IACpB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,gBAAgB,CAAC,CAAC;AAC/C,CAAC;AAED;;GAEG;AACH,SAAS,UAAU;IACjB,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IACnC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAClD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAqB,CAAC;IACjD,CAAC;IAAC,WAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,UAAU,CAAC,SAAiB;IACnC,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IACnC,MAAM,MAAM,GAAqB,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;IAC3D,aAAa,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AACpE,CAAC;AAED;;GAEG;AACH,SAAS,WAAW,CAAC,EAAa,EAAE,QAAgB;IAClD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE;YAC/B,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,SAAS,yBAAyB,CAAC,WAAoB;IACrD,MAAM,QAAQ,GAAG,WAAW,CAAC,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC,CAAC,CAAC,iBAAiB,CAAC;IACrE,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;kBAWI,QAAQ;;CAEzB,CAAC,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,UAA4B,EAC5B,WAAoB;IAEpB,2BAA2B;IAC3B,IAAI,QAA6C,CAAC;IAClD,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,UAAU,CAAC,YAAY,EAAE,CAAC;IAC7C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,wBAAwB;QACxB,yBAAyB,CAAC,WAAW,CAAC,CAAC;QACvC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,kBAAkB;IAClB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,UAAU,EAAE,CAAC;QACvB,iBAAiB;QACjB,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,UAAU,CAAC,CAAC;QAEjE,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,CAAC,GAAG,CAAC,cAAc,OAAO,CAAC,IAAI,KAAK,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;YACpF,OAAO,MAAM,CAAC,UAAU,CAAC;QAC3B,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,+BAA+B,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;QAChE,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;IACvC,CAAC;IAED,gBAAgB;IAChB,MAAM,EAAE,GAAG,eAAe,CAAC;QACzB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,MAAM,wBAAwB,CAAC,EAAE,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;QAC5E,OAAO,SAAS,CAAC;IACnB,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,wBAAwB,CACrC,EAAa,EACb,QAA6C,EAC7C,WAAoB;IAEpB,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAC;IAEnD,SAAS;IACT,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACjD,CAAC;IAED,iBAAiB;IACjB,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;IACnC,OAAO,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC,MAAM,GAAG,CAAC,gBAAgB,CAAC,CAAC;IACtD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,WAAW;IACX,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,EAAE,EAAE,YAAY,QAAQ,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC;QAC3E,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAExC,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9D,OAAO,CAAC,GAAG,CAAC,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC,eAAe,CAAC,CAAC;YACvD,SAAS;QACX,CAAC;QAED,cAAc;QACd,IAAI,GAAG,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;YAC3B,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;YACnC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;YACxB,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;YAC7C,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;YAC5C,OAAO,QAAQ,CAAC,EAAE,CAAC;QACrB,CAAC;QAED,aAAa;QACb,OAAO,MAAM,gBAAgB,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC;IACjD,CAAC;AACH,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,gBAAgB,CAAC,EAAa,EAAE,WAAoB;IACjE,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;IAEtC,QAAQ;IACR,MAAM,IAAI,GAAG,oBAAoB,CAAC,YAAY,EAAE,CAAC;IACjD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,yBAAyB,CAAC,WAAW,CAAC,CAAC;QACvC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,gBAAgB;IAChB,MAAM,UAAU,GAAG,IAAI,oBAAoB,CAAC,IAAI,CAAC,CAAC;IAElD,OAAO;IACP,MAAM,WAAW,GAAG,MAAM,UAAU,CAAC,WAAW,EAAE,CAAC;IACnD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,yBAAyB,CAAC,WAAW,CAAC,CAAC;QACvC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,aAAa;IACb,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,EAAE,EAAE,wBAAwB,WAAW,KAAK,CAAC,CAAC;IAC/E,MAAM,WAAW,GAAG,MAAM,IAAI,WAAW,CAAC;IAE1C,WAAW;IACX,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QAC/B,MAAM,SAAS,GAAG,MAAM,UAAU,CAAC,aAAa,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QAExE,OAAO,CAAC,GAAG,CAAC,cAAc,WAAW,UAAU,CAAC,CAAC;QAEjD,WAAW;QACX,UAAU,CAAC,SAAS,CAAC,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;QAC3C,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;QAE5C,OAAO,SAAS,CAAC;IACnB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC;QAC7C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
|