@geeseeker/easyai-dev 3.0.0-alpha.1 → 3.0.1
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 +90 -88
- package/README_AI.md +143 -0
- package/bin/easyai-dev.js +127 -1
- package/lib/init.js +425 -0
- package/lib/server/index.d.ts +14 -0
- package/lib/server/index.d.ts.map +1 -0
- package/lib/server/index.js +126 -0
- package/lib/server/index.js.map +1 -0
- package/lib/server/resources/journal-resource.d.ts +8 -0
- package/lib/server/resources/journal-resource.d.ts.map +1 -0
- package/lib/server/resources/journal-resource.js +46 -0
- package/lib/server/resources/journal-resource.js.map +1 -0
- package/lib/server/resources/spec-resource.d.ts +11 -0
- package/lib/server/resources/spec-resource.d.ts.map +1 -0
- package/lib/server/resources/spec-resource.js +126 -0
- package/lib/server/resources/spec-resource.js.map +1 -0
- package/lib/server/resources/status-resource.d.ts +8 -0
- package/lib/server/resources/status-resource.d.ts.map +1 -0
- package/lib/server/resources/status-resource.js +36 -0
- package/lib/server/resources/status-resource.js.map +1 -0
- package/lib/server/resources/subtask-context-resource.d.ts +8 -0
- package/lib/server/resources/subtask-context-resource.d.ts.map +1 -0
- package/lib/server/resources/subtask-context-resource.js +93 -0
- package/lib/server/resources/subtask-context-resource.js.map +1 -0
- package/lib/server/resources/task-context-resource.d.ts +8 -0
- package/lib/server/resources/task-context-resource.d.ts.map +1 -0
- package/lib/server/resources/task-context-resource.js +76 -0
- package/lib/server/resources/task-context-resource.js.map +1 -0
- package/lib/server/tools/conflict-check.d.ts +7 -0
- package/lib/server/tools/conflict-check.d.ts.map +1 -0
- package/lib/server/tools/conflict-check.js +242 -0
- package/lib/server/tools/conflict-check.js.map +1 -0
- package/lib/server/tools/context-budget.d.ts +7 -0
- package/lib/server/tools/context-budget.d.ts.map +1 -0
- package/lib/server/tools/context-budget.js +178 -0
- package/lib/server/tools/context-budget.js.map +1 -0
- package/lib/server/tools/context-generate.d.ts +7 -0
- package/lib/server/tools/context-generate.d.ts.map +1 -0
- package/lib/server/tools/context-generate.js +208 -0
- package/lib/server/tools/context-generate.js.map +1 -0
- package/lib/server/tools/framework-tools.d.ts +20 -0
- package/lib/server/tools/framework-tools.d.ts.map +1 -0
- package/lib/server/tools/framework-tools.js +412 -0
- package/lib/server/tools/framework-tools.js.map +1 -0
- package/lib/server/tools/journal-append.d.ts +7 -0
- package/lib/server/tools/journal-append.d.ts.map +1 -0
- package/lib/server/tools/journal-append.js +55 -0
- package/lib/server/tools/journal-append.js.map +1 -0
- package/lib/server/tools/journal-search.d.ts +7 -0
- package/lib/server/tools/journal-search.d.ts.map +1 -0
- package/lib/server/tools/journal-search.js +63 -0
- package/lib/server/tools/journal-search.js.map +1 -0
- package/lib/server/tools/plan-validate.d.ts +7 -0
- package/lib/server/tools/plan-validate.d.ts.map +1 -0
- package/lib/server/tools/plan-validate.js +146 -0
- package/lib/server/tools/plan-validate.js.map +1 -0
- package/lib/server/tools/spec-validate.d.ts +7 -0
- package/lib/server/tools/spec-validate.d.ts.map +1 -0
- package/lib/server/tools/spec-validate.js +170 -0
- package/lib/server/tools/spec-validate.js.map +1 -0
- package/lib/server/tools/subtask-tools.d.ts +12 -0
- package/lib/server/tools/subtask-tools.d.ts.map +1 -0
- package/lib/server/tools/subtask-tools.js +383 -0
- package/lib/server/tools/subtask-tools.js.map +1 -0
- package/lib/server/tools/task-append-log.d.ts +7 -0
- package/lib/server/tools/task-append-log.d.ts.map +1 -0
- package/lib/server/tools/task-append-log.js +108 -0
- package/lib/server/tools/task-append-log.js.map +1 -0
- package/lib/server/tools/task-cancel.d.ts +7 -0
- package/lib/server/tools/task-cancel.d.ts.map +1 -0
- package/lib/server/tools/task-cancel.js +104 -0
- package/lib/server/tools/task-cancel.js.map +1 -0
- package/lib/server/tools/task-create.d.ts +7 -0
- package/lib/server/tools/task-create.d.ts.map +1 -0
- package/lib/server/tools/task-create.js +98 -0
- package/lib/server/tools/task-create.js.map +1 -0
- package/lib/server/tools/task-get.d.ts +7 -0
- package/lib/server/tools/task-get.d.ts.map +1 -0
- package/lib/server/tools/task-get.js +152 -0
- package/lib/server/tools/task-get.js.map +1 -0
- package/lib/server/tools/task-list.d.ts +7 -0
- package/lib/server/tools/task-list.d.ts.map +1 -0
- package/lib/server/tools/task-list.js +66 -0
- package/lib/server/tools/task-list.js.map +1 -0
- package/lib/server/tools/task-transition.d.ts +7 -0
- package/lib/server/tools/task-transition.d.ts.map +1 -0
- package/lib/server/tools/task-transition.js +259 -0
- package/lib/server/tools/task-transition.js.map +1 -0
- package/lib/server/tools/worktree-tools.d.ts +17 -0
- package/lib/server/tools/worktree-tools.d.ts.map +1 -0
- package/lib/server/tools/worktree-tools.js +336 -0
- package/lib/server/tools/worktree-tools.js.map +1 -0
- package/lib/server/utils/capability-gate.d.ts +50 -0
- package/lib/server/utils/capability-gate.d.ts.map +1 -0
- package/lib/server/utils/capability-gate.js +146 -0
- package/lib/server/utils/capability-gate.js.map +1 -0
- package/lib/server/utils/git-utils.d.ts +33 -0
- package/lib/server/utils/git-utils.d.ts.map +1 -0
- package/lib/server/utils/git-utils.js +84 -0
- package/lib/server/utils/git-utils.js.map +1 -0
- package/lib/server/utils/hash-utils.d.ts +78 -0
- package/lib/server/utils/hash-utils.d.ts.map +1 -0
- package/lib/server/utils/hash-utils.js +153 -0
- package/lib/server/utils/hash-utils.js.map +1 -0
- package/lib/server/utils/journal-utils.d.ts +69 -0
- package/lib/server/utils/journal-utils.d.ts.map +1 -0
- package/lib/server/utils/journal-utils.js +387 -0
- package/lib/server/utils/journal-utils.js.map +1 -0
- package/lib/server/utils/status-utils.d.ts +58 -0
- package/lib/server/utils/status-utils.d.ts.map +1 -0
- package/lib/server/utils/status-utils.js +70 -0
- package/lib/server/utils/status-utils.js.map +1 -0
- package/lib/server/utils/task-utils.d.ts +104 -0
- package/lib/server/utils/task-utils.d.ts.map +1 -0
- package/lib/server/utils/task-utils.js +396 -0
- package/lib/server/utils/task-utils.js.map +1 -0
- package/lib/server/utils/uri-utils.d.ts +9 -0
- package/lib/server/utils/uri-utils.d.ts.map +1 -0
- package/lib/server/utils/uri-utils.js +21 -0
- package/lib/server/utils/uri-utils.js.map +1 -0
- package/package.json +30 -21
- package/skeleton/.agents/rules/anti-hallucination.md +42 -0
- package/skeleton/.agents/rules/coding-standards.md +41 -0
- package/skeleton/.agents/rules/project-identity.md +71 -0
- package/skeleton/.agents/skills/common-framework-evolve/.gitkeep +0 -0
- package/skeleton/.agents/skills/common-framework-evolve/SKILL.md +105 -0
- package/skeleton/.agents/skills/common-session-close/.gitkeep +0 -0
- package/skeleton/.agents/skills/common-session-close/SKILL.md +83 -0
- package/skeleton/.agents/skills/common-spec-update/.gitkeep +0 -0
- package/skeleton/.agents/skills/common-spec-update/SKILL.md +87 -0
- package/skeleton/.agents/skills/pm-brainstorm/.gitkeep +0 -0
- package/skeleton/.agents/skills/pm-brainstorm/SKILL.md +114 -0
- package/skeleton/.agents/skills/pm-session-start/.gitkeep +0 -0
- package/skeleton/.agents/skills/pm-session-start/SKILL.md +73 -0
- package/skeleton/.agents/skills/pm-task-planning/SKILL.md +200 -0
- package/skeleton/.agents/skills/pm-task-review/.gitkeep +0 -0
- package/skeleton/.agents/skills/pm-task-review/SKILL.md +144 -0
- package/skeleton/.agents/skills/worker-check/.gitkeep +0 -0
- package/skeleton/.agents/skills/worker-check/SKILL.md +194 -0
- package/skeleton/.agents/skills/worker-debug/.gitkeep +0 -0
- package/skeleton/.agents/skills/worker-debug/SKILL.md +241 -0
- package/skeleton/.agents/skills/worker-implement/.gitkeep +0 -0
- package/skeleton/.agents/skills/worker-implement/SKILL.md +192 -0
- package/skeleton/.agents/workflows/pm.md +81 -0
- package/skeleton/.agents/workflows/worker.md +100 -0
- package/skeleton/.docs/README.md +25 -0
- package/skeleton/.docs/archive/.gitkeep +0 -0
- package/skeleton/.docs/design/.gitkeep +0 -0
- package/skeleton/.docs/guides/.gitkeep +0 -0
- package/skeleton/.docs/notes/.gitkeep +0 -0
- package/skeleton/.docs/requirements/.gitkeep +0 -0
- package/skeleton/.trellis/config/config.yaml +48 -0
- package/skeleton/.trellis/spec/backend/.gitkeep +0 -0
- package/skeleton/.trellis/spec/frontend/.gitkeep +0 -0
- package/skeleton/.trellis/spec/guides/.gitkeep +0 -0
- package/skeleton/.trellis/spec/guides/external-cli-guide.md +253 -0
- package/skeleton/.trellis/spec/guides/task-workflow.md +34 -0
- package/skeleton/.trellis/spec/guides/testing.md +32 -0
- package/skeleton/.trellis/spec/spec-schema.json +64 -0
- package/skeleton/.trellis/tasks/.gitkeep +0 -0
- package/skeleton/.trellis/workspace/.gitkeep +0 -0
- package/skeleton/README.md +25 -0
- package/LICENSE +0 -21
- package/src/cli/index.js +0 -40
- package/src/commands/init.js +0 -37
- package/src/commands/update.js +0 -33
- package/templates/README.md +0 -22
- package/templates/agents/README.md +0 -4
- package/templates/trellis/README.md +0 -4
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { getProjectRoot } from "./task-utils.js";
|
|
4
|
+
// ============ 常量 ============
|
|
5
|
+
const WORKSPACE_ROOT = ".trellis/workspace";
|
|
6
|
+
const MAX_LINES_PER_FILE = 2000;
|
|
7
|
+
const DEFAULT_USER = "default";
|
|
8
|
+
// ============ 工具函数 ============
|
|
9
|
+
/**
|
|
10
|
+
* 获取用户 journal 目录
|
|
11
|
+
* 按 architecture §6.4,journal 文件位于 .trellis/workspace/{user}/
|
|
12
|
+
* @param user - 用户名,默认为 'default'
|
|
13
|
+
* @returns journal 目录的绝对路径
|
|
14
|
+
*/
|
|
15
|
+
function getJournalDir(user = DEFAULT_USER) {
|
|
16
|
+
// 防止路径遍历攻击
|
|
17
|
+
if (user.includes("..") || user.includes("/") || user.includes("\\")) {
|
|
18
|
+
throw new Error(`非法的用户名: ${user}`);
|
|
19
|
+
}
|
|
20
|
+
const projectRoot = getProjectRoot();
|
|
21
|
+
// 修复: journal 文件应位于 .trellis/workspace/{user}/,而非 .trellis/workspace/journal/{user}/
|
|
22
|
+
const journalDir = path.join(projectRoot, WORKSPACE_ROOT, user);
|
|
23
|
+
return journalDir;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* 获取最新(或当前活跃)的 journal 文件路径
|
|
27
|
+
* 返回当前正在写入的文件(最高页码的文件,或 journal.md 如果不存在编号文件)
|
|
28
|
+
* @param user - 用户名,默认为 'default'
|
|
29
|
+
* @returns 最新 journal 文件的绝对路径
|
|
30
|
+
*/
|
|
31
|
+
function getLatestJournalFile(user = DEFAULT_USER) {
|
|
32
|
+
const journalDir = getJournalDir(user);
|
|
33
|
+
// 确保 journal 目录存在
|
|
34
|
+
if (!fs.existsSync(journalDir)) {
|
|
35
|
+
fs.mkdirSync(journalDir, { recursive: true });
|
|
36
|
+
}
|
|
37
|
+
// 列出所有 journal 文件并按页码排序(从高到低)
|
|
38
|
+
// journal.md = page 0, journal-1.md = page 1, journal-2.md = page 2, ...
|
|
39
|
+
const entries = fs.readdirSync(journalDir);
|
|
40
|
+
const journalFiles = entries
|
|
41
|
+
.filter((name) => name.startsWith("journal") && name.endsWith(".md"))
|
|
42
|
+
.map((name) => {
|
|
43
|
+
if (name === "journal.md") {
|
|
44
|
+
return { name, page: 0 };
|
|
45
|
+
}
|
|
46
|
+
const match = name.match(/journal-(\d+)\.md/);
|
|
47
|
+
return match ? { name, page: parseInt(match[1], 10) } : null;
|
|
48
|
+
})
|
|
49
|
+
.filter((item) => item !== null)
|
|
50
|
+
.sort((a, b) => b.page - a.page); // 降序排列,最高页码在前
|
|
51
|
+
// 如果存在文件,返回最高页码的文件(正在写入的文件)
|
|
52
|
+
if (journalFiles.length > 0) {
|
|
53
|
+
return path.join(journalDir, journalFiles[0].name);
|
|
54
|
+
}
|
|
55
|
+
// 否则返回默认 journal.md 路径
|
|
56
|
+
return path.join(journalDir, "journal.md");
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* 获取下一个编号的 journal 文件名
|
|
60
|
+
* @param journalDir - journal 目录路径
|
|
61
|
+
* @returns 下一个编号的文件名(如 journal-1.md)
|
|
62
|
+
*/
|
|
63
|
+
function getNextJournalFileName(journalDir) {
|
|
64
|
+
const entries = fs.readdirSync(journalDir);
|
|
65
|
+
const numberedFiles = entries
|
|
66
|
+
.filter((name) => name.startsWith("journal-") && name.endsWith(".md"))
|
|
67
|
+
.map((name) => {
|
|
68
|
+
const match = name.match(/journal-(\d+)\.md/);
|
|
69
|
+
return match ? parseInt(match[1], 10) : 0;
|
|
70
|
+
});
|
|
71
|
+
const maxNumber = numberedFiles.length > 0 ? Math.max(...numberedFiles) : 0;
|
|
72
|
+
const nextNumber = maxNumber + 1;
|
|
73
|
+
return `journal-${nextNumber}.md`;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 计算文件的行数
|
|
77
|
+
* @param filePath - 文件路径
|
|
78
|
+
* @returns 文件行数
|
|
79
|
+
*/
|
|
80
|
+
function getFileLineCount(filePath) {
|
|
81
|
+
if (!fs.existsSync(filePath)) {
|
|
82
|
+
return 0;
|
|
83
|
+
}
|
|
84
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
85
|
+
return content.split("\n").length;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* 追加日志条目到 journal 文件
|
|
89
|
+
* 如果当前文件超过 MAX_LINES_PER_FILE,自动创建新文件
|
|
90
|
+
* @param entry - 日志条目
|
|
91
|
+
* @param user - 用户名,默认为 'default'
|
|
92
|
+
*/
|
|
93
|
+
function appendJournalEntry(entry, user = DEFAULT_USER) {
|
|
94
|
+
const journalDir = getJournalDir(user);
|
|
95
|
+
let journalFile = getLatestJournalFile(user);
|
|
96
|
+
// 确保 journal 目录存在
|
|
97
|
+
if (!fs.existsSync(journalDir)) {
|
|
98
|
+
fs.mkdirSync(journalDir, { recursive: true });
|
|
99
|
+
}
|
|
100
|
+
// 检查当前文件行数
|
|
101
|
+
const currentLineCount = getFileLineCount(journalFile);
|
|
102
|
+
const entryContent = serializeJournalEntry(entry);
|
|
103
|
+
// 如果超过最大行数,创建新文件
|
|
104
|
+
if (currentLineCount + entryContent.split("\n").length > MAX_LINES_PER_FILE) {
|
|
105
|
+
const newFileName = getNextJournalFileName(journalDir);
|
|
106
|
+
journalFile = path.join(journalDir, newFileName);
|
|
107
|
+
}
|
|
108
|
+
// 追加条目
|
|
109
|
+
const separator = fs.existsSync(journalFile) && getFileLineCount(journalFile) > 0 ? "\n" : "";
|
|
110
|
+
fs.appendFileSync(journalFile, separator + entryContent + "\n");
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* 转义 YAML 字符串值
|
|
114
|
+
* 对于包含特殊字符的字符串,使用单引号包裹并转义内部单引号
|
|
115
|
+
* @param value - 原始字符串值
|
|
116
|
+
* @returns 转义后的字符串
|
|
117
|
+
*/
|
|
118
|
+
function escapeYamlString(value) {
|
|
119
|
+
// 如果字符串包含特殊字符,使用单引号包裹并转义内部单引号
|
|
120
|
+
const specialChars = ['"', "\\", ":", "#"];
|
|
121
|
+
const hasSpecialChar = specialChars.some((char) => value.includes(char));
|
|
122
|
+
if (hasSpecialChar) {
|
|
123
|
+
// 单引号包裹:内部单引号通过双写转义(' → '')
|
|
124
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
125
|
+
}
|
|
126
|
+
return value;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* 序列化单个日志条目为 YAML frontmatter 格式
|
|
130
|
+
* @param entry - 日志条目
|
|
131
|
+
* @returns 序列化后的字符串
|
|
132
|
+
*/
|
|
133
|
+
function serializeJournalEntry(entry) {
|
|
134
|
+
const lines = ["---"];
|
|
135
|
+
// date
|
|
136
|
+
lines.push(`date: ${entry.date}`);
|
|
137
|
+
// tags - 转义包含特殊字符的标签
|
|
138
|
+
if (entry.tags && entry.tags.length > 0) {
|
|
139
|
+
const tagsStr = entry.tags.map((t) => escapeYamlString(t)).join(", ");
|
|
140
|
+
lines.push(`tags: [${tagsStr}]`);
|
|
141
|
+
}
|
|
142
|
+
// tasks_touched - 转义包含特殊字符的任务 ID
|
|
143
|
+
if (entry.tasks_touched && entry.tasks_touched.length > 0) {
|
|
144
|
+
const tasksStr = entry.tasks_touched
|
|
145
|
+
.map((t) => escapeYamlString(t))
|
|
146
|
+
.join(", ");
|
|
147
|
+
lines.push(`tasks_touched: [${tasksStr}]`);
|
|
148
|
+
}
|
|
149
|
+
lines.push("---");
|
|
150
|
+
lines.push("");
|
|
151
|
+
lines.push(entry.content);
|
|
152
|
+
return lines.join("\n");
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* 解析 journal 文件中的所有条目
|
|
156
|
+
* 条目由 YAML frontmatter 包裹,使用 `---` 作为开始和结束标记
|
|
157
|
+
* @param content - journal 文件内容
|
|
158
|
+
* @returns 解析后的日志条目列表
|
|
159
|
+
*/
|
|
160
|
+
function parseJournalEntries(content) {
|
|
161
|
+
const entries = [];
|
|
162
|
+
let state = "outside_entry";
|
|
163
|
+
let currentEntry = {
|
|
164
|
+
date: "",
|
|
165
|
+
tags: [],
|
|
166
|
+
tasks_touched: [],
|
|
167
|
+
content: "",
|
|
168
|
+
};
|
|
169
|
+
let frontmatterLines = [];
|
|
170
|
+
let bodyLines = [];
|
|
171
|
+
const lines = content.split("\n");
|
|
172
|
+
// 使用索引迭代,以支持 body 状态下的 lookahead
|
|
173
|
+
for (let i = 0; i < lines.length; i++) {
|
|
174
|
+
const line = lines[i];
|
|
175
|
+
const trimmed = line.trim();
|
|
176
|
+
if (trimmed === "---") {
|
|
177
|
+
if (state === "outside_entry") {
|
|
178
|
+
// 遇到第一个 ---,进入 frontmatter
|
|
179
|
+
state = "in_frontmatter";
|
|
180
|
+
frontmatterLines = [];
|
|
181
|
+
bodyLines = [];
|
|
182
|
+
}
|
|
183
|
+
else if (state === "in_frontmatter") {
|
|
184
|
+
// 遇到第二个 ---,frontmatter 结束,进入 body
|
|
185
|
+
state = "in_body";
|
|
186
|
+
// 解析 frontmatter
|
|
187
|
+
currentEntry = parseFrontmatterLines(frontmatterLines);
|
|
188
|
+
}
|
|
189
|
+
else if (state === "in_body") {
|
|
190
|
+
// 在 body 中遇到 ---:预查下一行是否为合法 frontmatter key
|
|
191
|
+
// 只有确认是新条目头部(如 date:)才切分,否则视为 Markdown 分隔线
|
|
192
|
+
const nextNonEmpty = findNextNonEmptyLine(lines, i + 1);
|
|
193
|
+
if (nextNonEmpty !== null && isFrontmatterKey(nextNonEmpty)) {
|
|
194
|
+
// 确认是新条目,保存当前条目并开始新 frontmatter
|
|
195
|
+
currentEntry.content = bodyLines.join("\n").trim();
|
|
196
|
+
if (currentEntry.date || currentEntry.content) {
|
|
197
|
+
entries.push(currentEntry);
|
|
198
|
+
}
|
|
199
|
+
// 重置状态
|
|
200
|
+
state = "in_frontmatter";
|
|
201
|
+
frontmatterLines = [];
|
|
202
|
+
bodyLines = [];
|
|
203
|
+
currentEntry = {
|
|
204
|
+
date: "",
|
|
205
|
+
tags: [],
|
|
206
|
+
tasks_touched: [],
|
|
207
|
+
content: "",
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
// 不是新条目,--- 作为 body 内容保留
|
|
212
|
+
bodyLines.push(line);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
if (state === "in_frontmatter") {
|
|
218
|
+
frontmatterLines.push(line);
|
|
219
|
+
}
|
|
220
|
+
else if (state === "in_body") {
|
|
221
|
+
bodyLines.push(line);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// 处理最后一个条目(文件可能不以 --- 结尾)
|
|
226
|
+
if (state === "in_body") {
|
|
227
|
+
currentEntry.content = bodyLines.join("\n").trim();
|
|
228
|
+
if (currentEntry.date || currentEntry.content) {
|
|
229
|
+
entries.push(currentEntry);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return entries;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* 从指定索引开始,查找下一个非空行
|
|
236
|
+
* @param lines - 行数组
|
|
237
|
+
* @param startIdx - 起始索引
|
|
238
|
+
* @returns 非空行内容(trimmed),如果到末尾都未找到则返回 null
|
|
239
|
+
*/
|
|
240
|
+
function findNextNonEmptyLine(lines, startIdx) {
|
|
241
|
+
for (let j = startIdx; j < lines.length; j++) {
|
|
242
|
+
const t = lines[j].trim();
|
|
243
|
+
if (t)
|
|
244
|
+
return t;
|
|
245
|
+
}
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* 判断一行是否为合法的 journal frontmatter key
|
|
250
|
+
* 目前支持的 key:date, tags, tasks_touched
|
|
251
|
+
*/
|
|
252
|
+
function isFrontmatterKey(line) {
|
|
253
|
+
return /^(date|tags|tasks_touched)\s*:/.test(line);
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* 解析 frontmatter 行数组,返回 JournalEntry
|
|
257
|
+
* @param lines - frontmatter 行数组
|
|
258
|
+
* @returns 解析后的日志条目(不包含 content)
|
|
259
|
+
*/
|
|
260
|
+
function parseFrontmatterLines(lines) {
|
|
261
|
+
const entry = {
|
|
262
|
+
date: "",
|
|
263
|
+
tags: [],
|
|
264
|
+
tasks_touched: [],
|
|
265
|
+
content: "",
|
|
266
|
+
};
|
|
267
|
+
for (const line of lines) {
|
|
268
|
+
const trimmed = line.trim();
|
|
269
|
+
if (!trimmed || trimmed.startsWith("#")) {
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
const colonIndex = trimmed.indexOf(":");
|
|
273
|
+
if (colonIndex === -1) {
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
const key = trimmed.substring(0, colonIndex).trim();
|
|
277
|
+
const value = trimmed.substring(colonIndex + 1).trim();
|
|
278
|
+
if (key === "date") {
|
|
279
|
+
entry.date = value.replace(/^["']|["']$/g, "");
|
|
280
|
+
}
|
|
281
|
+
else if (key === "tags") {
|
|
282
|
+
// 解析数组格式 [item1, item2]
|
|
283
|
+
const arrayMatch = value.match(/^\[(.*)\]$/);
|
|
284
|
+
if (arrayMatch) {
|
|
285
|
+
entry.tags = arrayMatch[1]
|
|
286
|
+
.split(",")
|
|
287
|
+
.map((item) => item.trim().replace(/^["']|["']$/g, ""))
|
|
288
|
+
.filter(Boolean);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
else if (key === "tasks_touched") {
|
|
292
|
+
const arrayMatch = value.match(/^\[(.*)\]$/);
|
|
293
|
+
if (arrayMatch) {
|
|
294
|
+
entry.tasks_touched = arrayMatch[1]
|
|
295
|
+
.split(",")
|
|
296
|
+
.map((item) => item.trim().replace(/^["']|["']$/g, ""))
|
|
297
|
+
.filter(Boolean);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return entry;
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* 搜索日志条目
|
|
305
|
+
* @param query - 搜索查询选项
|
|
306
|
+
* @param user - 用户名,默认为 'default'
|
|
307
|
+
* @returns 匹配的日志条目列表
|
|
308
|
+
*/
|
|
309
|
+
function searchJournal(query, user = DEFAULT_USER) {
|
|
310
|
+
const journalDir = getJournalDir(user);
|
|
311
|
+
if (!fs.existsSync(journalDir)) {
|
|
312
|
+
return [];
|
|
313
|
+
}
|
|
314
|
+
// 获取所有 journal 文件并按页码排序(从高到低)
|
|
315
|
+
// journal.md = page 0, journal-1.md = page 1, journal-2.md = page 2, ...
|
|
316
|
+
const entries = fs.readdirSync(journalDir);
|
|
317
|
+
const journalFiles = entries
|
|
318
|
+
.filter((name) => name.startsWith("journal") && name.endsWith(".md"))
|
|
319
|
+
.map((name) => {
|
|
320
|
+
if (name === "journal.md") {
|
|
321
|
+
return { name, page: 0 };
|
|
322
|
+
}
|
|
323
|
+
const match = name.match(/journal-(\d+)\.md/);
|
|
324
|
+
return match ? { name, page: parseInt(match[1], 10) } : null;
|
|
325
|
+
})
|
|
326
|
+
.filter((item) => item !== null)
|
|
327
|
+
.sort((a, b) => b.page - a.page); // 降序排列,从最高页码开始读取
|
|
328
|
+
// 解析所有条目(从最新文件开始读取)
|
|
329
|
+
const allEntries = [];
|
|
330
|
+
for (const file of journalFiles) {
|
|
331
|
+
const filePath = path.join(journalDir, file.name);
|
|
332
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
333
|
+
const parsed = parseJournalEntries(content);
|
|
334
|
+
// 将当前文件的条目反转,使文件内最新的条目排在前面
|
|
335
|
+
allEntries.push(...parsed.reverse());
|
|
336
|
+
}
|
|
337
|
+
// 过滤条目
|
|
338
|
+
const filtered = allEntries.filter((entry) => {
|
|
339
|
+
// 标签过滤
|
|
340
|
+
if (query.tags && query.tags.length > 0) {
|
|
341
|
+
const hasAllTags = query.tags.every((tag) => entry.tags.includes(tag));
|
|
342
|
+
if (!hasAllTags) {
|
|
343
|
+
return false;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
// 关键词过滤
|
|
347
|
+
if (query.keywords && query.keywords.length > 0) {
|
|
348
|
+
const contentLower = entry.content.toLowerCase();
|
|
349
|
+
const hasAllKeywords = query.keywords.every((kw) => contentLower.includes(kw.toLowerCase()));
|
|
350
|
+
if (!hasAllKeywords) {
|
|
351
|
+
return false;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
// 日期范围过滤
|
|
355
|
+
if (query.date_range) {
|
|
356
|
+
const entryDate = new Date(entry.date);
|
|
357
|
+
if (query.date_range.from) {
|
|
358
|
+
const fromDate = new Date(query.date_range.from);
|
|
359
|
+
if (entryDate < fromDate) {
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
if (query.date_range.to) {
|
|
364
|
+
const toDate = new Date(query.date_range.to);
|
|
365
|
+
if (entryDate > toDate) {
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
return true;
|
|
371
|
+
});
|
|
372
|
+
return filtered;
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* 获取最新的 N 条日志条目
|
|
376
|
+
* 条目按时间倒序排列(最新的在前)
|
|
377
|
+
* @param count - 获取的条目数量,默认为 10
|
|
378
|
+
* @param user - 用户名,默认为 'default'
|
|
379
|
+
* @returns 最新的日志条目列表
|
|
380
|
+
*/
|
|
381
|
+
function getLatestEntries(count = 10, user = DEFAULT_USER) {
|
|
382
|
+
const allEntries = searchJournal({}, user);
|
|
383
|
+
// searchJournal 已经返回倒序的条目(最新的在前),直接取前 count 个即可
|
|
384
|
+
return allEntries.slice(0, count);
|
|
385
|
+
}
|
|
386
|
+
export { WORKSPACE_ROOT, MAX_LINES_PER_FILE, DEFAULT_USER, getJournalDir, getLatestJournalFile, appendJournalEntry, parseJournalEntries, searchJournal, getLatestEntries, };
|
|
387
|
+
//# sourceMappingURL=journal-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"journal-utils.js","sourceRoot":"","sources":["../../src/utils/journal-utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git 信息接口
|
|
3
|
+
*/
|
|
4
|
+
interface GitInfo {
|
|
5
|
+
branch: string;
|
|
6
|
+
status: string;
|
|
7
|
+
recent_commits: Array<{
|
|
8
|
+
hash: string;
|
|
9
|
+
message: string;
|
|
10
|
+
date: string;
|
|
11
|
+
author: string;
|
|
12
|
+
}>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* 任务摘要接口
|
|
16
|
+
*/
|
|
17
|
+
interface TaskSummary {
|
|
18
|
+
id: string;
|
|
19
|
+
title: string;
|
|
20
|
+
status: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* 任务统计接口
|
|
24
|
+
*/
|
|
25
|
+
interface TaskStats {
|
|
26
|
+
total: number;
|
|
27
|
+
active: number;
|
|
28
|
+
by_status: Record<string, number>;
|
|
29
|
+
active_tasks: TaskSummary[];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 日志摘要接口
|
|
33
|
+
*/
|
|
34
|
+
interface JournalSummary {
|
|
35
|
+
latest_count: number;
|
|
36
|
+
entries: Array<{
|
|
37
|
+
date: string;
|
|
38
|
+
tags: string[];
|
|
39
|
+
content: string;
|
|
40
|
+
}>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 项目状态数据接口
|
|
44
|
+
*/
|
|
45
|
+
export interface ProjectStatusData {
|
|
46
|
+
git: GitInfo;
|
|
47
|
+
tasks: TaskStats;
|
|
48
|
+
journal: JournalSummary;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* 获取项目状态数据
|
|
52
|
+
* @param commitCount - 获取的 Git 提交数量,默认为 5
|
|
53
|
+
* @param journalCount - 获取的日志条目数量,默认为 3
|
|
54
|
+
* @returns 项目状态数据
|
|
55
|
+
*/
|
|
56
|
+
export declare function getProjectStatusData(commitCount?: number, journalCount?: number): ProjectStatusData;
|
|
57
|
+
export {};
|
|
58
|
+
//# sourceMappingURL=status-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-utils.d.ts","sourceRoot":"","sources":["../../src/utils/status-utils.ts"],"names":[],"mappings":"AAkBA;;GAEG;AACH,UAAU,OAAO;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,KAAK,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;CACJ;AAED;;GAEG;AACH,UAAU,WAAW;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,UAAU,SAAS;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,YAAY,EAAE,WAAW,EAAE,CAAC;CAC7B;AAED;;GAEG;AACH,UAAU,cAAc;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,KAAK,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,EAAE,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC,CAAC;CACJ;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,cAAc,CAAC;CACzB;AAID;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,GAAE,MAAU,EACvB,YAAY,GAAE,MAAU,GACvB,iBAAiB,CAkEnB"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import { getGitBranch, getGitStatus, getRecentCommits, } from './git-utils.js';
|
|
4
|
+
import { listTaskDirs, getTaskDir, parseTaskMd, } from './task-utils.js';
|
|
5
|
+
import { getLatestEntries, } from './journal-utils.js';
|
|
6
|
+
// ============ 工具函数 ============
|
|
7
|
+
/**
|
|
8
|
+
* 获取项目状态数据
|
|
9
|
+
* @param commitCount - 获取的 Git 提交数量,默认为 5
|
|
10
|
+
* @param journalCount - 获取的日志条目数量,默认为 3
|
|
11
|
+
* @returns 项目状态数据
|
|
12
|
+
*/
|
|
13
|
+
export function getProjectStatusData(commitCount = 5, journalCount = 3) {
|
|
14
|
+
// Git 信息
|
|
15
|
+
const gitInfo = {
|
|
16
|
+
branch: getGitBranch(),
|
|
17
|
+
status: getGitStatus() || 'clean',
|
|
18
|
+
recent_commits: getRecentCommits(commitCount).map(c => ({
|
|
19
|
+
hash: c.hash.substring(0, 8),
|
|
20
|
+
message: c.message,
|
|
21
|
+
date: c.date,
|
|
22
|
+
author: c.author,
|
|
23
|
+
})),
|
|
24
|
+
};
|
|
25
|
+
// 任务列表
|
|
26
|
+
const taskDirs = listTaskDirs();
|
|
27
|
+
const tasks = [];
|
|
28
|
+
for (const taskDir of taskDirs) {
|
|
29
|
+
const taskPath = getTaskDir(taskDir);
|
|
30
|
+
const taskMdPath = path.join(taskPath, 'task.md');
|
|
31
|
+
if (fs.existsSync(taskMdPath)) {
|
|
32
|
+
const content = fs.readFileSync(taskMdPath, 'utf-8');
|
|
33
|
+
const parsed = parseTaskMd(content);
|
|
34
|
+
tasks.push({
|
|
35
|
+
id: parsed.metadata.id,
|
|
36
|
+
title: parsed.metadata.title,
|
|
37
|
+
status: parsed.metadata.status,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// 活跃任务(排除已完成、已归档和已取消)
|
|
42
|
+
const activeTasks = tasks.filter(t => t.status !== 'completed' && t.status !== 'archived' && t.status !== 'cancelled');
|
|
43
|
+
// 计算按状态分组的任务计数
|
|
44
|
+
const byStatus = {};
|
|
45
|
+
for (const task of tasks) {
|
|
46
|
+
byStatus[task.status] = (byStatus[task.status] || 0) + 1;
|
|
47
|
+
}
|
|
48
|
+
// 最新日志
|
|
49
|
+
const latestJournalEntries = getLatestEntries(journalCount);
|
|
50
|
+
const journalSummary = {
|
|
51
|
+
latest_count: latestJournalEntries.length,
|
|
52
|
+
entries: latestJournalEntries.map(entry => ({
|
|
53
|
+
date: entry.date,
|
|
54
|
+
tags: entry.tags,
|
|
55
|
+
content: entry.content.substring(0, 100) +
|
|
56
|
+
(entry.content.length > 100 ? '...' : ''),
|
|
57
|
+
})),
|
|
58
|
+
};
|
|
59
|
+
return {
|
|
60
|
+
git: gitInfo,
|
|
61
|
+
tasks: {
|
|
62
|
+
total: tasks.length,
|
|
63
|
+
active: activeTasks.length,
|
|
64
|
+
by_status: byStatus,
|
|
65
|
+
active_tasks: activeTasks,
|
|
66
|
+
},
|
|
67
|
+
journal: journalSummary,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=status-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-utils.js","sourceRoot":"","sources":["../../src/utils/status-utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
declare const TRELLIS_ROOT = ".trellis";
|
|
2
|
+
declare const TASKS_ROOT = ".trellis/tasks";
|
|
3
|
+
declare const ARCHIVE_ROOT = ".trellis/tasks/archive";
|
|
4
|
+
/**
|
|
5
|
+
* 任务状态枚举
|
|
6
|
+
*/
|
|
7
|
+
type TaskStatus = "pending" | "in_progress" | "under_review" | "completed" | "archived" | "cancelled" | "rejected";
|
|
8
|
+
/**
|
|
9
|
+
* 合法状态转移矩阵(来自 architecture §5.2)
|
|
10
|
+
* Key: 当前状态, Value: 允许转移到的状态列表
|
|
11
|
+
*/
|
|
12
|
+
declare const VALID_TRANSITIONS: Record<TaskStatus, TaskStatus[]>;
|
|
13
|
+
/**
|
|
14
|
+
* 任务元数据接口
|
|
15
|
+
*/
|
|
16
|
+
interface TaskMetadata {
|
|
17
|
+
id: string;
|
|
18
|
+
title: string;
|
|
19
|
+
status: TaskStatus;
|
|
20
|
+
description: string;
|
|
21
|
+
acceptance_criteria: string;
|
|
22
|
+
file_scope?: string;
|
|
23
|
+
assign_strategy?: string;
|
|
24
|
+
created_at: string;
|
|
25
|
+
updated_at: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 解析后的任务文档结构
|
|
29
|
+
*/
|
|
30
|
+
interface ParsedTask {
|
|
31
|
+
metadata: TaskMetadata;
|
|
32
|
+
body: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 获取项目根目录
|
|
36
|
+
* 优先级:EASYAI_PROJECT_ROOT 环境变量 → 向上查找 .trellis 目录
|
|
37
|
+
* @returns 项目根目录的绝对路径
|
|
38
|
+
*/
|
|
39
|
+
declare function getProjectRoot(): string;
|
|
40
|
+
/**
|
|
41
|
+
* 获取任务目录绝对路径
|
|
42
|
+
* @returns 任务目录的绝对路径
|
|
43
|
+
*/
|
|
44
|
+
declare function getTasksDir(): string;
|
|
45
|
+
/**
|
|
46
|
+
* 获取归档目录绝对路径
|
|
47
|
+
* @returns 归档目录的绝对路径
|
|
48
|
+
*/
|
|
49
|
+
declare function getArchiveDir(): string;
|
|
50
|
+
/**
|
|
51
|
+
* 获取指定任务的目录路径
|
|
52
|
+
* @param taskId - 任务 ID(如 T001-login-api)
|
|
53
|
+
* @returns 任务目录的绝对路径
|
|
54
|
+
*/
|
|
55
|
+
declare function getTaskDir(taskId: string): string;
|
|
56
|
+
/**
|
|
57
|
+
* 将文本转换为 kebab-case slug
|
|
58
|
+
* - 转换为小写 ASCII
|
|
59
|
+
* - 将空格和特殊字符替换为连字符
|
|
60
|
+
* - 截断至 30 个字符
|
|
61
|
+
* @param text - 输入文本(支持中文和英文)
|
|
62
|
+
* @returns kebab-case slug
|
|
63
|
+
*/
|
|
64
|
+
declare function slugify(text: string): string;
|
|
65
|
+
/**
|
|
66
|
+
* 生成任务 ID(格式:T{NNN}-{slug})
|
|
67
|
+
* 自动递增序号,基于现有任务目录(包括归档目录中的任务)
|
|
68
|
+
* @param title - 任务标题
|
|
69
|
+
* @returns 任务 ID(如 T001-login-api)
|
|
70
|
+
*/
|
|
71
|
+
declare function generateTaskId(title: string): string;
|
|
72
|
+
/**
|
|
73
|
+
* 解析 task.md 文件内容
|
|
74
|
+
* @param content - task.md 文件内容
|
|
75
|
+
* @returns 解析后的元数据和正文
|
|
76
|
+
*/
|
|
77
|
+
declare function parseTaskMd(content: string): ParsedTask;
|
|
78
|
+
/**
|
|
79
|
+
* 序列化为 task.md 文件格式
|
|
80
|
+
* @param metadata - 任务元数据
|
|
81
|
+
* @param body - 任务正文
|
|
82
|
+
* @returns task.md 文件内容
|
|
83
|
+
*/
|
|
84
|
+
declare function serializeTaskMd(metadata: TaskMetadata, body: string): string;
|
|
85
|
+
/**
|
|
86
|
+
* 校验状态转移是否合法
|
|
87
|
+
* @param from - 当前状态
|
|
88
|
+
* @param to - 目标状态
|
|
89
|
+
* @returns 是否允许转移
|
|
90
|
+
*/
|
|
91
|
+
declare function isValidTransition(from: TaskStatus, to: TaskStatus): boolean;
|
|
92
|
+
/**
|
|
93
|
+
* 列出所有任务目录(排除归档目录)
|
|
94
|
+
* @returns 任务目录名列表
|
|
95
|
+
*/
|
|
96
|
+
declare function listTaskDirs(): string[];
|
|
97
|
+
/**
|
|
98
|
+
* 确保目录存在,不存在则创建
|
|
99
|
+
* @param dirPath - 目录路径
|
|
100
|
+
*/
|
|
101
|
+
declare function ensureDir(dirPath: string): void;
|
|
102
|
+
export type { TaskStatus, TaskMetadata, ParsedTask };
|
|
103
|
+
export { TRELLIS_ROOT, TASKS_ROOT, ARCHIVE_ROOT, VALID_TRANSITIONS, getProjectRoot, getTasksDir, getArchiveDir, getTaskDir, generateTaskId, slugify, parseTaskMd, serializeTaskMd, isValidTransition, listTaskDirs, ensureDir, };
|
|
104
|
+
//# sourceMappingURL=task-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-utils.d.ts","sourceRoot":"","sources":["../../src/utils/task-utils.ts"],"names":[],"mappings":"AAKA,QAAA,MAAM,YAAY,aAAa,CAAC;AAChC,QAAA,MAAM,UAAU,mBAAmB,CAAC;AACpC,QAAA,MAAM,YAAY,2BAA2B,CAAC;AAI9C;;GAEG;AACH,KAAK,UAAU,GACX,SAAS,GACT,aAAa,GACb,cAAc,GACd,WAAW,GACX,UAAU,GACV,WAAW,GACX,UAAU,CAAC;AAEf;;;GAGG;AACH,QAAA,MAAM,iBAAiB,EAAE,MAAM,CAAC,UAAU,EAAE,UAAU,EAAE,CAQvD,CAAC;AAEF;;GAEG;AACH,UAAU,YAAY;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,UAAU,UAAU;IAClB,QAAQ,EAAE,YAAY,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;CACd;AAQD;;;;GAIG;AACH,iBAAS,cAAc,IAAI,MAAM,CAiChC;AAED;;;GAGG;AACH,iBAAS,WAAW,IAAI,MAAM,CAG7B;AAED;;;GAGG;AACH,iBAAS,aAAa,IAAI,MAAM,CAG/B;AAED;;;;GAIG;AACH,iBAAS,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAO1C;AAED;;;;;;;GAOG;AACH,iBAAS,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA0BrC;AAED;;;;;GAKG;AACH,iBAAS,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAiD7C;AAgKD;;;;GAIG;AACH,iBAAS,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CA4BhD;AAED;;;;;GAKG;AACH,iBAAS,eAAe,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAoBrE;AAED;;;;;GAKG;AACH,iBAAS,iBAAiB,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,UAAU,GAAG,OAAO,CAGpE;AAED;;;GAGG;AACH,iBAAS,YAAY,IAAI,MAAM,EAAE,CAahC;AAED;;;GAGG;AACH,iBAAS,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAIxC;AAID,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC;AACrD,OAAO,EACL,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACd,WAAW,EACX,aAAa,EACb,UAAU,EACV,cAAc,EACd,OAAO,EACP,WAAW,EACX,eAAe,EACf,iBAAiB,EACjB,YAAY,EACZ,SAAS,GACV,CAAC"}
|