@locusai/sdk 0.13.0 → 0.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/worker.d.ts.map +1 -1
- package/dist/agent/worker.js +300 -12
- package/dist/core/config.d.ts +2 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/prompt-builder.d.ts +1 -0
- package/dist/core/prompt-builder.d.ts.map +1 -1
- package/dist/discussion/agents/facilitator-prompt.d.ts +13 -0
- package/dist/discussion/agents/facilitator-prompt.d.ts.map +1 -0
- package/dist/discussion/discussion-facilitator.d.ts +67 -0
- package/dist/discussion/discussion-facilitator.d.ts.map +1 -0
- package/dist/discussion/discussion-manager.d.ts +59 -0
- package/dist/discussion/discussion-manager.d.ts.map +1 -0
- package/dist/discussion/discussion-types.d.ts +89 -0
- package/dist/discussion/discussion-types.d.ts.map +1 -0
- package/dist/discussion/index.d.ts +5 -0
- package/dist/discussion/index.d.ts.map +1 -0
- package/dist/index-node.d.ts +1 -0
- package/dist/index-node.d.ts.map +1 -1
- package/dist/index-node.js +735 -105
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +37 -0
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/agent/worker.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAc,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGlE,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD;;;;;;;;;;GAUG;AACH,qBAAa,WAAW;IAgBV,OAAO,CAAC,MAAM;IAf1B,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,WAAW,CAAc;IAGjC,OAAO,CAAC,QAAQ,CAAM;IACtB,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,iBAAiB,CAA+C;IACxE,OAAO,CAAC,aAAa,CAAuB;IAG5C,OAAO,CAAC,iBAAiB,CAA4C;IACrE,OAAO,CAAC,aAAa,CAAgB;gBAEjB,MAAM,EAAE,YAAY;IAqDxC,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,GAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,OAAgB;YAmB5D,eAAe;YAcf,WAAW;IAgDzB;;OAEG;YACW,WAAW;IAoCzB,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,aAAa;IAoBf,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/agent/worker.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAc,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGlE,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD;;;;;;;;;;GAUG;AACH,qBAAa,WAAW;IAgBV,OAAO,CAAC,MAAM;IAf1B,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,WAAW,CAAc;IAGjC,OAAO,CAAC,QAAQ,CAAM;IACtB,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,iBAAiB,CAA+C;IACxE,OAAO,CAAC,aAAa,CAAuB;IAG5C,OAAO,CAAC,iBAAiB,CAA4C;IACrE,OAAO,CAAC,aAAa,CAAgB;gBAEjB,MAAM,EAAE,YAAY;IAqDxC,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,GAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,OAAgB;YAmB5D,eAAe;YAcf,WAAW;IAgDzB;;OAEG;YACW,WAAW;IAoCzB,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,aAAa;IAoBf,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA4I3B"}
|
package/dist/agent/worker.js
CHANGED
|
@@ -391,6 +391,39 @@ var init_workspaces = __esm(() => {
|
|
|
391
391
|
};
|
|
392
392
|
});
|
|
393
393
|
|
|
394
|
+
// src/discussion/discussion-types.ts
|
|
395
|
+
var import_zod, DiscussionMessageSchema, DiscussionInsightSchema, DiscussionSchema;
|
|
396
|
+
var init_discussion_types = __esm(() => {
|
|
397
|
+
import_zod = require("zod");
|
|
398
|
+
DiscussionMessageSchema = import_zod.z.object({
|
|
399
|
+
role: import_zod.z.enum(["user", "assistant"]),
|
|
400
|
+
content: import_zod.z.string(),
|
|
401
|
+
timestamp: import_zod.z.number()
|
|
402
|
+
});
|
|
403
|
+
DiscussionInsightSchema = import_zod.z.object({
|
|
404
|
+
id: import_zod.z.string(),
|
|
405
|
+
type: import_zod.z.enum(["decision", "requirement", "idea", "concern", "learning"]),
|
|
406
|
+
title: import_zod.z.string(),
|
|
407
|
+
content: import_zod.z.string(),
|
|
408
|
+
tags: import_zod.z.array(import_zod.z.string()).default([]),
|
|
409
|
+
createdAt: import_zod.z.string()
|
|
410
|
+
});
|
|
411
|
+
DiscussionSchema = import_zod.z.object({
|
|
412
|
+
id: import_zod.z.string(),
|
|
413
|
+
title: import_zod.z.string(),
|
|
414
|
+
topic: import_zod.z.string(),
|
|
415
|
+
status: import_zod.z.enum(["active", "completed", "archived"]).default("active"),
|
|
416
|
+
messages: import_zod.z.array(DiscussionMessageSchema).default([]),
|
|
417
|
+
insights: import_zod.z.array(DiscussionInsightSchema).default([]),
|
|
418
|
+
createdAt: import_zod.z.string(),
|
|
419
|
+
updatedAt: import_zod.z.string(),
|
|
420
|
+
metadata: import_zod.z.object({
|
|
421
|
+
model: import_zod.z.string(),
|
|
422
|
+
provider: import_zod.z.string()
|
|
423
|
+
})
|
|
424
|
+
});
|
|
425
|
+
});
|
|
426
|
+
|
|
394
427
|
// src/index.ts
|
|
395
428
|
var exports_src = {};
|
|
396
429
|
__export(exports_src, {
|
|
@@ -403,6 +436,9 @@ __export(exports_src, {
|
|
|
403
436
|
LocusClient: () => LocusClient,
|
|
404
437
|
InvitationsModule: () => InvitationsModule,
|
|
405
438
|
DocsModule: () => DocsModule,
|
|
439
|
+
DiscussionSchema: () => DiscussionSchema,
|
|
440
|
+
DiscussionMessageSchema: () => DiscussionMessageSchema,
|
|
441
|
+
DiscussionInsightSchema: () => DiscussionInsightSchema,
|
|
406
442
|
CiModule: () => CiModule,
|
|
407
443
|
AuthModule: () => AuthModule
|
|
408
444
|
});
|
|
@@ -508,6 +544,7 @@ var init_src = __esm(() => {
|
|
|
508
544
|
init_sprints();
|
|
509
545
|
init_tasks();
|
|
510
546
|
init_workspaces();
|
|
547
|
+
init_discussion_types();
|
|
511
548
|
import_axios = __toESM(require("axios"));
|
|
512
549
|
init_events();
|
|
513
550
|
init_auth();
|
|
@@ -554,7 +591,8 @@ var init_config = __esm(() => {
|
|
|
554
591
|
documentsDir: "documents",
|
|
555
592
|
sessionsDir: "sessions",
|
|
556
593
|
reviewsDir: "reviews",
|
|
557
|
-
plansDir: "plans"
|
|
594
|
+
plansDir: "plans",
|
|
595
|
+
discussionsDir: "discussions"
|
|
558
596
|
};
|
|
559
597
|
LOCUS_GITIGNORE_PATTERNS = [
|
|
560
598
|
"# Locus AI - Session data (user-specific, can grow large)",
|
|
@@ -569,6 +607,9 @@ var init_config = __esm(() => {
|
|
|
569
607
|
"# Locus AI - Plans (generated per task)",
|
|
570
608
|
".locus/plans/",
|
|
571
609
|
"",
|
|
610
|
+
"# Locus AI - Discussions (AI discussion sessions)",
|
|
611
|
+
".locus/discussions/",
|
|
612
|
+
"",
|
|
572
613
|
"# Locus AI - Settings (contains API key, telegram config, etc.)",
|
|
573
614
|
".locus/settings.json",
|
|
574
615
|
"",
|
|
@@ -1871,6 +1912,187 @@ var init_git_workflow = __esm(() => {
|
|
|
1871
1912
|
import_node_child_process4 = require("node:child_process");
|
|
1872
1913
|
});
|
|
1873
1914
|
|
|
1915
|
+
// src/discussion/discussion-manager.ts
|
|
1916
|
+
class DiscussionManager {
|
|
1917
|
+
discussionsDir;
|
|
1918
|
+
constructor(projectPath) {
|
|
1919
|
+
this.discussionsDir = getLocusPath(projectPath, "discussionsDir");
|
|
1920
|
+
}
|
|
1921
|
+
create(topic, model, provider) {
|
|
1922
|
+
this.ensureDir();
|
|
1923
|
+
const now = new Date().toISOString();
|
|
1924
|
+
const id = `disc-${Date.now()}`;
|
|
1925
|
+
const discussion = {
|
|
1926
|
+
id,
|
|
1927
|
+
title: topic,
|
|
1928
|
+
topic,
|
|
1929
|
+
status: "active",
|
|
1930
|
+
messages: [],
|
|
1931
|
+
insights: [],
|
|
1932
|
+
createdAt: now,
|
|
1933
|
+
updatedAt: now,
|
|
1934
|
+
metadata: { model, provider }
|
|
1935
|
+
};
|
|
1936
|
+
this.save(discussion);
|
|
1937
|
+
return discussion;
|
|
1938
|
+
}
|
|
1939
|
+
save(discussion) {
|
|
1940
|
+
this.ensureDir();
|
|
1941
|
+
const jsonPath = import_node_path5.join(this.discussionsDir, `${discussion.id}.json`);
|
|
1942
|
+
const mdPath = import_node_path5.join(this.discussionsDir, `summary-${discussion.id}.md`);
|
|
1943
|
+
import_node_fs3.writeFileSync(jsonPath, JSON.stringify(discussion, null, 2), "utf-8");
|
|
1944
|
+
import_node_fs3.writeFileSync(mdPath, this.toMarkdown(discussion), "utf-8");
|
|
1945
|
+
}
|
|
1946
|
+
load(id) {
|
|
1947
|
+
this.ensureDir();
|
|
1948
|
+
const filePath = import_node_path5.join(this.discussionsDir, `${id}.json`);
|
|
1949
|
+
if (!import_node_fs3.existsSync(filePath)) {
|
|
1950
|
+
return null;
|
|
1951
|
+
}
|
|
1952
|
+
try {
|
|
1953
|
+
return JSON.parse(import_node_fs3.readFileSync(filePath, "utf-8"));
|
|
1954
|
+
} catch {
|
|
1955
|
+
return null;
|
|
1956
|
+
}
|
|
1957
|
+
}
|
|
1958
|
+
list(status) {
|
|
1959
|
+
this.ensureDir();
|
|
1960
|
+
const files = import_node_fs3.readdirSync(this.discussionsDir).filter((f) => f.endsWith(".json"));
|
|
1961
|
+
const discussions = [];
|
|
1962
|
+
for (const file of files) {
|
|
1963
|
+
try {
|
|
1964
|
+
const discussion = JSON.parse(import_node_fs3.readFileSync(import_node_path5.join(this.discussionsDir, file), "utf-8"));
|
|
1965
|
+
if (!status || discussion.status === status) {
|
|
1966
|
+
discussions.push(discussion);
|
|
1967
|
+
}
|
|
1968
|
+
} catch {}
|
|
1969
|
+
}
|
|
1970
|
+
discussions.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
|
|
1971
|
+
return discussions;
|
|
1972
|
+
}
|
|
1973
|
+
complete(id) {
|
|
1974
|
+
const discussion = this.load(id);
|
|
1975
|
+
if (!discussion) {
|
|
1976
|
+
throw new Error(`Discussion not found: ${id}`);
|
|
1977
|
+
}
|
|
1978
|
+
discussion.status = "completed";
|
|
1979
|
+
discussion.updatedAt = new Date().toISOString();
|
|
1980
|
+
this.save(discussion);
|
|
1981
|
+
return discussion;
|
|
1982
|
+
}
|
|
1983
|
+
archive(id) {
|
|
1984
|
+
const discussion = this.load(id);
|
|
1985
|
+
if (!discussion) {
|
|
1986
|
+
throw new Error(`Discussion not found: ${id}`);
|
|
1987
|
+
}
|
|
1988
|
+
discussion.status = "archived";
|
|
1989
|
+
discussion.updatedAt = new Date().toISOString();
|
|
1990
|
+
this.save(discussion);
|
|
1991
|
+
}
|
|
1992
|
+
delete(id) {
|
|
1993
|
+
this.ensureDir();
|
|
1994
|
+
const jsonPath = import_node_path5.join(this.discussionsDir, `${id}.json`);
|
|
1995
|
+
const mdPath = import_node_path5.join(this.discussionsDir, `summary-${id}.md`);
|
|
1996
|
+
if (import_node_fs3.existsSync(jsonPath)) {
|
|
1997
|
+
import_node_fs3.unlinkSync(jsonPath);
|
|
1998
|
+
}
|
|
1999
|
+
if (import_node_fs3.existsSync(mdPath)) {
|
|
2000
|
+
import_node_fs3.unlinkSync(mdPath);
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
addMessage(id, role, content) {
|
|
2004
|
+
const discussion = this.load(id);
|
|
2005
|
+
if (!discussion) {
|
|
2006
|
+
throw new Error(`Discussion not found: ${id}`);
|
|
2007
|
+
}
|
|
2008
|
+
discussion.messages.push({
|
|
2009
|
+
role,
|
|
2010
|
+
content,
|
|
2011
|
+
timestamp: Date.now()
|
|
2012
|
+
});
|
|
2013
|
+
discussion.updatedAt = new Date().toISOString();
|
|
2014
|
+
this.save(discussion);
|
|
2015
|
+
return discussion;
|
|
2016
|
+
}
|
|
2017
|
+
addInsight(id, insight) {
|
|
2018
|
+
const discussion = this.load(id);
|
|
2019
|
+
if (!discussion) {
|
|
2020
|
+
throw new Error(`Discussion not found: ${id}`);
|
|
2021
|
+
}
|
|
2022
|
+
discussion.insights.push(insight);
|
|
2023
|
+
discussion.updatedAt = new Date().toISOString();
|
|
2024
|
+
this.save(discussion);
|
|
2025
|
+
return discussion;
|
|
2026
|
+
}
|
|
2027
|
+
getAllInsights() {
|
|
2028
|
+
const discussions = this.list("completed");
|
|
2029
|
+
const insights = [];
|
|
2030
|
+
for (const discussion of discussions) {
|
|
2031
|
+
insights.push(...discussion.insights);
|
|
2032
|
+
}
|
|
2033
|
+
insights.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
|
|
2034
|
+
return insights;
|
|
2035
|
+
}
|
|
2036
|
+
getMarkdown(id) {
|
|
2037
|
+
const discussion = this.load(id);
|
|
2038
|
+
if (!discussion)
|
|
2039
|
+
return null;
|
|
2040
|
+
return this.toMarkdown(discussion);
|
|
2041
|
+
}
|
|
2042
|
+
toMarkdown(discussion) {
|
|
2043
|
+
const lines = [];
|
|
2044
|
+
lines.push(`# Discussion: ${discussion.title}`);
|
|
2045
|
+
lines.push("");
|
|
2046
|
+
lines.push(`**Status:** ${discussion.status.toUpperCase()}`);
|
|
2047
|
+
lines.push(`**Topic:** ${discussion.topic}`);
|
|
2048
|
+
lines.push(`**Created:** ${discussion.createdAt}`);
|
|
2049
|
+
lines.push(`**Updated:** ${discussion.updatedAt}`);
|
|
2050
|
+
lines.push(`**Model:** ${discussion.metadata.model} (${discussion.metadata.provider})`);
|
|
2051
|
+
lines.push("");
|
|
2052
|
+
if (discussion.messages.length > 0) {
|
|
2053
|
+
lines.push(`## Messages (${discussion.messages.length})`);
|
|
2054
|
+
lines.push("");
|
|
2055
|
+
for (const msg of discussion.messages) {
|
|
2056
|
+
const time = new Date(msg.timestamp).toISOString();
|
|
2057
|
+
const roleLabel = msg.role === "user" ? "User" : "Assistant";
|
|
2058
|
+
lines.push(`### ${roleLabel} — ${time}`);
|
|
2059
|
+
lines.push("");
|
|
2060
|
+
lines.push(msg.content);
|
|
2061
|
+
lines.push("");
|
|
2062
|
+
}
|
|
2063
|
+
}
|
|
2064
|
+
if (discussion.insights.length > 0) {
|
|
2065
|
+
lines.push(`## Insights (${discussion.insights.length})`);
|
|
2066
|
+
lines.push("");
|
|
2067
|
+
for (const insight of discussion.insights) {
|
|
2068
|
+
lines.push(`### [${insight.type.toUpperCase()}] ${insight.title}`);
|
|
2069
|
+
lines.push("");
|
|
2070
|
+
lines.push(insight.content);
|
|
2071
|
+
if (insight.tags.length > 0) {
|
|
2072
|
+
lines.push("");
|
|
2073
|
+
lines.push(`**Tags:** ${insight.tags.join(", ")}`);
|
|
2074
|
+
}
|
|
2075
|
+
lines.push("");
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
lines.push("---");
|
|
2079
|
+
lines.push(`*Discussion ID: ${discussion.id}*`);
|
|
2080
|
+
return lines.join(`
|
|
2081
|
+
`);
|
|
2082
|
+
}
|
|
2083
|
+
ensureDir() {
|
|
2084
|
+
if (!import_node_fs3.existsSync(this.discussionsDir)) {
|
|
2085
|
+
import_node_fs3.mkdirSync(this.discussionsDir, { recursive: true });
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
var import_node_fs3, import_node_path5;
|
|
2090
|
+
var init_discussion_manager = __esm(() => {
|
|
2091
|
+
init_config();
|
|
2092
|
+
import_node_fs3 = require("node:fs");
|
|
2093
|
+
import_node_path5 = require("node:path");
|
|
2094
|
+
});
|
|
2095
|
+
|
|
1874
2096
|
// src/core/prompt-builder.ts
|
|
1875
2097
|
class PromptBuilder {
|
|
1876
2098
|
projectPath;
|
|
@@ -1909,6 +2131,15 @@ ${knowledgeBase}
|
|
|
1909
2131
|
These are accumulated lessons from past tasks. Follow them to avoid repeating mistakes:
|
|
1910
2132
|
${learnings}
|
|
1911
2133
|
</learnings>
|
|
2134
|
+
`;
|
|
2135
|
+
}
|
|
2136
|
+
const discussionInsights = this.getDiscussionInsightsContent();
|
|
2137
|
+
if (discussionInsights) {
|
|
2138
|
+
sections += `
|
|
2139
|
+
<discussion_insights>
|
|
2140
|
+
These are key decisions and insights from product discussions. Follow them to maintain product coherence:
|
|
2141
|
+
${discussionInsights}
|
|
2142
|
+
</discussion_insights>
|
|
1912
2143
|
`;
|
|
1913
2144
|
}
|
|
1914
2145
|
if (task.docs && task.docs.length > 0) {
|
|
@@ -1997,6 +2228,15 @@ ${knowledgeBase}
|
|
|
1997
2228
|
These are accumulated lessons from past tasks. Follow them to avoid repeating mistakes:
|
|
1998
2229
|
${learnings}
|
|
1999
2230
|
</learnings>
|
|
2231
|
+
`;
|
|
2232
|
+
}
|
|
2233
|
+
const discussionInsights = this.getDiscussionInsightsContent();
|
|
2234
|
+
if (discussionInsights) {
|
|
2235
|
+
sections += `
|
|
2236
|
+
<discussion_insights>
|
|
2237
|
+
These are key decisions and insights from product discussions. Follow them to maintain product coherence:
|
|
2238
|
+
${discussionInsights}
|
|
2239
|
+
</discussion_insights>
|
|
2000
2240
|
`;
|
|
2001
2241
|
}
|
|
2002
2242
|
return `<direct_execution>
|
|
@@ -2011,9 +2251,9 @@ ${sections}
|
|
|
2011
2251
|
}
|
|
2012
2252
|
getProjectContext() {
|
|
2013
2253
|
const contextPath = getLocusPath(this.projectPath, "contextFile");
|
|
2014
|
-
if (
|
|
2254
|
+
if (import_node_fs4.existsSync(contextPath)) {
|
|
2015
2255
|
try {
|
|
2016
|
-
const context =
|
|
2256
|
+
const context = import_node_fs4.readFileSync(contextPath, "utf-8");
|
|
2017
2257
|
if (context.trim().length > 20) {
|
|
2018
2258
|
return context;
|
|
2019
2259
|
}
|
|
@@ -2024,10 +2264,10 @@ ${sections}
|
|
|
2024
2264
|
return this.getFallbackContext() || null;
|
|
2025
2265
|
}
|
|
2026
2266
|
getFallbackContext() {
|
|
2027
|
-
const readmePath =
|
|
2028
|
-
if (
|
|
2267
|
+
const readmePath = import_node_path6.join(this.projectPath, "README.md");
|
|
2268
|
+
if (import_node_fs4.existsSync(readmePath)) {
|
|
2029
2269
|
try {
|
|
2030
|
-
const content =
|
|
2270
|
+
const content = import_node_fs4.readFileSync(readmePath, "utf-8");
|
|
2031
2271
|
const limit = 1000;
|
|
2032
2272
|
return content.slice(0, limit) + (content.length > limit ? `
|
|
2033
2273
|
...(truncated)...` : "");
|
|
@@ -2041,15 +2281,16 @@ ${sections}
|
|
|
2041
2281
|
return `You have access to the following documentation directories for context:
|
|
2042
2282
|
- Artifacts: \`.locus/artifacts\` (local-only, not synced to cloud)
|
|
2043
2283
|
- Documents: \`.locus/documents\` (synced from cloud)
|
|
2284
|
+
- Discussions: \`.locus/discussions\` (product discussion insights and decisions)
|
|
2044
2285
|
If you need more information about the project strategies, plans, or architecture, read files in these directories.`;
|
|
2045
2286
|
}
|
|
2046
2287
|
getLearningsContent() {
|
|
2047
2288
|
const learningsPath = getLocusPath(this.projectPath, "learningsFile");
|
|
2048
|
-
if (!
|
|
2289
|
+
if (!import_node_fs4.existsSync(learningsPath)) {
|
|
2049
2290
|
return null;
|
|
2050
2291
|
}
|
|
2051
2292
|
try {
|
|
2052
|
-
const content =
|
|
2293
|
+
const content = import_node_fs4.readFileSync(learningsPath, "utf-8");
|
|
2053
2294
|
const lines = content.split(`
|
|
2054
2295
|
`).filter((l) => l.startsWith("- "));
|
|
2055
2296
|
if (lines.length === 0) {
|
|
@@ -2061,6 +2302,53 @@ If you need more information about the project strategies, plans, or architectur
|
|
|
2061
2302
|
return null;
|
|
2062
2303
|
}
|
|
2063
2304
|
}
|
|
2305
|
+
getDiscussionInsightsContent() {
|
|
2306
|
+
try {
|
|
2307
|
+
const manager = new DiscussionManager(this.projectPath);
|
|
2308
|
+
const insights = manager.getAllInsights();
|
|
2309
|
+
if (insights.length === 0) {
|
|
2310
|
+
return null;
|
|
2311
|
+
}
|
|
2312
|
+
const groups = {};
|
|
2313
|
+
for (const insight of insights) {
|
|
2314
|
+
const key = insight.type;
|
|
2315
|
+
if (!groups[key]) {
|
|
2316
|
+
groups[key] = [];
|
|
2317
|
+
}
|
|
2318
|
+
groups[key].push(insight);
|
|
2319
|
+
}
|
|
2320
|
+
const typeLabels = {
|
|
2321
|
+
decision: "Decisions",
|
|
2322
|
+
requirement: "Requirements",
|
|
2323
|
+
idea: "Ideas",
|
|
2324
|
+
concern: "Concerns",
|
|
2325
|
+
learning: "Learnings"
|
|
2326
|
+
};
|
|
2327
|
+
let output = "";
|
|
2328
|
+
for (const [type, label] of Object.entries(typeLabels)) {
|
|
2329
|
+
const items = groups[type];
|
|
2330
|
+
if (!items || items.length === 0)
|
|
2331
|
+
continue;
|
|
2332
|
+
output += `## ${label}
|
|
2333
|
+
`;
|
|
2334
|
+
for (const item of items) {
|
|
2335
|
+
output += `- [${item.title}]: ${item.content}
|
|
2336
|
+
`;
|
|
2337
|
+
}
|
|
2338
|
+
output += `
|
|
2339
|
+
`;
|
|
2340
|
+
}
|
|
2341
|
+
if (output.length === 0) {
|
|
2342
|
+
return null;
|
|
2343
|
+
}
|
|
2344
|
+
if (output.length > 2000) {
|
|
2345
|
+
output = `${output.slice(0, 1997)}...`;
|
|
2346
|
+
}
|
|
2347
|
+
return output.trimEnd();
|
|
2348
|
+
} catch {
|
|
2349
|
+
return null;
|
|
2350
|
+
}
|
|
2351
|
+
}
|
|
2064
2352
|
roleToText(role) {
|
|
2065
2353
|
if (!role) {
|
|
2066
2354
|
return null;
|
|
@@ -2081,11 +2369,12 @@ If you need more information about the project strategies, plans, or architectur
|
|
|
2081
2369
|
}
|
|
2082
2370
|
}
|
|
2083
2371
|
}
|
|
2084
|
-
var
|
|
2372
|
+
var import_node_fs4, import_node_path6, import_shared2;
|
|
2085
2373
|
var init_prompt_builder = __esm(() => {
|
|
2374
|
+
init_discussion_manager();
|
|
2086
2375
|
init_config();
|
|
2087
|
-
|
|
2088
|
-
|
|
2376
|
+
import_node_fs4 = require("node:fs");
|
|
2377
|
+
import_node_path6 = require("node:path");
|
|
2089
2378
|
import_shared2 = require("@locusai/shared");
|
|
2090
2379
|
});
|
|
2091
2380
|
|
|
@@ -2408,7 +2697,6 @@ Branch: \`${result.branch}\`` : "";
|
|
|
2408
2697
|
this.log("All tasks done. Creating pull request...", "info");
|
|
2409
2698
|
const prResult = this.gitWorkflow.createPullRequest(this.completedTaskList, this.taskSummaries);
|
|
2410
2699
|
if (prResult.url) {
|
|
2411
|
-
this.log(`PR created: ${prResult.url}`, "success");
|
|
2412
2700
|
for (const task of this.completedTaskList) {
|
|
2413
2701
|
try {
|
|
2414
2702
|
await this.client.tasks.update(task.id, this.config.workspaceId, {
|
package/dist/core/config.d.ts
CHANGED
|
@@ -21,8 +21,9 @@ export declare const LOCUS_CONFIG: {
|
|
|
21
21
|
sessionsDir: string;
|
|
22
22
|
reviewsDir: string;
|
|
23
23
|
plansDir: string;
|
|
24
|
+
discussionsDir: string;
|
|
24
25
|
};
|
|
25
|
-
export declare const LOCUS_GITIGNORE_PATTERNS: readonly ["# Locus AI - Session data (user-specific, can grow large)", ".locus/sessions/", "", "# Locus AI - Artifacts (local-only, user-specific)", ".locus/artifacts/", "", "# Locus AI - Review reports (generated per sprint)", ".locus/reviews/", "", "# Locus AI - Plans (generated per task)", ".locus/plans/", "", "# Locus AI - Settings (contains API key, telegram config, etc.)", ".locus/settings.json", "", "# Locus AI - Configuration (contains project context, etc.)", ".locus/config.json"];
|
|
26
|
+
export declare const LOCUS_GITIGNORE_PATTERNS: readonly ["# Locus AI - Session data (user-specific, can grow large)", ".locus/sessions/", "", "# Locus AI - Artifacts (local-only, user-specific)", ".locus/artifacts/", "", "# Locus AI - Review reports (generated per sprint)", ".locus/reviews/", "", "# Locus AI - Plans (generated per task)", ".locus/plans/", "", "# Locus AI - Discussions (AI discussion sessions)", ".locus/discussions/", "", "# Locus AI - Settings (contains API key, telegram config, etc.)", ".locus/settings.json", "", "# Locus AI - Configuration (contains project context, etc.)", ".locus/config.json"];
|
|
26
27
|
export declare function getLocusPath(projectPath: string, fileName: keyof typeof LOCUS_CONFIG): string;
|
|
27
28
|
/**
|
|
28
29
|
* Gets the artifacts directory path for a specific agent.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,QAAQ;;;CAGX,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,OAAO,QAAQ,CAAC,CAAC;AAEhE,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAGlD,CAAC;AAEF,eAAO,MAAM,qBAAqB,gCAAgC,CAAC;AAEnE,eAAO,MAAM,aAAa;;;CAGhB,CAAC;AAEX,eAAO,MAAM,YAAY
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,QAAQ;;;CAGX,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,OAAO,QAAQ,CAAC,CAAC;AAEhE,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAGlD,CAAC;AAEF,eAAO,MAAM,qBAAqB,gCAAgC,CAAC;AAEnE,eAAO,MAAM,aAAa;;;CAGhB,CAAC;AAEX,eAAO,MAAM,YAAY;;;;;;;;;;;;;CAaxB,CAAC;AAIF,eAAO,MAAM,wBAAwB,gkBAqB3B,CAAC;AAEX,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,OAAO,YAAY,GAClC,MAAM,CAER;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,GACd,MAAM,CASR"}
|
|
@@ -8,6 +8,7 @@ export declare class PromptBuilder {
|
|
|
8
8
|
private getFallbackContext;
|
|
9
9
|
private getKnowledgeBaseSection;
|
|
10
10
|
private getLearningsContent;
|
|
11
|
+
private getDiscussionInsightsContent;
|
|
11
12
|
roleToText(role: Task["assigneeRole"]): string | null;
|
|
12
13
|
}
|
|
13
14
|
//# sourceMappingURL=prompt-builder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt-builder.d.ts","sourceRoot":"","sources":["../../src/core/prompt-builder.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,IAAI,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"prompt-builder.d.ts","sourceRoot":"","sources":["../../src/core/prompt-builder.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAKrD,qBAAa,aAAa;IACZ,OAAO,CAAC,WAAW;gBAAX,WAAW,EAAE,MAAM;IAEjC,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC;IAuFlC,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAqCxD,OAAO,CAAC,iBAAiB;IAiBzB,OAAO,CAAC,kBAAkB;IAiB1B,OAAO,CAAC,uBAAuB;IAQ/B,OAAO,CAAC,mBAAmB;IAiB3B,OAAO,CAAC,4BAA4B;IAqDpC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,cAAc,CAAC,GAAG,MAAM,GAAG,IAAI;CAoBtD"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DiscussionInsight, DiscussionMessage } from "../discussion-types.js";
|
|
2
|
+
export interface FacilitatorPromptInput {
|
|
3
|
+
topic: string;
|
|
4
|
+
projectContext: string | null;
|
|
5
|
+
learnings: string | null;
|
|
6
|
+
knowledgeBase: string;
|
|
7
|
+
previousMessages: DiscussionMessage[];
|
|
8
|
+
insights: DiscussionInsight[];
|
|
9
|
+
isFirstMessage: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function buildFacilitatorPrompt(input: FacilitatorPromptInput): string;
|
|
12
|
+
export declare function buildSummaryPrompt(topic: string, messages: DiscussionMessage[], insights: DiscussionInsight[]): string;
|
|
13
|
+
//# sourceMappingURL=facilitator-prompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facilitator-prompt.d.ts","sourceRoot":"","sources":["../../../src/discussion/agents/facilitator-prompt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,wBAAwB,CAAC;AAEhC,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,iBAAiB,EAAE,CAAC;IACtC,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,sBAAsB,GAAG,MAAM,CAwF5E;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,iBAAiB,EAAE,EAC7B,QAAQ,EAAE,iBAAiB,EAAE,GAC5B,MAAM,CAwCR"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { LogFn } from "../ai/factory.js";
|
|
2
|
+
import type { AiRunner } from "../ai/runner.js";
|
|
3
|
+
import { Provider } from "../core/config.js";
|
|
4
|
+
import type { StreamChunk } from "../exec/types.js";
|
|
5
|
+
import type { DiscussionManager } from "./discussion-manager.js";
|
|
6
|
+
import type { Discussion, DiscussionInsight } from "./discussion-types.js";
|
|
7
|
+
export interface DiscussionFacilitatorConfig {
|
|
8
|
+
projectPath: string;
|
|
9
|
+
aiRunner: AiRunner;
|
|
10
|
+
discussionManager: DiscussionManager;
|
|
11
|
+
log?: LogFn;
|
|
12
|
+
provider: Provider;
|
|
13
|
+
model: string;
|
|
14
|
+
}
|
|
15
|
+
export interface StartDiscussionResult {
|
|
16
|
+
discussion: Discussion;
|
|
17
|
+
message: string;
|
|
18
|
+
}
|
|
19
|
+
export interface ContinueDiscussionResult {
|
|
20
|
+
response: string;
|
|
21
|
+
insights: DiscussionInsight[];
|
|
22
|
+
}
|
|
23
|
+
export declare class DiscussionFacilitator {
|
|
24
|
+
private projectPath;
|
|
25
|
+
private aiRunner;
|
|
26
|
+
private discussionManager;
|
|
27
|
+
private log;
|
|
28
|
+
private provider;
|
|
29
|
+
private model;
|
|
30
|
+
constructor(config: DiscussionFacilitatorConfig);
|
|
31
|
+
/**
|
|
32
|
+
* Start a new discussion on a topic. Creates the discussion,
|
|
33
|
+
* generates the AI's opening question, and saves it.
|
|
34
|
+
*/
|
|
35
|
+
startDiscussion(topic: string): Promise<StartDiscussionResult>;
|
|
36
|
+
/**
|
|
37
|
+
* Continue a discussion with a user message. Runs the AI to generate
|
|
38
|
+
* a response, extracts insights, and saves everything.
|
|
39
|
+
* Non-streaming path for Telegram and other non-interactive consumers.
|
|
40
|
+
*/
|
|
41
|
+
continueDiscussion(discussionId: string, userMessage: string): Promise<ContinueDiscussionResult>;
|
|
42
|
+
/**
|
|
43
|
+
* Continue a discussion with streaming support for CLI consumption.
|
|
44
|
+
* Yields stream chunks in real-time and returns the final result.
|
|
45
|
+
*/
|
|
46
|
+
continueDiscussionStream(discussionId: string, userMessage: string): AsyncGenerator<StreamChunk, ContinueDiscussionResult, unknown>;
|
|
47
|
+
/**
|
|
48
|
+
* Generate a final summary of the discussion, save it as the last
|
|
49
|
+
* assistant message, and mark the discussion as completed.
|
|
50
|
+
*/
|
|
51
|
+
summarizeDiscussion(discussionId: string): Promise<string>;
|
|
52
|
+
/**
|
|
53
|
+
* Extract <insight>...</insight> XML blocks from the AI response.
|
|
54
|
+
* Returns the cleaned response text (with insight tags removed) and
|
|
55
|
+
* the parsed insight objects.
|
|
56
|
+
*/
|
|
57
|
+
private parseInsights;
|
|
58
|
+
/**
|
|
59
|
+
* Build context from project files (LOCUS.md, LEARNINGS.md).
|
|
60
|
+
* Reuses the same logic as PromptBuilder.
|
|
61
|
+
*/
|
|
62
|
+
private buildContext;
|
|
63
|
+
private getProjectContext;
|
|
64
|
+
private getLearningsContent;
|
|
65
|
+
private getKnowledgeBaseSection;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=discussion-facilitator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discussion-facilitator.d.ts","sourceRoot":"","sources":["../../src/discussion/discussion-facilitator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAgB,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAKpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE3E,MAAM,WAAW,2BAA2B;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,QAAQ,CAAC;IACnB,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,GAAG,CAAC,EAAE,KAAK,CAAC;IACZ,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,UAAU,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,iBAAiB,EAAE,CAAC;CAC/B;AAED,qBAAa,qBAAqB;IAChC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,GAAG,CAAQ;IACnB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,KAAK,CAAS;gBAEV,MAAM,EAAE,2BAA2B;IAS/C;;;OAGG;IACG,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IA6CpE;;;;OAIG;IACG,kBAAkB,CACtB,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,wBAAwB,CAAC;IAsCpC;;;OAGG;IACI,wBAAwB,CAC7B,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,GAClB,cAAc,CAAC,WAAW,EAAE,wBAAwB,EAAE,OAAO,CAAC;IAkDjE;;;OAGG;IACG,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAwBhE;;;;OAIG;IACH,OAAO,CAAC,aAAa;IAyCrB;;;OAGG;IACH,OAAO,CAAC,YAAY;IAYpB,OAAO,CAAC,iBAAiB;IAezB,OAAO,CAAC,mBAAmB;IAiB3B,OAAO,CAAC,uBAAuB;CAMhC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { Discussion, DiscussionInsight } from "./discussion-types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Manages the lifecycle of discussions:
|
|
4
|
+
* create, save, load, list, complete, archive, delete.
|
|
5
|
+
*/
|
|
6
|
+
export declare class DiscussionManager {
|
|
7
|
+
private discussionsDir;
|
|
8
|
+
constructor(projectPath: string);
|
|
9
|
+
/**
|
|
10
|
+
* Create a new discussion for a given topic.
|
|
11
|
+
*/
|
|
12
|
+
create(topic: string, model: string, provider: string): Discussion;
|
|
13
|
+
/**
|
|
14
|
+
* Save a discussion to disk as JSON and summary markdown.
|
|
15
|
+
*/
|
|
16
|
+
save(discussion: Discussion): void;
|
|
17
|
+
/**
|
|
18
|
+
* Load a discussion by ID.
|
|
19
|
+
*/
|
|
20
|
+
load(id: string): Discussion | null;
|
|
21
|
+
/**
|
|
22
|
+
* List all discussions, optionally filtered by status. Sorted newest first.
|
|
23
|
+
*/
|
|
24
|
+
list(status?: Discussion["status"]): Discussion[];
|
|
25
|
+
/**
|
|
26
|
+
* Mark a discussion as completed.
|
|
27
|
+
*/
|
|
28
|
+
complete(id: string): Discussion;
|
|
29
|
+
/**
|
|
30
|
+
* Mark a discussion as archived.
|
|
31
|
+
*/
|
|
32
|
+
archive(id: string): void;
|
|
33
|
+
/**
|
|
34
|
+
* Delete a discussion's files entirely.
|
|
35
|
+
*/
|
|
36
|
+
delete(id: string): void;
|
|
37
|
+
/**
|
|
38
|
+
* Append a message to a discussion and save.
|
|
39
|
+
*/
|
|
40
|
+
addMessage(id: string, role: "user" | "assistant", content: string): Discussion;
|
|
41
|
+
/**
|
|
42
|
+
* Append an insight to a discussion and save.
|
|
43
|
+
*/
|
|
44
|
+
addInsight(id: string, insight: DiscussionInsight): Discussion;
|
|
45
|
+
/**
|
|
46
|
+
* Aggregate insights across all completed discussions.
|
|
47
|
+
*/
|
|
48
|
+
getAllInsights(): DiscussionInsight[];
|
|
49
|
+
/**
|
|
50
|
+
* Get the markdown content of a discussion for display.
|
|
51
|
+
*/
|
|
52
|
+
getMarkdown(id: string): string | null;
|
|
53
|
+
/**
|
|
54
|
+
* Render a discussion as readable markdown.
|
|
55
|
+
*/
|
|
56
|
+
toMarkdown(discussion: Discussion): string;
|
|
57
|
+
private ensureDir;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=discussion-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discussion-manager.d.ts","sourceRoot":"","sources":["../../src/discussion/discussion-manager.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE3E;;;GAGG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,cAAc,CAAS;gBAEnB,WAAW,EAAE,MAAM;IAI/B;;OAEG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU;IAsBlE;;OAEG;IACH,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI;IAUlC;;OAEG;IACH,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAenC;;OAEG;IACH,IAAI,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,GAAG,UAAU,EAAE;IA6BjD;;OAEG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU;IAahC;;OAEG;IACH,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAWzB;;OAEG;IACH,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAcxB;;OAEG;IACH,UAAU,CACR,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,GAAG,WAAW,EAC1B,OAAO,EAAE,MAAM,GACd,UAAU;IAiBb;;OAEG;IACH,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,UAAU;IAa9D;;OAEG;IACH,cAAc,IAAI,iBAAiB,EAAE;IAiBrC;;OAEG;IACH,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAMtC;;OAEG;IACH,UAAU,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM;IAkD1C,OAAO,CAAC,SAAS;CAKlB"}
|