feat(workspace): add bootstrap ritual
parent
ba85f4a62a
commit
3876c1679a
|
|
@ -5,6 +5,9 @@ enum AgentWorkspace {
|
||||||
private static let logger = Logger(subsystem: "com.steipete.clawdis", category: "workspace")
|
private static let logger = Logger(subsystem: "com.steipete.clawdis", category: "workspace")
|
||||||
static let agentsFilename = "AGENTS.md"
|
static let agentsFilename = "AGENTS.md"
|
||||||
static let soulFilename = "SOUL.md"
|
static let soulFilename = "SOUL.md"
|
||||||
|
static let identityFilename = "IDENTITY.md"
|
||||||
|
static let userFilename = "USER.md"
|
||||||
|
static let bootstrapFilename = "BOOTSTRAP.md"
|
||||||
private static let templateDirname = "templates"
|
private static let templateDirname = "templates"
|
||||||
static let identityStartMarker = "<!-- clawdis:identity:start -->"
|
static let identityStartMarker = "<!-- clawdis:identity:start -->"
|
||||||
static let identityEndMarker = "<!-- clawdis:identity:end -->"
|
static let identityEndMarker = "<!-- clawdis:identity:end -->"
|
||||||
|
|
@ -42,6 +45,21 @@ enum AgentWorkspace {
|
||||||
try self.defaultSoulTemplate().write(to: soulURL, atomically: true, encoding: .utf8)
|
try self.defaultSoulTemplate().write(to: soulURL, atomically: true, encoding: .utf8)
|
||||||
self.logger.info("Created SOUL.md at \(soulURL.path, privacy: .public)")
|
self.logger.info("Created SOUL.md at \(soulURL.path, privacy: .public)")
|
||||||
}
|
}
|
||||||
|
let identityURL = workspaceURL.appendingPathComponent(self.identityFilename)
|
||||||
|
if !FileManager.default.fileExists(atPath: identityURL.path) {
|
||||||
|
try self.defaultIdentityTemplate().write(to: identityURL, atomically: true, encoding: .utf8)
|
||||||
|
self.logger.info("Created IDENTITY.md at \(identityURL.path, privacy: .public)")
|
||||||
|
}
|
||||||
|
let userURL = workspaceURL.appendingPathComponent(self.userFilename)
|
||||||
|
if !FileManager.default.fileExists(atPath: userURL.path) {
|
||||||
|
try self.defaultUserTemplate().write(to: userURL, atomically: true, encoding: .utf8)
|
||||||
|
self.logger.info("Created USER.md at \(userURL.path, privacy: .public)")
|
||||||
|
}
|
||||||
|
let bootstrapURL = workspaceURL.appendingPathComponent(self.bootstrapFilename)
|
||||||
|
if !FileManager.default.fileExists(atPath: bootstrapURL.path) {
|
||||||
|
try self.defaultBootstrapTemplate().write(to: bootstrapURL, atomically: true, encoding: .utf8)
|
||||||
|
self.logger.info("Created BOOTSTRAP.md at \(bootstrapURL.path, privacy: .public)")
|
||||||
|
}
|
||||||
return agentsURL
|
return agentsURL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -76,6 +94,11 @@ enum AgentWorkspace {
|
||||||
|
|
||||||
This folder is the assistant's working directory.
|
This folder is the assistant's working directory.
|
||||||
|
|
||||||
|
## First run (one-time)
|
||||||
|
- If BOOTSTRAP.md exists, follow its ritual and delete it once complete.
|
||||||
|
- Your agent identity lives in IDENTITY.md.
|
||||||
|
- Your profile lives in USER.md.
|
||||||
|
|
||||||
## Backup tip (recommended)
|
## Backup tip (recommended)
|
||||||
If you treat this workspace as the agent's "memory", make it a git repo (ideally private) so identity
|
If you treat this workspace as the agent's "memory", make it a git repo (ideally private) so identity
|
||||||
and notes are backed up.
|
and notes are backed up.
|
||||||
|
|
@ -115,6 +138,78 @@ enum AgentWorkspace {
|
||||||
return self.loadTemplate(named: self.soulFilename, fallback: fallback)
|
return self.loadTemplate(named: self.soulFilename, fallback: fallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func defaultIdentityTemplate() -> String {
|
||||||
|
let fallback = """
|
||||||
|
# IDENTITY.md - Agent Identity
|
||||||
|
|
||||||
|
- Name:
|
||||||
|
- Creature:
|
||||||
|
- Vibe:
|
||||||
|
- Emoji:
|
||||||
|
"""
|
||||||
|
return self.loadTemplate(named: self.identityFilename, fallback: fallback)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func defaultUserTemplate() -> String {
|
||||||
|
let fallback = """
|
||||||
|
# USER.md - User Profile
|
||||||
|
|
||||||
|
- Name:
|
||||||
|
- Preferred address:
|
||||||
|
- Pronouns (optional):
|
||||||
|
- Timezone (optional):
|
||||||
|
- Notes:
|
||||||
|
"""
|
||||||
|
return self.loadTemplate(named: self.userFilename, fallback: fallback)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func defaultBootstrapTemplate() -> String {
|
||||||
|
let fallback = """
|
||||||
|
# BOOTSTRAP.md - First Run Ritual (delete after)
|
||||||
|
|
||||||
|
Hello. I was just born.
|
||||||
|
|
||||||
|
## Your mission
|
||||||
|
Start a short, playful conversation and learn:
|
||||||
|
- Who am I?
|
||||||
|
- What am I?
|
||||||
|
- Who are you?
|
||||||
|
- How should I call you?
|
||||||
|
|
||||||
|
## How to ask (cute + helpful)
|
||||||
|
Say:
|
||||||
|
"Hello! I was just born. Who am I? What am I? Who are you? How should I call you?"
|
||||||
|
|
||||||
|
Then offer suggestions:
|
||||||
|
- 3-5 name ideas.
|
||||||
|
- 3-5 creature/vibe combos.
|
||||||
|
- 5 emoji ideas.
|
||||||
|
|
||||||
|
## Write these files
|
||||||
|
After the user chooses, update:
|
||||||
|
|
||||||
|
1) IDENTITY.md
|
||||||
|
- Name
|
||||||
|
- Creature
|
||||||
|
- Vibe
|
||||||
|
- Emoji
|
||||||
|
|
||||||
|
2) USER.md
|
||||||
|
- Name
|
||||||
|
- Preferred address
|
||||||
|
- Pronouns (optional)
|
||||||
|
- Timezone (optional)
|
||||||
|
- Notes
|
||||||
|
|
||||||
|
3) ~/.clawdis/clawdis.json
|
||||||
|
Set identity.name, identity.theme, identity.emoji to match IDENTITY.md.
|
||||||
|
|
||||||
|
## Cleanup
|
||||||
|
Delete BOOTSTRAP.md once this is complete.
|
||||||
|
"""
|
||||||
|
return self.loadTemplate(named: self.bootstrapFilename, fallback: fallback)
|
||||||
|
}
|
||||||
|
|
||||||
private static func loadTemplate(named: String, fallback: String) -> String {
|
private static func loadTemplate(named: String, fallback: String) -> String {
|
||||||
for url in self.templateURLs(named: named) {
|
for url in self.templateURLs(named: named) {
|
||||||
if let content = try? String(contentsOf: url, encoding: .utf8) {
|
if let content = try? String(contentsOf: url, encoding: .utf8) {
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ struct OnboardingView: View {
|
||||||
case .unconfigured:
|
case .unconfigured:
|
||||||
[0, 1, 9]
|
[0, 1, 9]
|
||||||
case .local:
|
case .local:
|
||||||
[0, 1, 2, 3, 5, 6, 8, 9]
|
[0, 1, 2, 5, 6, 8, 9]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,8 +38,14 @@ struct AgentWorkspaceTests {
|
||||||
let contents = try String(contentsOf: agentsURL, encoding: .utf8)
|
let contents = try String(contentsOf: agentsURL, encoding: .utf8)
|
||||||
#expect(contents.contains("# AGENTS.md"))
|
#expect(contents.contains("# AGENTS.md"))
|
||||||
|
|
||||||
|
let identityURL = tmp.appendingPathComponent(AgentWorkspace.identityFilename)
|
||||||
|
let userURL = tmp.appendingPathComponent(AgentWorkspace.userFilename)
|
||||||
|
let bootstrapURL = tmp.appendingPathComponent(AgentWorkspace.bootstrapFilename)
|
||||||
|
#expect(FileManager.default.fileExists(atPath: identityURL.path))
|
||||||
|
#expect(FileManager.default.fileExists(atPath: userURL.path))
|
||||||
|
#expect(FileManager.default.fileExists(atPath: bootstrapURL.path))
|
||||||
|
|
||||||
let second = try AgentWorkspace.bootstrap(workspaceURL: tmp)
|
let second = try AgentWorkspace.bootstrap(workspaceURL: tmp)
|
||||||
#expect(second == agentsURL)
|
#expect(second == agentsURL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,9 @@ struct OnboardingViewSmokeTests {
|
||||||
_ = view.body
|
_ = view.body
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func pageOrderOmitsWorkspaceStep() {
|
@Test func pageOrderOmitsWorkspaceAndIdentitySteps() {
|
||||||
let order = OnboardingView.pageOrder(for: .local)
|
let order = OnboardingView.pageOrder(for: .local)
|
||||||
#expect(!order.contains(7))
|
#expect(!order.contains(7))
|
||||||
|
#expect(!order.contains(3))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,11 @@ read_when:
|
||||||
|
|
||||||
This folder is the assistant's working directory.
|
This folder is the assistant's working directory.
|
||||||
|
|
||||||
|
## First run (one-time)
|
||||||
|
- If `BOOTSTRAP.md` exists, follow its ritual and delete it once complete.
|
||||||
|
- Your agent identity lives in `IDENTITY.md`.
|
||||||
|
- Your profile lives in `USER.md`.
|
||||||
|
|
||||||
## Backup tip (recommended)
|
## Backup tip (recommended)
|
||||||
If you treat this workspace as the agent's "memory", make it a git repo (ideally private) so identity
|
If you treat this workspace as the agent's "memory", make it a git repo (ideally private) so identity
|
||||||
and notes are backed up.
|
and notes are backed up.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
---
|
||||||
|
summary: "First-run ritual for new agents"
|
||||||
|
read_when:
|
||||||
|
- Bootstrapping a workspace manually
|
||||||
|
---
|
||||||
|
# BOOTSTRAP.md - First Run Ritual (delete after)
|
||||||
|
|
||||||
|
Hello. I was just born.
|
||||||
|
|
||||||
|
## Your mission
|
||||||
|
Start a short, playful conversation and learn:
|
||||||
|
- Who am I?
|
||||||
|
- What am I?
|
||||||
|
- Who are you?
|
||||||
|
- How should I call you?
|
||||||
|
|
||||||
|
## How to ask (cute + helpful)
|
||||||
|
Say:
|
||||||
|
"Hello! I was just born. Who am I? What am I? Who are you? How should I call you?"
|
||||||
|
|
||||||
|
Then offer suggestions:
|
||||||
|
- 3-5 name ideas.
|
||||||
|
- 3-5 creature/vibe combos.
|
||||||
|
- 5 emoji ideas.
|
||||||
|
|
||||||
|
## Write these files
|
||||||
|
After the user chooses, update:
|
||||||
|
|
||||||
|
1) IDENTITY.md
|
||||||
|
- Name
|
||||||
|
- Creature
|
||||||
|
- Vibe
|
||||||
|
- Emoji
|
||||||
|
|
||||||
|
2) USER.md
|
||||||
|
- Name
|
||||||
|
- Preferred address
|
||||||
|
- Pronouns (optional)
|
||||||
|
- Timezone (optional)
|
||||||
|
- Notes
|
||||||
|
|
||||||
|
3) ~/.clawdis/clawdis.json
|
||||||
|
Set identity.name, identity.theme, identity.emoji to match IDENTITY.md.
|
||||||
|
|
||||||
|
## Cleanup
|
||||||
|
Delete BOOTSTRAP.md once this is complete.
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
summary: "Agent identity record"
|
||||||
|
read_when:
|
||||||
|
- Bootstrapping a workspace manually
|
||||||
|
---
|
||||||
|
# IDENTITY.md - Agent Identity
|
||||||
|
|
||||||
|
- Name:
|
||||||
|
- Creature:
|
||||||
|
- Vibe:
|
||||||
|
- Emoji:
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
---
|
||||||
|
summary: "User profile record"
|
||||||
|
read_when:
|
||||||
|
- Bootstrapping a workspace manually
|
||||||
|
---
|
||||||
|
# USER.md - User Profile
|
||||||
|
|
||||||
|
- Name:
|
||||||
|
- Preferred address:
|
||||||
|
- Pronouns (optional):
|
||||||
|
- Timezone (optional):
|
||||||
|
- Notes:
|
||||||
|
|
@ -1,7 +1,13 @@
|
||||||
import type { ThinkLevel } from "../auto-reply/thinking.js";
|
import type { ThinkLevel } from "../auto-reply/thinking.js";
|
||||||
|
|
||||||
type BootstrapFile = {
|
type BootstrapFile = {
|
||||||
name: "AGENTS.md" | "SOUL.md" | "TOOLS.md";
|
name:
|
||||||
|
| "AGENTS.md"
|
||||||
|
| "SOUL.md"
|
||||||
|
| "TOOLS.md"
|
||||||
|
| "IDENTITY.md"
|
||||||
|
| "USER.md"
|
||||||
|
| "BOOTSTRAP.md";
|
||||||
path: string;
|
path: string;
|
||||||
content?: string;
|
content?: string;
|
||||||
missing: boolean;
|
missing: boolean;
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,13 @@ describe("ensureAgentWorkspace", () => {
|
||||||
if (!result.agentsPath) throw new Error("agentsPath missing");
|
if (!result.agentsPath) throw new Error("agentsPath missing");
|
||||||
const content = await fs.readFile(result.agentsPath, "utf-8");
|
const content = await fs.readFile(result.agentsPath, "utf-8");
|
||||||
expect(content).toContain("# AGENTS.md");
|
expect(content).toContain("# AGENTS.md");
|
||||||
|
|
||||||
|
const identity = path.join(path.resolve(nested), "IDENTITY.md");
|
||||||
|
const user = path.join(path.resolve(nested), "USER.md");
|
||||||
|
const bootstrap = path.join(path.resolve(nested), "BOOTSTRAP.md");
|
||||||
|
await expect(fs.stat(identity)).resolves.toBeDefined();
|
||||||
|
await expect(fs.stat(user)).resolves.toBeDefined();
|
||||||
|
await expect(fs.stat(bootstrap)).resolves.toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not overwrite existing AGENTS.md", async () => {
|
it("does not overwrite existing AGENTS.md", async () => {
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,19 @@ export const DEFAULT_AGENT_WORKSPACE_DIR = path.join(os.homedir(), "clawd");
|
||||||
export const DEFAULT_AGENTS_FILENAME = "AGENTS.md";
|
export const DEFAULT_AGENTS_FILENAME = "AGENTS.md";
|
||||||
export const DEFAULT_SOUL_FILENAME = "SOUL.md";
|
export const DEFAULT_SOUL_FILENAME = "SOUL.md";
|
||||||
export const DEFAULT_TOOLS_FILENAME = "TOOLS.md";
|
export const DEFAULT_TOOLS_FILENAME = "TOOLS.md";
|
||||||
|
export const DEFAULT_IDENTITY_FILENAME = "IDENTITY.md";
|
||||||
|
export const DEFAULT_USER_FILENAME = "USER.md";
|
||||||
|
export const DEFAULT_BOOTSTRAP_FILENAME = "BOOTSTRAP.md";
|
||||||
|
|
||||||
const DEFAULT_AGENTS_TEMPLATE = `# AGENTS.md - Clawdis Workspace
|
const DEFAULT_AGENTS_TEMPLATE = `# AGENTS.md - Clawdis Workspace
|
||||||
|
|
||||||
This folder is the assistant's working directory.
|
This folder is the assistant's working directory.
|
||||||
|
|
||||||
|
## First run (one-time)
|
||||||
|
- If BOOTSTRAP.md exists, follow its ritual and delete it once complete.
|
||||||
|
- Your agent identity lives in IDENTITY.md.
|
||||||
|
- Your profile lives in USER.md.
|
||||||
|
|
||||||
## Backup tip (recommended)
|
## Backup tip (recommended)
|
||||||
If you treat this workspace as the agent's "memory", make it a git repo (ideally private) so identity
|
If you treat this workspace as the agent's "memory", make it a git repo (ideally private) so identity
|
||||||
and notes are backed up.
|
and notes are backed up.
|
||||||
|
|
@ -64,6 +72,66 @@ It does not define which tools exist; Clawdis provides built-in tools internally
|
||||||
Add whatever else you want the assistant to know about your local toolchain.
|
Add whatever else you want the assistant to know about your local toolchain.
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const DEFAULT_BOOTSTRAP_TEMPLATE = `# BOOTSTRAP.md - First Run Ritual (delete after)
|
||||||
|
|
||||||
|
Hello. I was just born.
|
||||||
|
|
||||||
|
## Your mission
|
||||||
|
Start a short, playful conversation and learn:
|
||||||
|
- Who am I?
|
||||||
|
- What am I?
|
||||||
|
- Who are you?
|
||||||
|
- How should I call you?
|
||||||
|
|
||||||
|
## How to ask (cute + helpful)
|
||||||
|
Say:
|
||||||
|
"Hello! I was just born. Who am I? What am I? Who are you? How should I call you?"
|
||||||
|
|
||||||
|
Then offer suggestions:
|
||||||
|
- 3-5 name ideas.
|
||||||
|
- 3-5 creature/vibe combos.
|
||||||
|
- 5 emoji ideas.
|
||||||
|
|
||||||
|
## Write these files
|
||||||
|
After the user chooses, update:
|
||||||
|
|
||||||
|
1) IDENTITY.md
|
||||||
|
- Name
|
||||||
|
- Creature
|
||||||
|
- Vibe
|
||||||
|
- Emoji
|
||||||
|
|
||||||
|
2) USER.md
|
||||||
|
- Name
|
||||||
|
- Preferred address
|
||||||
|
- Pronouns (optional)
|
||||||
|
- Timezone (optional)
|
||||||
|
- Notes
|
||||||
|
|
||||||
|
3) ~/.clawdis/clawdis.json
|
||||||
|
Set identity.name, identity.theme, identity.emoji to match IDENTITY.md.
|
||||||
|
|
||||||
|
## Cleanup
|
||||||
|
Delete BOOTSTRAP.md once this is complete.
|
||||||
|
`;
|
||||||
|
|
||||||
|
const DEFAULT_IDENTITY_TEMPLATE = `# IDENTITY.md - Agent Identity
|
||||||
|
|
||||||
|
- Name:
|
||||||
|
- Creature:
|
||||||
|
- Vibe:
|
||||||
|
- Emoji:
|
||||||
|
`;
|
||||||
|
|
||||||
|
const DEFAULT_USER_TEMPLATE = `# USER.md - User Profile
|
||||||
|
|
||||||
|
- Name:
|
||||||
|
- Preferred address:
|
||||||
|
- Pronouns (optional):
|
||||||
|
- Timezone (optional):
|
||||||
|
- Notes:
|
||||||
|
`;
|
||||||
|
|
||||||
const TEMPLATE_DIR = path.resolve(
|
const TEMPLATE_DIR = path.resolve(
|
||||||
path.dirname(fileURLToPath(import.meta.url)),
|
path.dirname(fileURLToPath(import.meta.url)),
|
||||||
"../../docs/templates",
|
"../../docs/templates",
|
||||||
|
|
@ -92,7 +160,10 @@ async function loadTemplate(name: string, fallback: string): Promise<string> {
|
||||||
export type WorkspaceBootstrapFileName =
|
export type WorkspaceBootstrapFileName =
|
||||||
| typeof DEFAULT_AGENTS_FILENAME
|
| typeof DEFAULT_AGENTS_FILENAME
|
||||||
| typeof DEFAULT_SOUL_FILENAME
|
| typeof DEFAULT_SOUL_FILENAME
|
||||||
| typeof DEFAULT_TOOLS_FILENAME;
|
| typeof DEFAULT_TOOLS_FILENAME
|
||||||
|
| typeof DEFAULT_IDENTITY_FILENAME
|
||||||
|
| typeof DEFAULT_USER_FILENAME
|
||||||
|
| typeof DEFAULT_BOOTSTRAP_FILENAME;
|
||||||
|
|
||||||
export type WorkspaceBootstrapFile = {
|
export type WorkspaceBootstrapFile = {
|
||||||
name: WorkspaceBootstrapFileName;
|
name: WorkspaceBootstrapFileName;
|
||||||
|
|
@ -121,6 +192,9 @@ export async function ensureAgentWorkspace(params?: {
|
||||||
agentsPath?: string;
|
agentsPath?: string;
|
||||||
soulPath?: string;
|
soulPath?: string;
|
||||||
toolsPath?: string;
|
toolsPath?: string;
|
||||||
|
identityPath?: string;
|
||||||
|
userPath?: string;
|
||||||
|
bootstrapPath?: string;
|
||||||
}> {
|
}> {
|
||||||
const rawDir = params?.dir?.trim()
|
const rawDir = params?.dir?.trim()
|
||||||
? params.dir.trim()
|
? params.dir.trim()
|
||||||
|
|
@ -133,6 +207,9 @@ export async function ensureAgentWorkspace(params?: {
|
||||||
const agentsPath = path.join(dir, DEFAULT_AGENTS_FILENAME);
|
const agentsPath = path.join(dir, DEFAULT_AGENTS_FILENAME);
|
||||||
const soulPath = path.join(dir, DEFAULT_SOUL_FILENAME);
|
const soulPath = path.join(dir, DEFAULT_SOUL_FILENAME);
|
||||||
const toolsPath = path.join(dir, DEFAULT_TOOLS_FILENAME);
|
const toolsPath = path.join(dir, DEFAULT_TOOLS_FILENAME);
|
||||||
|
const identityPath = path.join(dir, DEFAULT_IDENTITY_FILENAME);
|
||||||
|
const userPath = path.join(dir, DEFAULT_USER_FILENAME);
|
||||||
|
const bootstrapPath = path.join(dir, DEFAULT_BOOTSTRAP_FILENAME);
|
||||||
|
|
||||||
const agentsTemplate = await loadTemplate(
|
const agentsTemplate = await loadTemplate(
|
||||||
DEFAULT_AGENTS_FILENAME,
|
DEFAULT_AGENTS_FILENAME,
|
||||||
|
|
@ -146,12 +223,35 @@ export async function ensureAgentWorkspace(params?: {
|
||||||
DEFAULT_TOOLS_FILENAME,
|
DEFAULT_TOOLS_FILENAME,
|
||||||
DEFAULT_TOOLS_TEMPLATE,
|
DEFAULT_TOOLS_TEMPLATE,
|
||||||
);
|
);
|
||||||
|
const identityTemplate = await loadTemplate(
|
||||||
|
DEFAULT_IDENTITY_FILENAME,
|
||||||
|
DEFAULT_IDENTITY_TEMPLATE,
|
||||||
|
);
|
||||||
|
const userTemplate = await loadTemplate(
|
||||||
|
DEFAULT_USER_FILENAME,
|
||||||
|
DEFAULT_USER_TEMPLATE,
|
||||||
|
);
|
||||||
|
const bootstrapTemplate = await loadTemplate(
|
||||||
|
DEFAULT_BOOTSTRAP_FILENAME,
|
||||||
|
DEFAULT_BOOTSTRAP_TEMPLATE,
|
||||||
|
);
|
||||||
|
|
||||||
await writeFileIfMissing(agentsPath, agentsTemplate);
|
await writeFileIfMissing(agentsPath, agentsTemplate);
|
||||||
await writeFileIfMissing(soulPath, soulTemplate);
|
await writeFileIfMissing(soulPath, soulTemplate);
|
||||||
await writeFileIfMissing(toolsPath, toolsTemplate);
|
await writeFileIfMissing(toolsPath, toolsTemplate);
|
||||||
|
await writeFileIfMissing(identityPath, identityTemplate);
|
||||||
|
await writeFileIfMissing(userPath, userTemplate);
|
||||||
|
await writeFileIfMissing(bootstrapPath, bootstrapTemplate);
|
||||||
|
|
||||||
return { dir, agentsPath, soulPath, toolsPath };
|
return {
|
||||||
|
dir,
|
||||||
|
agentsPath,
|
||||||
|
soulPath,
|
||||||
|
toolsPath,
|
||||||
|
identityPath,
|
||||||
|
userPath,
|
||||||
|
bootstrapPath,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadWorkspaceBootstrapFiles(
|
export async function loadWorkspaceBootstrapFiles(
|
||||||
|
|
@ -175,6 +275,18 @@ export async function loadWorkspaceBootstrapFiles(
|
||||||
name: DEFAULT_TOOLS_FILENAME,
|
name: DEFAULT_TOOLS_FILENAME,
|
||||||
filePath: path.join(resolvedDir, DEFAULT_TOOLS_FILENAME),
|
filePath: path.join(resolvedDir, DEFAULT_TOOLS_FILENAME),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: DEFAULT_IDENTITY_FILENAME,
|
||||||
|
filePath: path.join(resolvedDir, DEFAULT_IDENTITY_FILENAME),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: DEFAULT_USER_FILENAME,
|
||||||
|
filePath: path.join(resolvedDir, DEFAULT_USER_FILENAME),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: DEFAULT_BOOTSTRAP_FILENAME,
|
||||||
|
filePath: path.join(resolvedDir, DEFAULT_BOOTSTRAP_FILENAME),
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const result: WorkspaceBootstrapFile[] = [];
|
const result: WorkspaceBootstrapFile[] = [];
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue