Orginize
This commit is contained in:
@@ -0,0 +1,312 @@
|
||||
/**
|
||||
* Agent Markdown workspace at ~/.agent/workspace — soul files + optional daily memory.
|
||||
* Defaults ship on the system image at /share/agent-workspace/ and are seeded
|
||||
* into the personal drive when SOUL.md is missing (portable across peers via Hyperdrive).
|
||||
*/
|
||||
|
||||
/** @type {readonly string[]} Canonical Markdown load order */
|
||||
var BARE_AGENT_WORKSPACE_FILES = Object.freeze([
|
||||
'SOUL.md',
|
||||
'AGENTS.md',
|
||||
'IDENTITY.md',
|
||||
'USER.md',
|
||||
'TOOLS.md',
|
||||
'MEMORY.md',
|
||||
'BOOTSTRAP.md',
|
||||
'HEARTBEAT.md',
|
||||
'PROMPT.md'
|
||||
])
|
||||
|
||||
/** System-drive templates (kernel share) */
|
||||
var BARE_AGENT_WORKSPACE_SHARE = '/share/agent-workspace'
|
||||
|
||||
/** Relative paths under workspace/ and share root for skill templates */
|
||||
var BARE_AGENT_SKILL_SEED_REL = Object.freeze([
|
||||
'skills/.gitkeep',
|
||||
'skills/p2p-os-status/SKILL.md',
|
||||
'skills/bare-os-kernel-proc/SKILL.md',
|
||||
'skills/bare-os-super-developer/SKILL.md',
|
||||
'skills/agent-ops/SKILL.md',
|
||||
'skills/xai-compat/SKILL.md',
|
||||
'skills/holesail/SKILL.md',
|
||||
'skills/hdms/SKILL.md',
|
||||
'skills/bareos-code-change/SKILL.md',
|
||||
'skills/hyperdrive-replication/SKILL.md',
|
||||
'skills/protomux-channel/SKILL.md',
|
||||
'skills/ctx-api-change/SKILL.md',
|
||||
'skills/proc-node-change/SKILL.md',
|
||||
'skills/seed-rpc-change/SKILL.md',
|
||||
'skills/coreutils-command-change/SKILL.md',
|
||||
'skills/shell-grammar-change/SKILL.md',
|
||||
'skills/docs-contract-update/SKILL.md',
|
||||
'skills/kernel-program-extension/SKILL.md',
|
||||
'skills/appstore/SKILL.md',
|
||||
'skills/pear-dev/SKILL.md',
|
||||
'skills/pear-runtime-debug/SKILL.md',
|
||||
'skills/holepunch-local-mirror/SKILL.md'
|
||||
])
|
||||
|
||||
/**
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {Uint8Array} buf
|
||||
*/
|
||||
function bareAgentWorkspaceDecode(ctx, buf) {
|
||||
if (!buf || !buf.length) return ''
|
||||
if (
|
||||
typeof ctx.b4a !== 'undefined' &&
|
||||
ctx.b4a &&
|
||||
typeof ctx.b4a.toString === 'function'
|
||||
)
|
||||
return ctx.b4a.toString(buf)
|
||||
return String(new TextDecoder().decode(buf))
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string} UTC YYYY-MM-DD
|
||||
*/
|
||||
function bareAgentWorkspaceUtcYmd() {
|
||||
const d = new Date()
|
||||
const y = d.getUTCFullYear()
|
||||
const m = d.getUTCMonth() + 1
|
||||
const day = d.getUTCDate()
|
||||
const pad = (n) => (n < 10 ? '0' : '') + n
|
||||
return y + '-' + pad(m) + '-' + pad(day)
|
||||
}
|
||||
|
||||
/**
|
||||
* Seed ~/.agent/workspace from /share/agent-workspace when SOUL.md is absent.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {{ dir: string, workspace: string, workspaceMemory: string, workspaceSkills: string }} paths
|
||||
*/
|
||||
async function bareAgentEnsureWorkspace(ctx, paths) {
|
||||
const vfs = ctx.vfs
|
||||
if (!vfs || typeof vfs.mkdir !== 'function' || typeof vfs.readFile !== 'function')
|
||||
return
|
||||
if (typeof vfs.writeFile !== 'function') return
|
||||
try {
|
||||
const b = await vfs.readFile(paths.workspace + '/SOUL.md')
|
||||
if (b && b.length) return
|
||||
} catch {
|
||||
/* missing — seed */
|
||||
}
|
||||
try {
|
||||
await vfs.mkdir(paths.workspace, { recursive: true })
|
||||
await vfs.mkdir(paths.workspaceMemory, { recursive: true })
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
const share = BARE_AGENT_WORKSPACE_SHARE
|
||||
for (const name of BARE_AGENT_WORKSPACE_FILES) {
|
||||
try {
|
||||
const buf = await vfs.readFile(share + '/' + name)
|
||||
await vfs.writeFile(paths.workspace + '/' + name, buf)
|
||||
} catch {
|
||||
/* template missing on image — skip */
|
||||
}
|
||||
}
|
||||
try {
|
||||
const gk = await vfs.readFile(share + '/memory/.gitkeep')
|
||||
await vfs.writeFile(paths.workspaceMemory + '/.gitkeep', gk)
|
||||
} catch {
|
||||
/* optional */
|
||||
}
|
||||
/** @type {[string, string][]} */
|
||||
const stubs = [
|
||||
['loader.stub.js', paths.dir + '/loader.js'],
|
||||
['index.stub.js', paths.dir + '/index.js'],
|
||||
['skill-loader.stub.js', paths.dir + '/skill-loader.js'],
|
||||
['README-agent.md', paths.dir + '/README-agent.md']
|
||||
]
|
||||
for (const [srcName, dest] of stubs) {
|
||||
try {
|
||||
const buf = await vfs.readFile(share + '/' + srcName)
|
||||
await vfs.writeFile(dest, buf)
|
||||
} catch {
|
||||
/* optional */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure workspace/skills templates and ~/.agent/skill-loader.js exist (idempotent; for upgrades).
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {{ workspace: string, workspaceSkills: string, dir: string }} paths
|
||||
* @param {Record<string, unknown>} [config]
|
||||
*/
|
||||
async function bareAgentEnsureSkillTemplates(ctx, paths, config) {
|
||||
const vfs = ctx.vfs
|
||||
if (
|
||||
!vfs ||
|
||||
typeof vfs.readFile !== 'function' ||
|
||||
typeof vfs.writeFile !== 'function' ||
|
||||
typeof vfs.mkdir !== 'function'
|
||||
)
|
||||
return
|
||||
const provider =
|
||||
config && typeof config === 'object' ? String(config.provider || '').trim().toLowerCase() : ''
|
||||
try {
|
||||
await vfs.mkdir(paths.workspaceSkills, { recursive: true })
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
const share = BARE_AGENT_WORKSPACE_SHARE
|
||||
for (const rel of BARE_AGENT_SKILL_SEED_REL) {
|
||||
if (rel === 'skills/xai-compat/SKILL.md' && provider !== 'xai') {
|
||||
if (typeof vfs.unlink === 'function') {
|
||||
try {
|
||||
await vfs.unlink(paths.workspace + '/' + rel)
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
const dest = paths.workspace + '/' + rel
|
||||
try {
|
||||
const b = await vfs.readFile(dest)
|
||||
if (b && b.length) continue
|
||||
} catch {
|
||||
/* missing — copy */
|
||||
}
|
||||
try {
|
||||
const buf = await vfs.readFile(share + '/' + rel)
|
||||
const parent = dest.replace(/\/[^/]+$/, '')
|
||||
await vfs.mkdir(parent, { recursive: true })
|
||||
await vfs.writeFile(dest, buf)
|
||||
} catch {
|
||||
/* template missing on image */
|
||||
}
|
||||
}
|
||||
try {
|
||||
await vfs.readFile(paths.dir + '/skill-loader.js')
|
||||
} catch {
|
||||
try {
|
||||
const buf = await vfs.readFile(share + '/skill-loader.stub.js')
|
||||
await vfs.writeFile(paths.dir + '/skill-loader.js', buf)
|
||||
} catch {
|
||||
/* optional */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {string} text
|
||||
*/
|
||||
function bareAgentWorkspaceEncode(ctx, text) {
|
||||
const s = String(text)
|
||||
if (
|
||||
typeof ctx.b4a !== 'undefined' &&
|
||||
ctx.b4a &&
|
||||
typeof ctx.b4a.from === 'function'
|
||||
)
|
||||
return ctx.b4a.from(s)
|
||||
return new TextEncoder().encode(s)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Record<string, unknown>} config
|
||||
*/
|
||||
function bareAgentIdentityMarkdownForConfig(config) {
|
||||
const label = String(config.agent_label || '').trim() || 'BareAgent'
|
||||
const owner = String(config.owner_name || '').trim()
|
||||
const role = owner
|
||||
? 'Decentralized OS intelligence for **' +
|
||||
owner +
|
||||
'** · upstream [bare-operating-system](https://git.ssh.surf/snxraven/bare-operating-system).'
|
||||
: 'Decentralized OS Intelligence for snxraven\'s bare-operating-system'
|
||||
return (
|
||||
'# IDENTITY.md\n\n' +
|
||||
'**Name:** ' +
|
||||
label +
|
||||
'\n' +
|
||||
'**Role:** ' +
|
||||
role +
|
||||
'\n' +
|
||||
'**Emoji:** 🦾\n' +
|
||||
'**Version:** 0.1\n'
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Record<string, unknown>} config
|
||||
*/
|
||||
function bareAgentUserMarkdownForConfig(config) {
|
||||
const owner = String(config.owner_name || '').trim()
|
||||
const opLine = owner
|
||||
? '- **Operator (this Hyperdrive):** ' + owner + '\n'
|
||||
: '- **Operator:** (set `owner_name` via `agent --config` or `edit_agent_config`)\n'
|
||||
return (
|
||||
'# USER.md - About the Owner\n\n' +
|
||||
opLine +
|
||||
'- **Upstream maintainer (repo):** snxraven\n' +
|
||||
'- **Location:** Atlanta, Georgia, US\n' +
|
||||
'- **Expertise:** P2P systems, Bare runtime, Hyperdrive, decentralized identity, POSIX-in-JS\n' +
|
||||
'- **Preferences:** Concise technical answers, bullet points, no corporate speak, direct honesty\n' +
|
||||
'- **Permissions:** Full access to system drive and personal Hyperdrive within tool policy\n'
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewrite IDENTITY.md / USER.md from ~/.agent/config.json (owner_name, agent_label).
|
||||
* Call after seeding workspace or when those keys change.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {{ workspace: string }} paths
|
||||
* @param {Record<string, unknown>} config
|
||||
*/
|
||||
async function bareAgentSyncWorkspaceFromConfig(ctx, paths, config) {
|
||||
const vfs = ctx.vfs
|
||||
if (!vfs || typeof vfs.writeFile !== 'function' || typeof vfs.mkdir !== 'function')
|
||||
return
|
||||
const label = String(config.agent_label || '').trim()
|
||||
const owner = String(config.owner_name || '').trim()
|
||||
if (!label && !owner) return
|
||||
try {
|
||||
await vfs.mkdir(paths.workspace, { recursive: true })
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
try {
|
||||
const idMd = bareAgentIdentityMarkdownForConfig(config)
|
||||
await vfs.writeFile(
|
||||
paths.workspace + '/IDENTITY.md',
|
||||
bareAgentWorkspaceEncode(ctx, idMd)
|
||||
)
|
||||
const userMd = bareAgentUserMarkdownForConfig(config)
|
||||
await vfs.writeFile(paths.workspace + '/USER.md', bareAgentWorkspaceEncode(ctx, userMd))
|
||||
} catch {
|
||||
/* ignore — best-effort */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build concatenated system prompt block (Markdown) from workspace files.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {{ workspace: string, workspaceMemory: string }} paths
|
||||
* @param {number} [maxChars]
|
||||
*/
|
||||
async function bareAgentLoadWorkspacePrompt(ctx, paths, maxChars) {
|
||||
const vfs = ctx.vfs
|
||||
if (!vfs || typeof vfs.readFile !== 'function') return ''
|
||||
const cap = Math.min(Math.max(Number(maxChars) || 24000, 4000), 64000)
|
||||
let out = '# Agent workspace (~/.agent/workspace)\n\n'
|
||||
for (const name of BARE_AGENT_WORKSPACE_FILES) {
|
||||
try {
|
||||
const buf = await vfs.readFile(paths.workspace + '/' + name)
|
||||
const t = bareAgentWorkspaceDecode(ctx, buf).trim()
|
||||
out += '=== ' + name + ' ===\n' + (t || '(empty)') + '\n\n'
|
||||
} catch {
|
||||
out += '=== ' + name + ' ===\n(File not found)\n\n'
|
||||
}
|
||||
}
|
||||
const day = bareAgentWorkspaceUtcYmd()
|
||||
try {
|
||||
const buf = await vfs.readFile(paths.workspaceMemory + '/' + day + '.md')
|
||||
const t = bareAgentWorkspaceDecode(ctx, buf).trim()
|
||||
if (t) out += '=== memory/' + day + '.md ===\n' + t + '\n\n'
|
||||
} catch {
|
||||
/* no daily log */
|
||||
}
|
||||
if (out.length > cap) out = out.slice(0, cap) + '\n… truncated\n'
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user