@robota-sdk/agent-sdk 3.0.0-beta.56 → 3.0.0-beta.57
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 +15 -4
- package/dist/node/index.cjs +1966 -561
- package/dist/node/index.d.cts +232 -19
- package/dist/node/index.d.ts +232 -19
- package/dist/node/index.js +1938 -541
- package/package.json +6 -5
package/dist/node/index.cjs
CHANGED
|
@@ -39,19 +39,23 @@ __export(index_exports, {
|
|
|
39
39
|
BundlePluginInstaller: () => BundlePluginInstaller,
|
|
40
40
|
BundlePluginLoader: () => BundlePluginLoader,
|
|
41
41
|
CommandRegistry: () => CommandRegistry,
|
|
42
|
+
EditCheckpointStore: () => EditCheckpointStore,
|
|
42
43
|
InteractiveSession: () => InteractiveSession,
|
|
44
|
+
MEMORY_INDEX_MAX_BYTES: () => MEMORY_INDEX_MAX_BYTES,
|
|
45
|
+
MEMORY_INDEX_MAX_LINES: () => MEMORY_INDEX_MAX_LINES,
|
|
43
46
|
MarketplaceClient: () => MarketplaceClient,
|
|
44
47
|
PluginCommandSource: () => PluginCommandSource,
|
|
45
48
|
PluginSettingsStore: () => PluginSettingsStore,
|
|
49
|
+
ProjectMemoryStore: () => ProjectMemoryStore,
|
|
46
50
|
PromptExecutor: () => PromptExecutor,
|
|
47
51
|
SkillCommandSource: () => SkillCommandSource,
|
|
48
52
|
SubagentManager: () => import_agent_runtime7.SubagentManager,
|
|
49
53
|
SystemCommandExecutor: () => SystemCommandExecutor,
|
|
50
|
-
TRUST_TO_MODE: () =>
|
|
54
|
+
TRUST_TO_MODE: () => import_agent_core5.TRUST_TO_MODE,
|
|
51
55
|
WorktreeSubagentRunner: () => import_agent_runtime8.WorktreeSubagentRunner,
|
|
52
56
|
assembleSubagentPrompt: () => assembleSubagentPrompt,
|
|
53
57
|
buildSkillPrompt: () => buildSkillPrompt,
|
|
54
|
-
chatEntryToMessage: () =>
|
|
58
|
+
chatEntryToMessage: () => import_agent_core6.chatEntryToMessage,
|
|
55
59
|
createAgentTool: () => createAgentTool,
|
|
56
60
|
createBackgroundProcessTool: () => createBackgroundProcessTool,
|
|
57
61
|
createCommandExecutionTool: () => createCommandExecutionTool,
|
|
@@ -61,33 +65,44 @@ __export(index_exports, {
|
|
|
61
65
|
createSubagentSession: () => createSubagentSession,
|
|
62
66
|
createSystemCommands: () => createSystemCommands,
|
|
63
67
|
createWorktreeSubagentRunner: () => import_agent_runtime8.createWorktreeSubagentRunner,
|
|
64
|
-
|
|
68
|
+
discoverTaskFiles: () => discoverTaskFiles,
|
|
69
|
+
evaluatePermission: () => import_agent_core7.evaluatePermission,
|
|
65
70
|
executeSkill: () => executeSkill,
|
|
71
|
+
formatTaskContext: () => formatTaskContext,
|
|
66
72
|
getBackgroundTaskTransitions: () => import_agent_runtime4.getBackgroundTaskTransitions,
|
|
67
73
|
getBuiltInAgent: () => getBuiltInAgent,
|
|
68
74
|
getForkWorkerSuffix: () => getForkWorkerSuffix,
|
|
69
|
-
getMessagesForAPI: () =>
|
|
75
|
+
getMessagesForAPI: () => import_agent_core6.getMessagesForAPI,
|
|
70
76
|
getSubagentSuffix: () => getSubagentSuffix,
|
|
71
|
-
isChatEntry: () =>
|
|
77
|
+
isChatEntry: () => import_agent_core6.isChatEntry,
|
|
78
|
+
isMemoryType: () => isMemoryType,
|
|
72
79
|
isTerminalBackgroundTaskStatus: () => import_agent_runtime4.isTerminalBackgroundTaskStatus,
|
|
73
|
-
|
|
80
|
+
loadTaskContext: () => loadTaskContext,
|
|
81
|
+
messageToHistoryEntry: () => import_agent_core6.messageToHistoryEntry,
|
|
74
82
|
parseFrontmatter: () => parseFrontmatter,
|
|
83
|
+
parseTaskFile: () => parseTaskFile,
|
|
84
|
+
planSelfHostingVerification: () => planSelfHostingVerification,
|
|
75
85
|
preprocessShellCommands: () => preprocessShellCommands,
|
|
76
86
|
projectPaths: () => projectPaths,
|
|
77
87
|
promptForApproval: () => promptForApproval,
|
|
88
|
+
readCurrentGitBranch: () => readCurrentGitBranch,
|
|
78
89
|
resolveSubagentLogDir: () => resolveSubagentLogDir,
|
|
79
90
|
retrieveAgentToolDeps: () => retrieveAgentToolDeps,
|
|
80
|
-
runHooks: () =>
|
|
91
|
+
runHooks: () => import_agent_core8.runHooks,
|
|
92
|
+
selectRelevantTasks: () => selectRelevantTasks,
|
|
81
93
|
storeAgentToolDeps: () => storeAgentToolDeps,
|
|
82
94
|
substituteVariables: () => substituteVariables,
|
|
83
95
|
summarizeBackgroundJobGroup: () => summarizeBackgroundJobGroup,
|
|
84
96
|
transitionBackgroundTaskStatus: () => import_agent_runtime4.transitionBackgroundTaskStatus,
|
|
85
|
-
|
|
97
|
+
transitionSelfHostingLoop: () => transitionSelfHostingLoop,
|
|
98
|
+
updateTaskFileStatus: () => updateTaskFileStatus,
|
|
99
|
+
userPaths: () => userPaths,
|
|
100
|
+
wrapEditCheckpointTools: () => wrapEditCheckpointTools
|
|
86
101
|
});
|
|
87
102
|
module.exports = __toCommonJS(index_exports);
|
|
88
103
|
|
|
89
104
|
// src/interactive/interactive-session.ts
|
|
90
|
-
var
|
|
105
|
+
var import_agent_core4 = require("@robota-sdk/agent-core");
|
|
91
106
|
|
|
92
107
|
// src/commands/capability-descriptors.ts
|
|
93
108
|
function inferKind(command) {
|
|
@@ -186,6 +201,28 @@ function buildBackgroundSubcommands() {
|
|
|
186
201
|
{ name: "close", description: "Dismiss a terminal background task", source: "builtin" }
|
|
187
202
|
];
|
|
188
203
|
}
|
|
204
|
+
function buildRewindSubcommands() {
|
|
205
|
+
return [
|
|
206
|
+
{ name: "list", description: "List edit checkpoints", source: "builtin" },
|
|
207
|
+
{ name: "restore", description: "Restore code to a checkpoint", source: "builtin" },
|
|
208
|
+
{ name: "code", description: "Restore code to a checkpoint", source: "builtin" }
|
|
209
|
+
];
|
|
210
|
+
}
|
|
211
|
+
function buildMemorySubcommands() {
|
|
212
|
+
return [
|
|
213
|
+
{ name: "list", description: "List project memory topics", source: "builtin" },
|
|
214
|
+
{ name: "show", description: "Show project memory index or a topic", source: "builtin" },
|
|
215
|
+
{ name: "add", description: "Save durable project memory", source: "builtin" },
|
|
216
|
+
{ name: "pending", description: "List pending memory candidates", source: "builtin" },
|
|
217
|
+
{ name: "approve", description: "Approve a pending memory candidate", source: "builtin" },
|
|
218
|
+
{ name: "reject", description: "Reject a pending memory candidate", source: "builtin" },
|
|
219
|
+
{
|
|
220
|
+
name: "used",
|
|
221
|
+
description: "Show memory references used in the current turn",
|
|
222
|
+
source: "builtin"
|
|
223
|
+
}
|
|
224
|
+
];
|
|
225
|
+
}
|
|
189
226
|
function createBuiltinCommands() {
|
|
190
227
|
return [
|
|
191
228
|
{ name: "help", description: "Show available commands", source: "builtin" },
|
|
@@ -222,6 +259,18 @@ function createBuiltinCommands() {
|
|
|
222
259
|
{ name: "cost", description: "Show session info", source: "builtin" },
|
|
223
260
|
{ name: "context", description: "Context window info", source: "builtin" },
|
|
224
261
|
{ name: "permissions", description: "Permission rules", source: "builtin" },
|
|
262
|
+
{
|
|
263
|
+
name: "memory",
|
|
264
|
+
description: "Inspect, save, review, and audit project memory",
|
|
265
|
+
source: "builtin",
|
|
266
|
+
subcommands: buildMemorySubcommands()
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
name: "rewind",
|
|
270
|
+
description: "List and restore edit checkpoints",
|
|
271
|
+
source: "builtin",
|
|
272
|
+
subcommands: buildRewindSubcommands()
|
|
273
|
+
},
|
|
225
274
|
{
|
|
226
275
|
name: "provider",
|
|
227
276
|
description: "Manage provider profiles",
|
|
@@ -468,8 +517,502 @@ Next offset: ${page.nextCursor.offset}` : "";
|
|
|
468
517
|
return { message: `Unknown background action: ${action}`, success: false };
|
|
469
518
|
}
|
|
470
519
|
|
|
520
|
+
// src/memory/pending-memory-store.ts
|
|
521
|
+
var import_node_fs2 = require("fs");
|
|
522
|
+
var import_node_path2 = require("path");
|
|
523
|
+
var PENDING_FILENAME = "pending.json";
|
|
524
|
+
function memoryRoot(cwd) {
|
|
525
|
+
return (0, import_node_path2.join)(cwd, ".robota", "memory");
|
|
526
|
+
}
|
|
527
|
+
function emptyDocument() {
|
|
528
|
+
return { version: 1, records: [] };
|
|
529
|
+
}
|
|
530
|
+
var PendingMemoryStore = class {
|
|
531
|
+
path;
|
|
532
|
+
now;
|
|
533
|
+
constructor(cwd, now = () => /* @__PURE__ */ new Date()) {
|
|
534
|
+
this.path = (0, import_node_path2.join)(memoryRoot(cwd), PENDING_FILENAME);
|
|
535
|
+
this.now = now;
|
|
536
|
+
}
|
|
537
|
+
getPath() {
|
|
538
|
+
return this.path;
|
|
539
|
+
}
|
|
540
|
+
list(status) {
|
|
541
|
+
const records = this.read().records;
|
|
542
|
+
return status ? records.filter((record) => record.status === status) : records;
|
|
543
|
+
}
|
|
544
|
+
get(id) {
|
|
545
|
+
return this.read().records.find((record) => record.id === id);
|
|
546
|
+
}
|
|
547
|
+
upsert(candidate, status, reason) {
|
|
548
|
+
const document = this.read();
|
|
549
|
+
const updatedAt = this.now().toISOString();
|
|
550
|
+
const existingIndex = document.records.findIndex((record2) => record2.id === candidate.id);
|
|
551
|
+
const record = {
|
|
552
|
+
...candidate,
|
|
553
|
+
status,
|
|
554
|
+
updatedAt,
|
|
555
|
+
decisionReason: reason
|
|
556
|
+
};
|
|
557
|
+
if (existingIndex >= 0) {
|
|
558
|
+
document.records[existingIndex] = { ...document.records[existingIndex], ...record };
|
|
559
|
+
} else {
|
|
560
|
+
document.records.push(record);
|
|
561
|
+
}
|
|
562
|
+
this.write(document);
|
|
563
|
+
}
|
|
564
|
+
mark(id, status, reason) {
|
|
565
|
+
const document = this.read();
|
|
566
|
+
const index = document.records.findIndex((record2) => record2.id === id);
|
|
567
|
+
if (index < 0) throw new Error(`Memory candidate not found: ${id}`);
|
|
568
|
+
const record = {
|
|
569
|
+
...document.records[index],
|
|
570
|
+
status,
|
|
571
|
+
updatedAt: this.now().toISOString(),
|
|
572
|
+
decisionReason: reason
|
|
573
|
+
};
|
|
574
|
+
document.records[index] = record;
|
|
575
|
+
this.write(document);
|
|
576
|
+
return record;
|
|
577
|
+
}
|
|
578
|
+
read() {
|
|
579
|
+
if (!(0, import_node_fs2.existsSync)(this.path)) return emptyDocument();
|
|
580
|
+
try {
|
|
581
|
+
const parsed = JSON.parse((0, import_node_fs2.readFileSync)(this.path, "utf8"));
|
|
582
|
+
return { version: 1, records: parsed.records ?? [] };
|
|
583
|
+
} catch {
|
|
584
|
+
return emptyDocument();
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
write(document) {
|
|
588
|
+
(0, import_node_fs2.mkdirSync)((0, import_node_path2.dirname)(this.path), { recursive: true });
|
|
589
|
+
(0, import_node_fs2.writeFileSync)(this.path, JSON.stringify(document, null, 2), "utf8");
|
|
590
|
+
}
|
|
591
|
+
};
|
|
592
|
+
|
|
593
|
+
// src/memory/project-memory-store.ts
|
|
594
|
+
var import_fs = require("fs");
|
|
595
|
+
var import_path = require("path");
|
|
596
|
+
var MEMORY_INDEX_MAX_LINES = 200;
|
|
597
|
+
var MEMORY_INDEX_MAX_BYTES = Number("25600");
|
|
598
|
+
var INDEX_FILENAME = "MEMORY.md";
|
|
599
|
+
var TOPICS_DIRNAME = "topics";
|
|
600
|
+
var DATE_LENGTH = 10;
|
|
601
|
+
var MAX_TOPIC_LENGTH = 80;
|
|
602
|
+
var DEFAULT_TOPIC = "general";
|
|
603
|
+
var TOPIC_EXTENSION = ".md";
|
|
604
|
+
var VALID_TYPES = ["user", "feedback", "project", "reference"];
|
|
605
|
+
function isMemoryType(value) {
|
|
606
|
+
return VALID_TYPES.includes(value);
|
|
607
|
+
}
|
|
608
|
+
function memoryRoot2(cwd) {
|
|
609
|
+
return (0, import_path.join)(cwd, ".robota", "memory");
|
|
610
|
+
}
|
|
611
|
+
function truncateToUtf8Bytes(value, maxBytes) {
|
|
612
|
+
const buffer = Buffer.from(value, "utf8");
|
|
613
|
+
if (buffer.byteLength <= maxBytes) return value;
|
|
614
|
+
return buffer.subarray(0, maxBytes).toString("utf8");
|
|
615
|
+
}
|
|
616
|
+
function limitLines(value, maxLines) {
|
|
617
|
+
const lines = value.split(/\r?\n/);
|
|
618
|
+
const limited = lines.slice(0, maxLines);
|
|
619
|
+
return {
|
|
620
|
+
content: limited.join("\n").trimEnd(),
|
|
621
|
+
truncated: lines.length > maxLines
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
function sanitizeTopic(topic) {
|
|
625
|
+
const normalized = topic.trim().toLowerCase().replace(/[^a-z0-9가-힣_-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, MAX_TOPIC_LENGTH);
|
|
626
|
+
return normalized || DEFAULT_TOPIC;
|
|
627
|
+
}
|
|
628
|
+
function formatEntry(date, input, topic) {
|
|
629
|
+
const day = date.toISOString().slice(0, DATE_LENGTH);
|
|
630
|
+
const text = input.text.trim().replace(/\s+/g, " ");
|
|
631
|
+
return `[${day}] (${input.type}/${topic}) ${text}`;
|
|
632
|
+
}
|
|
633
|
+
function normalizeMemoryText(text) {
|
|
634
|
+
return text.trim().replace(/\s+/g, " ");
|
|
635
|
+
}
|
|
636
|
+
var ProjectMemoryStore = class {
|
|
637
|
+
cwd;
|
|
638
|
+
now;
|
|
639
|
+
constructor(cwd, now = () => /* @__PURE__ */ new Date()) {
|
|
640
|
+
this.cwd = cwd;
|
|
641
|
+
this.now = now;
|
|
642
|
+
}
|
|
643
|
+
getIndexPath() {
|
|
644
|
+
return (0, import_path.join)(memoryRoot2(this.cwd), INDEX_FILENAME);
|
|
645
|
+
}
|
|
646
|
+
getTopicsPath() {
|
|
647
|
+
return (0, import_path.join)(memoryRoot2(this.cwd), TOPICS_DIRNAME);
|
|
648
|
+
}
|
|
649
|
+
loadStartupMemory() {
|
|
650
|
+
const path = this.getIndexPath();
|
|
651
|
+
if (!(0, import_fs.existsSync)(path)) {
|
|
652
|
+
return { content: "", path, lineCount: 0, truncated: false };
|
|
653
|
+
}
|
|
654
|
+
const raw = (0, import_fs.readFileSync)(path, "utf8");
|
|
655
|
+
const byBytes = truncateToUtf8Bytes(raw, MEMORY_INDEX_MAX_BYTES);
|
|
656
|
+
const byteTruncated = Buffer.byteLength(raw, "utf8") > MEMORY_INDEX_MAX_BYTES;
|
|
657
|
+
const byLines = limitLines(byBytes, MEMORY_INDEX_MAX_LINES);
|
|
658
|
+
return {
|
|
659
|
+
content: byLines.content,
|
|
660
|
+
path,
|
|
661
|
+
lineCount: byLines.content.length === 0 ? 0 : byLines.content.split(/\r?\n/).length,
|
|
662
|
+
truncated: byteTruncated || byLines.truncated
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
list() {
|
|
666
|
+
const topicsPath = this.getTopicsPath();
|
|
667
|
+
const topics = (0, import_fs.existsSync)(topicsPath) ? (0, import_fs.readdirSync)(topicsPath, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(TOPIC_EXTENSION)).map((entry) => ({
|
|
668
|
+
name: (0, import_path.basename)(entry.name, TOPIC_EXTENSION),
|
|
669
|
+
path: (0, import_path.join)(topicsPath, entry.name)
|
|
670
|
+
})).sort((a, b) => a.name.localeCompare(b.name)) : [];
|
|
671
|
+
return {
|
|
672
|
+
indexPath: this.getIndexPath(),
|
|
673
|
+
topicsPath,
|
|
674
|
+
topics
|
|
675
|
+
};
|
|
676
|
+
}
|
|
677
|
+
readTopic(topic) {
|
|
678
|
+
const normalized = sanitizeTopic(topic);
|
|
679
|
+
const path = (0, import_path.join)(this.getTopicsPath(), `${normalized}${TOPIC_EXTENSION}`);
|
|
680
|
+
if (!(0, import_fs.existsSync)(path)) return "";
|
|
681
|
+
return (0, import_fs.readFileSync)(path, "utf8").trimEnd();
|
|
682
|
+
}
|
|
683
|
+
append(input) {
|
|
684
|
+
const topic = sanitizeTopic(input.topic);
|
|
685
|
+
const root = memoryRoot2(this.cwd);
|
|
686
|
+
const topicsPath = this.getTopicsPath();
|
|
687
|
+
(0, import_fs.mkdirSync)(topicsPath, { recursive: true });
|
|
688
|
+
const indexPath = this.getIndexPath();
|
|
689
|
+
const topicPath = (0, import_path.join)(topicsPath, `${topic}${TOPIC_EXTENSION}`);
|
|
690
|
+
const entry = formatEntry(this.now(), input, topic);
|
|
691
|
+
const topicHeader = (0, import_fs.existsSync)(topicPath) ? "" : `# ${topic}
|
|
692
|
+
|
|
693
|
+
`;
|
|
694
|
+
const normalizedText = normalizeMemoryText(input.text);
|
|
695
|
+
if ((0, import_fs.existsSync)(topicPath) && (0, import_fs.readFileSync)(topicPath, "utf8").includes(`) ${normalizedText}`)) {
|
|
696
|
+
return { indexPath, topicPath, topic, deduplicated: true };
|
|
697
|
+
}
|
|
698
|
+
if (!(0, import_fs.existsSync)(indexPath)) {
|
|
699
|
+
(0, import_fs.mkdirSync)(root, { recursive: true });
|
|
700
|
+
(0, import_fs.writeFileSync)(indexPath, "# Project Memory\n\n", "utf8");
|
|
701
|
+
}
|
|
702
|
+
(0, import_fs.appendFileSync)(indexPath, `- ${entry}
|
|
703
|
+
`, "utf8");
|
|
704
|
+
(0, import_fs.appendFileSync)(topicPath, `${topicHeader}- ${entry}
|
|
705
|
+
`, "utf8");
|
|
706
|
+
return { indexPath, topicPath, topic, deduplicated: false };
|
|
707
|
+
}
|
|
708
|
+
};
|
|
709
|
+
|
|
710
|
+
// src/memory/memory-policy-evaluator.ts
|
|
711
|
+
var SENSITIVE_PATTERNS = [
|
|
712
|
+
/\b(api[_-]?key|secret|token|password|private key)\b/i,
|
|
713
|
+
/\b\d{3}-\d{2}-\d{4}\b/,
|
|
714
|
+
/\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b/,
|
|
715
|
+
/주민등록|비밀번호|시크릿|토큰/u
|
|
716
|
+
];
|
|
717
|
+
function containsSensitiveMemoryContent(text) {
|
|
718
|
+
return SENSITIVE_PATTERNS.some((pattern) => pattern.test(text));
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
// src/commands/memory-command.ts
|
|
722
|
+
var SUBCOMMAND_INDEX = 0;
|
|
723
|
+
var TYPE_INDEX = 1;
|
|
724
|
+
var TOPIC_INDEX = 2;
|
|
725
|
+
var TEXT_START_INDEX = 3;
|
|
726
|
+
function usage() {
|
|
727
|
+
return {
|
|
728
|
+
message: "Usage: memory list | memory show [topic] | memory add <user|feedback|project|reference> <topic> <text> | memory pending | memory approve <id> | memory reject <id> | memory used",
|
|
729
|
+
success: false
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
function formatList(store) {
|
|
733
|
+
const summary = store.list();
|
|
734
|
+
const topics = summary.topics.length > 0 ? summary.topics.map((topic) => `- ${topic.name}: ${topic.path}`).join("\n") : "(none)";
|
|
735
|
+
return {
|
|
736
|
+
message: [
|
|
737
|
+
`Memory index: ${summary.indexPath}`,
|
|
738
|
+
`Topics directory: ${summary.topicsPath}`,
|
|
739
|
+
"Topics:",
|
|
740
|
+
topics
|
|
741
|
+
].join("\n"),
|
|
742
|
+
success: true,
|
|
743
|
+
data: {
|
|
744
|
+
indexPath: summary.indexPath,
|
|
745
|
+
topicsPath: summary.topicsPath,
|
|
746
|
+
topicCount: summary.topics.length
|
|
747
|
+
}
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
function formatShow(store, topic) {
|
|
751
|
+
if (!topic || topic === "index") {
|
|
752
|
+
const memory = store.loadStartupMemory();
|
|
753
|
+
return {
|
|
754
|
+
message: memory.content || "(empty memory index)",
|
|
755
|
+
success: true,
|
|
756
|
+
data: {
|
|
757
|
+
path: memory.path,
|
|
758
|
+
lineCount: memory.lineCount,
|
|
759
|
+
truncated: memory.truncated
|
|
760
|
+
}
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
const content = store.readTopic(topic);
|
|
764
|
+
return {
|
|
765
|
+
message: content || `(empty memory topic: ${topic})`,
|
|
766
|
+
success: true,
|
|
767
|
+
data: { topic }
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
function parseAdd(args) {
|
|
771
|
+
const type = args[TYPE_INDEX];
|
|
772
|
+
const topic = args[TOPIC_INDEX];
|
|
773
|
+
const text = args.slice(TEXT_START_INDEX).join(" ").trim();
|
|
774
|
+
if (!type || !isMemoryType(type) || !topic || text.length === 0) return void 0;
|
|
775
|
+
return { type, topic, text };
|
|
776
|
+
}
|
|
777
|
+
function formatPending(store) {
|
|
778
|
+
const records = store.list("pending");
|
|
779
|
+
const lines = records.length > 0 ? records.map(
|
|
780
|
+
(record) => `- ${record.id} ${record.type}/${record.topic} confidence=${record.confidence}: ${record.text}`
|
|
781
|
+
) : ["(no pending memory candidates)"];
|
|
782
|
+
return {
|
|
783
|
+
message: ["Pending memory candidates:", ...lines].join("\n"),
|
|
784
|
+
success: true,
|
|
785
|
+
data: { count: records.length }
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
function recordEvent(session, event) {
|
|
789
|
+
session.recordMemoryEvent({
|
|
790
|
+
...event,
|
|
791
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
function approvePending(session, pendingStore, memoryStore, id) {
|
|
795
|
+
if (!id) return usage();
|
|
796
|
+
try {
|
|
797
|
+
const approved = pendingStore.mark(id, "approved", "approved-by-user");
|
|
798
|
+
const saved = memoryStore.append(approved);
|
|
799
|
+
const record = pendingStore.mark(id, "saved", "approved-and-saved");
|
|
800
|
+
recordEvent(session, {
|
|
801
|
+
type: "memory_candidate_approved",
|
|
802
|
+
candidateId: record.id,
|
|
803
|
+
topic: record.topic,
|
|
804
|
+
reason: "approved-by-user"
|
|
805
|
+
});
|
|
806
|
+
recordEvent(session, {
|
|
807
|
+
type: "memory_candidate_saved",
|
|
808
|
+
candidateId: record.id,
|
|
809
|
+
topic: record.topic,
|
|
810
|
+
reason: saved.deduplicated ? "deduplicated" : "approved-and-saved"
|
|
811
|
+
});
|
|
812
|
+
return {
|
|
813
|
+
message: saved.deduplicated ? `Saved memory candidate ${id} was already present in ${saved.topicPath}` : `Saved memory candidate ${id} to ${saved.topicPath}`,
|
|
814
|
+
success: true,
|
|
815
|
+
data: {
|
|
816
|
+
id,
|
|
817
|
+
status: record.status,
|
|
818
|
+
topic: saved.topic,
|
|
819
|
+
topicPath: saved.topicPath,
|
|
820
|
+
deduplicated: saved.deduplicated
|
|
821
|
+
}
|
|
822
|
+
};
|
|
823
|
+
} catch (error) {
|
|
824
|
+
return {
|
|
825
|
+
message: error instanceof Error ? error.message : String(error),
|
|
826
|
+
success: false
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
function rejectPending(session, pendingStore, id) {
|
|
831
|
+
if (!id) return usage();
|
|
832
|
+
try {
|
|
833
|
+
const record = pendingStore.mark(id, "rejected", "rejected-by-user");
|
|
834
|
+
recordEvent(session, {
|
|
835
|
+
type: "memory_candidate_rejected",
|
|
836
|
+
candidateId: record.id,
|
|
837
|
+
topic: record.topic,
|
|
838
|
+
reason: "rejected-by-user"
|
|
839
|
+
});
|
|
840
|
+
return {
|
|
841
|
+
message: `Rejected memory candidate ${id}`,
|
|
842
|
+
success: true,
|
|
843
|
+
data: { id, status: record.status }
|
|
844
|
+
};
|
|
845
|
+
} catch (error) {
|
|
846
|
+
return {
|
|
847
|
+
message: error instanceof Error ? error.message : String(error),
|
|
848
|
+
success: false
|
|
849
|
+
};
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
function formatUsed(session) {
|
|
853
|
+
const references = session.getUsedMemoryReferences();
|
|
854
|
+
const lines = references.length > 0 ? references.map((reference) => {
|
|
855
|
+
const suffix = reference.truncated ? " truncated=true" : "";
|
|
856
|
+
return `- ${reference.topic} score=${reference.score}${suffix}: ${reference.path}`;
|
|
857
|
+
}) : ["(no memory used in current turn)"];
|
|
858
|
+
return {
|
|
859
|
+
message: ["Used memory references:", ...lines].join("\n"),
|
|
860
|
+
success: true,
|
|
861
|
+
data: { count: references.length, references }
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
function executeMemoryCommand(session, rawArgs) {
|
|
865
|
+
const args = rawArgs.trim().split(/\s+/).filter(Boolean);
|
|
866
|
+
const subcommand = args[SUBCOMMAND_INDEX] ?? "list";
|
|
867
|
+
const store = new ProjectMemoryStore(session.getCwd());
|
|
868
|
+
const pendingStore = new PendingMemoryStore(session.getCwd());
|
|
869
|
+
if (subcommand === "list") return formatList(store);
|
|
870
|
+
if (subcommand === "show") return formatShow(store, args[TYPE_INDEX]);
|
|
871
|
+
if (subcommand === "pending") return formatPending(pendingStore);
|
|
872
|
+
if (subcommand === "approve")
|
|
873
|
+
return approvePending(session, pendingStore, store, args[TYPE_INDEX]);
|
|
874
|
+
if (subcommand === "reject") return rejectPending(session, pendingStore, args[TYPE_INDEX]);
|
|
875
|
+
if (subcommand === "used") return formatUsed(session);
|
|
876
|
+
if (subcommand === "add") {
|
|
877
|
+
const input = parseAdd(args);
|
|
878
|
+
if (!input) return usage();
|
|
879
|
+
if (containsSensitiveMemoryContent(input.text)) {
|
|
880
|
+
return {
|
|
881
|
+
message: "Refusing to save sensitive memory content.",
|
|
882
|
+
success: false
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
const result = store.append(input);
|
|
886
|
+
return {
|
|
887
|
+
message: result.deduplicated ? `${input.type} memory already exists in ${result.topicPath}` : `Saved ${input.type} memory to ${result.topicPath}`,
|
|
888
|
+
success: true,
|
|
889
|
+
data: {
|
|
890
|
+
indexPath: result.indexPath,
|
|
891
|
+
topicPath: result.topicPath,
|
|
892
|
+
topic: result.topic,
|
|
893
|
+
deduplicated: result.deduplicated
|
|
894
|
+
}
|
|
895
|
+
};
|
|
896
|
+
}
|
|
897
|
+
return usage();
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
// src/commands/rewind-command.ts
|
|
901
|
+
var SUBCOMMAND_INDEX2 = 0;
|
|
902
|
+
var CHECKPOINT_ID_INDEX = 1;
|
|
903
|
+
var PROMPT_PREVIEW_LENGTH = 120;
|
|
904
|
+
var ELLIPSIS_LENGTH = 3;
|
|
905
|
+
function usage2() {
|
|
906
|
+
return {
|
|
907
|
+
message: "Usage: rewind [list] | rewind restore <checkpoint-id> | rewind code <checkpoint-id>",
|
|
908
|
+
success: false
|
|
909
|
+
};
|
|
910
|
+
}
|
|
911
|
+
function formatPrompt(prompt) {
|
|
912
|
+
const compact = prompt.replace(/\s+/g, " ").trim();
|
|
913
|
+
if (compact.length <= PROMPT_PREVIEW_LENGTH) return compact;
|
|
914
|
+
return `${compact.slice(0, PROMPT_PREVIEW_LENGTH - ELLIPSIS_LENGTH)}...`;
|
|
915
|
+
}
|
|
916
|
+
function formatList2(checkpoints) {
|
|
917
|
+
const lines = checkpoints.length > 0 ? checkpoints.map(
|
|
918
|
+
(checkpoint) => `- ${checkpoint.id} files=${checkpoint.fileCount} ${checkpoint.createdAt} ${formatPrompt(
|
|
919
|
+
checkpoint.prompt
|
|
920
|
+
)}`
|
|
921
|
+
) : ["(no edit checkpoints)"];
|
|
922
|
+
return {
|
|
923
|
+
message: ["Edit checkpoints:", ...lines].join("\n"),
|
|
924
|
+
success: true,
|
|
925
|
+
data: { count: checkpoints.length, checkpoints: [...checkpoints] }
|
|
926
|
+
};
|
|
927
|
+
}
|
|
928
|
+
async function restore(session, checkpointId) {
|
|
929
|
+
if (!checkpointId) return usage2();
|
|
930
|
+
try {
|
|
931
|
+
const result = await session.restoreEditCheckpoint(checkpointId);
|
|
932
|
+
return {
|
|
933
|
+
message: [
|
|
934
|
+
`Restored code to ${result.target.id}.`,
|
|
935
|
+
`Restored files: ${result.restoredFileCount}`,
|
|
936
|
+
`Rolled back checkpoints: ${result.restoredCheckpointCount}`
|
|
937
|
+
].join("\n"),
|
|
938
|
+
success: true,
|
|
939
|
+
data: {
|
|
940
|
+
target: result.target,
|
|
941
|
+
restoredCheckpointCount: result.restoredCheckpointCount,
|
|
942
|
+
restoredFileCount: result.restoredFileCount,
|
|
943
|
+
removedCheckpointCount: result.removedCheckpointCount
|
|
944
|
+
}
|
|
945
|
+
};
|
|
946
|
+
} catch (error) {
|
|
947
|
+
return {
|
|
948
|
+
message: error instanceof Error ? error.message : String(error),
|
|
949
|
+
success: false
|
|
950
|
+
};
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
async function executeRewindCommand(session, rawArgs) {
|
|
954
|
+
const args = rawArgs.trim().split(/\s+/).filter(Boolean);
|
|
955
|
+
const subcommand = args[SUBCOMMAND_INDEX2] ?? "list";
|
|
956
|
+
if (subcommand === "list") {
|
|
957
|
+
return formatList2(session.listEditCheckpoints());
|
|
958
|
+
}
|
|
959
|
+
if (subcommand === "restore" || subcommand === "code") {
|
|
960
|
+
return restore(session, args[CHECKPOINT_ID_INDEX]);
|
|
961
|
+
}
|
|
962
|
+
return usage2();
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
// src/commands/system-command-executor.ts
|
|
966
|
+
var SystemCommandExecutor = class {
|
|
967
|
+
commands;
|
|
968
|
+
constructor(commands) {
|
|
969
|
+
this.commands = /* @__PURE__ */ new Map();
|
|
970
|
+
for (const cmd of commands ?? createSystemCommands()) {
|
|
971
|
+
this.commands.set(cmd.name, cmd);
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
/** Register an additional command. */
|
|
975
|
+
register(command) {
|
|
976
|
+
this.commands.set(command.name, command);
|
|
977
|
+
}
|
|
978
|
+
/** Execute a command by name. Returns null if command not found. */
|
|
979
|
+
async execute(name, session, args) {
|
|
980
|
+
const cmd = this.commands.get(name);
|
|
981
|
+
if (!cmd) return null;
|
|
982
|
+
return await cmd.execute(session, args);
|
|
983
|
+
}
|
|
984
|
+
/** List all registered commands. */
|
|
985
|
+
listCommands() {
|
|
986
|
+
return [...this.commands.values()];
|
|
987
|
+
}
|
|
988
|
+
listModelInvocableCommands() {
|
|
989
|
+
return this.listCommands().filter((command) => command.modelInvocable === true).map((command) => ({
|
|
990
|
+
name: `/${command.name}`,
|
|
991
|
+
kind: "builtin-command",
|
|
992
|
+
description: command.description,
|
|
993
|
+
userInvocable: command.userInvocable !== false,
|
|
994
|
+
modelInvocable: true,
|
|
995
|
+
...command.argumentHint ? { argumentHint: command.argumentHint } : {},
|
|
996
|
+
...command.safety ? { safety: command.safety } : {}
|
|
997
|
+
}));
|
|
998
|
+
}
|
|
999
|
+
isModelInvocable(name) {
|
|
1000
|
+
return this.commands.get(name)?.modelInvocable === true;
|
|
1001
|
+
}
|
|
1002
|
+
async executeModelInvocable(name, session, args) {
|
|
1003
|
+
if (!this.isModelInvocable(name)) return null;
|
|
1004
|
+
return this.execute(name, session, args);
|
|
1005
|
+
}
|
|
1006
|
+
/** Check if a command exists. */
|
|
1007
|
+
hasCommand(name) {
|
|
1008
|
+
return this.commands.has(name);
|
|
1009
|
+
}
|
|
1010
|
+
};
|
|
1011
|
+
|
|
471
1012
|
// src/commands/system-command.ts
|
|
472
1013
|
var VALID_MODES = ["plan", "default", "acceptEdits", "bypassPermissions"];
|
|
1014
|
+
var MEMORY_COMMAND_DESCRIPTION = "Project memory command. Use it to inspect project memory when stored context may help, save durable preferences, project conventions, feedback, or references worth reusing across sessions, review pending candidates, and report memory provenance. Do not store secrets, credentials, or transient facts.";
|
|
1015
|
+
var MEMORY_COMMAND_ARGUMENT_HINT = "list | show [topic] | add <user|feedback|project|reference> <topic> <text> | pending | approve <id> | reject <id> | used";
|
|
473
1016
|
function createSystemCommands() {
|
|
474
1017
|
return [
|
|
475
1018
|
{
|
|
@@ -487,6 +1030,8 @@ function createSystemCommands() {
|
|
|
487
1030
|
" cost \u2014 Show session info",
|
|
488
1031
|
" context \u2014 Context window info",
|
|
489
1032
|
" permissions \u2014 Permission rules",
|
|
1033
|
+
" memory \u2014 Manage project memory and pending candidates",
|
|
1034
|
+
" rewind \u2014 List or restore edit checkpoints",
|
|
490
1035
|
" provider \u2014 Provider profile status and switching",
|
|
491
1036
|
" resume \u2014 Resume a previous session",
|
|
492
1037
|
" background \u2014 List/cancel/close background tasks",
|
|
@@ -629,6 +1174,21 @@ Messages: ${messageCount}`,
|
|
|
629
1174
|
};
|
|
630
1175
|
}
|
|
631
1176
|
},
|
|
1177
|
+
{
|
|
1178
|
+
name: "memory",
|
|
1179
|
+
description: MEMORY_COMMAND_DESCRIPTION,
|
|
1180
|
+
modelInvocable: true,
|
|
1181
|
+
argumentHint: MEMORY_COMMAND_ARGUMENT_HINT,
|
|
1182
|
+
safety: "write",
|
|
1183
|
+
execute: executeMemoryCommand
|
|
1184
|
+
},
|
|
1185
|
+
{
|
|
1186
|
+
name: "rewind",
|
|
1187
|
+
description: "List edit checkpoints or restore code to a previous checkpoint.",
|
|
1188
|
+
argumentHint: "list | restore CHECKPOINT_ID | code CHECKPOINT_ID",
|
|
1189
|
+
safety: "write",
|
|
1190
|
+
execute: executeRewindCommand
|
|
1191
|
+
},
|
|
632
1192
|
{
|
|
633
1193
|
name: "resume",
|
|
634
1194
|
description: "Resume a previous session",
|
|
@@ -671,51 +1231,6 @@ Messages: ${messageCount}`,
|
|
|
671
1231
|
}
|
|
672
1232
|
];
|
|
673
1233
|
}
|
|
674
|
-
var SystemCommandExecutor = class {
|
|
675
|
-
commands;
|
|
676
|
-
constructor(commands) {
|
|
677
|
-
this.commands = /* @__PURE__ */ new Map();
|
|
678
|
-
for (const cmd of commands ?? createSystemCommands()) {
|
|
679
|
-
this.commands.set(cmd.name, cmd);
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
/** Register an additional command. */
|
|
683
|
-
register(command) {
|
|
684
|
-
this.commands.set(command.name, command);
|
|
685
|
-
}
|
|
686
|
-
/** Execute a command by name. Returns null if command not found. */
|
|
687
|
-
async execute(name, session, args) {
|
|
688
|
-
const cmd = this.commands.get(name);
|
|
689
|
-
if (!cmd) return null;
|
|
690
|
-
return await cmd.execute(session, args);
|
|
691
|
-
}
|
|
692
|
-
/** List all registered commands. */
|
|
693
|
-
listCommands() {
|
|
694
|
-
return [...this.commands.values()];
|
|
695
|
-
}
|
|
696
|
-
listModelInvocableCommands() {
|
|
697
|
-
return this.listCommands().filter((command) => command.modelInvocable === true).map((command) => ({
|
|
698
|
-
name: `/${command.name}`,
|
|
699
|
-
kind: "builtin-command",
|
|
700
|
-
description: command.description,
|
|
701
|
-
userInvocable: command.userInvocable !== false,
|
|
702
|
-
modelInvocable: true,
|
|
703
|
-
...command.argumentHint ? { argumentHint: command.argumentHint } : {},
|
|
704
|
-
...command.safety ? { safety: command.safety } : {}
|
|
705
|
-
}));
|
|
706
|
-
}
|
|
707
|
-
isModelInvocable(name) {
|
|
708
|
-
return this.commands.get(name)?.modelInvocable === true;
|
|
709
|
-
}
|
|
710
|
-
async executeModelInvocable(name, session, args) {
|
|
711
|
-
if (!this.isModelInvocable(name)) return null;
|
|
712
|
-
return this.execute(name, session, args);
|
|
713
|
-
}
|
|
714
|
-
/** Check if a command exists. */
|
|
715
|
-
hasCommand(name) {
|
|
716
|
-
return this.commands.has(name);
|
|
717
|
-
}
|
|
718
|
-
};
|
|
719
1234
|
|
|
720
1235
|
// src/utils/skill-prompt.ts
|
|
721
1236
|
var import_node_child_process = require("child_process");
|
|
@@ -1048,11 +1563,11 @@ function createInProcessSubagentRunner(deps) {
|
|
|
1048
1563
|
|
|
1049
1564
|
// src/tools/agent-tool.ts
|
|
1050
1565
|
var AGENT_TOOL_DESCRIPTION = [
|
|
1051
|
-
"Creates
|
|
1052
|
-
"
|
|
1566
|
+
"Creates delegated subagent jobs in isolated contexts.",
|
|
1567
|
+
"Without jobs, one tool call creates one subagent job from prompt.",
|
|
1568
|
+
"For explicit multi-agent or parallel-agent requests, use one Agent tool call with jobs containing one entry per requested role.",
|
|
1053
1569
|
"When the user explicitly asks to create, run, spawn, delegate to, or use agents/subagents, start the requested subagent job immediately.",
|
|
1054
1570
|
"Do not ask a follow-up question unless execution is impossible or unsafe.",
|
|
1055
|
-
"For multiple or parallel agents, create one Agent tool call per requested role in the current turn.",
|
|
1056
1571
|
"Subagent jobs run as background tasks by default.",
|
|
1057
1572
|
"The tool waits for a terminal result and returns completed, failed, or timed-out outcome data to the parent conversation.",
|
|
1058
1573
|
"Execution is represented by a real tool call and runtime background task event."
|
|
@@ -1060,11 +1575,11 @@ var AGENT_TOOL_DESCRIPTION = [
|
|
|
1060
1575
|
function createAgentToolPromptDescription(agentDefinitions = []) {
|
|
1061
1576
|
const availableAgents = agentDefinitions.length > 0 ? ` Available agent types: ${agentDefinitions.map((agent) => `${agent.name} (${agent.description})`).join(", ")}.` : "";
|
|
1062
1577
|
return [
|
|
1063
|
-
"Agent \u2014 creates
|
|
1064
|
-
"
|
|
1578
|
+
"Agent \u2014 creates isolated subagent jobs.",
|
|
1579
|
+
"Without jobs, one Agent tool call corresponds to one subagent job.",
|
|
1580
|
+
"For explicit multi-agent or parallel-agent requests, use one Agent tool call with jobs containing one entry per requested role.",
|
|
1065
1581
|
"When the user explicitly asks to create, run, spawn, delegate to, or use agents/subagents, start the requested subagent job immediately.",
|
|
1066
1582
|
"Do not ask a follow-up question unless execution is impossible or unsafe.",
|
|
1067
|
-
"For multiple or parallel agents, create one Agent tool call per requested role in the current turn.",
|
|
1068
1583
|
"The tool returns terminal result data.",
|
|
1069
1584
|
"Runtime mode is background.",
|
|
1070
1585
|
availableAgents
|
|
@@ -1074,10 +1589,18 @@ function asZodSchema(schema) {
|
|
|
1074
1589
|
return schema;
|
|
1075
1590
|
}
|
|
1076
1591
|
var AgentSchema = import_zod.z.object({
|
|
1077
|
-
prompt: import_zod.z.string().describe("The task for
|
|
1592
|
+
prompt: import_zod.z.string().optional().describe("The task for a single subagent to perform. Required when jobs is omitted."),
|
|
1078
1593
|
subagent_type: import_zod.z.string().optional().describe('Agent type: "general-purpose", "Explore", "Plan", or a custom agent name'),
|
|
1079
1594
|
model: import_zod.z.string().optional().describe("Optional model override"),
|
|
1080
|
-
isolation: import_zod.z.enum(["none", "worktree"]).optional().describe('Optional runtime isolation mode. "worktree" runs in a Git worktree.')
|
|
1595
|
+
isolation: import_zod.z.enum(["none", "worktree"]).optional().describe('Optional runtime isolation mode. "worktree" runs in a Git worktree.'),
|
|
1596
|
+
jobs: import_zod.z.array(
|
|
1597
|
+
import_zod.z.object({
|
|
1598
|
+
prompt: import_zod.z.string().describe("The task for this subagent to perform"),
|
|
1599
|
+
subagent_type: import_zod.z.string().optional().describe("Agent type for this job"),
|
|
1600
|
+
model: import_zod.z.string().optional().describe("Optional model override for this job"),
|
|
1601
|
+
isolation: import_zod.z.enum(["none", "worktree"]).optional().describe("Isolation for this job")
|
|
1602
|
+
}).passthrough()
|
|
1603
|
+
).optional().describe("Batch of subagent jobs to start in one Agent tool call")
|
|
1081
1604
|
}).passthrough();
|
|
1082
1605
|
var sessionDepsStore = /* @__PURE__ */ new WeakMap();
|
|
1083
1606
|
function storeAgentToolDeps(key, deps) {
|
|
@@ -1140,7 +1663,22 @@ function stringifyAgentError(message, agentId) {
|
|
|
1140
1663
|
agentId
|
|
1141
1664
|
});
|
|
1142
1665
|
}
|
|
1666
|
+
function stringifyAgentBatchResult(input) {
|
|
1667
|
+
const successfulJobs = input.jobs.filter((job) => job.success);
|
|
1668
|
+
const agentIds = input.jobs.map((job) => job.agentId).filter((agentId) => typeof agentId === "string" && agentId.length > 0);
|
|
1669
|
+
return JSON.stringify({
|
|
1670
|
+
success: input.jobs.every((job) => job.success),
|
|
1671
|
+
output: successfulJobs.map((job) => job.output ?? "").filter(Boolean).join("\n\n"),
|
|
1672
|
+
groupId: input.groupId,
|
|
1673
|
+
agentIds,
|
|
1674
|
+
jobs: input.jobs
|
|
1675
|
+
});
|
|
1676
|
+
}
|
|
1143
1677
|
async function runManagedAgent(args, deps, manager) {
|
|
1678
|
+
if (typeof args.prompt !== "string" || args.prompt.length === 0) {
|
|
1679
|
+
return stringifyAgentError("prompt is required when jobs is omitted");
|
|
1680
|
+
}
|
|
1681
|
+
const singleArgs = { ...args, prompt: args.prompt };
|
|
1144
1682
|
const agentType = args.subagent_type ?? "general-purpose";
|
|
1145
1683
|
const agentDef = resolveAgentDefinition2(agentType, deps.customAgentRegistry);
|
|
1146
1684
|
if (!agentDef) {
|
|
@@ -1148,7 +1686,7 @@ async function runManagedAgent(args, deps, manager) {
|
|
|
1148
1686
|
}
|
|
1149
1687
|
let agentId;
|
|
1150
1688
|
try {
|
|
1151
|
-
const state = await manager.spawn(createSpawnRequest(
|
|
1689
|
+
const state = await manager.spawn(createSpawnRequest(singleArgs, agentType, agentDef, deps));
|
|
1152
1690
|
agentId = state.id;
|
|
1153
1691
|
const response = await manager.wait(state.id);
|
|
1154
1692
|
return stringifyAgentSuccess(response);
|
|
@@ -1157,14 +1695,86 @@ async function runManagedAgent(args, deps, manager) {
|
|
|
1157
1695
|
return stringifyAgentError(message, agentId);
|
|
1158
1696
|
}
|
|
1159
1697
|
}
|
|
1160
|
-
function
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1698
|
+
function createBatchGroupId() {
|
|
1699
|
+
return `agent_group_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
|
|
1700
|
+
}
|
|
1701
|
+
async function runManagedAgentBatch(jobs, deps, manager) {
|
|
1702
|
+
const groupId = createBatchGroupId();
|
|
1703
|
+
const resolvedJobs = jobs.map((job, index) => {
|
|
1704
|
+
const agentType = job.subagent_type ?? "general-purpose";
|
|
1705
|
+
const agentDef = resolveAgentDefinition2(agentType, deps.customAgentRegistry);
|
|
1706
|
+
return { index, job, agentType, agentDef };
|
|
1707
|
+
});
|
|
1708
|
+
const invalidJobs = resolvedJobs.filter((job) => job.agentDef === void 0).map((job) => ({
|
|
1709
|
+
index: job.index,
|
|
1710
|
+
success: false,
|
|
1711
|
+
subagent_type: job.agentType,
|
|
1712
|
+
error: `Unknown agent type: ${job.agentType}`
|
|
1713
|
+
}));
|
|
1714
|
+
const validJobs = resolvedJobs.filter(
|
|
1715
|
+
(job) => job.agentDef !== void 0
|
|
1716
|
+
);
|
|
1717
|
+
const startedJobs = await Promise.all(
|
|
1718
|
+
validJobs.map(async (job) => {
|
|
1719
|
+
try {
|
|
1720
|
+
const state = await manager.spawn(
|
|
1721
|
+
createSpawnRequest(job.job, job.agentType, job.agentDef, deps)
|
|
1722
|
+
);
|
|
1723
|
+
return { ...job, agentId: state.id, spawnError: void 0 };
|
|
1724
|
+
} catch (error) {
|
|
1725
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1726
|
+
return { ...job, agentId: void 0, spawnError: message };
|
|
1727
|
+
}
|
|
1728
|
+
})
|
|
1729
|
+
);
|
|
1730
|
+
const terminalJobs = await Promise.all(
|
|
1731
|
+
startedJobs.map(async (job) => {
|
|
1732
|
+
if (job.spawnError || !job.agentId) {
|
|
1733
|
+
return {
|
|
1734
|
+
index: job.index,
|
|
1735
|
+
success: false,
|
|
1736
|
+
subagent_type: job.agentType,
|
|
1737
|
+
error: `Sub-agent error: ${job.spawnError ?? "missing agent id"}`
|
|
1738
|
+
};
|
|
1739
|
+
}
|
|
1740
|
+
try {
|
|
1741
|
+
const result = await manager.wait(job.agentId);
|
|
1742
|
+
return {
|
|
1743
|
+
index: job.index,
|
|
1744
|
+
success: true,
|
|
1745
|
+
agentId: result.jobId,
|
|
1746
|
+
subagent_type: job.agentType,
|
|
1747
|
+
output: result.output,
|
|
1748
|
+
metadata: result.metadata
|
|
1749
|
+
};
|
|
1750
|
+
} catch (error) {
|
|
1751
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1752
|
+
return {
|
|
1753
|
+
index: job.index,
|
|
1754
|
+
success: false,
|
|
1755
|
+
agentId: job.agentId,
|
|
1756
|
+
subagent_type: job.agentType,
|
|
1757
|
+
error: `Sub-agent error: ${message}`
|
|
1758
|
+
};
|
|
1759
|
+
}
|
|
1760
|
+
})
|
|
1761
|
+
);
|
|
1762
|
+
const batchJobs = [...invalidJobs, ...terminalJobs].sort(
|
|
1763
|
+
(left, right) => left.index - right.index
|
|
1764
|
+
);
|
|
1765
|
+
return stringifyAgentBatchResult({ groupId, jobs: batchJobs });
|
|
1766
|
+
}
|
|
1767
|
+
function createAgentTool(deps) {
|
|
1768
|
+
const manager = createSubagentManager(deps);
|
|
1769
|
+
return (0, import_agent_tools.createZodFunctionTool)(
|
|
1770
|
+
"Agent",
|
|
1771
|
+
AGENT_TOOL_DESCRIPTION,
|
|
1772
|
+
asZodSchema(AgentSchema),
|
|
1773
|
+
async (params) => {
|
|
1774
|
+
const args = params;
|
|
1775
|
+
if (Array.isArray(args.jobs) && args.jobs.length > 0) {
|
|
1776
|
+
return runManagedAgentBatch(args.jobs, deps, manager);
|
|
1777
|
+
}
|
|
1168
1778
|
return runManagedAgent(
|
|
1169
1779
|
{
|
|
1170
1780
|
prompt: args.prompt,
|
|
@@ -1255,8 +1865,8 @@ var BackgroundJobOrchestrator = class {
|
|
|
1255
1865
|
createRecord(state) {
|
|
1256
1866
|
let resolveGroup = () => {
|
|
1257
1867
|
};
|
|
1258
|
-
const completion = new Promise((
|
|
1259
|
-
resolveGroup =
|
|
1868
|
+
const completion = new Promise((resolve4) => {
|
|
1869
|
+
resolveGroup = resolve4;
|
|
1260
1870
|
});
|
|
1261
1871
|
return { state, completion, resolve: resolveGroup };
|
|
1262
1872
|
}
|
|
@@ -1381,6 +1991,8 @@ function retrieveSessionBackgroundTaskManager(key) {
|
|
|
1381
1991
|
}
|
|
1382
1992
|
|
|
1383
1993
|
// src/interactive/interactive-session-execution.ts
|
|
1994
|
+
var import_node_crypto = require("crypto");
|
|
1995
|
+
var import_agent_core2 = require("@robota-sdk/agent-core");
|
|
1384
1996
|
function isAbortError(err) {
|
|
1385
1997
|
return err instanceof DOMException && err.name === "AbortError" || err instanceof Error && (err.message.includes("aborted") || err.message.includes("abort"));
|
|
1386
1998
|
}
|
|
@@ -1398,11 +2010,13 @@ function extractToolSummaries(history, historyBefore) {
|
|
|
1398
2010
|
}
|
|
1399
2011
|
function buildResult(response, sessionHistory, interactiveHistory, historyBefore, contextState) {
|
|
1400
2012
|
const toolSummaries = extractToolSummaries(sessionHistory, historyBefore);
|
|
2013
|
+
const usage3 = extractTurnUsage(sessionHistory, historyBefore, contextState);
|
|
1401
2014
|
return {
|
|
1402
2015
|
response,
|
|
1403
2016
|
history: interactiveHistory,
|
|
1404
2017
|
toolSummaries,
|
|
1405
|
-
contextState
|
|
2018
|
+
contextState,
|
|
2019
|
+
...usage3 && { usage: usage3 }
|
|
1406
2020
|
};
|
|
1407
2021
|
}
|
|
1408
2022
|
function buildInterruptedResult(sessionHistory, interactiveHistory, historyBefore, contextState) {
|
|
@@ -1412,14 +2026,51 @@ function buildInterruptedResult(sessionHistory, interactiveHistory, historyBefor
|
|
|
1412
2026
|
const msg = sessionHistory[i];
|
|
1413
2027
|
if (msg?.role === "assistant" && msg.content) parts.push(msg.content);
|
|
1414
2028
|
}
|
|
2029
|
+
const usage3 = extractTurnUsage(sessionHistory, historyBefore, contextState);
|
|
1415
2030
|
return {
|
|
1416
2031
|
response: parts.join("\n\n"),
|
|
1417
2032
|
history: interactiveHistory,
|
|
1418
2033
|
toolSummaries,
|
|
1419
|
-
contextState
|
|
2034
|
+
contextState,
|
|
2035
|
+
...usage3 && { usage: usage3 }
|
|
2036
|
+
};
|
|
2037
|
+
}
|
|
2038
|
+
function createUsageSummaryEntry(usage3) {
|
|
2039
|
+
return {
|
|
2040
|
+
id: `usage_${(0, import_node_crypto.randomUUID)()}`,
|
|
2041
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
2042
|
+
category: "event",
|
|
2043
|
+
type: "usage-summary",
|
|
2044
|
+
data: usage3
|
|
2045
|
+
};
|
|
2046
|
+
}
|
|
2047
|
+
function extractTurnUsage(sessionHistory, historyBefore, contextState) {
|
|
2048
|
+
const turnMessages = sessionHistory.slice(historyBefore);
|
|
2049
|
+
let promptTokens = 0;
|
|
2050
|
+
let completionTokens = 0;
|
|
2051
|
+
let foundUsage = false;
|
|
2052
|
+
for (const message of turnMessages) {
|
|
2053
|
+
if (message.role !== "assistant") continue;
|
|
2054
|
+
const usage3 = (0, import_agent_core2.collectAssistantUsageMetadata)(message);
|
|
2055
|
+
if (!usage3) continue;
|
|
2056
|
+
foundUsage = true;
|
|
2057
|
+
promptTokens += usage3.inputTokens;
|
|
2058
|
+
completionTokens += usage3.outputTokens;
|
|
2059
|
+
}
|
|
2060
|
+
if (!foundUsage) return void 0;
|
|
2061
|
+
return {
|
|
2062
|
+
kind: "exact",
|
|
2063
|
+
scope: "turn",
|
|
2064
|
+
promptTokens,
|
|
2065
|
+
completionTokens,
|
|
2066
|
+
totalTokens: promptTokens + completionTokens,
|
|
2067
|
+
contextUsedTokens: contextState.usedTokens,
|
|
2068
|
+
contextMaxTokens: contextState.maxTokens,
|
|
2069
|
+
contextUsedPercentage: contextState.usedPercentage,
|
|
2070
|
+
costStatus: "unknown"
|
|
1420
2071
|
};
|
|
1421
2072
|
}
|
|
1422
|
-
function persistSession(sessionStore, session, sessionName, cwd, history, backgroundState) {
|
|
2073
|
+
function persistSession(sessionStore, session, sessionName, cwd, history, backgroundState, memoryState) {
|
|
1423
2074
|
try {
|
|
1424
2075
|
const sessionId = session.getSessionId();
|
|
1425
2076
|
const existing = sessionStore.load(sessionId);
|
|
@@ -1438,6 +2089,10 @@ function persistSession(sessionStore, session, sessionName, cwd, history, backgr
|
|
|
1438
2089
|
backgroundTaskEvents: [...backgroundState.events],
|
|
1439
2090
|
backgroundJobGroups: [...backgroundState.groups ?? []],
|
|
1440
2091
|
backgroundJobGroupEvents: [...backgroundState.groupEvents ?? []]
|
|
2092
|
+
} : {},
|
|
2093
|
+
...memoryState ? {
|
|
2094
|
+
memoryEvents: [...memoryState.events],
|
|
2095
|
+
usedMemoryReferences: [...memoryState.usedReferences]
|
|
1441
2096
|
} : {}
|
|
1442
2097
|
});
|
|
1443
2098
|
} catch {
|
|
@@ -1460,17 +2115,97 @@ var NOOP_TERMINAL = {
|
|
|
1460
2115
|
};
|
|
1461
2116
|
|
|
1462
2117
|
// src/interactive/interactive-session-streaming.ts
|
|
1463
|
-
var
|
|
2118
|
+
var import_node_crypto2 = require("crypto");
|
|
2119
|
+
var import_node_fs3 = require("fs");
|
|
1464
2120
|
var TOOL_ARG_DISPLAY_MAX = 80;
|
|
1465
2121
|
var TAIL_KEEP = 30;
|
|
1466
2122
|
var MAX_COMPLETED_TOOLS = 50;
|
|
1467
2123
|
var STREAMING_FLUSH_INTERVAL_MS = 16;
|
|
2124
|
+
var DEFAULT_START_LINE = 1;
|
|
2125
|
+
var EDIT_DIFF_CONTEXT_LINES = 3;
|
|
1468
2126
|
function extractFirstArg2(toolArgs) {
|
|
1469
2127
|
if (!toolArgs) return "";
|
|
1470
2128
|
const firstVal = Object.values(toolArgs)[0];
|
|
1471
2129
|
const raw = typeof firstVal === "string" ? firstVal : JSON.stringify(firstVal ?? "");
|
|
1472
2130
|
return raw.length > TOOL_ARG_DISPLAY_MAX ? raw.slice(0, TOOL_ARG_DISPLAY_MAX - TAIL_KEEP - 3) + "..." + raw.slice(-TAIL_KEEP) : raw;
|
|
1473
2131
|
}
|
|
2132
|
+
function getStringArg(args, snake, camel) {
|
|
2133
|
+
const value = args?.[snake] ?? args?.[camel];
|
|
2134
|
+
return typeof value === "string" ? value : null;
|
|
2135
|
+
}
|
|
2136
|
+
function parseStartLine(toolResultData) {
|
|
2137
|
+
if (!toolResultData) return DEFAULT_START_LINE;
|
|
2138
|
+
try {
|
|
2139
|
+
const parsed = JSON.parse(toolResultData);
|
|
2140
|
+
return typeof parsed.startLine === "number" && Number.isFinite(parsed.startLine) ? parsed.startLine : DEFAULT_START_LINE;
|
|
2141
|
+
} catch {
|
|
2142
|
+
return DEFAULT_START_LINE;
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
2145
|
+
function buildEditDiffState(event) {
|
|
2146
|
+
if (event.toolName !== "Edit") return {};
|
|
2147
|
+
const filePath = getStringArg(event.toolArgs, "file_path", "filePath");
|
|
2148
|
+
const oldString = getStringArg(event.toolArgs, "old_string", "oldString");
|
|
2149
|
+
const newString = getStringArg(event.toolArgs, "new_string", "newString");
|
|
2150
|
+
if (!filePath || oldString === null || newString === null || oldString === newString) return {};
|
|
2151
|
+
const startLine = parseStartLine(event.toolResultData);
|
|
2152
|
+
return {
|
|
2153
|
+
diffFile: filePath,
|
|
2154
|
+
diffLines: buildEditDiffLinesWithContext(oldString, newString, startLine, filePath)
|
|
2155
|
+
};
|
|
2156
|
+
}
|
|
2157
|
+
function buildEditDiffLines(oldString, newString, startLine) {
|
|
2158
|
+
return [
|
|
2159
|
+
...oldString.split("\n").map((text, index) => ({
|
|
2160
|
+
type: "remove",
|
|
2161
|
+
text,
|
|
2162
|
+
lineNumber: startLine + index
|
|
2163
|
+
})),
|
|
2164
|
+
...newString.split("\n").map((text, index) => ({
|
|
2165
|
+
type: "add",
|
|
2166
|
+
text,
|
|
2167
|
+
lineNumber: startLine + index
|
|
2168
|
+
}))
|
|
2169
|
+
];
|
|
2170
|
+
}
|
|
2171
|
+
function buildEditDiffLinesWithContext(oldString, newString, startLine, filePath) {
|
|
2172
|
+
const diffLines = buildEditDiffLines(oldString, newString, startLine);
|
|
2173
|
+
let fileLines;
|
|
2174
|
+
try {
|
|
2175
|
+
fileLines = (0, import_node_fs3.readFileSync)(filePath, "utf8").split("\n");
|
|
2176
|
+
} catch {
|
|
2177
|
+
return diffLines;
|
|
2178
|
+
}
|
|
2179
|
+
const beforeContext = [];
|
|
2180
|
+
const contextStart = Math.max(0, startLine - 1 - EDIT_DIFF_CONTEXT_LINES);
|
|
2181
|
+
for (let index = contextStart; index < startLine - 1; index++) {
|
|
2182
|
+
if (index < fileLines.length) {
|
|
2183
|
+
beforeContext.push({ type: "context", text: fileLines[index], lineNumber: index + 1 });
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
2186
|
+
const afterContext = [];
|
|
2187
|
+
const afterStart = startLine - 1 + newString.split("\n").length;
|
|
2188
|
+
for (let index = afterStart; index < afterStart + EDIT_DIFF_CONTEXT_LINES; index++) {
|
|
2189
|
+
if (index < fileLines.length) {
|
|
2190
|
+
afterContext.push({ type: "context", text: fileLines[index], lineNumber: index + 1 });
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
const hunkStart = beforeContext[0]?.lineNumber ?? diffLines[0]?.lineNumber ?? afterContext[0]?.lineNumber ?? startLine;
|
|
2194
|
+
const oldLineCount = oldString.split("\n").length;
|
|
2195
|
+
const newLineCount = newString.split("\n").length;
|
|
2196
|
+
const oldHunkLineCount = beforeContext.length + oldLineCount + afterContext.length;
|
|
2197
|
+
const newHunkLineCount = beforeContext.length + newLineCount + afterContext.length;
|
|
2198
|
+
return [
|
|
2199
|
+
{
|
|
2200
|
+
type: "hunk",
|
|
2201
|
+
text: `@@ -${hunkStart},${oldHunkLineCount} +${hunkStart},${newHunkLineCount} @@`,
|
|
2202
|
+
lineNumber: hunkStart
|
|
2203
|
+
},
|
|
2204
|
+
...beforeContext,
|
|
2205
|
+
...diffLines,
|
|
2206
|
+
...afterContext
|
|
2207
|
+
];
|
|
2208
|
+
}
|
|
1474
2209
|
function pushToolSummaryToHistory(state) {
|
|
1475
2210
|
if (state.activeTools.length === 0) return;
|
|
1476
2211
|
const summary = state.activeTools.map((t) => {
|
|
@@ -1478,7 +2213,7 @@ function pushToolSummaryToHistory(state) {
|
|
|
1478
2213
|
return `${status} ${t.toolName}${t.firstArg ? `(${t.firstArg})` : ""}`;
|
|
1479
2214
|
}).join("\n");
|
|
1480
2215
|
state.history.push({
|
|
1481
|
-
id: (0,
|
|
2216
|
+
id: (0, import_node_crypto2.randomUUID)(),
|
|
1482
2217
|
timestamp: /* @__PURE__ */ new Date(),
|
|
1483
2218
|
category: "event",
|
|
1484
2219
|
type: "tool-summary",
|
|
@@ -1487,7 +2222,10 @@ function pushToolSummaryToHistory(state) {
|
|
|
1487
2222
|
toolName: t.toolName,
|
|
1488
2223
|
firstArg: t.firstArg,
|
|
1489
2224
|
isRunning: t.isRunning,
|
|
1490
|
-
result: t.result
|
|
2225
|
+
result: t.result,
|
|
2226
|
+
diffFile: t.diffFile,
|
|
2227
|
+
diffLines: t.diffLines,
|
|
2228
|
+
toolResultData: t.toolResultData
|
|
1491
2229
|
})),
|
|
1492
2230
|
summary
|
|
1493
2231
|
}
|
|
@@ -1511,7 +2249,7 @@ function applyToolStart(state, event) {
|
|
|
1511
2249
|
const toolState = { toolName: event.toolName, firstArg, isRunning: true };
|
|
1512
2250
|
state.activeTools.push(toolState);
|
|
1513
2251
|
state.history.push({
|
|
1514
|
-
id: (0,
|
|
2252
|
+
id: (0, import_node_crypto2.randomUUID)(),
|
|
1515
2253
|
timestamp: /* @__PURE__ */ new Date(),
|
|
1516
2254
|
category: "event",
|
|
1517
2255
|
type: "tool-start",
|
|
@@ -1523,11 +2261,17 @@ function applyToolEnd(state, event) {
|
|
|
1523
2261
|
const result = event.denied ? "denied" : event.success === false ? "error" : "success";
|
|
1524
2262
|
const idx = state.activeTools.findIndex((t) => t.toolName === event.toolName && t.isRunning);
|
|
1525
2263
|
if (idx === -1) return null;
|
|
1526
|
-
const finished = {
|
|
2264
|
+
const finished = {
|
|
2265
|
+
...state.activeTools[idx],
|
|
2266
|
+
...buildEditDiffState(event),
|
|
2267
|
+
isRunning: false,
|
|
2268
|
+
result,
|
|
2269
|
+
toolResultData: event.toolResultData
|
|
2270
|
+
};
|
|
1527
2271
|
state.activeTools[idx] = finished;
|
|
1528
2272
|
state.activeTools = trimCompletedTools(state.activeTools);
|
|
1529
2273
|
state.history.push({
|
|
1530
|
-
id: (0,
|
|
2274
|
+
id: (0, import_node_crypto2.randomUUID)(),
|
|
1531
2275
|
timestamp: /* @__PURE__ */ new Date(),
|
|
1532
2276
|
category: "event",
|
|
1533
2277
|
type: "tool-end",
|
|
@@ -1535,12 +2279,307 @@ function applyToolEnd(state, event) {
|
|
|
1535
2279
|
toolName: finished.toolName,
|
|
1536
2280
|
firstArg: finished.firstArg,
|
|
1537
2281
|
isRunning: false,
|
|
1538
|
-
result
|
|
2282
|
+
result,
|
|
2283
|
+
toolResultData: event.toolResultData
|
|
1539
2284
|
}
|
|
1540
2285
|
});
|
|
1541
2286
|
return finished;
|
|
1542
2287
|
}
|
|
1543
2288
|
|
|
2289
|
+
// src/config/config-loader.ts
|
|
2290
|
+
var import_fs2 = require("fs");
|
|
2291
|
+
var import_path2 = require("path");
|
|
2292
|
+
|
|
2293
|
+
// src/config/config-types.ts
|
|
2294
|
+
var import_zod2 = require("zod");
|
|
2295
|
+
var UniversalValueSchema = import_zod2.z.lazy(
|
|
2296
|
+
() => import_zod2.z.union([
|
|
2297
|
+
import_zod2.z.string(),
|
|
2298
|
+
import_zod2.z.number(),
|
|
2299
|
+
import_zod2.z.boolean(),
|
|
2300
|
+
import_zod2.z.null(),
|
|
2301
|
+
import_zod2.z.undefined(),
|
|
2302
|
+
import_zod2.z.date(),
|
|
2303
|
+
import_zod2.z.array(UniversalValueSchema),
|
|
2304
|
+
import_zod2.z.record(UniversalValueSchema)
|
|
2305
|
+
])
|
|
2306
|
+
);
|
|
2307
|
+
var ProviderSchema = import_zod2.z.object({
|
|
2308
|
+
name: import_zod2.z.string().optional(),
|
|
2309
|
+
model: import_zod2.z.string().optional(),
|
|
2310
|
+
apiKey: import_zod2.z.string().optional(),
|
|
2311
|
+
baseURL: import_zod2.z.string().optional(),
|
|
2312
|
+
timeout: import_zod2.z.number().optional(),
|
|
2313
|
+
options: import_zod2.z.record(UniversalValueSchema).optional()
|
|
2314
|
+
});
|
|
2315
|
+
var ProviderProfileSchema = import_zod2.z.object({
|
|
2316
|
+
type: import_zod2.z.string().optional(),
|
|
2317
|
+
model: import_zod2.z.string().optional(),
|
|
2318
|
+
apiKey: import_zod2.z.string().optional(),
|
|
2319
|
+
baseURL: import_zod2.z.string().optional(),
|
|
2320
|
+
timeout: import_zod2.z.number().optional(),
|
|
2321
|
+
options: import_zod2.z.record(UniversalValueSchema).optional()
|
|
2322
|
+
});
|
|
2323
|
+
var PermissionsSchema = import_zod2.z.object({
|
|
2324
|
+
/** Patterns that are always approved without prompting */
|
|
2325
|
+
allow: import_zod2.z.array(import_zod2.z.string()).optional(),
|
|
2326
|
+
/** Patterns that are always denied */
|
|
2327
|
+
deny: import_zod2.z.array(import_zod2.z.string()).optional()
|
|
2328
|
+
});
|
|
2329
|
+
var EnvSchema = import_zod2.z.record(import_zod2.z.string()).optional();
|
|
2330
|
+
var CommandHookDefinitionSchema = import_zod2.z.object({
|
|
2331
|
+
type: import_zod2.z.literal("command"),
|
|
2332
|
+
command: import_zod2.z.string(),
|
|
2333
|
+
timeout: import_zod2.z.number().optional()
|
|
2334
|
+
});
|
|
2335
|
+
var HttpHookDefinitionSchema = import_zod2.z.object({
|
|
2336
|
+
type: import_zod2.z.literal("http"),
|
|
2337
|
+
url: import_zod2.z.string(),
|
|
2338
|
+
headers: import_zod2.z.record(import_zod2.z.string()).optional(),
|
|
2339
|
+
timeout: import_zod2.z.number().optional()
|
|
2340
|
+
});
|
|
2341
|
+
var PromptHookDefinitionSchema = import_zod2.z.object({
|
|
2342
|
+
type: import_zod2.z.literal("prompt"),
|
|
2343
|
+
prompt: import_zod2.z.string(),
|
|
2344
|
+
model: import_zod2.z.string().optional()
|
|
2345
|
+
});
|
|
2346
|
+
var AgentHookDefinitionSchema = import_zod2.z.object({
|
|
2347
|
+
type: import_zod2.z.literal("agent"),
|
|
2348
|
+
agent: import_zod2.z.string(),
|
|
2349
|
+
maxTurns: import_zod2.z.number().optional(),
|
|
2350
|
+
timeout: import_zod2.z.number().optional()
|
|
2351
|
+
});
|
|
2352
|
+
var HookDefinitionSchema = import_zod2.z.discriminatedUnion("type", [
|
|
2353
|
+
CommandHookDefinitionSchema,
|
|
2354
|
+
HttpHookDefinitionSchema,
|
|
2355
|
+
PromptHookDefinitionSchema,
|
|
2356
|
+
AgentHookDefinitionSchema
|
|
2357
|
+
]);
|
|
2358
|
+
var HookGroupSchema = import_zod2.z.object({
|
|
2359
|
+
matcher: import_zod2.z.string(),
|
|
2360
|
+
hooks: import_zod2.z.array(HookDefinitionSchema)
|
|
2361
|
+
});
|
|
2362
|
+
var HooksSchema = import_zod2.z.object({
|
|
2363
|
+
PreToolUse: import_zod2.z.array(HookGroupSchema).optional(),
|
|
2364
|
+
PostToolUse: import_zod2.z.array(HookGroupSchema).optional(),
|
|
2365
|
+
SessionStart: import_zod2.z.array(HookGroupSchema).optional(),
|
|
2366
|
+
SessionEnd: import_zod2.z.array(HookGroupSchema).optional(),
|
|
2367
|
+
Stop: import_zod2.z.array(HookGroupSchema).optional(),
|
|
2368
|
+
StopFailure: import_zod2.z.array(HookGroupSchema).optional(),
|
|
2369
|
+
PreCompact: import_zod2.z.array(HookGroupSchema).optional(),
|
|
2370
|
+
PostCompact: import_zod2.z.array(HookGroupSchema).optional(),
|
|
2371
|
+
UserPromptSubmit: import_zod2.z.array(HookGroupSchema).optional(),
|
|
2372
|
+
SubagentStart: import_zod2.z.array(HookGroupSchema).optional(),
|
|
2373
|
+
SubagentStop: import_zod2.z.array(HookGroupSchema).optional(),
|
|
2374
|
+
WorktreeCreate: import_zod2.z.array(HookGroupSchema).optional(),
|
|
2375
|
+
WorktreeRemove: import_zod2.z.array(HookGroupSchema).optional()
|
|
2376
|
+
}).optional();
|
|
2377
|
+
var EnabledPluginsSchema = import_zod2.z.record(import_zod2.z.boolean()).optional();
|
|
2378
|
+
var MarketplaceSourceSchema = import_zod2.z.object({
|
|
2379
|
+
source: import_zod2.z.object({
|
|
2380
|
+
type: import_zod2.z.enum(["github", "git", "local", "url"]),
|
|
2381
|
+
repo: import_zod2.z.string().optional(),
|
|
2382
|
+
url: import_zod2.z.string().optional(),
|
|
2383
|
+
path: import_zod2.z.string().optional(),
|
|
2384
|
+
ref: import_zod2.z.string().optional()
|
|
2385
|
+
})
|
|
2386
|
+
});
|
|
2387
|
+
var ExtraKnownMarketplacesSchema = import_zod2.z.record(MarketplaceSourceSchema).optional().catch(void 0);
|
|
2388
|
+
var SettingsSchema = import_zod2.z.object({
|
|
2389
|
+
/** Trust level used when no --permission-mode flag is given */
|
|
2390
|
+
defaultTrustLevel: import_zod2.z.enum(["safe", "moderate", "full"]).optional(),
|
|
2391
|
+
/** Response language (e.g., "ko", "en", "ja"). Injected into system prompt. */
|
|
2392
|
+
language: import_zod2.z.string().optional(),
|
|
2393
|
+
/** Active provider profile key from providers. */
|
|
2394
|
+
currentProvider: import_zod2.z.string().optional(),
|
|
2395
|
+
/** Provider profiles keyed by user-facing profile name. */
|
|
2396
|
+
providers: import_zod2.z.record(ProviderProfileSchema).optional(),
|
|
2397
|
+
/** Legacy single-provider settings. Prefer currentProvider + providers for new config. */
|
|
2398
|
+
provider: ProviderSchema.optional(),
|
|
2399
|
+
permissions: PermissionsSchema.optional(),
|
|
2400
|
+
env: EnvSchema,
|
|
2401
|
+
hooks: HooksSchema,
|
|
2402
|
+
/** Plugin enablement map: plugin name -> enabled/disabled */
|
|
2403
|
+
enabledPlugins: EnabledPluginsSchema,
|
|
2404
|
+
/** Extra marketplace URLs for BundlePlugin discovery */
|
|
2405
|
+
extraKnownMarketplaces: ExtraKnownMarketplacesSchema
|
|
2406
|
+
});
|
|
2407
|
+
|
|
2408
|
+
// src/config/config-loader.ts
|
|
2409
|
+
function getHomeDir() {
|
|
2410
|
+
return process.env.HOME ?? process.env.USERPROFILE ?? "/";
|
|
2411
|
+
}
|
|
2412
|
+
var DEFAULTS = {
|
|
2413
|
+
defaultTrustLevel: "moderate",
|
|
2414
|
+
provider: {
|
|
2415
|
+
name: "anthropic",
|
|
2416
|
+
model: "claude-opus-4-5",
|
|
2417
|
+
apiKey: void 0
|
|
2418
|
+
},
|
|
2419
|
+
permissions: {
|
|
2420
|
+
allow: [],
|
|
2421
|
+
deny: []
|
|
2422
|
+
},
|
|
2423
|
+
env: {}
|
|
2424
|
+
};
|
|
2425
|
+
function readJsonFile(filePath) {
|
|
2426
|
+
if (!(0, import_fs2.existsSync)(filePath)) {
|
|
2427
|
+
return void 0;
|
|
2428
|
+
}
|
|
2429
|
+
const raw = (0, import_fs2.readFileSync)(filePath, "utf-8").trim();
|
|
2430
|
+
if (raw.length === 0) {
|
|
2431
|
+
return void 0;
|
|
2432
|
+
}
|
|
2433
|
+
try {
|
|
2434
|
+
return JSON.parse(raw);
|
|
2435
|
+
} catch {
|
|
2436
|
+
return void 0;
|
|
2437
|
+
}
|
|
2438
|
+
}
|
|
2439
|
+
function resolveEnvRef(value) {
|
|
2440
|
+
const ENV_PREFIX = "$ENV:";
|
|
2441
|
+
if (value.startsWith(ENV_PREFIX)) {
|
|
2442
|
+
const varName = value.slice(ENV_PREFIX.length);
|
|
2443
|
+
return process.env[varName] ?? value;
|
|
2444
|
+
}
|
|
2445
|
+
return value;
|
|
2446
|
+
}
|
|
2447
|
+
function resolveEnvRefs(settings) {
|
|
2448
|
+
const provider = settings.provider?.apiKey !== void 0 ? {
|
|
2449
|
+
...settings.provider,
|
|
2450
|
+
apiKey: resolveEnvRef(settings.provider.apiKey)
|
|
2451
|
+
} : settings.provider;
|
|
2452
|
+
if (settings.providers !== void 0) {
|
|
2453
|
+
const providers = Object.fromEntries(
|
|
2454
|
+
Object.entries(settings.providers).map(([name, profile]) => [
|
|
2455
|
+
name,
|
|
2456
|
+
{
|
|
2457
|
+
...profile,
|
|
2458
|
+
...profile.apiKey !== void 0 && { apiKey: resolveEnvRef(profile.apiKey) }
|
|
2459
|
+
}
|
|
2460
|
+
])
|
|
2461
|
+
);
|
|
2462
|
+
return {
|
|
2463
|
+
...settings,
|
|
2464
|
+
provider,
|
|
2465
|
+
providers
|
|
2466
|
+
};
|
|
2467
|
+
}
|
|
2468
|
+
return {
|
|
2469
|
+
...settings,
|
|
2470
|
+
provider
|
|
2471
|
+
};
|
|
2472
|
+
}
|
|
2473
|
+
function mergeSettings(layers) {
|
|
2474
|
+
return layers.reduce((merged, layer) => {
|
|
2475
|
+
return {
|
|
2476
|
+
...merged,
|
|
2477
|
+
...layer,
|
|
2478
|
+
provider: merged.provider !== void 0 || layer.provider !== void 0 ? { ...merged.provider, ...layer.provider } : void 0,
|
|
2479
|
+
permissions: merged.permissions !== void 0 || layer.permissions !== void 0 ? {
|
|
2480
|
+
allow: layer.permissions?.allow ?? merged.permissions?.allow,
|
|
2481
|
+
deny: layer.permissions?.deny ?? merged.permissions?.deny
|
|
2482
|
+
} : void 0,
|
|
2483
|
+
env: {
|
|
2484
|
+
...merged.env ?? {},
|
|
2485
|
+
...layer.env ?? {}
|
|
2486
|
+
},
|
|
2487
|
+
providers: merged.providers !== void 0 || layer.providers !== void 0 ? mergeProviders(merged.providers, layer.providers) : void 0,
|
|
2488
|
+
enabledPlugins: merged.enabledPlugins !== void 0 || layer.enabledPlugins !== void 0 ? { ...merged.enabledPlugins ?? {}, ...layer.enabledPlugins ?? {} } : void 0,
|
|
2489
|
+
extraKnownMarketplaces: layer.extraKnownMarketplaces ?? merged.extraKnownMarketplaces
|
|
2490
|
+
};
|
|
2491
|
+
}, {});
|
|
2492
|
+
}
|
|
2493
|
+
function mergeProviders(base, override) {
|
|
2494
|
+
const result = { ...base ?? {} };
|
|
2495
|
+
for (const [name, profile] of Object.entries(override ?? {})) {
|
|
2496
|
+
result[name] = {
|
|
2497
|
+
...result[name],
|
|
2498
|
+
...profile
|
|
2499
|
+
};
|
|
2500
|
+
}
|
|
2501
|
+
return result;
|
|
2502
|
+
}
|
|
2503
|
+
function resolveProvider(merged) {
|
|
2504
|
+
if (merged.currentProvider !== void 0) {
|
|
2505
|
+
const profile = merged.providers?.[merged.currentProvider];
|
|
2506
|
+
if (profile === void 0) {
|
|
2507
|
+
throw new Error(`currentProvider "${merged.currentProvider}" was not found in providers`);
|
|
2508
|
+
}
|
|
2509
|
+
if (profile.type === void 0) {
|
|
2510
|
+
throw new Error(`Provider profile "${merged.currentProvider}" is missing type`);
|
|
2511
|
+
}
|
|
2512
|
+
return {
|
|
2513
|
+
name: profile.type,
|
|
2514
|
+
model: profile.model ?? DEFAULTS.provider.model,
|
|
2515
|
+
apiKey: profile.apiKey ?? DEFAULTS.provider.apiKey,
|
|
2516
|
+
...profile.baseURL !== void 0 && { baseURL: profile.baseURL },
|
|
2517
|
+
...profile.timeout !== void 0 && { timeout: profile.timeout },
|
|
2518
|
+
...profile.options !== void 0 && { options: profile.options }
|
|
2519
|
+
};
|
|
2520
|
+
}
|
|
2521
|
+
return {
|
|
2522
|
+
name: merged.provider?.name ?? DEFAULTS.provider.name,
|
|
2523
|
+
model: merged.provider?.model ?? DEFAULTS.provider.model,
|
|
2524
|
+
apiKey: merged.provider?.apiKey ?? DEFAULTS.provider.apiKey,
|
|
2525
|
+
...merged.provider?.baseURL !== void 0 && { baseURL: merged.provider.baseURL },
|
|
2526
|
+
...merged.provider?.timeout !== void 0 && { timeout: merged.provider.timeout },
|
|
2527
|
+
...merged.provider?.options !== void 0 && { options: merged.provider.options }
|
|
2528
|
+
};
|
|
2529
|
+
}
|
|
2530
|
+
function toResolvedConfig(merged) {
|
|
2531
|
+
return {
|
|
2532
|
+
defaultTrustLevel: merged.defaultTrustLevel ?? DEFAULTS.defaultTrustLevel,
|
|
2533
|
+
language: merged.language,
|
|
2534
|
+
currentProvider: merged.currentProvider,
|
|
2535
|
+
provider: resolveProvider(merged),
|
|
2536
|
+
permissions: {
|
|
2537
|
+
allow: merged.permissions?.allow ?? DEFAULTS.permissions.allow,
|
|
2538
|
+
deny: merged.permissions?.deny ?? DEFAULTS.permissions.deny
|
|
2539
|
+
},
|
|
2540
|
+
env: merged.env ?? DEFAULTS.env,
|
|
2541
|
+
hooks: merged.hooks ?? void 0,
|
|
2542
|
+
enabledPlugins: merged.enabledPlugins ?? void 0,
|
|
2543
|
+
extraKnownMarketplaces: merged.extraKnownMarketplaces ?? void 0
|
|
2544
|
+
};
|
|
2545
|
+
}
|
|
2546
|
+
function getSettingsPaths(cwd) {
|
|
2547
|
+
const home = getHomeDir();
|
|
2548
|
+
return [
|
|
2549
|
+
(0, import_path2.join)(home, ".robota", "settings.json"),
|
|
2550
|
+
// 1. user (lowest)
|
|
2551
|
+
(0, import_path2.join)(home, ".claude", "settings.json"),
|
|
2552
|
+
// 1b. user (Claude Code compat)
|
|
2553
|
+
(0, import_path2.join)(cwd, ".robota", "settings.json"),
|
|
2554
|
+
// 2. project
|
|
2555
|
+
(0, import_path2.join)(cwd, ".robota", "settings.local.json"),
|
|
2556
|
+
// 3. project-local
|
|
2557
|
+
(0, import_path2.join)(cwd, ".claude", "settings.json"),
|
|
2558
|
+
// 4. project, Claude Code compat
|
|
2559
|
+
(0, import_path2.join)(cwd, ".claude", "settings.local.json")
|
|
2560
|
+
// 5. project-local (highest)
|
|
2561
|
+
];
|
|
2562
|
+
}
|
|
2563
|
+
async function loadConfig(cwd) {
|
|
2564
|
+
const allPaths = getSettingsPaths(cwd);
|
|
2565
|
+
const rawEntries = [];
|
|
2566
|
+
for (const filePath of allPaths) {
|
|
2567
|
+
const raw = readJsonFile(filePath);
|
|
2568
|
+
if (raw !== void 0) {
|
|
2569
|
+
rawEntries.push({ raw, path: filePath });
|
|
2570
|
+
}
|
|
2571
|
+
}
|
|
2572
|
+
const parsedLayers = rawEntries.map(({ raw, path }) => {
|
|
2573
|
+
const result = SettingsSchema.safeParse(raw);
|
|
2574
|
+
if (!result.success) {
|
|
2575
|
+
throw new Error(`Invalid settings in ${path}: ${result.error.message}`);
|
|
2576
|
+
}
|
|
2577
|
+
return resolveEnvRefs(result.data);
|
|
2578
|
+
});
|
|
2579
|
+
const merged = mergeSettings(parsedLayers);
|
|
2580
|
+
return toResolvedConfig(merged);
|
|
2581
|
+
}
|
|
2582
|
+
|
|
1544
2583
|
// src/hooks/prompt-executor.ts
|
|
1545
2584
|
function extractJson(raw) {
|
|
1546
2585
|
const codeBlockMatch = /```(?:json)?\s*\n?([\s\S]*?)\n?\s*```/.exec(raw);
|
|
@@ -1667,6 +2706,8 @@ var TRUST_LEVEL_LABELS = {
|
|
|
1667
2706
|
moderate: "moderate",
|
|
1668
2707
|
full: "full"
|
|
1669
2708
|
};
|
|
2709
|
+
var PROJECT_MEMORY_PRIORITY = Number("25");
|
|
2710
|
+
var TASK_CONTEXT_PRIORITY = Number("27");
|
|
1670
2711
|
function createSection(id, title, priority, content, source) {
|
|
1671
2712
|
return { id, title, priority, content, source };
|
|
1672
2713
|
}
|
|
@@ -1717,6 +2758,26 @@ function createClaudeMdSection(claudeMd) {
|
|
|
1717
2758
|
if (claudeMd.trim().length === 0) return void 0;
|
|
1718
2759
|
return createSection("project-claude-md", "Project Notes", 20, claudeMd, "project-instructions");
|
|
1719
2760
|
}
|
|
2761
|
+
function createProjectMemorySection(memoryMd) {
|
|
2762
|
+
if (memoryMd === void 0 || memoryMd.trim().length === 0) return void 0;
|
|
2763
|
+
return createSection(
|
|
2764
|
+
"project-memory",
|
|
2765
|
+
"Project Memory",
|
|
2766
|
+
PROJECT_MEMORY_PRIORITY,
|
|
2767
|
+
memoryMd,
|
|
2768
|
+
"project-instructions"
|
|
2769
|
+
);
|
|
2770
|
+
}
|
|
2771
|
+
function createTaskContextSection(taskContext) {
|
|
2772
|
+
if (taskContext === void 0 || taskContext.trim().length === 0) return void 0;
|
|
2773
|
+
return createSection(
|
|
2774
|
+
"active-task-context",
|
|
2775
|
+
"Active Task Context",
|
|
2776
|
+
TASK_CONTEXT_PRIORITY,
|
|
2777
|
+
taskContext,
|
|
2778
|
+
"project-instructions"
|
|
2779
|
+
);
|
|
2780
|
+
}
|
|
1720
2781
|
function createToolDescriptionSection(descriptions) {
|
|
1721
2782
|
if (descriptions.length === 0) return void 0;
|
|
1722
2783
|
return createSection(
|
|
@@ -1789,6 +2850,8 @@ function buildSystemPrompt(params) {
|
|
|
1789
2850
|
const sections = [];
|
|
1790
2851
|
appendOptionalSection(sections, createAgentsMdSection(params.agentsMd));
|
|
1791
2852
|
appendOptionalSection(sections, createClaudeMdSection(params.claudeMd));
|
|
2853
|
+
appendOptionalSection(sections, createProjectMemorySection(params.memoryMd));
|
|
2854
|
+
appendOptionalSection(sections, createTaskContextSection(params.taskContext));
|
|
1792
2855
|
appendOptionalSection(sections, createWorkingDirectorySection(params.cwd));
|
|
1793
2856
|
sections.push(createProjectSection(params.projectInfo));
|
|
1794
2857
|
appendOptionalSection(sections, createResponseLanguageSection(params.language));
|
|
@@ -1823,18 +2886,18 @@ function createDefaultTools() {
|
|
|
1823
2886
|
}
|
|
1824
2887
|
|
|
1825
2888
|
// src/tools/background-process-tool.ts
|
|
1826
|
-
var
|
|
2889
|
+
var import_zod3 = require("zod");
|
|
1827
2890
|
var import_agent_tools3 = require("@robota-sdk/agent-tools");
|
|
1828
2891
|
var DEFAULT_PROCESS_TIMEOUT_MS = 12e4;
|
|
1829
2892
|
function asZodSchema2(schema) {
|
|
1830
2893
|
return schema;
|
|
1831
2894
|
}
|
|
1832
|
-
var BackgroundProcessSchema =
|
|
1833
|
-
command:
|
|
1834
|
-
timeout:
|
|
1835
|
-
workingDirectory:
|
|
1836
|
-
stdin:
|
|
1837
|
-
outputLimitBytes:
|
|
2895
|
+
var BackgroundProcessSchema = import_zod3.z.object({
|
|
2896
|
+
command: import_zod3.z.string().describe("The shell command to start in the background"),
|
|
2897
|
+
timeout: import_zod3.z.number().optional().describe("Optional timeout in milliseconds. Default is 120000."),
|
|
2898
|
+
workingDirectory: import_zod3.z.string().optional().describe("Working directory for the command. Defaults to the current project directory."),
|
|
2899
|
+
stdin: import_zod3.z.string().optional().describe("Optional stdin to write after the process starts."),
|
|
2900
|
+
outputLimitBytes: import_zod3.z.number().optional().describe("Maximum captured output bytes kept in the task result.")
|
|
1838
2901
|
});
|
|
1839
2902
|
function stringifyStarted(taskId, status, command) {
|
|
1840
2903
|
return JSON.stringify({
|
|
@@ -1883,11 +2946,11 @@ function createBackgroundProcessTool(deps) {
|
|
|
1883
2946
|
}
|
|
1884
2947
|
|
|
1885
2948
|
// src/tools/command-execution-tool.ts
|
|
1886
|
-
var
|
|
2949
|
+
var import_zod4 = require("zod");
|
|
1887
2950
|
var import_agent_tools4 = require("@robota-sdk/agent-tools");
|
|
1888
|
-
var CommandExecutionSchema =
|
|
1889
|
-
command:
|
|
1890
|
-
args:
|
|
2951
|
+
var CommandExecutionSchema = import_zod4.z.object({
|
|
2952
|
+
command: import_zod4.z.string().describe("Command name to execute, with or without a leading slash"),
|
|
2953
|
+
args: import_zod4.z.string().optional().describe("Arguments to pass to the command")
|
|
1891
2954
|
});
|
|
1892
2955
|
function asZodSchema3(schema) {
|
|
1893
2956
|
return schema;
|
|
@@ -1930,12 +2993,55 @@ function createCommandExecutionTool(deps) {
|
|
|
1930
2993
|
);
|
|
1931
2994
|
}
|
|
1932
2995
|
|
|
2996
|
+
// src/checkpoints/edit-checkpoint-tools.ts
|
|
2997
|
+
var CHECKPOINTED_TOOL_NAMES = /* @__PURE__ */ new Set(["Write", "Edit"]);
|
|
2998
|
+
function wrapEditCheckpointTools(tools, recorder) {
|
|
2999
|
+
return tools.map(
|
|
3000
|
+
(tool) => CHECKPOINTED_TOOL_NAMES.has(tool.getName()) ? new EditCheckpointToolWrapper(tool, recorder) : tool
|
|
3001
|
+
);
|
|
3002
|
+
}
|
|
3003
|
+
var EditCheckpointToolWrapper = class {
|
|
3004
|
+
constructor(delegate, recorder) {
|
|
3005
|
+
this.delegate = delegate;
|
|
3006
|
+
this.recorder = recorder;
|
|
3007
|
+
this.schema = delegate.schema;
|
|
3008
|
+
}
|
|
3009
|
+
schema;
|
|
3010
|
+
setEventService(eventService) {
|
|
3011
|
+
this.delegate.setEventService(eventService);
|
|
3012
|
+
}
|
|
3013
|
+
async execute(parameters, context) {
|
|
3014
|
+
const filePath = extractFilePath(parameters);
|
|
3015
|
+
if (filePath) {
|
|
3016
|
+
await this.recorder.captureFile(filePath);
|
|
3017
|
+
}
|
|
3018
|
+
return this.delegate.execute(parameters, context);
|
|
3019
|
+
}
|
|
3020
|
+
validate(parameters) {
|
|
3021
|
+
return this.delegate.validate(parameters);
|
|
3022
|
+
}
|
|
3023
|
+
validateParameters(parameters) {
|
|
3024
|
+
return this.delegate.validateParameters(parameters);
|
|
3025
|
+
}
|
|
3026
|
+
getDescription() {
|
|
3027
|
+
return this.delegate.getDescription();
|
|
3028
|
+
}
|
|
3029
|
+
getName() {
|
|
3030
|
+
return this.delegate.getName();
|
|
3031
|
+
}
|
|
3032
|
+
};
|
|
3033
|
+
function extractFilePath(parameters) {
|
|
3034
|
+
if (!parameters || typeof parameters !== "object") return void 0;
|
|
3035
|
+
const value = parameters.filePath;
|
|
3036
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
3037
|
+
}
|
|
3038
|
+
|
|
1933
3039
|
// src/assembly/create-session.ts
|
|
1934
3040
|
var import_agent_runtime6 = require("@robota-sdk/agent-runtime");
|
|
1935
3041
|
|
|
1936
3042
|
// src/agents/agent-definition-loader.ts
|
|
1937
|
-
var
|
|
1938
|
-
var
|
|
3043
|
+
var import_node_fs4 = require("fs");
|
|
3044
|
+
var import_node_path3 = require("path");
|
|
1939
3045
|
var import_node_os2 = require("os");
|
|
1940
3046
|
var LIST_KEYS2 = /* @__PURE__ */ new Set(["tools", "disallowedTools"]);
|
|
1941
3047
|
var NUMBER_KEYS = /* @__PURE__ */ new Set(["maxTurns"]);
|
|
@@ -1980,20 +3086,20 @@ function parseFrontmatter2(content) {
|
|
|
1980
3086
|
};
|
|
1981
3087
|
}
|
|
1982
3088
|
function scanAgentsDir(dir) {
|
|
1983
|
-
if (!(0,
|
|
3089
|
+
if (!(0, import_node_fs4.existsSync)(dir)) return [];
|
|
1984
3090
|
const agents = [];
|
|
1985
3091
|
let entries;
|
|
1986
3092
|
try {
|
|
1987
|
-
entries = (0,
|
|
3093
|
+
entries = (0, import_node_fs4.readdirSync)(dir, { withFileTypes: true });
|
|
1988
3094
|
} catch {
|
|
1989
3095
|
return [];
|
|
1990
3096
|
}
|
|
1991
3097
|
for (const entry of entries) {
|
|
1992
3098
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
1993
|
-
const filePath = (0,
|
|
1994
|
-
const content = (0,
|
|
3099
|
+
const filePath = (0, import_node_path3.join)(dir, entry.name);
|
|
3100
|
+
const content = (0, import_node_fs4.readFileSync)(filePath, "utf-8");
|
|
1995
3101
|
const { frontmatter, body } = parseFrontmatter2(content);
|
|
1996
|
-
const fallbackName = (0,
|
|
3102
|
+
const fallbackName = (0, import_node_path3.basename)(entry.name, ".md");
|
|
1997
3103
|
const agent = {
|
|
1998
3104
|
name: frontmatter?.name ?? fallbackName,
|
|
1999
3105
|
description: frontmatter?.description ?? "",
|
|
@@ -2018,11 +3124,11 @@ var AgentDefinitionLoader = class {
|
|
|
2018
3124
|
/** Load all agent definitions, merged with built-in agents. Custom overrides built-in on name collision. */
|
|
2019
3125
|
loadAll() {
|
|
2020
3126
|
const sources = [
|
|
2021
|
-
scanAgentsDir((0,
|
|
2022
|
-
scanAgentsDir((0,
|
|
2023
|
-
scanAgentsDir((0,
|
|
2024
|
-
scanAgentsDir((0,
|
|
2025
|
-
scanAgentsDir((0,
|
|
3127
|
+
scanAgentsDir((0, import_node_path3.join)(this.cwd, ".robota", "agents")),
|
|
3128
|
+
scanAgentsDir((0, import_node_path3.join)(this.cwd, ".agents", "agents")),
|
|
3129
|
+
scanAgentsDir((0, import_node_path3.join)(this.cwd, ".claude", "agents")),
|
|
3130
|
+
scanAgentsDir((0, import_node_path3.join)(this.home, ".robota", "agents")),
|
|
3131
|
+
scanAgentsDir((0, import_node_path3.join)(this.home, ".claude", "agents"))
|
|
2026
3132
|
];
|
|
2027
3133
|
const seen = /* @__PURE__ */ new Set();
|
|
2028
3134
|
const customAgents = [];
|
|
@@ -2049,7 +3155,7 @@ var AgentDefinitionLoader = class {
|
|
|
2049
3155
|
};
|
|
2050
3156
|
|
|
2051
3157
|
// src/assembly/background-task-hooks.ts
|
|
2052
|
-
var
|
|
3158
|
+
var import_agent_core3 = require("@robota-sdk/agent-core");
|
|
2053
3159
|
function getSubagentHookEvent(event) {
|
|
2054
3160
|
if (event.type === "background_task_started" && event.task.kind === "agent") {
|
|
2055
3161
|
return "SubagentStart";
|
|
@@ -2084,7 +3190,7 @@ function fireSubagentLifecycleHook(event, cwd, hooks, hookTypeExecutors) {
|
|
|
2084
3190
|
ROBOTA_AGENT_TYPE: event.task.agentType ?? event.task.label
|
|
2085
3191
|
}
|
|
2086
3192
|
};
|
|
2087
|
-
void (0,
|
|
3193
|
+
void (0, import_agent_core3.runHooks)(hooks, hookEventName, input, hookTypeExecutors).catch(() => void 0);
|
|
2088
3194
|
}
|
|
2089
3195
|
|
|
2090
3196
|
// src/assembly/create-session.ts
|
|
@@ -2100,7 +3206,7 @@ function createSession(options) {
|
|
|
2100
3206
|
const provider = options.provider;
|
|
2101
3207
|
const cwd = options.cwd ?? process.cwd();
|
|
2102
3208
|
const sessionId = options.sessionId ?? createSessionId();
|
|
2103
|
-
const defaultTools = createDefaultTools();
|
|
3209
|
+
const defaultTools = options.editCheckpointRecorder ? wrapEditCheckpointTools(createDefaultTools(), options.editCheckpointRecorder) : createDefaultTools();
|
|
2104
3210
|
const tools = [...defaultTools, ...options.additionalTools ?? []];
|
|
2105
3211
|
if (options.modelCommandExecutor && options.isModelCommandInvocable) {
|
|
2106
3212
|
tools.push(
|
|
@@ -2201,6 +3307,8 @@ function createSession(options) {
|
|
|
2201
3307
|
const systemMessage = buildPrompt({
|
|
2202
3308
|
agentsMd: options.context.agentsMd,
|
|
2203
3309
|
claudeMd: options.context.claudeMd,
|
|
3310
|
+
memoryMd: options.context.memoryMd,
|
|
3311
|
+
taskContext: options.context.taskContext,
|
|
2204
3312
|
toolDescriptions: options.toolDescriptions ?? (backgroundProcessToolDeps ? [
|
|
2205
3313
|
...defaultToolDescriptions,
|
|
2206
3314
|
"BackgroundProcess \u2014 start long-running shell commands as managed background tasks"
|
|
@@ -2254,6 +3362,7 @@ ${options.appendSystemPrompt}` : systemMessage;
|
|
|
2254
3362
|
sessionId,
|
|
2255
3363
|
permissionHandler: options.permissionHandler,
|
|
2256
3364
|
onTextDelta: options.onTextDelta,
|
|
3365
|
+
onContextUpdate: options.onContextUpdate,
|
|
2257
3366
|
onToolExecution: options.onToolExecution,
|
|
2258
3367
|
promptForApproval: options.promptForApproval,
|
|
2259
3368
|
onCompact: options.onCompact,
|
|
@@ -2278,334 +3387,229 @@ function logBackgroundTaskEvent(logger, sessionId, event) {
|
|
|
2278
3387
|
}
|
|
2279
3388
|
|
|
2280
3389
|
// src/assembly/subagent-logger.ts
|
|
2281
|
-
var
|
|
2282
|
-
var
|
|
3390
|
+
var import_node_fs5 = require("fs");
|
|
3391
|
+
var import_node_path4 = require("path");
|
|
2283
3392
|
var import_agent_sessions3 = require("@robota-sdk/agent-sessions");
|
|
2284
3393
|
function createSubagentLogger(parentSessionId, _agentId, baseLogsDir) {
|
|
2285
|
-
const subagentDir = (0,
|
|
2286
|
-
(0,
|
|
3394
|
+
const subagentDir = (0, import_node_path4.join)(baseLogsDir, parentSessionId, "subagents");
|
|
3395
|
+
(0, import_node_fs5.mkdirSync)(subagentDir, { recursive: true });
|
|
2287
3396
|
return new import_agent_sessions3.FileSessionLogger(subagentDir);
|
|
2288
3397
|
}
|
|
2289
|
-
function resolveSubagentLogDir(parentSessionId, baseLogsDir) {
|
|
2290
|
-
return (0,
|
|
2291
|
-
}
|
|
2292
|
-
|
|
2293
|
-
// src/interactive/interactive-session-init.ts
|
|
2294
|
-
var import_agent_sessions4 = require("@robota-sdk/agent-sessions");
|
|
2295
|
-
|
|
2296
|
-
// src/paths.ts
|
|
2297
|
-
var import_node_path4 = require("path");
|
|
2298
|
-
var import_node_os3 = require("os");
|
|
2299
|
-
function projectPaths(cwd) {
|
|
2300
|
-
const base = (0, import_node_path4.join)(cwd, ".robota");
|
|
2301
|
-
return {
|
|
2302
|
-
settings: (0, import_node_path4.join)(base, "settings.json"),
|
|
2303
|
-
settingsLocal: (0, import_node_path4.join)(base, "settings.local.json"),
|
|
2304
|
-
logs: (0, import_node_path4.join)(base, "logs"),
|
|
2305
|
-
sessions: (0, import_node_path4.join)(base, "sessions")
|
|
2306
|
-
};
|
|
2307
|
-
}
|
|
2308
|
-
function userPaths() {
|
|
2309
|
-
const base = (0, import_node_path4.join)((0, import_node_os3.homedir)(), ".robota");
|
|
2310
|
-
return {
|
|
2311
|
-
settings: (0, import_node_path4.join)(base, "settings.json"),
|
|
2312
|
-
sessions: (0, import_node_path4.join)(base, "sessions")
|
|
2313
|
-
};
|
|
2314
|
-
}
|
|
2315
|
-
|
|
2316
|
-
// src/config/config-loader.ts
|
|
2317
|
-
var import_fs = require("fs");
|
|
2318
|
-
var import_path = require("path");
|
|
2319
|
-
|
|
2320
|
-
// src/config/config-types.ts
|
|
2321
|
-
var import_zod4 = require("zod");
|
|
2322
|
-
var ProviderSchema = import_zod4.z.object({
|
|
2323
|
-
name: import_zod4.z.string().optional(),
|
|
2324
|
-
model: import_zod4.z.string().optional(),
|
|
2325
|
-
apiKey: import_zod4.z.string().optional(),
|
|
2326
|
-
baseURL: import_zod4.z.string().optional(),
|
|
2327
|
-
timeout: import_zod4.z.number().optional()
|
|
2328
|
-
});
|
|
2329
|
-
var ProviderProfileSchema = import_zod4.z.object({
|
|
2330
|
-
type: import_zod4.z.string().optional(),
|
|
2331
|
-
model: import_zod4.z.string().optional(),
|
|
2332
|
-
apiKey: import_zod4.z.string().optional(),
|
|
2333
|
-
baseURL: import_zod4.z.string().optional(),
|
|
2334
|
-
timeout: import_zod4.z.number().optional()
|
|
2335
|
-
});
|
|
2336
|
-
var PermissionsSchema = import_zod4.z.object({
|
|
2337
|
-
/** Patterns that are always approved without prompting */
|
|
2338
|
-
allow: import_zod4.z.array(import_zod4.z.string()).optional(),
|
|
2339
|
-
/** Patterns that are always denied */
|
|
2340
|
-
deny: import_zod4.z.array(import_zod4.z.string()).optional()
|
|
2341
|
-
});
|
|
2342
|
-
var EnvSchema = import_zod4.z.record(import_zod4.z.string()).optional();
|
|
2343
|
-
var CommandHookDefinitionSchema = import_zod4.z.object({
|
|
2344
|
-
type: import_zod4.z.literal("command"),
|
|
2345
|
-
command: import_zod4.z.string(),
|
|
2346
|
-
timeout: import_zod4.z.number().optional()
|
|
2347
|
-
});
|
|
2348
|
-
var HttpHookDefinitionSchema = import_zod4.z.object({
|
|
2349
|
-
type: import_zod4.z.literal("http"),
|
|
2350
|
-
url: import_zod4.z.string(),
|
|
2351
|
-
headers: import_zod4.z.record(import_zod4.z.string()).optional(),
|
|
2352
|
-
timeout: import_zod4.z.number().optional()
|
|
2353
|
-
});
|
|
2354
|
-
var PromptHookDefinitionSchema = import_zod4.z.object({
|
|
2355
|
-
type: import_zod4.z.literal("prompt"),
|
|
2356
|
-
prompt: import_zod4.z.string(),
|
|
2357
|
-
model: import_zod4.z.string().optional()
|
|
2358
|
-
});
|
|
2359
|
-
var AgentHookDefinitionSchema = import_zod4.z.object({
|
|
2360
|
-
type: import_zod4.z.literal("agent"),
|
|
2361
|
-
agent: import_zod4.z.string(),
|
|
2362
|
-
maxTurns: import_zod4.z.number().optional(),
|
|
2363
|
-
timeout: import_zod4.z.number().optional()
|
|
2364
|
-
});
|
|
2365
|
-
var HookDefinitionSchema = import_zod4.z.discriminatedUnion("type", [
|
|
2366
|
-
CommandHookDefinitionSchema,
|
|
2367
|
-
HttpHookDefinitionSchema,
|
|
2368
|
-
PromptHookDefinitionSchema,
|
|
2369
|
-
AgentHookDefinitionSchema
|
|
2370
|
-
]);
|
|
2371
|
-
var HookGroupSchema = import_zod4.z.object({
|
|
2372
|
-
matcher: import_zod4.z.string(),
|
|
2373
|
-
hooks: import_zod4.z.array(HookDefinitionSchema)
|
|
2374
|
-
});
|
|
2375
|
-
var HooksSchema = import_zod4.z.object({
|
|
2376
|
-
PreToolUse: import_zod4.z.array(HookGroupSchema).optional(),
|
|
2377
|
-
PostToolUse: import_zod4.z.array(HookGroupSchema).optional(),
|
|
2378
|
-
SessionStart: import_zod4.z.array(HookGroupSchema).optional(),
|
|
2379
|
-
SessionEnd: import_zod4.z.array(HookGroupSchema).optional(),
|
|
2380
|
-
Stop: import_zod4.z.array(HookGroupSchema).optional(),
|
|
2381
|
-
StopFailure: import_zod4.z.array(HookGroupSchema).optional(),
|
|
2382
|
-
PreCompact: import_zod4.z.array(HookGroupSchema).optional(),
|
|
2383
|
-
PostCompact: import_zod4.z.array(HookGroupSchema).optional(),
|
|
2384
|
-
UserPromptSubmit: import_zod4.z.array(HookGroupSchema).optional(),
|
|
2385
|
-
SubagentStart: import_zod4.z.array(HookGroupSchema).optional(),
|
|
2386
|
-
SubagentStop: import_zod4.z.array(HookGroupSchema).optional(),
|
|
2387
|
-
WorktreeCreate: import_zod4.z.array(HookGroupSchema).optional(),
|
|
2388
|
-
WorktreeRemove: import_zod4.z.array(HookGroupSchema).optional()
|
|
2389
|
-
}).optional();
|
|
2390
|
-
var EnabledPluginsSchema = import_zod4.z.record(import_zod4.z.boolean()).optional();
|
|
2391
|
-
var MarketplaceSourceSchema = import_zod4.z.object({
|
|
2392
|
-
source: import_zod4.z.object({
|
|
2393
|
-
type: import_zod4.z.enum(["github", "git", "local", "url"]),
|
|
2394
|
-
repo: import_zod4.z.string().optional(),
|
|
2395
|
-
url: import_zod4.z.string().optional(),
|
|
2396
|
-
path: import_zod4.z.string().optional(),
|
|
2397
|
-
ref: import_zod4.z.string().optional()
|
|
2398
|
-
})
|
|
2399
|
-
});
|
|
2400
|
-
var ExtraKnownMarketplacesSchema = import_zod4.z.record(MarketplaceSourceSchema).optional().catch(void 0);
|
|
2401
|
-
var SettingsSchema = import_zod4.z.object({
|
|
2402
|
-
/** Trust level used when no --permission-mode flag is given */
|
|
2403
|
-
defaultTrustLevel: import_zod4.z.enum(["safe", "moderate", "full"]).optional(),
|
|
2404
|
-
/** Response language (e.g., "ko", "en", "ja"). Injected into system prompt. */
|
|
2405
|
-
language: import_zod4.z.string().optional(),
|
|
2406
|
-
/** Active provider profile key from providers. */
|
|
2407
|
-
currentProvider: import_zod4.z.string().optional(),
|
|
2408
|
-
/** Provider profiles keyed by user-facing profile name. */
|
|
2409
|
-
providers: import_zod4.z.record(ProviderProfileSchema).optional(),
|
|
2410
|
-
/** Legacy single-provider settings. Prefer currentProvider + providers for new config. */
|
|
2411
|
-
provider: ProviderSchema.optional(),
|
|
2412
|
-
permissions: PermissionsSchema.optional(),
|
|
2413
|
-
env: EnvSchema,
|
|
2414
|
-
hooks: HooksSchema,
|
|
2415
|
-
/** Plugin enablement map: plugin name -> enabled/disabled */
|
|
2416
|
-
enabledPlugins: EnabledPluginsSchema,
|
|
2417
|
-
/** Extra marketplace URLs for BundlePlugin discovery */
|
|
2418
|
-
extraKnownMarketplaces: ExtraKnownMarketplacesSchema
|
|
2419
|
-
});
|
|
2420
|
-
|
|
2421
|
-
// src/config/config-loader.ts
|
|
2422
|
-
function getHomeDir() {
|
|
2423
|
-
return process.env.HOME ?? process.env.USERPROFILE ?? "/";
|
|
2424
|
-
}
|
|
2425
|
-
var DEFAULTS = {
|
|
2426
|
-
defaultTrustLevel: "moderate",
|
|
2427
|
-
provider: {
|
|
2428
|
-
name: "anthropic",
|
|
2429
|
-
model: "claude-opus-4-5",
|
|
2430
|
-
apiKey: void 0
|
|
2431
|
-
},
|
|
2432
|
-
permissions: {
|
|
2433
|
-
allow: [],
|
|
2434
|
-
deny: []
|
|
2435
|
-
},
|
|
2436
|
-
env: {}
|
|
2437
|
-
};
|
|
2438
|
-
function readJsonFile(filePath) {
|
|
2439
|
-
if (!(0, import_fs.existsSync)(filePath)) {
|
|
2440
|
-
return void 0;
|
|
2441
|
-
}
|
|
2442
|
-
const raw = (0, import_fs.readFileSync)(filePath, "utf-8").trim();
|
|
2443
|
-
if (raw.length === 0) {
|
|
2444
|
-
return void 0;
|
|
2445
|
-
}
|
|
2446
|
-
try {
|
|
2447
|
-
return JSON.parse(raw);
|
|
2448
|
-
} catch {
|
|
2449
|
-
return void 0;
|
|
2450
|
-
}
|
|
2451
|
-
}
|
|
2452
|
-
function resolveEnvRef(value) {
|
|
2453
|
-
const ENV_PREFIX = "$ENV:";
|
|
2454
|
-
if (value.startsWith(ENV_PREFIX)) {
|
|
2455
|
-
const varName = value.slice(ENV_PREFIX.length);
|
|
2456
|
-
return process.env[varName] ?? value;
|
|
2457
|
-
}
|
|
2458
|
-
return value;
|
|
2459
|
-
}
|
|
2460
|
-
function resolveEnvRefs(settings) {
|
|
2461
|
-
const provider = settings.provider?.apiKey !== void 0 ? {
|
|
2462
|
-
...settings.provider,
|
|
2463
|
-
apiKey: resolveEnvRef(settings.provider.apiKey)
|
|
2464
|
-
} : settings.provider;
|
|
2465
|
-
if (settings.providers !== void 0) {
|
|
2466
|
-
const providers = Object.fromEntries(
|
|
2467
|
-
Object.entries(settings.providers).map(([name, profile]) => [
|
|
2468
|
-
name,
|
|
2469
|
-
{
|
|
2470
|
-
...profile,
|
|
2471
|
-
...profile.apiKey !== void 0 && { apiKey: resolveEnvRef(profile.apiKey) }
|
|
2472
|
-
}
|
|
2473
|
-
])
|
|
2474
|
-
);
|
|
2475
|
-
return {
|
|
2476
|
-
...settings,
|
|
2477
|
-
provider,
|
|
2478
|
-
providers
|
|
2479
|
-
};
|
|
2480
|
-
}
|
|
2481
|
-
return {
|
|
2482
|
-
...settings,
|
|
2483
|
-
provider
|
|
2484
|
-
};
|
|
2485
|
-
}
|
|
2486
|
-
function mergeSettings(layers) {
|
|
2487
|
-
return layers.reduce((merged, layer) => {
|
|
2488
|
-
return {
|
|
2489
|
-
...merged,
|
|
2490
|
-
...layer,
|
|
2491
|
-
provider: merged.provider !== void 0 || layer.provider !== void 0 ? { ...merged.provider, ...layer.provider } : void 0,
|
|
2492
|
-
permissions: merged.permissions !== void 0 || layer.permissions !== void 0 ? {
|
|
2493
|
-
allow: layer.permissions?.allow ?? merged.permissions?.allow,
|
|
2494
|
-
deny: layer.permissions?.deny ?? merged.permissions?.deny
|
|
2495
|
-
} : void 0,
|
|
2496
|
-
env: {
|
|
2497
|
-
...merged.env ?? {},
|
|
2498
|
-
...layer.env ?? {}
|
|
2499
|
-
},
|
|
2500
|
-
providers: merged.providers !== void 0 || layer.providers !== void 0 ? mergeProviders(merged.providers, layer.providers) : void 0,
|
|
2501
|
-
enabledPlugins: merged.enabledPlugins !== void 0 || layer.enabledPlugins !== void 0 ? { ...merged.enabledPlugins ?? {}, ...layer.enabledPlugins ?? {} } : void 0,
|
|
2502
|
-
extraKnownMarketplaces: layer.extraKnownMarketplaces ?? merged.extraKnownMarketplaces
|
|
2503
|
-
};
|
|
2504
|
-
}, {});
|
|
2505
|
-
}
|
|
2506
|
-
function mergeProviders(base, override) {
|
|
2507
|
-
const result = { ...base ?? {} };
|
|
2508
|
-
for (const [name, profile] of Object.entries(override ?? {})) {
|
|
2509
|
-
result[name] = {
|
|
2510
|
-
...result[name],
|
|
2511
|
-
...profile
|
|
2512
|
-
};
|
|
2513
|
-
}
|
|
2514
|
-
return result;
|
|
3398
|
+
function resolveSubagentLogDir(parentSessionId, baseLogsDir) {
|
|
3399
|
+
return (0, import_node_path4.join)(baseLogsDir, parentSessionId, "subagents");
|
|
2515
3400
|
}
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
return {
|
|
2526
|
-
name: profile.type,
|
|
2527
|
-
model: profile.model ?? DEFAULTS.provider.model,
|
|
2528
|
-
apiKey: profile.apiKey ?? DEFAULTS.provider.apiKey,
|
|
2529
|
-
...profile.baseURL !== void 0 && { baseURL: profile.baseURL },
|
|
2530
|
-
...profile.timeout !== void 0 && { timeout: profile.timeout }
|
|
2531
|
-
};
|
|
2532
|
-
}
|
|
3401
|
+
|
|
3402
|
+
// src/interactive/interactive-session-init.ts
|
|
3403
|
+
var import_agent_sessions4 = require("@robota-sdk/agent-sessions");
|
|
3404
|
+
|
|
3405
|
+
// src/paths.ts
|
|
3406
|
+
var import_node_path5 = require("path");
|
|
3407
|
+
var import_node_os3 = require("os");
|
|
3408
|
+
function projectPaths(cwd) {
|
|
3409
|
+
const base = (0, import_node_path5.join)(cwd, ".robota");
|
|
2533
3410
|
return {
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
3411
|
+
settings: (0, import_node_path5.join)(base, "settings.json"),
|
|
3412
|
+
settingsLocal: (0, import_node_path5.join)(base, "settings.local.json"),
|
|
3413
|
+
logs: (0, import_node_path5.join)(base, "logs"),
|
|
3414
|
+
sessions: (0, import_node_path5.join)(base, "sessions"),
|
|
3415
|
+
memory: (0, import_node_path5.join)(base, "memory"),
|
|
3416
|
+
checkpoints: (0, import_node_path5.join)(base, "checkpoints")
|
|
2539
3417
|
};
|
|
2540
3418
|
}
|
|
2541
|
-
function
|
|
3419
|
+
function userPaths() {
|
|
3420
|
+
const base = (0, import_node_path5.join)((0, import_node_os3.homedir)(), ".robota");
|
|
2542
3421
|
return {
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
currentProvider: merged.currentProvider,
|
|
2546
|
-
provider: resolveProvider(merged),
|
|
2547
|
-
permissions: {
|
|
2548
|
-
allow: merged.permissions?.allow ?? DEFAULTS.permissions.allow,
|
|
2549
|
-
deny: merged.permissions?.deny ?? DEFAULTS.permissions.deny
|
|
2550
|
-
},
|
|
2551
|
-
env: merged.env ?? DEFAULTS.env,
|
|
2552
|
-
hooks: merged.hooks ?? void 0,
|
|
2553
|
-
enabledPlugins: merged.enabledPlugins ?? void 0,
|
|
2554
|
-
extraKnownMarketplaces: merged.extraKnownMarketplaces ?? void 0
|
|
3422
|
+
settings: (0, import_node_path5.join)(base, "settings.json"),
|
|
3423
|
+
sessions: (0, import_node_path5.join)(base, "sessions")
|
|
2555
3424
|
};
|
|
2556
3425
|
}
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
3426
|
+
|
|
3427
|
+
// src/context/context-loader.ts
|
|
3428
|
+
var import_fs3 = require("fs");
|
|
3429
|
+
var import_path3 = require("path");
|
|
3430
|
+
|
|
3431
|
+
// src/context/task-context.ts
|
|
3432
|
+
var import_node_fs6 = require("fs");
|
|
3433
|
+
var import_node_path6 = require("path");
|
|
3434
|
+
var TASKS_DIR = (0, import_node_path6.join)(".agents", "tasks");
|
|
3435
|
+
var README_FILENAME = "README.md";
|
|
3436
|
+
var MARKDOWN_EXTENSION = ".md";
|
|
3437
|
+
var DEFAULT_MAX_TASKS = Number("3");
|
|
3438
|
+
var STATUS_PRIORITIES = {
|
|
3439
|
+
"in-progress": Number("1"),
|
|
3440
|
+
todo: Number("2"),
|
|
3441
|
+
blocked: Number("3"),
|
|
3442
|
+
unknown: Number("4"),
|
|
3443
|
+
completed: Number("5")
|
|
3444
|
+
};
|
|
3445
|
+
function normalizeStatus(value) {
|
|
3446
|
+
const normalized = value?.trim().toLowerCase();
|
|
3447
|
+
if (normalized === "todo" || normalized === "in-progress" || normalized === "blocked" || normalized === "completed") {
|
|
3448
|
+
return normalized;
|
|
3449
|
+
}
|
|
3450
|
+
return "unknown";
|
|
3451
|
+
}
|
|
3452
|
+
function extractTitle(content, taskPath) {
|
|
3453
|
+
const heading = content.split(/\r?\n/).find((line) => /^#\s+/.test(line));
|
|
3454
|
+
return heading?.replace(/^#\s+/, "").trim() || (0, import_node_path6.basename)(taskPath, MARKDOWN_EXTENSION);
|
|
3455
|
+
}
|
|
3456
|
+
function extractMetadata(content, key) {
|
|
3457
|
+
const matcher = new RegExp(`^- \\*\\*${key}\\*\\*:\\s*(.+)$`, "im");
|
|
3458
|
+
return matcher.exec(content)?.[1]?.trim();
|
|
3459
|
+
}
|
|
3460
|
+
function extractSection(content, title) {
|
|
3461
|
+
const lines = content.split(/\r?\n/);
|
|
3462
|
+
const heading = new RegExp(`^(#{2,6})\\s+${title}\\b`, "i");
|
|
3463
|
+
const startIndex = lines.findIndex((line) => heading.test(line));
|
|
3464
|
+
if (startIndex < 0) {
|
|
3465
|
+
return void 0;
|
|
3466
|
+
}
|
|
3467
|
+
const collected = [];
|
|
3468
|
+
for (const line of lines.slice(startIndex + Number("1"))) {
|
|
3469
|
+
if (/^##\s+/.test(line)) {
|
|
3470
|
+
break;
|
|
2581
3471
|
}
|
|
3472
|
+
collected.push(line);
|
|
3473
|
+
}
|
|
3474
|
+
const result = collected.join("\n").trim();
|
|
3475
|
+
return result.length > 0 ? result : void 0;
|
|
3476
|
+
}
|
|
3477
|
+
function extractOpenItems(content) {
|
|
3478
|
+
return content.split(/\r?\n/).map((line) => /^- \[ \]\s+(.+)$/.exec(line)?.[1]?.trim()).filter((item) => item !== void 0 && item.length > 0);
|
|
3479
|
+
}
|
|
3480
|
+
function taskSortScore(task, currentBranch) {
|
|
3481
|
+
if (currentBranch && task.branch === currentBranch) {
|
|
3482
|
+
return Number("0");
|
|
3483
|
+
}
|
|
3484
|
+
return STATUS_PRIORITIES[task.status];
|
|
3485
|
+
}
|
|
3486
|
+
function formatTask(task) {
|
|
3487
|
+
const lines = [`### ${task.title}`, `- **Path:** \`${task.relativePath}\``];
|
|
3488
|
+
lines.push(`- **Status:** ${task.status}`);
|
|
3489
|
+
if (task.branch) lines.push(`- **Branch:** ${task.branch}`);
|
|
3490
|
+
if (task.scope) lines.push(`- **Scope:** ${task.scope}`);
|
|
3491
|
+
if (task.objective) lines.push(`- **Objective:** ${task.objective}`);
|
|
3492
|
+
if (task.openItems.length > 0) {
|
|
3493
|
+
lines.push("- **Open items:**");
|
|
3494
|
+
lines.push(...task.openItems.map((item) => ` - ${item}`));
|
|
3495
|
+
}
|
|
3496
|
+
return lines.join("\n");
|
|
3497
|
+
}
|
|
3498
|
+
function formatDate(date) {
|
|
3499
|
+
return date.toISOString().slice(Number("0"), Number("10"));
|
|
3500
|
+
}
|
|
3501
|
+
function upsertStatusLine(content, status) {
|
|
3502
|
+
const lines = content.split(/\r?\n/);
|
|
3503
|
+
const statusLine = `- **Status**: ${status}`;
|
|
3504
|
+
const statusIndex = lines.findIndex((line) => /^- \*\*Status\*\*:\s*/.test(line));
|
|
3505
|
+
if (statusIndex >= Number("0")) {
|
|
3506
|
+
lines[statusIndex] = statusLine;
|
|
3507
|
+
return lines.join("\n");
|
|
3508
|
+
}
|
|
3509
|
+
const hasTopHeading = lines.length > Number("0") && /^#\s+/.test(lines[Number("0")]);
|
|
3510
|
+
if (hasTopHeading) {
|
|
3511
|
+
lines.splice(Number("1"), Number("0"), "", statusLine);
|
|
3512
|
+
} else {
|
|
3513
|
+
lines.unshift(statusLine, "");
|
|
2582
3514
|
}
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
3515
|
+
return lines.join("\n");
|
|
3516
|
+
}
|
|
3517
|
+
function appendProgressEntry(content, now, progressMessage) {
|
|
3518
|
+
const entryLines = [`### ${formatDate(now)}`, `- ${progressMessage.trim()}`];
|
|
3519
|
+
const lines = content.replace(/\s+$/u, "").split(/\r?\n/);
|
|
3520
|
+
const progressIndex = lines.findIndex((line) => /^## Progress\s*$/.test(line));
|
|
3521
|
+
if (progressIndex < Number("0")) {
|
|
3522
|
+
return [...lines, "", "## Progress", "", ...entryLines, ""].join("\n");
|
|
3523
|
+
}
|
|
3524
|
+
const nextHeadingIndex = lines.findIndex(
|
|
3525
|
+
(line, index) => index > progressIndex && /^##\s+/.test(line)
|
|
3526
|
+
);
|
|
3527
|
+
if (nextHeadingIndex < Number("0")) {
|
|
3528
|
+
return [...lines, "", ...entryLines, ""].join("\n");
|
|
3529
|
+
}
|
|
3530
|
+
lines.splice(nextHeadingIndex, Number("0"), "", ...entryLines, "");
|
|
3531
|
+
return lines.join("\n");
|
|
3532
|
+
}
|
|
3533
|
+
function resolveGitDirectory(cwd) {
|
|
3534
|
+
let current = (0, import_node_path6.resolve)(cwd);
|
|
3535
|
+
let reachedRoot = false;
|
|
3536
|
+
while (!reachedRoot) {
|
|
3537
|
+
const gitPath = (0, import_node_path6.join)(current, ".git");
|
|
3538
|
+
if ((0, import_node_fs6.existsSync)(gitPath)) {
|
|
3539
|
+
const stats = (0, import_node_fs6.statSync)(gitPath);
|
|
3540
|
+
if (stats.isDirectory()) return gitPath;
|
|
3541
|
+
const content = (0, import_node_fs6.readFileSync)(gitPath, "utf8").trim();
|
|
3542
|
+
const gitdir = content.match(/^gitdir:\s*(.+)$/)?.[1];
|
|
3543
|
+
if (gitdir) return (0, import_node_path6.isAbsolute)(gitdir) ? gitdir : (0, import_node_path6.resolve)(current, gitdir);
|
|
2587
3544
|
}
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
3545
|
+
const parent = (0, import_node_path6.dirname)(current);
|
|
3546
|
+
reachedRoot = parent === current;
|
|
3547
|
+
current = parent;
|
|
3548
|
+
}
|
|
3549
|
+
return void 0;
|
|
3550
|
+
}
|
|
3551
|
+
function readCurrentGitBranch(cwd) {
|
|
3552
|
+
const gitDir = resolveGitDirectory(cwd);
|
|
3553
|
+
if (!gitDir) return void 0;
|
|
3554
|
+
const headPath = (0, import_node_path6.join)(gitDir, "HEAD");
|
|
3555
|
+
if (!(0, import_node_fs6.existsSync)(headPath)) return void 0;
|
|
3556
|
+
const head = (0, import_node_fs6.readFileSync)(headPath, "utf8").trim();
|
|
3557
|
+
const branch = head.match(/^ref:\s+refs\/heads\/(.+)$/)?.[1];
|
|
3558
|
+
return branch?.trim();
|
|
3559
|
+
}
|
|
3560
|
+
function discoverTaskFiles(cwd) {
|
|
3561
|
+
const tasksDir = (0, import_node_path6.join)(cwd, TASKS_DIR);
|
|
3562
|
+
if (!(0, import_node_fs6.existsSync)(tasksDir)) {
|
|
3563
|
+
return [];
|
|
3564
|
+
}
|
|
3565
|
+
return (0, import_node_fs6.readdirSync)(tasksDir, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => entry.name).filter((name) => name !== README_FILENAME && name.endsWith(MARKDOWN_EXTENSION)).sort((a, b) => a.localeCompare(b)).map((name) => (0, import_node_path6.join)(tasksDir, name));
|
|
3566
|
+
}
|
|
3567
|
+
function parseTaskFile(taskPath, cwd) {
|
|
3568
|
+
const content = (0, import_node_fs6.readFileSync)(taskPath, "utf8");
|
|
3569
|
+
return {
|
|
3570
|
+
path: taskPath,
|
|
3571
|
+
relativePath: (0, import_node_path6.relative)(cwd, taskPath),
|
|
3572
|
+
title: extractTitle(content, taskPath),
|
|
3573
|
+
status: normalizeStatus(extractMetadata(content, "Status")),
|
|
3574
|
+
branch: extractMetadata(content, "Branch"),
|
|
3575
|
+
scope: extractMetadata(content, "Scope"),
|
|
3576
|
+
objective: extractSection(content, "Objective"),
|
|
3577
|
+
openItems: extractOpenItems(content)
|
|
3578
|
+
};
|
|
3579
|
+
}
|
|
3580
|
+
function selectRelevantTasks(tasks, options = {}) {
|
|
3581
|
+
const maxTasks = options.maxTasks ?? DEFAULT_MAX_TASKS;
|
|
3582
|
+
return [...tasks].filter((task) => task.status !== "completed").sort(
|
|
3583
|
+
(left, right) => taskSortScore(left, options.currentBranch) - taskSortScore(right, options.currentBranch) || left.relativePath.localeCompare(right.relativePath)
|
|
3584
|
+
).slice(Number("0"), maxTasks);
|
|
3585
|
+
}
|
|
3586
|
+
function formatTaskContext(tasks) {
|
|
3587
|
+
return tasks.map(formatTask).join("\n\n");
|
|
3588
|
+
}
|
|
3589
|
+
function loadTaskContext(cwd, options = {}) {
|
|
3590
|
+
const currentBranch = options.currentBranch ?? readCurrentGitBranch(cwd);
|
|
3591
|
+
const tasks = discoverTaskFiles(cwd).map((path) => parseTaskFile(path, cwd));
|
|
3592
|
+
return formatTaskContext(selectRelevantTasks(tasks, { ...options, currentBranch }));
|
|
3593
|
+
}
|
|
3594
|
+
function updateTaskFileStatus(taskPath, status, options = {}) {
|
|
3595
|
+
const updated = upsertStatusLine((0, import_node_fs6.readFileSync)(taskPath, "utf8"), status);
|
|
3596
|
+
const withProgress = options.progressMessage ? appendProgressEntry(updated, options.now ?? /* @__PURE__ */ new Date(), options.progressMessage) : updated;
|
|
3597
|
+
(0, import_node_fs6.writeFileSync)(taskPath, withProgress, "utf8");
|
|
2592
3598
|
}
|
|
2593
3599
|
|
|
2594
3600
|
// src/context/context-loader.ts
|
|
2595
|
-
var import_fs2 = require("fs");
|
|
2596
|
-
var import_path2 = require("path");
|
|
2597
3601
|
var AGENTS_FILENAME = "AGENTS.md";
|
|
2598
3602
|
var CLAUDE_FILENAME = "CLAUDE.md";
|
|
2599
3603
|
function collectFilesWalkingUp(startDir, filename) {
|
|
2600
3604
|
const found = [];
|
|
2601
|
-
let current = (0,
|
|
3605
|
+
let current = (0, import_path3.resolve)(startDir);
|
|
2602
3606
|
let atRoot = false;
|
|
2603
3607
|
while (!atRoot) {
|
|
2604
|
-
const candidate = (0,
|
|
2605
|
-
if ((0,
|
|
3608
|
+
const candidate = (0, import_path3.join)(current, filename);
|
|
3609
|
+
if ((0, import_fs3.existsSync)(candidate)) {
|
|
2606
3610
|
found.push(candidate);
|
|
2607
3611
|
}
|
|
2608
|
-
const parent = (0,
|
|
3612
|
+
const parent = (0, import_path3.dirname)(current);
|
|
2609
3613
|
atRoot = parent === current;
|
|
2610
3614
|
if (!atRoot) {
|
|
2611
3615
|
current = parent;
|
|
@@ -2640,47 +3644,51 @@ function extractCompactInstructions(content) {
|
|
|
2640
3644
|
async function loadContext(cwd) {
|
|
2641
3645
|
const agentsPaths = collectFilesWalkingUp(cwd, AGENTS_FILENAME);
|
|
2642
3646
|
const claudePaths = collectFilesWalkingUp(cwd, CLAUDE_FILENAME);
|
|
2643
|
-
const agentsMd = agentsPaths.map((p) => (0,
|
|
2644
|
-
const claudeMd = claudePaths.map((p) => (0,
|
|
3647
|
+
const agentsMd = agentsPaths.map((p) => (0, import_fs3.readFileSync)(p, "utf-8")).join("\n\n");
|
|
3648
|
+
const claudeMd = claudePaths.map((p) => (0, import_fs3.readFileSync)(p, "utf-8")).join("\n\n");
|
|
2645
3649
|
const compactInstructions = extractCompactInstructions(claudeMd);
|
|
2646
|
-
|
|
3650
|
+
const startupMemory = new ProjectMemoryStore(cwd).loadStartupMemory();
|
|
3651
|
+
const memoryMd = startupMemory.content || void 0;
|
|
3652
|
+
const loadedTaskContext = loadTaskContext(cwd);
|
|
3653
|
+
const taskContext = loadedTaskContext.trim().length > 0 ? loadedTaskContext : void 0;
|
|
3654
|
+
return { agentsMd, claudeMd, memoryMd, taskContext, compactInstructions };
|
|
2647
3655
|
}
|
|
2648
3656
|
|
|
2649
3657
|
// src/context/project-detector.ts
|
|
2650
|
-
var
|
|
2651
|
-
var
|
|
3658
|
+
var import_fs4 = require("fs");
|
|
3659
|
+
var import_path4 = require("path");
|
|
2652
3660
|
function tryReadJson(filePath) {
|
|
2653
|
-
if (!(0,
|
|
3661
|
+
if (!(0, import_fs4.existsSync)(filePath)) return void 0;
|
|
2654
3662
|
try {
|
|
2655
|
-
return JSON.parse((0,
|
|
3663
|
+
return JSON.parse((0, import_fs4.readFileSync)(filePath, "utf-8"));
|
|
2656
3664
|
} catch {
|
|
2657
3665
|
return void 0;
|
|
2658
3666
|
}
|
|
2659
3667
|
}
|
|
2660
3668
|
function detectPackageManager(cwd) {
|
|
2661
|
-
if ((0,
|
|
3669
|
+
if ((0, import_fs4.existsSync)((0, import_path4.join)(cwd, "pnpm-workspace.yaml")) || (0, import_fs4.existsSync)((0, import_path4.join)(cwd, "pnpm-lock.yaml"))) {
|
|
2662
3670
|
return "pnpm";
|
|
2663
3671
|
}
|
|
2664
|
-
if ((0,
|
|
3672
|
+
if ((0, import_fs4.existsSync)((0, import_path4.join)(cwd, "yarn.lock"))) {
|
|
2665
3673
|
return "yarn";
|
|
2666
3674
|
}
|
|
2667
|
-
if ((0,
|
|
3675
|
+
if ((0, import_fs4.existsSync)((0, import_path4.join)(cwd, "bun.lockb"))) {
|
|
2668
3676
|
return "bun";
|
|
2669
3677
|
}
|
|
2670
|
-
if ((0,
|
|
3678
|
+
if ((0, import_fs4.existsSync)((0, import_path4.join)(cwd, "package-lock.json"))) {
|
|
2671
3679
|
return "npm";
|
|
2672
3680
|
}
|
|
2673
3681
|
return void 0;
|
|
2674
3682
|
}
|
|
2675
3683
|
async function detectProject(cwd) {
|
|
2676
|
-
const pkgJsonPath = (0,
|
|
2677
|
-
const tsconfigPath = (0,
|
|
2678
|
-
const pyprojectPath = (0,
|
|
2679
|
-
const cargoPath = (0,
|
|
2680
|
-
const goModPath = (0,
|
|
2681
|
-
if ((0,
|
|
3684
|
+
const pkgJsonPath = (0, import_path4.join)(cwd, "package.json");
|
|
3685
|
+
const tsconfigPath = (0, import_path4.join)(cwd, "tsconfig.json");
|
|
3686
|
+
const pyprojectPath = (0, import_path4.join)(cwd, "pyproject.toml");
|
|
3687
|
+
const cargoPath = (0, import_path4.join)(cwd, "Cargo.toml");
|
|
3688
|
+
const goModPath = (0, import_path4.join)(cwd, "go.mod");
|
|
3689
|
+
if ((0, import_fs4.existsSync)(pkgJsonPath)) {
|
|
2682
3690
|
const pkgJson = tryReadJson(pkgJsonPath);
|
|
2683
|
-
const language = (0,
|
|
3691
|
+
const language = (0, import_fs4.existsSync)(tsconfigPath) ? "typescript" : "javascript";
|
|
2684
3692
|
const packageManager = detectPackageManager(cwd);
|
|
2685
3693
|
return {
|
|
2686
3694
|
type: "node",
|
|
@@ -2689,19 +3697,19 @@ async function detectProject(cwd) {
|
|
|
2689
3697
|
language
|
|
2690
3698
|
};
|
|
2691
3699
|
}
|
|
2692
|
-
if ((0,
|
|
3700
|
+
if ((0, import_fs4.existsSync)(pyprojectPath) || (0, import_fs4.existsSync)((0, import_path4.join)(cwd, "setup.py"))) {
|
|
2693
3701
|
return {
|
|
2694
3702
|
type: "python",
|
|
2695
3703
|
language: "python"
|
|
2696
3704
|
};
|
|
2697
3705
|
}
|
|
2698
|
-
if ((0,
|
|
3706
|
+
if ((0, import_fs4.existsSync)(cargoPath)) {
|
|
2699
3707
|
return {
|
|
2700
3708
|
type: "rust",
|
|
2701
3709
|
language: "rust"
|
|
2702
3710
|
};
|
|
2703
3711
|
}
|
|
2704
|
-
if ((0,
|
|
3712
|
+
if ((0, import_fs4.existsSync)(goModPath)) {
|
|
2705
3713
|
return {
|
|
2706
3714
|
type: "go",
|
|
2707
3715
|
language: "go"
|
|
@@ -2714,8 +3722,8 @@ async function detectProject(cwd) {
|
|
|
2714
3722
|
}
|
|
2715
3723
|
|
|
2716
3724
|
// src/plugins/plugin-settings-store.ts
|
|
2717
|
-
var
|
|
2718
|
-
var
|
|
3725
|
+
var import_node_fs7 = require("fs");
|
|
3726
|
+
var import_node_path7 = require("path");
|
|
2719
3727
|
var PluginSettingsStore = class {
|
|
2720
3728
|
settingsPath;
|
|
2721
3729
|
constructor(settingsPath) {
|
|
@@ -2723,11 +3731,11 @@ var PluginSettingsStore = class {
|
|
|
2723
3731
|
}
|
|
2724
3732
|
/** Read the full settings file from disk. */
|
|
2725
3733
|
readAll() {
|
|
2726
|
-
if (!(0,
|
|
3734
|
+
if (!(0, import_node_fs7.existsSync)(this.settingsPath)) {
|
|
2727
3735
|
return {};
|
|
2728
3736
|
}
|
|
2729
3737
|
try {
|
|
2730
|
-
const raw = (0,
|
|
3738
|
+
const raw = (0, import_node_fs7.readFileSync)(this.settingsPath, "utf-8");
|
|
2731
3739
|
const data = JSON.parse(raw);
|
|
2732
3740
|
if (typeof data === "object" && data !== null) {
|
|
2733
3741
|
return data;
|
|
@@ -2739,11 +3747,11 @@ var PluginSettingsStore = class {
|
|
|
2739
3747
|
}
|
|
2740
3748
|
/** Write the full settings file to disk. */
|
|
2741
3749
|
writeAll(settings) {
|
|
2742
|
-
const dir = (0,
|
|
2743
|
-
if (!(0,
|
|
2744
|
-
(0,
|
|
3750
|
+
const dir = (0, import_node_path7.dirname)(this.settingsPath);
|
|
3751
|
+
if (!(0, import_node_fs7.existsSync)(dir)) {
|
|
3752
|
+
(0, import_node_fs7.mkdirSync)(dir, { recursive: true });
|
|
2745
3753
|
}
|
|
2746
|
-
(0,
|
|
3754
|
+
(0, import_node_fs7.writeFileSync)(this.settingsPath, JSON.stringify(settings, null, 2), "utf-8");
|
|
2747
3755
|
}
|
|
2748
3756
|
// --- enabledPlugins ---
|
|
2749
3757
|
/** Get the enabledPlugins map. */
|
|
@@ -2815,11 +3823,11 @@ var PluginSettingsStore = class {
|
|
|
2815
3823
|
};
|
|
2816
3824
|
|
|
2817
3825
|
// src/plugins/bundle-plugin-loader.ts
|
|
2818
|
-
var
|
|
2819
|
-
var
|
|
3826
|
+
var import_node_fs9 = require("fs");
|
|
3827
|
+
var import_node_path8 = require("path");
|
|
2820
3828
|
|
|
2821
3829
|
// src/plugins/bundle-plugin-utils.ts
|
|
2822
|
-
var
|
|
3830
|
+
var import_node_fs8 = require("fs");
|
|
2823
3831
|
function parseSkillFrontmatter(raw) {
|
|
2824
3832
|
const trimmed = raw.trimStart();
|
|
2825
3833
|
if (!trimmed.startsWith("---")) {
|
|
@@ -2868,9 +3876,9 @@ function validateManifest(data) {
|
|
|
2868
3876
|
};
|
|
2869
3877
|
}
|
|
2870
3878
|
function getSortedSubdirs(dirPath) {
|
|
2871
|
-
if (!(0,
|
|
3879
|
+
if (!(0, import_node_fs8.existsSync)(dirPath)) return [];
|
|
2872
3880
|
try {
|
|
2873
|
-
const entries = (0,
|
|
3881
|
+
const entries = (0, import_node_fs8.readdirSync)(dirPath, { withFileTypes: true });
|
|
2874
3882
|
return entries.filter((e) => e.isDirectory()).map((e) => e.name).sort();
|
|
2875
3883
|
} catch {
|
|
2876
3884
|
return [];
|
|
@@ -2900,23 +3908,23 @@ var BundlePluginLoader = class {
|
|
|
2900
3908
|
* For each marketplace/plugin pair, the latest version (lexicographically last) is loaded.
|
|
2901
3909
|
*/
|
|
2902
3910
|
discoverAndLoad() {
|
|
2903
|
-
const cacheDir = (0,
|
|
2904
|
-
if (!(0,
|
|
3911
|
+
const cacheDir = (0, import_node_path8.join)(this.pluginsDir, "cache");
|
|
3912
|
+
if (!(0, import_node_fs9.existsSync)(cacheDir)) {
|
|
2905
3913
|
return [];
|
|
2906
3914
|
}
|
|
2907
3915
|
const results = [];
|
|
2908
3916
|
const marketplaces = getSortedSubdirs(cacheDir);
|
|
2909
3917
|
for (const marketplace of marketplaces) {
|
|
2910
|
-
const marketplaceDir = (0,
|
|
3918
|
+
const marketplaceDir = (0, import_node_path8.join)(cacheDir, marketplace);
|
|
2911
3919
|
const plugins = getSortedSubdirs(marketplaceDir);
|
|
2912
3920
|
for (const pluginName of plugins) {
|
|
2913
|
-
const pluginDir = (0,
|
|
3921
|
+
const pluginDir = (0, import_node_path8.join)(marketplaceDir, pluginName);
|
|
2914
3922
|
const versions = getSortedSubdirs(pluginDir);
|
|
2915
3923
|
if (versions.length === 0) continue;
|
|
2916
3924
|
const latestVersion = versions[versions.length - 1];
|
|
2917
|
-
const versionDir = (0,
|
|
2918
|
-
const manifestPath = (0,
|
|
2919
|
-
if (!(0,
|
|
3925
|
+
const versionDir = (0, import_node_path8.join)(pluginDir, latestVersion);
|
|
3926
|
+
const manifestPath = (0, import_node_path8.join)(versionDir, ".claude-plugin", "plugin.json");
|
|
3927
|
+
if (!(0, import_node_fs9.existsSync)(manifestPath)) continue;
|
|
2920
3928
|
const manifest = this.readManifest(manifestPath);
|
|
2921
3929
|
if (!manifest) continue;
|
|
2922
3930
|
const pluginId = `${manifest.name}@${marketplace}`;
|
|
@@ -2930,7 +3938,7 @@ var BundlePluginLoader = class {
|
|
|
2930
3938
|
/** Read and validate a plugin.json manifest. Returns null on failure. */
|
|
2931
3939
|
readManifest(path) {
|
|
2932
3940
|
try {
|
|
2933
|
-
const raw = (0,
|
|
3941
|
+
const raw = (0, import_node_fs9.readFileSync)(path, "utf-8");
|
|
2934
3942
|
const data = JSON.parse(raw);
|
|
2935
3943
|
return validateManifest(data);
|
|
2936
3944
|
} catch {
|
|
@@ -2965,15 +3973,15 @@ var BundlePluginLoader = class {
|
|
|
2965
3973
|
}
|
|
2966
3974
|
/** Load skills from the plugin's skills/ directory. */
|
|
2967
3975
|
loadSkills(pluginDir, pluginName) {
|
|
2968
|
-
const skillsDir = (0,
|
|
2969
|
-
if (!(0,
|
|
2970
|
-
const entries = (0,
|
|
3976
|
+
const skillsDir = (0, import_node_path8.join)(pluginDir, "skills");
|
|
3977
|
+
if (!(0, import_node_fs9.existsSync)(skillsDir)) return [];
|
|
3978
|
+
const entries = (0, import_node_fs9.readdirSync)(skillsDir, { withFileTypes: true });
|
|
2971
3979
|
const skills = [];
|
|
2972
3980
|
for (const entry of entries) {
|
|
2973
3981
|
if (!entry.isDirectory()) continue;
|
|
2974
|
-
const skillFile = (0,
|
|
2975
|
-
if (!(0,
|
|
2976
|
-
const raw = (0,
|
|
3982
|
+
const skillFile = (0, import_node_path8.join)(skillsDir, entry.name, "SKILL.md");
|
|
3983
|
+
if (!(0, import_node_fs9.existsSync)(skillFile)) continue;
|
|
3984
|
+
const raw = (0, import_node_fs9.readFileSync)(skillFile, "utf-8");
|
|
2977
3985
|
const { metadata, content } = parseSkillFrontmatter(raw);
|
|
2978
3986
|
const description = typeof metadata.description === "string" ? metadata.description : "";
|
|
2979
3987
|
const skill = {
|
|
@@ -2988,13 +3996,13 @@ var BundlePluginLoader = class {
|
|
|
2988
3996
|
}
|
|
2989
3997
|
/** Load commands from the plugin's commands/ directory (flat .md files). */
|
|
2990
3998
|
loadCommands(pluginDir, pluginName) {
|
|
2991
|
-
const commandsDir = (0,
|
|
2992
|
-
if (!(0,
|
|
2993
|
-
const entries = (0,
|
|
3999
|
+
const commandsDir = (0, import_node_path8.join)(pluginDir, "commands");
|
|
4000
|
+
if (!(0, import_node_fs9.existsSync)(commandsDir)) return [];
|
|
4001
|
+
const entries = (0, import_node_fs9.readdirSync)(commandsDir, { withFileTypes: true });
|
|
2994
4002
|
const commands = [];
|
|
2995
4003
|
for (const entry of entries) {
|
|
2996
4004
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
2997
|
-
const raw = (0,
|
|
4005
|
+
const raw = (0, import_node_fs9.readFileSync)((0, import_node_path8.join)(commandsDir, entry.name), "utf-8");
|
|
2998
4006
|
const { metadata, content } = parseSkillFrontmatter(raw);
|
|
2999
4007
|
const name = typeof metadata.name === "string" ? metadata.name : entry.name.replace(/\.md$/, "");
|
|
3000
4008
|
const description = typeof metadata.description === "string" ? metadata.description : "";
|
|
@@ -3009,10 +4017,10 @@ var BundlePluginLoader = class {
|
|
|
3009
4017
|
}
|
|
3010
4018
|
/** Load hooks from hooks/hooks.json if present. */
|
|
3011
4019
|
loadHooks(pluginDir) {
|
|
3012
|
-
const hooksPath = (0,
|
|
3013
|
-
if (!(0,
|
|
4020
|
+
const hooksPath = (0, import_node_path8.join)(pluginDir, "hooks", "hooks.json");
|
|
4021
|
+
if (!(0, import_node_fs9.existsSync)(hooksPath)) return {};
|
|
3014
4022
|
try {
|
|
3015
|
-
const raw = (0,
|
|
4023
|
+
const raw = (0, import_node_fs9.readFileSync)(hooksPath, "utf-8");
|
|
3016
4024
|
const data = JSON.parse(raw);
|
|
3017
4025
|
if (typeof data === "object" && data !== null) {
|
|
3018
4026
|
return data;
|
|
@@ -3024,12 +4032,12 @@ var BundlePluginLoader = class {
|
|
|
3024
4032
|
}
|
|
3025
4033
|
/** Load MCP server configuration if present. Checks `.mcp.json` at plugin root first. */
|
|
3026
4034
|
loadMcpConfig(pluginDir) {
|
|
3027
|
-
const primaryPath = (0,
|
|
3028
|
-
const fallbackPath = (0,
|
|
3029
|
-
const mcpPath = (0,
|
|
3030
|
-
if (!(0,
|
|
4035
|
+
const primaryPath = (0, import_node_path8.join)(pluginDir, ".mcp.json");
|
|
4036
|
+
const fallbackPath = (0, import_node_path8.join)(pluginDir, ".claude-plugin", "mcp.json");
|
|
4037
|
+
const mcpPath = (0, import_node_fs9.existsSync)(primaryPath) ? primaryPath : fallbackPath;
|
|
4038
|
+
if (!(0, import_node_fs9.existsSync)(mcpPath)) return void 0;
|
|
3031
4039
|
try {
|
|
3032
|
-
const raw = (0,
|
|
4040
|
+
const raw = (0, import_node_fs9.readFileSync)(mcpPath, "utf-8");
|
|
3033
4041
|
return JSON.parse(raw);
|
|
3034
4042
|
} catch {
|
|
3035
4043
|
return void 0;
|
|
@@ -3037,10 +4045,10 @@ var BundlePluginLoader = class {
|
|
|
3037
4045
|
}
|
|
3038
4046
|
/** Load agent definitions from agents/ directory if present. */
|
|
3039
4047
|
loadAgents(pluginDir) {
|
|
3040
|
-
const agentsDir = (0,
|
|
3041
|
-
if (!(0,
|
|
4048
|
+
const agentsDir = (0, import_node_path8.join)(pluginDir, "agents");
|
|
4049
|
+
if (!(0, import_node_fs9.existsSync)(agentsDir)) return [];
|
|
3042
4050
|
try {
|
|
3043
|
-
const entries = (0,
|
|
4051
|
+
const entries = (0, import_node_fs9.readdirSync)(agentsDir, { withFileTypes: true });
|
|
3044
4052
|
return entries.filter((e) => e.isDirectory() || e.name.endsWith(".md")).map((e) => e.name.replace(/\.md$/, ""));
|
|
3045
4053
|
} catch {
|
|
3046
4054
|
return [];
|
|
@@ -3050,8 +4058,8 @@ var BundlePluginLoader = class {
|
|
|
3050
4058
|
|
|
3051
4059
|
// src/plugins/bundle-plugin-installer.ts
|
|
3052
4060
|
var import_node_child_process2 = require("child_process");
|
|
3053
|
-
var
|
|
3054
|
-
var
|
|
4061
|
+
var import_node_fs10 = require("fs");
|
|
4062
|
+
var import_node_path9 = require("path");
|
|
3055
4063
|
var GIT_CLONE_TIMEOUT_MS = 6e4;
|
|
3056
4064
|
var BundlePluginInstaller = class {
|
|
3057
4065
|
pluginsDir;
|
|
@@ -3062,8 +4070,8 @@ var BundlePluginInstaller = class {
|
|
|
3062
4070
|
exec;
|
|
3063
4071
|
constructor(options) {
|
|
3064
4072
|
this.pluginsDir = options.pluginsDir;
|
|
3065
|
-
this.cacheDir = (0,
|
|
3066
|
-
this.registryPath = (0,
|
|
4073
|
+
this.cacheDir = (0, import_node_path9.join)(this.pluginsDir, "cache");
|
|
4074
|
+
this.registryPath = (0, import_node_path9.join)(this.pluginsDir, "installed_plugins.json");
|
|
3067
4075
|
this.settingsStore = options.settingsStore;
|
|
3068
4076
|
this.marketplaceClient = options.marketplaceClient;
|
|
3069
4077
|
this.exec = options.exec ?? this.defaultExec;
|
|
@@ -3083,8 +4091,8 @@ var BundlePluginInstaller = class {
|
|
|
3083
4091
|
throw new Error(`Plugin "${pluginName}" not found in marketplace "${marketplaceName}"`);
|
|
3084
4092
|
}
|
|
3085
4093
|
const version = this.resolveVersion(entry, marketplaceName);
|
|
3086
|
-
const targetDir = (0,
|
|
3087
|
-
if ((0,
|
|
4094
|
+
const targetDir = (0, import_node_path9.join)(this.cacheDir, marketplaceName, pluginName, version);
|
|
4095
|
+
if ((0, import_node_fs10.existsSync)(targetDir)) {
|
|
3088
4096
|
throw new Error(
|
|
3089
4097
|
`Plugin "${pluginName}" version "${version}" is already installed from "${marketplaceName}"`
|
|
3090
4098
|
);
|
|
@@ -3111,8 +4119,8 @@ var BundlePluginInstaller = class {
|
|
|
3111
4119
|
if (!record) {
|
|
3112
4120
|
throw new Error(`Plugin "${pluginId}" is not installed`);
|
|
3113
4121
|
}
|
|
3114
|
-
if ((0,
|
|
3115
|
-
(0,
|
|
4122
|
+
if ((0, import_node_fs10.existsSync)(record.installPath)) {
|
|
4123
|
+
(0, import_node_fs10.rmSync)(record.installPath, { recursive: true, force: true });
|
|
3116
4124
|
}
|
|
3117
4125
|
delete registry[pluginId];
|
|
3118
4126
|
this.writeRegistry(registry);
|
|
@@ -3158,18 +4166,18 @@ var BundlePluginInstaller = class {
|
|
|
3158
4166
|
}
|
|
3159
4167
|
/** Resolve the source and install the plugin. */
|
|
3160
4168
|
resolveAndInstall(rawSource, marketplaceName, pluginName, targetDir) {
|
|
3161
|
-
(0,
|
|
4169
|
+
(0, import_node_fs10.mkdirSync)(targetDir, { recursive: true });
|
|
3162
4170
|
const source = this.normalizeSource(rawSource);
|
|
3163
4171
|
try {
|
|
3164
4172
|
if (typeof source === "string") {
|
|
3165
4173
|
const marketplaceDir = this.marketplaceClient.getMarketplaceDir(marketplaceName);
|
|
3166
|
-
const sourcePath = (0,
|
|
3167
|
-
if (!(0,
|
|
4174
|
+
const sourcePath = (0, import_node_path9.join)(marketplaceDir, source);
|
|
4175
|
+
if (!(0, import_node_fs10.existsSync)(sourcePath)) {
|
|
3168
4176
|
throw new Error(
|
|
3169
4177
|
`Plugin source path "${source}" not found in marketplace "${marketplaceName}"`
|
|
3170
4178
|
);
|
|
3171
4179
|
}
|
|
3172
|
-
(0,
|
|
4180
|
+
(0, import_node_fs10.cpSync)(sourcePath, targetDir, { recursive: true });
|
|
3173
4181
|
} else if (source.type === "github") {
|
|
3174
4182
|
const repoUrl = `https://github.com/${source.repo}.git`;
|
|
3175
4183
|
this.cloneToDir(repoUrl, targetDir, pluginName);
|
|
@@ -3181,15 +4189,15 @@ var BundlePluginInstaller = class {
|
|
|
3181
4189
|
throw new Error(`Unknown source type: ${JSON.stringify(source)}`);
|
|
3182
4190
|
}
|
|
3183
4191
|
} catch (err) {
|
|
3184
|
-
if ((0,
|
|
3185
|
-
(0,
|
|
4192
|
+
if ((0, import_node_fs10.existsSync)(targetDir)) {
|
|
4193
|
+
(0, import_node_fs10.rmSync)(targetDir, { recursive: true, force: true });
|
|
3186
4194
|
}
|
|
3187
4195
|
throw err;
|
|
3188
4196
|
}
|
|
3189
4197
|
}
|
|
3190
4198
|
/** Clone a git repository to the target directory. */
|
|
3191
4199
|
cloneToDir(repoUrl, targetDir, pluginName) {
|
|
3192
|
-
(0,
|
|
4200
|
+
(0, import_node_fs10.rmSync)(targetDir, { recursive: true, force: true });
|
|
3193
4201
|
const command = `git clone --depth 1 ${repoUrl} ${targetDir}`;
|
|
3194
4202
|
try {
|
|
3195
4203
|
this.exec(command, { timeout: GIT_CLONE_TIMEOUT_MS, stdio: "pipe" });
|
|
@@ -3200,11 +4208,11 @@ var BundlePluginInstaller = class {
|
|
|
3200
4208
|
}
|
|
3201
4209
|
/** Read the installed_plugins.json registry. */
|
|
3202
4210
|
readRegistry() {
|
|
3203
|
-
if (!(0,
|
|
4211
|
+
if (!(0, import_node_fs10.existsSync)(this.registryPath)) {
|
|
3204
4212
|
return {};
|
|
3205
4213
|
}
|
|
3206
4214
|
try {
|
|
3207
|
-
const raw = (0,
|
|
4215
|
+
const raw = (0, import_node_fs10.readFileSync)(this.registryPath, "utf-8");
|
|
3208
4216
|
const data = JSON.parse(raw);
|
|
3209
4217
|
if (typeof data === "object" && data !== null) {
|
|
3210
4218
|
return data;
|
|
@@ -3216,11 +4224,11 @@ var BundlePluginInstaller = class {
|
|
|
3216
4224
|
}
|
|
3217
4225
|
/** Write the installed_plugins.json registry. */
|
|
3218
4226
|
writeRegistry(registry) {
|
|
3219
|
-
const dir = (0,
|
|
3220
|
-
if (!(0,
|
|
3221
|
-
(0,
|
|
4227
|
+
const dir = (0, import_node_path9.dirname)(this.registryPath);
|
|
4228
|
+
if (!(0, import_node_fs10.existsSync)(dir)) {
|
|
4229
|
+
(0, import_node_fs10.mkdirSync)(dir, { recursive: true });
|
|
3222
4230
|
}
|
|
3223
|
-
(0,
|
|
4231
|
+
(0, import_node_fs10.writeFileSync)(this.registryPath, JSON.stringify(registry, null, 2), "utf-8");
|
|
3224
4232
|
}
|
|
3225
4233
|
/** Default exec implementation using child_process. */
|
|
3226
4234
|
defaultExec(command, options) {
|
|
@@ -3230,18 +4238,18 @@ var BundlePluginInstaller = class {
|
|
|
3230
4238
|
|
|
3231
4239
|
// src/plugins/marketplace-client.ts
|
|
3232
4240
|
var import_node_child_process3 = require("child_process");
|
|
3233
|
-
var
|
|
3234
|
-
var
|
|
4241
|
+
var import_node_fs12 = require("fs");
|
|
4242
|
+
var import_node_path11 = require("path");
|
|
3235
4243
|
|
|
3236
4244
|
// src/plugins/marketplace-registry.ts
|
|
3237
|
-
var
|
|
3238
|
-
var
|
|
4245
|
+
var import_node_fs11 = require("fs");
|
|
4246
|
+
var import_node_path10 = require("path");
|
|
3239
4247
|
function readRegistry(registryPath) {
|
|
3240
|
-
if (!(0,
|
|
4248
|
+
if (!(0, import_node_fs11.existsSync)(registryPath)) {
|
|
3241
4249
|
return {};
|
|
3242
4250
|
}
|
|
3243
4251
|
try {
|
|
3244
|
-
const raw = (0,
|
|
4252
|
+
const raw = (0, import_node_fs11.readFileSync)(registryPath, "utf-8");
|
|
3245
4253
|
const data = JSON.parse(raw);
|
|
3246
4254
|
if (typeof data === "object" && data !== null) {
|
|
3247
4255
|
return data;
|
|
@@ -3252,18 +4260,18 @@ function readRegistry(registryPath) {
|
|
|
3252
4260
|
}
|
|
3253
4261
|
}
|
|
3254
4262
|
function writeRegistry(registryPath, registry) {
|
|
3255
|
-
const dir = (0,
|
|
3256
|
-
if (!(0,
|
|
3257
|
-
(0,
|
|
4263
|
+
const dir = (0, import_node_path10.dirname)(registryPath);
|
|
4264
|
+
if (!(0, import_node_fs11.existsSync)(dir)) {
|
|
4265
|
+
(0, import_node_fs11.mkdirSync)(dir, { recursive: true });
|
|
3258
4266
|
}
|
|
3259
|
-
(0,
|
|
4267
|
+
(0, import_node_fs11.writeFileSync)(registryPath, JSON.stringify(registry, null, 2), "utf-8");
|
|
3260
4268
|
}
|
|
3261
4269
|
function removeInstalledPluginsForMarketplace(pluginsDir, marketplaceName) {
|
|
3262
|
-
const installedPath = (0,
|
|
3263
|
-
if (!(0,
|
|
4270
|
+
const installedPath = (0, import_node_path10.join)(pluginsDir, "installed_plugins.json");
|
|
4271
|
+
if (!(0, import_node_fs11.existsSync)(installedPath)) return;
|
|
3264
4272
|
let registry;
|
|
3265
4273
|
try {
|
|
3266
|
-
const raw = (0,
|
|
4274
|
+
const raw = (0, import_node_fs11.readFileSync)(installedPath, "utf-8");
|
|
3267
4275
|
const data = JSON.parse(raw);
|
|
3268
4276
|
if (typeof data !== "object" || data === null) return;
|
|
3269
4277
|
registry = data;
|
|
@@ -3273,19 +4281,19 @@ function removeInstalledPluginsForMarketplace(pluginsDir, marketplaceName) {
|
|
|
3273
4281
|
let changed = false;
|
|
3274
4282
|
for (const [pluginId, record] of Object.entries(registry)) {
|
|
3275
4283
|
if (record.marketplace === marketplaceName) {
|
|
3276
|
-
if (record.installPath && (0,
|
|
3277
|
-
(0,
|
|
4284
|
+
if (record.installPath && (0, import_node_fs11.existsSync)(record.installPath)) {
|
|
4285
|
+
(0, import_node_fs11.rmSync)(record.installPath, { recursive: true, force: true });
|
|
3278
4286
|
}
|
|
3279
4287
|
delete registry[pluginId];
|
|
3280
4288
|
changed = true;
|
|
3281
4289
|
}
|
|
3282
4290
|
}
|
|
3283
4291
|
if (changed) {
|
|
3284
|
-
const dir = (0,
|
|
3285
|
-
if (!(0,
|
|
3286
|
-
(0,
|
|
4292
|
+
const dir = (0, import_node_path10.dirname)(installedPath);
|
|
4293
|
+
if (!(0, import_node_fs11.existsSync)(dir)) {
|
|
4294
|
+
(0, import_node_fs11.mkdirSync)(dir, { recursive: true });
|
|
3287
4295
|
}
|
|
3288
|
-
(0,
|
|
4296
|
+
(0, import_node_fs11.writeFileSync)(installedPath, JSON.stringify(registry, null, 2), "utf-8");
|
|
3289
4297
|
}
|
|
3290
4298
|
}
|
|
3291
4299
|
|
|
@@ -3299,8 +4307,8 @@ var MarketplaceClient = class {
|
|
|
3299
4307
|
constructor(options) {
|
|
3300
4308
|
this.pluginsDir = options.pluginsDir;
|
|
3301
4309
|
this.exec = options.exec ?? this.defaultExec;
|
|
3302
|
-
this.marketplacesDir = (0,
|
|
3303
|
-
this.registryPath = (0,
|
|
4310
|
+
this.marketplacesDir = (0, import_node_path11.join)(this.pluginsDir, "marketplaces");
|
|
4311
|
+
this.registryPath = (0, import_node_path11.join)(this.pluginsDir, "known_marketplaces.json");
|
|
3304
4312
|
}
|
|
3305
4313
|
/**
|
|
3306
4314
|
* Add a marketplace by cloning its repository.
|
|
@@ -3313,13 +4321,13 @@ var MarketplaceClient = class {
|
|
|
3313
4321
|
*/
|
|
3314
4322
|
addMarketplace(source) {
|
|
3315
4323
|
const tempName = "temp-" + Date.now().toString(36);
|
|
3316
|
-
const tempDir = (0,
|
|
3317
|
-
(0,
|
|
4324
|
+
const tempDir = (0, import_node_path11.join)(this.marketplacesDir, tempName);
|
|
4325
|
+
(0, import_node_fs12.mkdirSync)(this.marketplacesDir, { recursive: true });
|
|
3318
4326
|
if (source.type === "local") {
|
|
3319
|
-
if (!(0,
|
|
4327
|
+
if (!(0, import_node_fs12.existsSync)(source.path)) {
|
|
3320
4328
|
throw new Error(`Local marketplace path does not exist: ${source.path}`);
|
|
3321
4329
|
}
|
|
3322
|
-
(0,
|
|
4330
|
+
(0, import_node_fs12.cpSync)(source.path, tempDir, { recursive: true });
|
|
3323
4331
|
} else {
|
|
3324
4332
|
const cloneUrl = this.resolveCloneUrl(source);
|
|
3325
4333
|
const command = `git clone --depth 1 ${cloneUrl} ${tempDir}`;
|
|
@@ -3330,9 +4338,9 @@ var MarketplaceClient = class {
|
|
|
3330
4338
|
throw new Error(`Failed to clone marketplace: ${message}`);
|
|
3331
4339
|
}
|
|
3332
4340
|
}
|
|
3333
|
-
const manifestPath = (0,
|
|
3334
|
-
if (!(0,
|
|
3335
|
-
(0,
|
|
4341
|
+
const manifestPath = (0, import_node_path11.join)(tempDir, ".claude-plugin", "marketplace.json");
|
|
4342
|
+
if (!(0, import_node_fs12.existsSync)(manifestPath)) {
|
|
4343
|
+
(0, import_node_fs12.rmSync)(tempDir, { recursive: true, force: true });
|
|
3336
4344
|
throw new Error(
|
|
3337
4345
|
source.type === "local" ? "Local directory does not contain .claude-plugin/marketplace.json" : "Cloned repository does not contain .claude-plugin/marketplace.json"
|
|
3338
4346
|
);
|
|
@@ -3340,16 +4348,16 @@ var MarketplaceClient = class {
|
|
|
3340
4348
|
const manifest = this.readManifestFromPath(manifestPath);
|
|
3341
4349
|
const name = manifest.name;
|
|
3342
4350
|
if (!name) {
|
|
3343
|
-
(0,
|
|
4351
|
+
(0, import_node_fs12.rmSync)(tempDir, { recursive: true, force: true });
|
|
3344
4352
|
throw new Error('Marketplace manifest does not contain a "name" field');
|
|
3345
4353
|
}
|
|
3346
4354
|
const registry = readRegistry(this.registryPath);
|
|
3347
4355
|
if (registry[name]) {
|
|
3348
|
-
(0,
|
|
4356
|
+
(0, import_node_fs12.rmSync)(tempDir, { recursive: true, force: true });
|
|
3349
4357
|
throw new Error(`Marketplace "${name}" already exists`);
|
|
3350
4358
|
}
|
|
3351
|
-
const finalDir = (0,
|
|
3352
|
-
(0,
|
|
4359
|
+
const finalDir = (0, import_node_path11.join)(this.marketplacesDir, name);
|
|
4360
|
+
(0, import_node_fs12.renameSync)(tempDir, finalDir);
|
|
3353
4361
|
registry[name] = {
|
|
3354
4362
|
source,
|
|
3355
4363
|
installLocation: finalDir,
|
|
@@ -3370,8 +4378,8 @@ var MarketplaceClient = class {
|
|
|
3370
4378
|
throw new Error(`Marketplace "${name}" not found`);
|
|
3371
4379
|
}
|
|
3372
4380
|
removeInstalledPluginsForMarketplace(this.pluginsDir, name);
|
|
3373
|
-
if ((0,
|
|
3374
|
-
(0,
|
|
4381
|
+
if ((0, import_node_fs12.existsSync)(entry.installLocation)) {
|
|
4382
|
+
(0, import_node_fs12.rmSync)(entry.installLocation, { recursive: true, force: true });
|
|
3375
4383
|
}
|
|
3376
4384
|
delete registry[name];
|
|
3377
4385
|
writeRegistry(this.registryPath, registry);
|
|
@@ -3387,16 +4395,16 @@ var MarketplaceClient = class {
|
|
|
3387
4395
|
if (!entry) {
|
|
3388
4396
|
throw new Error(`Marketplace "${name}" not found`);
|
|
3389
4397
|
}
|
|
3390
|
-
if (!(0,
|
|
4398
|
+
if (!(0, import_node_fs12.existsSync)(entry.installLocation)) {
|
|
3391
4399
|
throw new Error(`Marketplace directory for "${name}" does not exist`);
|
|
3392
4400
|
}
|
|
3393
4401
|
if (entry.source.type === "local") {
|
|
3394
4402
|
const localSource = entry.source;
|
|
3395
|
-
if (!(0,
|
|
4403
|
+
if (!(0, import_node_fs12.existsSync)(localSource.path)) {
|
|
3396
4404
|
throw new Error(`Local marketplace path does not exist: ${localSource.path}`);
|
|
3397
4405
|
}
|
|
3398
|
-
(0,
|
|
3399
|
-
(0,
|
|
4406
|
+
(0, import_node_fs12.rmSync)(entry.installLocation, { recursive: true, force: true });
|
|
4407
|
+
(0, import_node_fs12.cpSync)(localSource.path, entry.installLocation, { recursive: true });
|
|
3400
4408
|
} else {
|
|
3401
4409
|
const command = `git -C ${entry.installLocation} pull`;
|
|
3402
4410
|
try {
|
|
@@ -3425,8 +4433,8 @@ var MarketplaceClient = class {
|
|
|
3425
4433
|
if (!entry) {
|
|
3426
4434
|
throw new Error(`Marketplace "${marketplaceName}" not found`);
|
|
3427
4435
|
}
|
|
3428
|
-
const manifestPath = (0,
|
|
3429
|
-
if (!(0,
|
|
4436
|
+
const manifestPath = (0, import_node_path11.join)(entry.installLocation, ".claude-plugin", "marketplace.json");
|
|
4437
|
+
if (!(0, import_node_fs12.existsSync)(manifestPath)) {
|
|
3430
4438
|
throw new Error(
|
|
3431
4439
|
`Marketplace "${marketplaceName}" does not contain .claude-plugin/marketplace.json`
|
|
3432
4440
|
);
|
|
@@ -3489,7 +4497,7 @@ var MarketplaceClient = class {
|
|
|
3489
4497
|
}
|
|
3490
4498
|
/** Read and parse a marketplace.json from a file path. */
|
|
3491
4499
|
readManifestFromPath(path) {
|
|
3492
|
-
const raw = (0,
|
|
4500
|
+
const raw = (0, import_node_fs12.readFileSync)(path, "utf-8");
|
|
3493
4501
|
const data = JSON.parse(raw);
|
|
3494
4502
|
if (typeof data !== "object" || data === null) {
|
|
3495
4503
|
throw new Error("Invalid marketplace manifest: not an object");
|
|
@@ -3507,9 +4515,9 @@ var MarketplaceClient = class {
|
|
|
3507
4515
|
};
|
|
3508
4516
|
|
|
3509
4517
|
// src/plugins/plugin-hooks-merger.ts
|
|
3510
|
-
var
|
|
4518
|
+
var import_node_path12 = require("path");
|
|
3511
4519
|
function buildPluginEnv(plugin) {
|
|
3512
|
-
const dataDir = (0,
|
|
4520
|
+
const dataDir = (0, import_node_path12.join)((0, import_node_path12.dirname)((0, import_node_path12.dirname)(plugin.pluginDir)), "data", plugin.manifest.name);
|
|
3513
4521
|
return {
|
|
3514
4522
|
CLAUDE_PLUGIN_ROOT: plugin.pluginDir,
|
|
3515
4523
|
CLAUDE_PLUGIN_PATH: plugin.pluginDir,
|
|
@@ -3572,15 +4580,15 @@ function mergeHooksIntoConfig(configHooks, pluginHooks) {
|
|
|
3572
4580
|
|
|
3573
4581
|
// src/interactive/interactive-session-init.ts
|
|
3574
4582
|
var import_node_os4 = require("os");
|
|
3575
|
-
var
|
|
4583
|
+
var import_node_path13 = require("path");
|
|
3576
4584
|
async function createInteractiveSession(options) {
|
|
3577
4585
|
const cwd = options.cwd;
|
|
3578
4586
|
const [config, context, projectInfo] = await Promise.all([
|
|
3579
|
-
loadConfig(cwd),
|
|
4587
|
+
options.config ? Promise.resolve(options.config) : loadConfig(cwd),
|
|
3580
4588
|
options.bare ? Promise.resolve({ agentsMd: "", claudeMd: "" }) : loadContext(cwd),
|
|
3581
4589
|
options.bare ? Promise.resolve({ type: "unknown", language: "unknown" }) : detectProject(cwd)
|
|
3582
4590
|
]);
|
|
3583
|
-
const pluginsDir = (0,
|
|
4591
|
+
const pluginsDir = (0, import_node_path13.join)((0, import_node_os4.homedir)(), ".robota", "plugins");
|
|
3584
4592
|
const pluginLoader = new BundlePluginLoader(pluginsDir);
|
|
3585
4593
|
let mergedConfig = config;
|
|
3586
4594
|
if (!options.bare) {
|
|
@@ -3613,6 +4621,7 @@ async function createInteractiveSession(options) {
|
|
|
3613
4621
|
permissionHandler: options.permissionHandler,
|
|
3614
4622
|
provider: options.provider,
|
|
3615
4623
|
onTextDelta: options.onTextDelta,
|
|
4624
|
+
onContextUpdate: options.onContextUpdate,
|
|
3616
4625
|
onToolExecution: options.onToolExecution,
|
|
3617
4626
|
sessionId,
|
|
3618
4627
|
allowedTools: options.allowedTools,
|
|
@@ -3629,7 +4638,8 @@ async function createInteractiveSession(options) {
|
|
|
3629
4638
|
]
|
|
3630
4639
|
} : {},
|
|
3631
4640
|
modelCommandExecutor: options.modelCommandExecutor,
|
|
3632
|
-
isModelCommandInvocable: options.isModelCommandInvocable
|
|
4641
|
+
isModelCommandInvocable: options.isModelCommandInvocable,
|
|
4642
|
+
editCheckpointRecorder: options.editCheckpointRecorder
|
|
3633
4643
|
});
|
|
3634
4644
|
}
|
|
3635
4645
|
function injectSavedMessage(session, msg) {
|
|
@@ -3655,7 +4665,9 @@ function loadSessionRecord(sessionStore, resumeSessionId, forkSession, existingS
|
|
|
3655
4665
|
backgroundTasks: [],
|
|
3656
4666
|
backgroundTaskEvents: [],
|
|
3657
4667
|
backgroundJobGroups: [],
|
|
3658
|
-
backgroundJobGroupEvents: []
|
|
4668
|
+
backgroundJobGroupEvents: [],
|
|
4669
|
+
memoryEvents: [],
|
|
4670
|
+
usedMemoryReferences: []
|
|
3659
4671
|
};
|
|
3660
4672
|
}
|
|
3661
4673
|
const history = record.history ?? [];
|
|
@@ -3663,6 +4675,8 @@ function loadSessionRecord(sessionStore, resumeSessionId, forkSession, existingS
|
|
|
3663
4675
|
const restoredBackgroundTaskEvents = record.backgroundTaskEvents ?? [];
|
|
3664
4676
|
const backgroundJobGroups = record.backgroundJobGroups ?? [];
|
|
3665
4677
|
const backgroundJobGroupEvents = record.backgroundJobGroupEvents ?? [];
|
|
4678
|
+
const memoryEvents = record.memoryEvents ?? [];
|
|
4679
|
+
const usedMemoryReferences = record.usedMemoryReferences ?? [];
|
|
3666
4680
|
const { backgroundTasks, backgroundTaskEvents } = reconcileRestoredBackgroundTasks(
|
|
3667
4681
|
restoredBackgroundTasks,
|
|
3668
4682
|
restoredBackgroundTaskEvents
|
|
@@ -3685,7 +4699,9 @@ function loadSessionRecord(sessionStore, resumeSessionId, forkSession, existingS
|
|
|
3685
4699
|
backgroundTasks,
|
|
3686
4700
|
backgroundTaskEvents,
|
|
3687
4701
|
backgroundJobGroups,
|
|
3688
|
-
backgroundJobGroupEvents
|
|
4702
|
+
backgroundJobGroupEvents,
|
|
4703
|
+
memoryEvents,
|
|
4704
|
+
usedMemoryReferences
|
|
3689
4705
|
};
|
|
3690
4706
|
}
|
|
3691
4707
|
function reconcileRestoredBackgroundTasks(tasks, events) {
|
|
@@ -3718,6 +4734,189 @@ function isRestoredTerminalStatus(status) {
|
|
|
3718
4734
|
return status === "completed" || status === "failed" || status === "cancelled";
|
|
3719
4735
|
}
|
|
3720
4736
|
|
|
4737
|
+
// src/checkpoints/edit-checkpoint-store.ts
|
|
4738
|
+
var import_promises = require("fs/promises");
|
|
4739
|
+
var import_node_fs13 = require("fs");
|
|
4740
|
+
var import_node_path14 = require("path");
|
|
4741
|
+
var MANIFEST_FILE = "manifest.json";
|
|
4742
|
+
var SNAPSHOT_DIR = "files";
|
|
4743
|
+
var ID_PAD = 4;
|
|
4744
|
+
var SNAPSHOT_PAD = 6;
|
|
4745
|
+
var EditCheckpointStore = class {
|
|
4746
|
+
cwd;
|
|
4747
|
+
rootDir;
|
|
4748
|
+
now;
|
|
4749
|
+
activeTurn = null;
|
|
4750
|
+
constructor(options) {
|
|
4751
|
+
this.cwd = (0, import_node_path14.resolve)(options.cwd);
|
|
4752
|
+
this.rootDir = projectPaths(this.cwd).checkpoints;
|
|
4753
|
+
this.now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
4754
|
+
}
|
|
4755
|
+
async beginTurn(input) {
|
|
4756
|
+
if (this.activeTurn) {
|
|
4757
|
+
await this.finalizeTurn();
|
|
4758
|
+
}
|
|
4759
|
+
const nextSequence = this.nextSequence(input.sessionId);
|
|
4760
|
+
const id = `turn-${String(nextSequence).padStart(ID_PAD, "0")}`;
|
|
4761
|
+
const dir = (0, import_node_path14.join)(this.sessionDir(input.sessionId), id);
|
|
4762
|
+
await (0, import_promises.mkdir)((0, import_node_path14.join)(dir, SNAPSHOT_DIR), { recursive: true });
|
|
4763
|
+
const manifest = {
|
|
4764
|
+
version: 1,
|
|
4765
|
+
id,
|
|
4766
|
+
sessionId: input.sessionId,
|
|
4767
|
+
sequence: nextSequence,
|
|
4768
|
+
prompt: input.prompt,
|
|
4769
|
+
createdAt: this.now().toISOString(),
|
|
4770
|
+
fileCount: 0,
|
|
4771
|
+
files: []
|
|
4772
|
+
};
|
|
4773
|
+
this.activeTurn = {
|
|
4774
|
+
manifest,
|
|
4775
|
+
dir,
|
|
4776
|
+
capturedPaths: /* @__PURE__ */ new Set()
|
|
4777
|
+
};
|
|
4778
|
+
return toSummary(manifest);
|
|
4779
|
+
}
|
|
4780
|
+
async captureFile(filePath) {
|
|
4781
|
+
if (!this.activeTurn) return;
|
|
4782
|
+
const originalPath = (0, import_node_path14.resolve)(this.cwd, filePath);
|
|
4783
|
+
if (this.activeTurn.capturedPaths.has(originalPath)) return;
|
|
4784
|
+
if (isInside(this.rootDir, originalPath)) return;
|
|
4785
|
+
const record = await this.createFileRecord(originalPath, this.activeTurn);
|
|
4786
|
+
this.activeTurn.manifest.files.push(record);
|
|
4787
|
+
this.activeTurn.manifest.fileCount = this.activeTurn.manifest.files.length;
|
|
4788
|
+
this.activeTurn.capturedPaths.add(originalPath);
|
|
4789
|
+
}
|
|
4790
|
+
async finalizeTurn() {
|
|
4791
|
+
if (!this.activeTurn) return void 0;
|
|
4792
|
+
const active = this.activeTurn;
|
|
4793
|
+
this.activeTurn = null;
|
|
4794
|
+
await this.writeManifest(active.dir, active.manifest);
|
|
4795
|
+
return toSummary(active.manifest);
|
|
4796
|
+
}
|
|
4797
|
+
list(sessionId) {
|
|
4798
|
+
return this.loadManifests(sessionId).map(toSummary);
|
|
4799
|
+
}
|
|
4800
|
+
async restoreToCheckpoint(sessionId, checkpointId) {
|
|
4801
|
+
const manifests = this.loadManifests(sessionId);
|
|
4802
|
+
const target = manifests.find((manifest) => manifest.id === checkpointId);
|
|
4803
|
+
if (!target) {
|
|
4804
|
+
throw new Error(`Unknown edit checkpoint: ${checkpointId}`);
|
|
4805
|
+
}
|
|
4806
|
+
const later = manifests.filter((manifest) => manifest.sequence > target.sequence).sort((a, b) => b.sequence - a.sequence);
|
|
4807
|
+
let restoredFileCount = 0;
|
|
4808
|
+
for (const manifest of later) {
|
|
4809
|
+
for (const file of manifest.files) {
|
|
4810
|
+
await this.restoreFile(sessionId, manifest.id, file);
|
|
4811
|
+
restoredFileCount += 1;
|
|
4812
|
+
}
|
|
4813
|
+
}
|
|
4814
|
+
for (const manifest of later) {
|
|
4815
|
+
await (0, import_promises.rm)(this.checkpointDir(sessionId, manifest.id), { recursive: true, force: true });
|
|
4816
|
+
}
|
|
4817
|
+
return {
|
|
4818
|
+
target: toSummary(target),
|
|
4819
|
+
restoredCheckpointCount: later.length,
|
|
4820
|
+
restoredFileCount,
|
|
4821
|
+
removedCheckpointCount: later.length
|
|
4822
|
+
};
|
|
4823
|
+
}
|
|
4824
|
+
async createFileRecord(originalPath, active) {
|
|
4825
|
+
const existed = await pathExists(originalPath);
|
|
4826
|
+
if (!existed) {
|
|
4827
|
+
return {
|
|
4828
|
+
originalPath,
|
|
4829
|
+
existed: false
|
|
4830
|
+
};
|
|
4831
|
+
}
|
|
4832
|
+
const snapshotFile = (0, import_node_path14.join)(
|
|
4833
|
+
SNAPSHOT_DIR,
|
|
4834
|
+
`${String(active.manifest.files.length + 1).padStart(SNAPSHOT_PAD, "0")}.content`
|
|
4835
|
+
);
|
|
4836
|
+
await (0, import_promises.copyFile)(originalPath, (0, import_node_path14.join)(active.dir, snapshotFile));
|
|
4837
|
+
return {
|
|
4838
|
+
originalPath,
|
|
4839
|
+
existed: true,
|
|
4840
|
+
snapshotFile
|
|
4841
|
+
};
|
|
4842
|
+
}
|
|
4843
|
+
async restoreFile(sessionId, checkpointId, record) {
|
|
4844
|
+
if (!record.existed) {
|
|
4845
|
+
await (0, import_promises.rm)(record.originalPath, { force: true });
|
|
4846
|
+
return;
|
|
4847
|
+
}
|
|
4848
|
+
if (!record.snapshotFile) {
|
|
4849
|
+
throw new Error(`Checkpoint file record is missing a snapshot: ${record.originalPath}`);
|
|
4850
|
+
}
|
|
4851
|
+
await (0, import_promises.mkdir)((0, import_node_path14.dirname)(record.originalPath), { recursive: true });
|
|
4852
|
+
await (0, import_promises.copyFile)(
|
|
4853
|
+
(0, import_node_path14.join)(this.checkpointDir(sessionId, checkpointId), record.snapshotFile),
|
|
4854
|
+
record.originalPath
|
|
4855
|
+
);
|
|
4856
|
+
}
|
|
4857
|
+
loadManifests(sessionId) {
|
|
4858
|
+
const dir = this.sessionDir(sessionId);
|
|
4859
|
+
return readDirSyncSafe(dir).map((entry) => (0, import_node_path14.join)(dir, entry, MANIFEST_FILE)).map((manifestPath) => readJsonManifest(manifestPath)).filter((manifest) => manifest !== void 0).sort((a, b) => a.sequence - b.sequence);
|
|
4860
|
+
}
|
|
4861
|
+
nextSequence(sessionId) {
|
|
4862
|
+
const last = this.list(sessionId).at(-1);
|
|
4863
|
+
return (last?.sequence ?? 0) + 1;
|
|
4864
|
+
}
|
|
4865
|
+
async writeManifest(dir, manifest) {
|
|
4866
|
+
await (0, import_promises.mkdir)(dir, { recursive: true });
|
|
4867
|
+
const path = (0, import_node_path14.join)(dir, MANIFEST_FILE);
|
|
4868
|
+
const tmp = `${path}.tmp`;
|
|
4869
|
+
await (0, import_promises.writeFile)(tmp, JSON.stringify(manifest, null, 2), "utf8");
|
|
4870
|
+
await (0, import_promises.rename)(tmp, path);
|
|
4871
|
+
}
|
|
4872
|
+
sessionDir(sessionId) {
|
|
4873
|
+
return (0, import_node_path14.join)(this.rootDir, safePathSegment(sessionId));
|
|
4874
|
+
}
|
|
4875
|
+
checkpointDir(sessionId, checkpointId) {
|
|
4876
|
+
return (0, import_node_path14.join)(this.sessionDir(sessionId), safePathSegment(checkpointId));
|
|
4877
|
+
}
|
|
4878
|
+
};
|
|
4879
|
+
function toSummary(manifest) {
|
|
4880
|
+
return {
|
|
4881
|
+
id: manifest.id,
|
|
4882
|
+
sessionId: manifest.sessionId,
|
|
4883
|
+
sequence: manifest.sequence,
|
|
4884
|
+
prompt: manifest.prompt,
|
|
4885
|
+
createdAt: manifest.createdAt,
|
|
4886
|
+
fileCount: manifest.fileCount
|
|
4887
|
+
};
|
|
4888
|
+
}
|
|
4889
|
+
function safePathSegment(value) {
|
|
4890
|
+
return value.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
4891
|
+
}
|
|
4892
|
+
function isInside(parent, child) {
|
|
4893
|
+
const rel = (0, import_node_path14.relative)(parent, child);
|
|
4894
|
+
return rel.length === 0 || !rel.startsWith("..") && !rel.startsWith("/");
|
|
4895
|
+
}
|
|
4896
|
+
async function pathExists(path) {
|
|
4897
|
+
try {
|
|
4898
|
+
await (0, import_promises.access)(path, import_node_fs13.constants.F_OK);
|
|
4899
|
+
return true;
|
|
4900
|
+
} catch {
|
|
4901
|
+
return false;
|
|
4902
|
+
}
|
|
4903
|
+
}
|
|
4904
|
+
function readDirSyncSafe(dir) {
|
|
4905
|
+
try {
|
|
4906
|
+
return (0, import_node_fs13.readdirSync)(dir);
|
|
4907
|
+
} catch {
|
|
4908
|
+
return [];
|
|
4909
|
+
}
|
|
4910
|
+
}
|
|
4911
|
+
function readJsonManifest(path) {
|
|
4912
|
+
try {
|
|
4913
|
+
const raw = (0, import_node_fs13.readFileSync)(path, "utf8");
|
|
4914
|
+
return JSON.parse(raw);
|
|
4915
|
+
} catch {
|
|
4916
|
+
return void 0;
|
|
4917
|
+
}
|
|
4918
|
+
}
|
|
4919
|
+
|
|
3721
4920
|
// src/interactive/interactive-session.ts
|
|
3722
4921
|
var InteractiveSession = class {
|
|
3723
4922
|
session = null;
|
|
@@ -3741,6 +4940,9 @@ var InteractiveSession = class {
|
|
|
3741
4940
|
backgroundTaskEvents = [];
|
|
3742
4941
|
backgroundJobGroups = [];
|
|
3743
4942
|
backgroundJobGroupEvents = [];
|
|
4943
|
+
memoryEvents = [];
|
|
4944
|
+
usedMemoryReferences = [];
|
|
4945
|
+
editCheckpointStore = null;
|
|
3744
4946
|
resumeSessionId;
|
|
3745
4947
|
forkSession;
|
|
3746
4948
|
backgroundTaskUnsubscribe = null;
|
|
@@ -3758,6 +4960,9 @@ var InteractiveSession = class {
|
|
|
3758
4960
|
this.sessionStore = options.sessionStore;
|
|
3759
4961
|
this.sessionName = options.sessionName;
|
|
3760
4962
|
this.cwd = ("cwd" in options ? options.cwd : void 0) ?? "";
|
|
4963
|
+
if ("session" in options && options.session && this.cwd) {
|
|
4964
|
+
this.editCheckpointStore = new EditCheckpointStore({ cwd: this.cwd });
|
|
4965
|
+
}
|
|
3761
4966
|
this.resumeSessionId = options.resumeSessionId;
|
|
3762
4967
|
this.forkSession = options.forkSession ?? false;
|
|
3763
4968
|
if ("session" in options && options.session) {
|
|
@@ -3780,21 +4985,27 @@ var InteractiveSession = class {
|
|
|
3780
4985
|
this.backgroundTaskEvents = restored.backgroundTaskEvents;
|
|
3781
4986
|
this.backgroundJobGroups = restored.backgroundJobGroups;
|
|
3782
4987
|
this.backgroundJobGroupEvents = restored.backgroundJobGroupEvents;
|
|
4988
|
+
this.memoryEvents = restored.memoryEvents;
|
|
4989
|
+
this.usedMemoryReferences = restored.usedMemoryReferences;
|
|
3783
4990
|
this.pendingRestoreMessages = restored.pendingRestoreMessages;
|
|
3784
4991
|
}
|
|
3785
4992
|
if (this.initialized) this.subscribeBackgroundTaskEvents();
|
|
3786
4993
|
if (this.initialized) this.persistCurrentSession();
|
|
3787
4994
|
}
|
|
3788
4995
|
async initializeAsync(options) {
|
|
4996
|
+
const config = await loadConfig(options.cwd);
|
|
4997
|
+
this.editCheckpointStore = new EditCheckpointStore({ cwd: options.cwd });
|
|
3789
4998
|
this.session = await createInteractiveSession({
|
|
3790
4999
|
cwd: options.cwd,
|
|
3791
5000
|
provider: options.provider,
|
|
5001
|
+
config,
|
|
3792
5002
|
permissionMode: options.permissionMode,
|
|
3793
5003
|
maxTurns: options.maxTurns,
|
|
3794
5004
|
permissionHandler: options.permissionHandler,
|
|
3795
5005
|
resumeSessionId: this.resumeSessionId,
|
|
3796
5006
|
forkSession: this.forkSession,
|
|
3797
5007
|
onTextDelta: (delta) => this.handleTextDelta(delta),
|
|
5008
|
+
onContextUpdate: (state) => this.emit("context_update", state),
|
|
3798
5009
|
onToolExecution: (event) => this.handleToolExecution(event),
|
|
3799
5010
|
bare: options.bare,
|
|
3800
5011
|
allowedTools: options.allowedTools,
|
|
@@ -3802,6 +5013,7 @@ var InteractiveSession = class {
|
|
|
3802
5013
|
backgroundTaskRunners: options.backgroundTaskRunners,
|
|
3803
5014
|
subagentRunnerFactory: options.subagentRunnerFactory,
|
|
3804
5015
|
...options.commandModules ? { commandModules: options.commandModules } : {},
|
|
5016
|
+
editCheckpointRecorder: this.editCheckpointStore,
|
|
3805
5017
|
commandDescriptors: this.commandExecutor.listModelInvocableCommands(),
|
|
3806
5018
|
...this.commandExecutor.listModelInvocableCommands().length > 0 ? {
|
|
3807
5019
|
modelCommandExecutor: (command, args) => this.executeModelCommand(command, args),
|
|
@@ -3944,9 +5156,38 @@ var InteractiveSession = class {
|
|
|
3944
5156
|
getName() {
|
|
3945
5157
|
return this.sessionName;
|
|
3946
5158
|
}
|
|
5159
|
+
getCwd() {
|
|
5160
|
+
return this.cwd ?? process.cwd();
|
|
5161
|
+
}
|
|
3947
5162
|
getSession() {
|
|
3948
5163
|
return this.getSessionOrThrow();
|
|
3949
5164
|
}
|
|
5165
|
+
listEditCheckpoints() {
|
|
5166
|
+
const sessionId = this.getSessionOrThrow().getSessionId();
|
|
5167
|
+
return this.getEditCheckpointStore().list(sessionId);
|
|
5168
|
+
}
|
|
5169
|
+
async restoreEditCheckpoint(checkpointId) {
|
|
5170
|
+
await this.ensureInitialized();
|
|
5171
|
+
if (this.executing) {
|
|
5172
|
+
throw new Error("Cannot restore edit checkpoint while a prompt is running.");
|
|
5173
|
+
}
|
|
5174
|
+
const result = await this.getEditCheckpointStore().restoreToCheckpoint(
|
|
5175
|
+
this.getSessionOrThrow().getSessionId(),
|
|
5176
|
+
checkpointId
|
|
5177
|
+
);
|
|
5178
|
+
this.history.push(
|
|
5179
|
+
(0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createSystemMessage)(`Restored edit checkpoint: ${checkpointId}`))
|
|
5180
|
+
);
|
|
5181
|
+
this.persistCurrentSession();
|
|
5182
|
+
return result;
|
|
5183
|
+
}
|
|
5184
|
+
getUsedMemoryReferences() {
|
|
5185
|
+
return [...this.usedMemoryReferences];
|
|
5186
|
+
}
|
|
5187
|
+
recordMemoryEvent(event) {
|
|
5188
|
+
this.memoryEvents.push(event);
|
|
5189
|
+
this.persistCurrentSession();
|
|
5190
|
+
}
|
|
3950
5191
|
listBackgroundTasks(filter) {
|
|
3951
5192
|
return this.getBackgroundTaskManagerOrThrow().list(filter);
|
|
3952
5193
|
}
|
|
@@ -4169,6 +5410,10 @@ var InteractiveSession = class {
|
|
|
4169
5410
|
events: this.backgroundTaskEvents,
|
|
4170
5411
|
groups: this.backgroundJobGroups,
|
|
4171
5412
|
groupEvents: this.backgroundJobGroupEvents
|
|
5413
|
+
},
|
|
5414
|
+
{
|
|
5415
|
+
events: this.memoryEvents,
|
|
5416
|
+
usedReferences: this.usedMemoryReferences
|
|
4172
5417
|
}
|
|
4173
5418
|
);
|
|
4174
5419
|
}
|
|
@@ -4176,7 +5421,7 @@ var InteractiveSession = class {
|
|
|
4176
5421
|
this.executing = true;
|
|
4177
5422
|
this.clearStreaming();
|
|
4178
5423
|
this.emit("thinking", true);
|
|
4179
|
-
this.history.push((0,
|
|
5424
|
+
this.history.push((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createUserMessage)(displayInput)));
|
|
4180
5425
|
}
|
|
4181
5426
|
finishForkSkillExecution() {
|
|
4182
5427
|
this.executing = false;
|
|
@@ -4191,7 +5436,7 @@ var InteractiveSession = class {
|
|
|
4191
5436
|
}
|
|
4192
5437
|
}
|
|
4193
5438
|
recordForkSkillError(err) {
|
|
4194
|
-
this.history.push((0,
|
|
5439
|
+
this.history.push((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createSystemMessage)(`Error: ${err.message}`)));
|
|
4195
5440
|
this.emit("error", err);
|
|
4196
5441
|
}
|
|
4197
5442
|
resolveForkAgentDefinition(agentType, options) {
|
|
@@ -4240,7 +5485,7 @@ var InteractiveSession = class {
|
|
|
4240
5485
|
toolSummaries: [],
|
|
4241
5486
|
contextState: this.getContextState()
|
|
4242
5487
|
};
|
|
4243
|
-
this.history.push((0,
|
|
5488
|
+
this.history.push((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createAssistantMessage)(result)));
|
|
4244
5489
|
this.emit("complete", executionResult);
|
|
4245
5490
|
this.emit("context_update", this.getContextState());
|
|
4246
5491
|
}
|
|
@@ -4248,9 +5493,11 @@ var InteractiveSession = class {
|
|
|
4248
5493
|
this.executing = true;
|
|
4249
5494
|
this.clearStreaming();
|
|
4250
5495
|
this.emit("thinking", true);
|
|
4251
|
-
this.history.push((0,
|
|
5496
|
+
this.history.push((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createUserMessage)(displayInput ?? input)));
|
|
4252
5497
|
const historyBefore = this.getSessionOrThrow().getHistory().length;
|
|
5498
|
+
this.usedMemoryReferences = [];
|
|
4253
5499
|
try {
|
|
5500
|
+
await this.beginEditCheckpointTurn(displayInput ?? input);
|
|
4254
5501
|
const response = await this.getSessionOrThrow().run(input, rawInput);
|
|
4255
5502
|
this.flushStreaming();
|
|
4256
5503
|
pushToolSummaryToHistory({ activeTools: this.activeTools, history: this.history });
|
|
@@ -4262,7 +5509,8 @@ var InteractiveSession = class {
|
|
|
4262
5509
|
historyBefore,
|
|
4263
5510
|
this.getContextState()
|
|
4264
5511
|
);
|
|
4265
|
-
this.history.push((0,
|
|
5512
|
+
this.history.push((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createAssistantMessage)(result.response)));
|
|
5513
|
+
if (result.usage) this.history.push(createUsageSummaryEntry(result.usage));
|
|
4266
5514
|
this.emit("complete", result);
|
|
4267
5515
|
this.emit("context_update", this.getContextState());
|
|
4268
5516
|
} catch (err) {
|
|
@@ -4277,17 +5525,19 @@ var InteractiveSession = class {
|
|
|
4277
5525
|
pushToolSummaryToHistory({ activeTools: this.activeTools, history: this.history });
|
|
4278
5526
|
this.clearStreaming();
|
|
4279
5527
|
if (result.response)
|
|
4280
|
-
this.history.push((0,
|
|
4281
|
-
this.history.push((
|
|
5528
|
+
this.history.push((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createAssistantMessage)(result.response)));
|
|
5529
|
+
if (result.usage) this.history.push(createUsageSummaryEntry(result.usage));
|
|
5530
|
+
this.history.push((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createSystemMessage)("Interrupted by user.")));
|
|
4282
5531
|
this.emit("interrupted", result);
|
|
4283
5532
|
} else {
|
|
4284
5533
|
pushToolSummaryToHistory({ activeTools: this.activeTools, history: this.history });
|
|
4285
5534
|
this.clearStreaming();
|
|
4286
5535
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
4287
|
-
this.history.push((0,
|
|
5536
|
+
this.history.push((0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createSystemMessage)(`Error: ${errMsg}`)));
|
|
4288
5537
|
this.emit("error", err instanceof Error ? err : new Error(errMsg));
|
|
4289
5538
|
}
|
|
4290
5539
|
} finally {
|
|
5540
|
+
await this.finalizeEditCheckpointTurn();
|
|
4291
5541
|
this.executing = false;
|
|
4292
5542
|
this.emit("thinking", false);
|
|
4293
5543
|
this.persistCurrentSession();
|
|
@@ -4300,6 +5550,31 @@ var InteractiveSession = class {
|
|
|
4300
5550
|
}
|
|
4301
5551
|
}
|
|
4302
5552
|
}
|
|
5553
|
+
getEditCheckpointStore() {
|
|
5554
|
+
if (!this.editCheckpointStore) {
|
|
5555
|
+
this.editCheckpointStore = new EditCheckpointStore({ cwd: this.getCwd() });
|
|
5556
|
+
}
|
|
5557
|
+
return this.editCheckpointStore;
|
|
5558
|
+
}
|
|
5559
|
+
async beginEditCheckpointTurn(prompt) {
|
|
5560
|
+
if (!this.editCheckpointStore) return;
|
|
5561
|
+
await this.editCheckpointStore.beginTurn({
|
|
5562
|
+
sessionId: this.getSessionOrThrow().getSessionId(),
|
|
5563
|
+
prompt
|
|
5564
|
+
});
|
|
5565
|
+
}
|
|
5566
|
+
async finalizeEditCheckpointTurn() {
|
|
5567
|
+
if (!this.editCheckpointStore) return;
|
|
5568
|
+
try {
|
|
5569
|
+
await this.editCheckpointStore.finalizeTurn();
|
|
5570
|
+
} catch (error) {
|
|
5571
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
5572
|
+
this.history.push(
|
|
5573
|
+
(0, import_agent_core4.messageToHistoryEntry)((0, import_agent_core4.createSystemMessage)(`Checkpoint error: ${err.message}`))
|
|
5574
|
+
);
|
|
5575
|
+
this.emit("error", err);
|
|
5576
|
+
}
|
|
5577
|
+
}
|
|
4303
5578
|
handleTextDelta(delta) {
|
|
4304
5579
|
this.streamingText += delta;
|
|
4305
5580
|
this.emit("text_delta", delta);
|
|
@@ -4350,14 +5625,14 @@ function createQuery(options) {
|
|
|
4350
5625
|
session.on("text_delta", options.onTextDelta);
|
|
4351
5626
|
}
|
|
4352
5627
|
return async (prompt) => {
|
|
4353
|
-
return new Promise((
|
|
5628
|
+
return new Promise((resolve4, reject) => {
|
|
4354
5629
|
const onComplete = (result) => {
|
|
4355
5630
|
cleanup();
|
|
4356
|
-
|
|
5631
|
+
resolve4(result.response);
|
|
4357
5632
|
};
|
|
4358
5633
|
const onInterrupted = (result) => {
|
|
4359
5634
|
cleanup();
|
|
4360
|
-
|
|
5635
|
+
resolve4(result.response);
|
|
4361
5636
|
};
|
|
4362
5637
|
const onError = (error) => {
|
|
4363
5638
|
cleanup();
|
|
@@ -4380,17 +5655,132 @@ function createQuery(options) {
|
|
|
4380
5655
|
}
|
|
4381
5656
|
|
|
4382
5657
|
// src/types.ts
|
|
4383
|
-
var
|
|
5658
|
+
var import_agent_core5 = require("@robota-sdk/agent-core");
|
|
4384
5659
|
|
|
4385
5660
|
// src/index.ts
|
|
4386
|
-
var
|
|
5661
|
+
var import_agent_core6 = require("@robota-sdk/agent-core");
|
|
5662
|
+
|
|
5663
|
+
// src/self-hosting/self-hosting-verification.ts
|
|
5664
|
+
var DEFAULT_BASE_REF = "origin/develop";
|
|
5665
|
+
var PACKAGE_VERIFY_COMMANDS = ["test", "typecheck", "build"];
|
|
5666
|
+
var TRANSITIONS = {
|
|
5667
|
+
idle: {
|
|
5668
|
+
checkpoint_created: "checkpointed",
|
|
5669
|
+
cancelled: "cancelled"
|
|
5670
|
+
},
|
|
5671
|
+
checkpointed: {
|
|
5672
|
+
edits_started: "editing",
|
|
5673
|
+
cancelled: "cancelled"
|
|
5674
|
+
},
|
|
5675
|
+
editing: {
|
|
5676
|
+
edits_applied: "verifying",
|
|
5677
|
+
verify_failed: "failed",
|
|
5678
|
+
cancelled: "cancelled"
|
|
5679
|
+
},
|
|
5680
|
+
verifying: {
|
|
5681
|
+
verify_passed: "passed",
|
|
5682
|
+
verify_failed: "failed",
|
|
5683
|
+
cancelled: "cancelled"
|
|
5684
|
+
},
|
|
5685
|
+
passed: {},
|
|
5686
|
+
failed: {
|
|
5687
|
+
rollback_completed: "rolled_back",
|
|
5688
|
+
cancelled: "cancelled"
|
|
5689
|
+
},
|
|
5690
|
+
rolled_back: {},
|
|
5691
|
+
cancelled: {}
|
|
5692
|
+
};
|
|
5693
|
+
function normalizePackageScopes(packageScopes) {
|
|
5694
|
+
if (!packageScopes) {
|
|
5695
|
+
return [];
|
|
5696
|
+
}
|
|
5697
|
+
return Array.from(new Set(packageScopes.map((scope) => scope.trim()).filter(Boolean)));
|
|
5698
|
+
}
|
|
5699
|
+
function packageVerificationSteps(packageScopes) {
|
|
5700
|
+
return packageScopes.flatMap(
|
|
5701
|
+
(scope) => PACKAGE_VERIFY_COMMANDS.map(
|
|
5702
|
+
(commandName) => ({
|
|
5703
|
+
id: `package-${commandName}:${scope}`,
|
|
5704
|
+
phase: "verify",
|
|
5705
|
+
description: `Run ${commandName} for ${scope} in a child process against the new on-disk tree.`,
|
|
5706
|
+
required: true,
|
|
5707
|
+
command: `pnpm --filter ${scope} ${commandName}`
|
|
5708
|
+
})
|
|
5709
|
+
)
|
|
5710
|
+
);
|
|
5711
|
+
}
|
|
5712
|
+
function preVerificationSteps() {
|
|
5713
|
+
return [
|
|
5714
|
+
{
|
|
5715
|
+
id: "checkpoint",
|
|
5716
|
+
phase: "checkpoint",
|
|
5717
|
+
description: "Create a recoverable turn-level checkpoint before the first mutation.",
|
|
5718
|
+
required: true
|
|
5719
|
+
},
|
|
5720
|
+
{
|
|
5721
|
+
id: "atomic-edit",
|
|
5722
|
+
phase: "edit",
|
|
5723
|
+
description: "Apply Write/Edit mutations through same-directory temp files and atomic rename.",
|
|
5724
|
+
required: true
|
|
5725
|
+
},
|
|
5726
|
+
{
|
|
5727
|
+
id: "handoff",
|
|
5728
|
+
phase: "handoff",
|
|
5729
|
+
description: "Keep the current process on already-loaded code and run verification child processes against disk.",
|
|
5730
|
+
required: true
|
|
5731
|
+
}
|
|
5732
|
+
];
|
|
5733
|
+
}
|
|
5734
|
+
function harnessVerificationStep(baseRef) {
|
|
5735
|
+
return {
|
|
5736
|
+
id: "harness-verify",
|
|
5737
|
+
phase: "verify",
|
|
5738
|
+
description: "Run Robota harness verification as the local CI-like gate.",
|
|
5739
|
+
required: true,
|
|
5740
|
+
command: `pnpm harness:verify -- --base-ref ${baseRef} --skip-record-check`
|
|
5741
|
+
};
|
|
5742
|
+
}
|
|
5743
|
+
function rollbackRecoveryStep() {
|
|
5744
|
+
return {
|
|
5745
|
+
id: "rollback-on-failure",
|
|
5746
|
+
phase: "recover",
|
|
5747
|
+
description: "Use the existing edit checkpoint restore path if verification fails.",
|
|
5748
|
+
required: true
|
|
5749
|
+
};
|
|
5750
|
+
}
|
|
5751
|
+
function planSelfHostingVerification(input) {
|
|
5752
|
+
if (input.changedFiles.length === 0) {
|
|
5753
|
+
throw new Error("Self-hosting verification requires at least one changed file.");
|
|
5754
|
+
}
|
|
5755
|
+
const baseRef = input.baseRef ?? DEFAULT_BASE_REF;
|
|
5756
|
+
const packageScopes = normalizePackageScopes(input.packageScopes);
|
|
5757
|
+
const steps = [
|
|
5758
|
+
...preVerificationSteps(),
|
|
5759
|
+
...packageVerificationSteps(packageScopes),
|
|
5760
|
+
harnessVerificationStep(baseRef),
|
|
5761
|
+
rollbackRecoveryStep()
|
|
5762
|
+
];
|
|
5763
|
+
return {
|
|
5764
|
+
changedFiles: [...input.changedFiles],
|
|
5765
|
+
packageScopes,
|
|
5766
|
+
baseRef,
|
|
5767
|
+
steps
|
|
5768
|
+
};
|
|
5769
|
+
}
|
|
5770
|
+
function transitionSelfHostingLoop(state, event) {
|
|
5771
|
+
const nextState = TRANSITIONS[state][event];
|
|
5772
|
+
if (!nextState) {
|
|
5773
|
+
throw new Error(`Invalid self-hosting loop transition: ${state} -> ${event}`);
|
|
5774
|
+
}
|
|
5775
|
+
return nextState;
|
|
5776
|
+
}
|
|
4387
5777
|
|
|
4388
5778
|
// src/subagents/index.ts
|
|
4389
5779
|
var import_agent_runtime7 = require("@robota-sdk/agent-runtime");
|
|
4390
5780
|
var import_agent_runtime8 = require("@robota-sdk/agent-runtime");
|
|
4391
5781
|
|
|
4392
5782
|
// src/index.ts
|
|
4393
|
-
var
|
|
5783
|
+
var import_agent_core7 = require("@robota-sdk/agent-core");
|
|
4394
5784
|
|
|
4395
5785
|
// src/permissions/permission-prompt.ts
|
|
4396
5786
|
var import_chalk = __toESM(require("chalk"), 1);
|
|
@@ -4413,7 +5803,7 @@ async function promptForApproval(terminal, toolName, toolArgs) {
|
|
|
4413
5803
|
}
|
|
4414
5804
|
|
|
4415
5805
|
// src/index.ts
|
|
4416
|
-
var
|
|
5806
|
+
var import_agent_core8 = require("@robota-sdk/agent-core");
|
|
4417
5807
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4418
5808
|
0 && (module.exports = {
|
|
4419
5809
|
AgentExecutor,
|
|
@@ -4425,10 +5815,14 @@ var import_agent_core7 = require("@robota-sdk/agent-core");
|
|
|
4425
5815
|
BundlePluginInstaller,
|
|
4426
5816
|
BundlePluginLoader,
|
|
4427
5817
|
CommandRegistry,
|
|
5818
|
+
EditCheckpointStore,
|
|
4428
5819
|
InteractiveSession,
|
|
5820
|
+
MEMORY_INDEX_MAX_BYTES,
|
|
5821
|
+
MEMORY_INDEX_MAX_LINES,
|
|
4429
5822
|
MarketplaceClient,
|
|
4430
5823
|
PluginCommandSource,
|
|
4431
5824
|
PluginSettingsStore,
|
|
5825
|
+
ProjectMemoryStore,
|
|
4432
5826
|
PromptExecutor,
|
|
4433
5827
|
SkillCommandSource,
|
|
4434
5828
|
SubagentManager,
|
|
@@ -4447,26 +5841,37 @@ var import_agent_core7 = require("@robota-sdk/agent-core");
|
|
|
4447
5841
|
createSubagentSession,
|
|
4448
5842
|
createSystemCommands,
|
|
4449
5843
|
createWorktreeSubagentRunner,
|
|
5844
|
+
discoverTaskFiles,
|
|
4450
5845
|
evaluatePermission,
|
|
4451
5846
|
executeSkill,
|
|
5847
|
+
formatTaskContext,
|
|
4452
5848
|
getBackgroundTaskTransitions,
|
|
4453
5849
|
getBuiltInAgent,
|
|
4454
5850
|
getForkWorkerSuffix,
|
|
4455
5851
|
getMessagesForAPI,
|
|
4456
5852
|
getSubagentSuffix,
|
|
4457
5853
|
isChatEntry,
|
|
5854
|
+
isMemoryType,
|
|
4458
5855
|
isTerminalBackgroundTaskStatus,
|
|
5856
|
+
loadTaskContext,
|
|
4459
5857
|
messageToHistoryEntry,
|
|
4460
5858
|
parseFrontmatter,
|
|
5859
|
+
parseTaskFile,
|
|
5860
|
+
planSelfHostingVerification,
|
|
4461
5861
|
preprocessShellCommands,
|
|
4462
5862
|
projectPaths,
|
|
4463
5863
|
promptForApproval,
|
|
5864
|
+
readCurrentGitBranch,
|
|
4464
5865
|
resolveSubagentLogDir,
|
|
4465
5866
|
retrieveAgentToolDeps,
|
|
4466
5867
|
runHooks,
|
|
5868
|
+
selectRelevantTasks,
|
|
4467
5869
|
storeAgentToolDeps,
|
|
4468
5870
|
substituteVariables,
|
|
4469
5871
|
summarizeBackgroundJobGroup,
|
|
4470
5872
|
transitionBackgroundTaskStatus,
|
|
4471
|
-
|
|
5873
|
+
transitionSelfHostingLoop,
|
|
5874
|
+
updateTaskFileStatus,
|
|
5875
|
+
userPaths,
|
|
5876
|
+
wrapEditCheckpointTools
|
|
4472
5877
|
});
|