235 lines
6.9 KiB
JavaScript
235 lines
6.9 KiB
JavaScript
/** Shared agent tool helpers (preamble for /bin/agent; schemas/dispatch are sibling files). */
|
|
|
|
/**
|
|
* Host-checkout verification hints (keep loosely aligned with scripts/lib/agent-check-hints-data.mjs).
|
|
* @param {string} combined paths + topic
|
|
* @returns {string[]}
|
|
*/
|
|
function bareAgentVerificationHintsList(combined) {
|
|
const c = String(combined || '').toLowerCase()
|
|
/** @type {string[]} */
|
|
const hints = []
|
|
if (/(^|\/)kernel\/|kernel\\|\/boot\/init|lib\/init|lib\\init/.test(c)) {
|
|
hints.push('npm run bundle:kernel', 'node scripts/verify-kernel-seeder-parity.mjs')
|
|
}
|
|
if (/bare-os-coreutils|kernel\/bin|kernel\\bin/.test(c)) {
|
|
hints.push('npm run build -w bare-os-coreutils', 'node scripts/verify-man-coverage.mjs')
|
|
}
|
|
if (/bare-os-booter|bare-os-ctx-api/.test(c)) {
|
|
hints.push(
|
|
'npm run test -w bare-os-booter',
|
|
'node scripts/verify-ctx-api-feature-bits.mjs'
|
|
)
|
|
}
|
|
if (/bare-os-protocol|seed-rpc|channel\.js/.test(c)) {
|
|
hints.push('npm run test -w bare-os-protocol')
|
|
}
|
|
if (/bare-os-seeder/.test(c)) {
|
|
hints.push('node scripts/verify-kernel-seeder-parity.mjs')
|
|
}
|
|
if (/bare-os-bare-libs|kernel\/lib\/bare|kernel\\lib\\bare/.test(c)) {
|
|
hints.push('npm run build -w bare-os-bare-libs', 'node scripts/verify-bundle-health.mjs')
|
|
}
|
|
if (/shell|sh\.js|test\.js/.test(c) && /booter/.test(c)) {
|
|
hints.push('npm run test:shell-fast')
|
|
}
|
|
if (/docs\/|handbook\/|developer-guide\//.test(c)) {
|
|
hints.push('npm run pretest', 'node scripts/verify-doc-links.mjs')
|
|
}
|
|
if (!hints.length) hints.push('npm run pretest', 'npm test')
|
|
return [...new Set(hints)]
|
|
}
|
|
|
|
/**
|
|
* @param {string} s
|
|
*/
|
|
function bareAgentShellQuote(s) {
|
|
return "'" + String(s).replace(/'/g, "'\\''") + "'"
|
|
}
|
|
|
|
/**
|
|
* @param {unknown} v
|
|
* @returns {string}
|
|
*/
|
|
function bareAgentJsonResult(v) {
|
|
try {
|
|
return JSON.stringify(v)
|
|
} catch {
|
|
return '{"error":"json_stringify_failed"}'
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* @param {Record<string, unknown>} ctx
|
|
* @param {string} absPath
|
|
*/
|
|
function bareAgentPathAllowed(absPath) {
|
|
if (typeof bareAgentPathAllowedRead === 'function') {
|
|
return bareAgentPathAllowedRead(absPath)
|
|
}
|
|
const p = String(absPath || '').replace(/\\/g, '/')
|
|
return Boolean(p.startsWith('/') && !p.includes('..'))
|
|
}
|
|
|
|
/**
|
|
* @param {string} command
|
|
* @param {unknown} denyList
|
|
*/
|
|
function bareAgentCommandDeniedByList(command, denyList) {
|
|
const cmd = String(command || '').toLowerCase()
|
|
const list = Array.isArray(denyList) ? denyList : []
|
|
for (let i = 0; i < list.length; i++) {
|
|
const needle = String(list[i] || '').trim().toLowerCase()
|
|
if (needle && cmd.includes(needle)) return needle
|
|
}
|
|
return ''
|
|
}
|
|
|
|
/**
|
|
* @param {Record<string, unknown>} base
|
|
* @param {Record<string, unknown>} patch
|
|
*/
|
|
function bareAgentMergeConfigPatch(base, patch) {
|
|
const out = { ...base }
|
|
const keys = [
|
|
'backend',
|
|
'rest_base_url',
|
|
'rest_api_key',
|
|
'model',
|
|
'qvac_model',
|
|
'qvac_profile',
|
|
'qvac_ctx_size',
|
|
'qvac_device',
|
|
'qvac_main_gpu',
|
|
'qvac_gpu_layers',
|
|
'max_tokens',
|
|
'temperature',
|
|
'provider',
|
|
'max_iterations',
|
|
'stream',
|
|
'tool_parallelism',
|
|
'request_timeout_ms',
|
|
'access_policy',
|
|
'allow_delete',
|
|
'require_confirm_token',
|
|
'command_deny',
|
|
'mutate_deny_prefixes',
|
|
'owner_name',
|
|
'agent_label',
|
|
'show_reasoning',
|
|
'reasoning_mode',
|
|
'reasoning_max_chars',
|
|
'reasoning_include_tools',
|
|
'allow_bridge_mutations',
|
|
'allow_host_notifications',
|
|
'allow_host_actions',
|
|
'emergency_stop_mutations',
|
|
'autonomous_mode_enabled',
|
|
'autonomous_max_runtime_ms',
|
|
'autonomous_completion_required_checks',
|
|
'autonomous_allow_paths',
|
|
'autonomous_deny_ops',
|
|
'autonomous_active',
|
|
'autonomous_started_at_ms',
|
|
'autonomous_stop_requested',
|
|
'autonomous_goal',
|
|
'autonomous_status',
|
|
'autonomous_last_error',
|
|
'context_compaction',
|
|
'compaction_keep_recent',
|
|
'compaction_tool_chars',
|
|
'plan_mode_active',
|
|
'todo_nudge_enabled'
|
|
]
|
|
const numKeys = new Set([
|
|
'max_tokens',
|
|
'temperature',
|
|
'max_iterations',
|
|
'tool_parallelism',
|
|
'request_timeout_ms',
|
|
'reasoning_max_chars',
|
|
'compaction_keep_recent',
|
|
'compaction_tool_chars',
|
|
'qvac_ctx_size',
|
|
'qvac_gpu_layers',
|
|
'autonomous_max_runtime_ms',
|
|
'autonomous_started_at_ms'
|
|
])
|
|
for (const k of keys) {
|
|
if (Object.prototype.hasOwnProperty.call(patch, k)) {
|
|
/** @type {unknown} */
|
|
const v = patch[k]
|
|
if (numKeys.has(k)) {
|
|
const n = Number(v)
|
|
if (Number.isFinite(n)) out[k] = n
|
|
} else if (
|
|
k === 'autonomous_completion_required_checks' ||
|
|
k === 'autonomous_allow_paths' ||
|
|
k === 'autonomous_deny_ops' ||
|
|
k === 'command_deny' ||
|
|
k === 'mutate_deny_prefixes'
|
|
) {
|
|
out[k] = Array.isArray(v) ? v.map((x) => String(x ?? '')).filter(Boolean) : out[k]
|
|
} else if (
|
|
k === 'stream' ||
|
|
k === 'allow_delete' ||
|
|
k === 'show_reasoning' ||
|
|
k === 'reasoning_include_tools' ||
|
|
k === 'allow_bridge_mutations' ||
|
|
k === 'allow_host_notifications' ||
|
|
k === 'allow_host_actions' ||
|
|
k === 'emergency_stop_mutations' ||
|
|
k === 'autonomous_mode_enabled' ||
|
|
k === 'autonomous_active' ||
|
|
k === 'autonomous_stop_requested' ||
|
|
k === 'plan_mode_active' ||
|
|
k === 'todo_nudge_enabled'
|
|
) {
|
|
out[k] = Boolean(v)
|
|
} else if (k === 'reasoning_mode') {
|
|
const mode = String(v ?? '').trim().toLowerCase()
|
|
out[k] = mode === 'summary' || mode === 'trace' ? mode : 'off'
|
|
} else if (k === 'context_compaction') {
|
|
const mode = String(v ?? '').trim().toLowerCase()
|
|
out[k] = mode === 'off' || mode === 'aggressive' ? mode : 'auto'
|
|
} else if (k === 'require_confirm_token') {
|
|
out[k] = String(v ?? '')
|
|
} else if (k === 'access_policy') {
|
|
const pol = String(v ?? '').trim().toLowerCase()
|
|
out[k] = pol === 'restricted' ? 'restricted' : 'full'
|
|
} else {
|
|
out[k] = String(v ?? '')
|
|
}
|
|
}
|
|
}
|
|
if (
|
|
patch.extra_headers &&
|
|
typeof patch.extra_headers === 'object' &&
|
|
!Array.isArray(patch.extra_headers)
|
|
) {
|
|
out.extra_headers = { .../** @type {Record<string, string>} */ (patch.extra_headers) }
|
|
}
|
|
return out
|
|
}
|
|
|
|
/**
|
|
* @param {Record<string, unknown>} ctx
|
|
* @param {{ config: string }} paths
|
|
* @param {Record<string, unknown>} config
|
|
*/
|
|
async function bareAgentSaveConfigFromTools(ctx, paths, config) {
|
|
if (typeof bareAgentSaveConfig === 'function') {
|
|
await bareAgentSaveConfig(ctx, paths, config)
|
|
return
|
|
}
|
|
const vfs = ctx.vfs
|
|
if (!vfs?.writeFile) return
|
|
const json = JSON.stringify(config, null, 2) + '\n'
|
|
const body =
|
|
typeof ctx.b4a !== 'undefined' && ctx.b4a && typeof ctx.b4a.from === 'function'
|
|
? ctx.b4a.from(json)
|
|
: new TextEncoder().encode(json)
|
|
await vfs.writeFile(paths.config, body)
|
|
}
|