titan-agent 6.0.2 → 6.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/goalDriver.js +107 -2
- package/dist/agent/goalDriver.js.map +1 -1
- package/dist/agent/goalProposer.js +11 -1
- package/dist/agent/goalProposer.js.map +1 -1
- package/dist/config/schema.js +21 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/utils/constants.js +1 -1
- package/dist/utils/constants.js.map +1 -1
- package/package.json +1 -1
- package/ui/dist/sw.js +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/agent/goalProposer.ts"],"sourcesContent":["/**\n * TITAN — Self-Directed Goal Proposer\n *\n * Runs during the nightly dreaming cycle (Phase 4: Dream) after memory\n * consolidation has happened. Each registered agent examines recent activity,\n * open issues, failed subtasks, and consolidation findings, then proposes\n * 0-3 new goals it thinks would be worth doing.\n *\n * Proposals go into the Command Post approval queue as `type: 'goal_proposal'`.\n * A human (or designated approver agent) accepts or rejects them. On accept,\n * the existing createGoal() pipeline fires and Initiative picks up the work.\n *\n * Opt-in via config.agent.autoProposeGoals (default false).\n * Rate-limited per-agent via config.agent.proposalRateLimitPerDay.\n */\nimport { existsSync, readFileSync, writeFileSync } from 'fs';\nimport { join } from 'path';\nimport { TITAN_HOME } from '../utils/constants.js';\nimport { mkdirIfNotExists } from '../utils/helpers.js';\nimport { loadConfig } from '../config/config.js';\nimport { chat } from '../providers/router.js';\nimport { auxChat, resolveAuxiliaryModel } from '../providers/auxiliary.js';\nimport { applyOutputGuardrails } from './outputGuardrails.js';\nimport { getActivity, requestGoalProposalApproval, type CPApproval } from './commandPost.js';\nimport { listGoals } from './goals.js';\nimport logger from '../utils/logger.js';\n\nconst COMPONENT = 'GoalProposer';\nconst RATE_STATE_PATH = join(TITAN_HOME, 'goal-proposer-state.json');\n\n// ── Types ────────────────────────────────────────────────────────\n\nexport interface ProposedGoal {\n title: string;\n description: string;\n rationale: string;\n priority?: number;\n tags?: string[];\n parentGoalId?: string;\n subtasks?: Array<{ title: string; description: string; dependsOn?: string[] }>;\n}\n\nexport interface GoalProposerContext {\n /** Recent activity feed entries — max last 50. */\n recentActivity?: string[];\n /** Titles of currently active goals so proposals don't duplicate. */\n activeGoals?: string[];\n /** Titles of recently failed subtasks worth retrying or reframing. */\n failedSubtasks?: string[];\n /** Free-form notes from the dreaming consolidation log. */\n consolidationNotes?: string;\n /**\n * v4.9.0-local.4: extra prompt blocks (episodic recall, experiment\n * history, identity) pre-loaded by the caller. Keeps buildPrompt\n * synchronous.\n */\n extraBlocks?: string[];\n}\n\ninterface RateLimitState {\n /** Map of agentId → ISO timestamps of proposals filed in the last 24h. */\n proposalsByAgent: Record<string, string[]>;\n}\n\n// ── Rate Limiting ────────────────────────────────────────────────\n\nfunction loadRateState(): RateLimitState {\n if (!existsSync(RATE_STATE_PATH)) return { proposalsByAgent: {} };\n try {\n const raw = readFileSync(RATE_STATE_PATH, 'utf-8');\n const parsed = JSON.parse(raw) as Partial<RateLimitState>;\n // v4.9.0-local.6: defensive normalize. A prior bug (+ the goal-\n // reset script) can write `{}` to this file, losing the\n // `proposalsByAgent` key. Without this, every\n // `state.proposalsByAgent[agentId]` access crashes with\n // \"Cannot read properties of undefined (reading '<agent>')\"\n // and proposals silently fail for hours.\n return {\n proposalsByAgent: parsed?.proposalsByAgent ?? {},\n };\n } catch {\n return { proposalsByAgent: {} };\n }\n}\n\nfunction saveRateState(state: RateLimitState): void {\n try {\n mkdirIfNotExists(TITAN_HOME);\n writeFileSync(RATE_STATE_PATH, JSON.stringify(state, null, 2), 'utf-8');\n } catch (err) {\n logger.warn(COMPONENT, `Failed to save rate state: ${(err as Error).message}`);\n }\n}\n\n/** Returns how many slots the agent has remaining in the current 24h window. */\nexport function remainingSlots(agentId: string, limitPerDay: number): number {\n const state = loadRateState();\n const now = Date.now();\n const dayMs = 24 * 3600 * 1000;\n const stamps = (state.proposalsByAgent[agentId] || []).filter(t => now - new Date(t).getTime() < dayMs);\n return Math.max(0, limitPerDay - stamps.length);\n}\n\nfunction recordProposal(agentId: string): void {\n const state = loadRateState();\n const now = Date.now();\n const dayMs = 24 * 3600 * 1000;\n const existing = (state.proposalsByAgent[agentId] || []).filter(t => now - new Date(t).getTime() < dayMs);\n existing.push(new Date().toISOString());\n state.proposalsByAgent[agentId] = existing;\n saveRateState(state);\n}\n\n// ── Prompt ───────────────────────────────────────────────────────\n\nfunction buildPrompt(agentId: string, slotsLeft: number, ctx: GoalProposerContext): string {\n const sections: string[] = [];\n sections.push(`You are agent \"${agentId}\". You have been given a quiet window to reflect on the system's current state and propose new goals that would meaningfully help.`);\n sections.push(`You may propose 0 to ${slotsLeft} goals. It is OK — often preferable — to propose zero if nothing is clearly worth doing.`);\n sections.push('');\n\n if (ctx.activeGoals && ctx.activeGoals.length) {\n sections.push('## Currently Active Goals (do not duplicate)');\n for (const title of ctx.activeGoals.slice(0, 20)) sections.push(`- ${title}`);\n sections.push('');\n }\n if (ctx.recentActivity && ctx.recentActivity.length) {\n sections.push('## Recent Activity (last ~50 events)');\n for (const line of ctx.recentActivity.slice(-50)) sections.push(`- ${line}`);\n sections.push('');\n }\n if (ctx.failedSubtasks && ctx.failedSubtasks.length) {\n sections.push('## Recently Failed Subtasks');\n for (const title of ctx.failedSubtasks.slice(0, 20)) sections.push(`- ${title}`);\n sections.push('');\n }\n if (ctx.consolidationNotes) {\n sections.push('## Memory Consolidation Notes');\n sections.push(ctx.consolidationNotes);\n sections.push('');\n }\n\n // v4.9.0-local.4: extra memory blocks (episodic, experiments,\n // identity) pre-loaded by the async caller and passed through ctx.\n // Keeps buildPrompt synchronous while still giving the proposer\n // full context of what TITAN has already done + who it is.\n if (ctx.extraBlocks && ctx.extraBlocks.length > 0) {\n for (const block of ctx.extraBlocks) {\n if (block && block.trim()) {\n sections.push(block);\n sections.push('');\n }\n }\n }\n\n sections.push('## Output Format');\n sections.push('Return ONLY a JSON array (no prose, no markdown fences). Each element:');\n sections.push('```');\n sections.push('{');\n sections.push(' \"title\": \"short imperative, under 80 chars\",');\n sections.push(' \"description\": \"what success looks like, 1-3 sentences\",');\n sections.push(' \"rationale\": \"why this goal is worth doing NOW\",');\n sections.push(' \"priority\": 1-5 (1 = highest),');\n sections.push(' \"tags\": [\"optional\", \"labels\"],');\n sections.push(' \"subtasks\": [{\"title\": \"...\", \"description\": \"...\"}]');\n sections.push('}');\n sections.push('```');\n sections.push('If nothing is worth proposing, return `[]`. Never return more than the slot limit.');\n\n return sections.join('\\n');\n}\n\n/** JSON schema passed to Ollama's native structured-outputs `format` field.\n * Constrains the model to emit an array of proposal objects matching the\n * fields normalizeProposal() accepts. Belt-and-suspenders — the downstream\n * defensive parser is still the authoritative validator. */\nconst PROPOSAL_ARRAY_SCHEMA: Record<string, unknown> = {\n type: 'array',\n items: {\n type: 'object',\n required: ['title', 'description', 'rationale'],\n properties: {\n title: { type: 'string' },\n description: { type: 'string' },\n rationale: { type: 'string' },\n priority: { type: 'number' },\n tags: { type: 'array', items: { type: 'string' } },\n subtasks: {\n type: 'array',\n items: {\n type: 'object',\n required: ['title', 'description'],\n properties: {\n title: { type: 'string' },\n description: { type: 'string' },\n dependsOn: { type: 'array', items: { type: 'string' } },\n },\n },\n },\n },\n },\n};\n\n// ── JSON Extraction ──────────────────────────────────────────────\n\n/** Defensively parse a JSON array from LLM output. Returns [] on failure. */\nfunction extractProposalArray(raw: string): unknown[] {\n const trimmed = raw.trim();\n // Try direct parse first.\n try {\n const parsed = JSON.parse(trimmed);\n if (Array.isArray(parsed)) return parsed;\n } catch { /* fall through */ }\n // Strip code fences.\n const fenceStripped = trimmed.replace(/^```(?:json)?\\s*/i, '').replace(/\\s*```$/, '');\n try {\n const parsed = JSON.parse(fenceStripped);\n if (Array.isArray(parsed)) return parsed;\n } catch { /* fall through */ }\n // Find the first `[...]` substring.\n const match = trimmed.match(/\\[[\\s\\S]*\\]/);\n if (match) {\n try {\n const parsed = JSON.parse(match[0]);\n if (Array.isArray(parsed)) return parsed;\n } catch { /* give up */ }\n }\n return [];\n}\n\nfunction normalizeProposal(raw: unknown): ProposedGoal | null {\n if (!raw || typeof raw !== 'object') return null;\n const r = raw as Record<string, unknown>;\n let title = typeof r.title === 'string' ? r.title.trim() : '';\n let description = typeof r.description === 'string' ? r.description.trim() : '';\n const rationale = typeof r.rationale === 'string' ? r.rationale.trim() : '';\n if (!title || !description || !rationale) return null;\n if (title.length > 200 || description.length > 2000 || rationale.length > 2000) return null;\n\n const priority = typeof r.priority === 'number' && r.priority >= 1 && r.priority <= 5\n ? Math.floor(r.priority)\n : undefined;\n let tags: string[] | undefined = Array.isArray(r.tags)\n ? r.tags.filter((t): t is string => typeof t === 'string' && t.length < 40).slice(0, 6)\n : undefined;\n const parentGoalId = typeof r.parentGoalId === 'string' ? r.parentGoalId : undefined;\n\n type Subtask = { title: string; description: string; dependsOn?: string[] };\n let subtasks: Subtask[] | undefined;\n if (Array.isArray(r.subtasks)) {\n const collected: Subtask[] = [];\n for (const s of r.subtasks) {\n if (!s || typeof s !== 'object') continue;\n const rec = s as Record<string, unknown>;\n const t = typeof rec.title === 'string' ? rec.title.trim() : '';\n const d = typeof rec.description === 'string' ? rec.description.trim() : '';\n if (!t || !d) continue;\n const deps = Array.isArray(rec.dependsOn)\n ? rec.dependsOn.filter((x): x is string => typeof x === 'string')\n : undefined;\n // Subtask-level rewrite happens after we know the parent goal's\n // self-mod status (below), so stash refs.\n void t; void d;\n collected.push({ title: t, description: d, dependsOn: deps });\n if (collected.length >= 12) break;\n }\n if (collected.length > 0) subtasks = collected;\n }\n\n // v4.9.0-local.8: self-mod disambiguation. When the proposer emits a\n // goal that sounds like it wants to modify \"the framework\" / \"core\" /\n // etc, the specialist picking it up historically interpreted this as\n // \"build something under ~/titan-saas\" because that's where Next.js\n // project scaffolding lives. We close the ambiguity at creation time:\n //\n // 1. Detect self-mod trigger words in title + description + tags\n // 2. If matched, ensure tags include 'self-mod' so the toolRunner\n // scope-lock + staging gate activates for work on this goal\n // 3. Append an explicit scope-lock note to the description pointing\n // at the actual target path\n // 4. Rewrite common ambiguous phrases in subtasks to spell out the\n // target path\n const selfModTriggers = [\n /\\bself[\\s-]?heal/i,\n /\\bself[\\s-]?repair/i,\n /\\bself[\\s-]?mod/i,\n /\\bcore[\\s-]framework/i,\n /\\bTITAN['’]?s?\\s+(own|core|framework|architecture|source|runtime)/i,\n /\\bframework\\s+(component|module|core|runtime)/i,\n ];\n const selfModTagValues = new Set([\n 'self-healing', 'self-repair', 'self-mod', 'self-modification',\n 'core-framework', 'framework', 'architecture', 'core', 'autonomy',\n ]);\n const tagsLower = new Set((tags || []).map(t => t.toLowerCase()));\n const haystack = `${title}\\n${description}\\n${(tags || []).join(' ')}`;\n const matchedByText = selfModTriggers.some(re => re.test(haystack));\n const matchedByTag = [...tagsLower].some(t => selfModTagValues.has(t));\n const isSelfMod = matchedByText || matchedByTag;\n\n if (isSelfMod) {\n const cfg = loadConfig();\n const target = (cfg.autonomy?.selfMod as { target?: string } | undefined)?.target || '/opt/TITAN';\n // Ensure the canonical 'self-mod' tag is present so toolRunner sees it\n tags = tags ? [...tags] : [];\n if (!tagsLower.has('self-mod')) tags.push('self-mod');\n tags = tags.slice(0, 6);\n\n // Append an unmistakable scope-lock note to the description — the\n // specialist reading this goal sees the target path explicitly\n // instead of having to infer \"the framework\" from context.\n const scopeNote = `\\n\\n[SCOPE-LOCK] This is a self-modification goal. All file writes MUST target ${target} (TITAN's own source tree). Writes to any other path will be refused by the toolRunner scope-lock. When staging is enabled, writes are diverted to ${target}/../self-mod-staging/<goalId>/ and surface as a self_mod_pr approval for human review before applying.`;\n if (!/\\[SCOPE-LOCK\\]/.test(description)) {\n description = (description + scopeNote).slice(0, 2000);\n }\n\n // Rewrite common ambiguous phrases in title/subtasks so the\n // specialist-level prompt mentions the target explicitly.\n const rewrite = (s: string): string => s\n .replace(/\\b(the\\s+)?core\\s+framework\\b/gi, `${target} (TITAN core framework)`)\n .replace(/\\b(the\\s+)?(TITAN\\s+)?framework\\b(?!\\s+component)/gi, `${target} (TITAN framework)`);\n title = rewrite(title).slice(0, 200);\n if (subtasks) {\n subtasks = subtasks.map(s => ({\n title: rewrite(s.title).slice(0, 200),\n description: rewrite(s.description).slice(0, 2000),\n dependsOn: s.dependsOn,\n }));\n }\n }\n\n return { title, description, rationale, priority, tags, parentGoalId, subtasks };\n}\n\n// ── Main Entry Point ─────────────────────────────────────────────\n\n/**\n * Generate goal proposals for a single agent and file them as pending approvals.\n * Returns the list of CPApproval records created (may be empty).\n *\n * Called by the dreaming watcher's Phase 4 (Dream). Safe to call ad-hoc from\n * debug endpoints or tests.\n */\nexport async function generateGoalProposals(\n agentId: string,\n ctx: GoalProposerContext,\n type: 'goal_proposal' | 'soma_proposal' = 'goal_proposal'\n): Promise<CPApproval[]> {\n const config = loadConfig();\n const enabled = config.agent.autoProposeGoals;\n if (!enabled) {\n logger.debug(COMPONENT, `autoProposeGoals disabled — skipping for agent ${agentId}`);\n return [];\n }\n\n const limit = config.agent.proposalRateLimitPerDay;\n const slotsLeft = remainingSlots(agentId, limit);\n if (slotsLeft <= 0) {\n logger.info(COMPONENT, `Agent ${agentId} has hit daily proposal limit (${limit}) — skipping`);\n return [];\n }\n\n const modelAlias = config.agent.proposalModel || 'fast';\n const model = config.agent.modelAliases[modelAlias] || modelAlias;\n\n // v4.9.0-local.4: pre-load extra memory blocks (episodic, experiments,\n // identity) before building the proposer prompt. Closes the repeat-\n // task feedback loop — the proposer now sees what TITAN has recently\n // done and won't re-propose the same ant colony sim three times.\n // Each block is best-effort; silent fallthrough if a module isn't\n // available at proposer time.\n const extraBlocks: string[] = [];\n try {\n const { renderRecallBlock } = await import('../memory/episodic.js');\n const block = renderRecallBlock({ limit: 12, windowHours: 72 });\n if (block) extraBlocks.push(block);\n } catch { /* ok */ }\n try {\n const { renderRecentExperimentsBlock } = await import('../memory/experiments.js');\n const block = renderRecentExperimentsBlock(8);\n if (block) extraBlocks.push(block);\n } catch { /* ok */ }\n try {\n const { getIdentity } = await import('../memory/identity.js');\n const id = getIdentity();\n if (id) {\n extraBlocks.push([\n '## Your identity (persistent)',\n `Mission: ${id.core.mission}`,\n `Non-negotiables: ${id.core.nonNegotiables.slice(0, 3).join('; ')}`,\n 'Propose ONLY goals that align with the mission and never violate a non-negotiable.',\n ].join('\\n'));\n }\n } catch { /* ok */ }\n\n const ctxWithBlocks: GoalProposerContext = { ...ctx, extraBlocks };\n const prompt = buildPrompt(agentId, slotsLeft, ctxWithBlocks);\n\n // v4.13 ancestor-extraction: route goal-proposal JSON extraction through\n // the auxiliary model client. The main agent model (gemma4:31b on the\n // Titan PC default) produces empty arrays for structured JSON tasks; a\n // dedicated fast+cheap model (minimax-m2.7:cloud) reliably produces valid\n // proposals. Falls back to the main `model` when no auxiliary is\n // configured.\n const auxModel = resolveAuxiliaryModel('json_extraction');\n const effectiveModel = auxModel || model;\n const isOllamaEffective = effectiveModel.toLowerCase().startsWith('ollama/');\n\n let rawContent: string;\n try {\n const response = await auxChat(\n 'json_extraction',\n {\n messages: [\n { role: 'system', content: 'You are a careful autonomous agent proposing new work. Output ONLY valid JSON. No explanation, no prose.' },\n { role: 'user', content: prompt },\n ],\n temperature: 0.4,\n maxTokens: 1500,\n ...(isOllamaEffective ? { format: PROPOSAL_ARRAY_SCHEMA } : {}),\n },\n model, // fallback to main agent model if no aux is configured\n );\n if (!response) {\n logger.warn(COMPONENT, `Auxiliary call returned null for agent ${agentId} — treating as no proposals`);\n return [];\n }\n rawContent = response.content || '';\n if (auxModel && auxModel !== model) {\n logger.info(COMPONENT, `Agent ${agentId} goal-proposal routed via auxiliary model ${auxModel} (main: ${model})`);\n }\n } catch (err) {\n logger.warn(COMPONENT, `LLM call failed for agent ${agentId}: ${(err as Error).message}`);\n return [];\n }\n\n // Strip chain-of-thought leakage before parsing JSON.\n const guarded = applyOutputGuardrails(rawContent, { type: 'sub_agent' });\n const parsed = extractProposalArray(guarded.content);\n if (parsed.length === 0) {\n logger.info(COMPONENT, `Agent ${agentId} proposed no goals (parsed empty array)`);\n return [];\n }\n\n const proposals: ProposedGoal[] = [];\n for (const item of parsed) {\n const normalized = normalizeProposal(item);\n if (normalized) proposals.push(normalized);\n if (proposals.length >= slotsLeft) break;\n }\n\n // v5.0.0: dedupe against ALL recent goals (not just active) and enforce\n // goal-overload backoff. Prevents the runaway loops that produced 1000+\n // duplicate \"Publish content\" goals.\n let allGoalTitles: string[] = [];\n let activeGoalCount = 0;\n try {\n const { listGoals } = await import('./goals.js');\n const all = listGoals();\n allGoalTitles = all.map(g => g.title);\n activeGoalCount = all.filter(g => g.status === 'active').length;\n } catch { /* best-effort */ }\n\n // Overload backoff: if the system is already swamped, only allow\n // cleanup / meta proposals (titles containing \"resolve\", \"cancel\",\n // \"close\", \"audit\", \"clean\", \"dedupe\"). Everything else is deferred\n // until the backlog drops.\n const isOverload = activeGoalCount >= 25;\n const isCleanupProposal = (t: string) => /\\b(resolve|cancel|close|audit|clean|dedupe|consolidate|prune)\\b/i.test(t);\n\n const approvals: CPApproval[] = [];\n for (const proposal of proposals) {\n // Dedupe against ANY existing goal (active, paused, completed, failed)\n const dup = allGoalTitles.find(t => titleSimilarity(t, proposal.title) >= 0.72);\n if (dup) {\n logger.info(COMPONENT, `Agent ${agentId} skipped duplicate proposal \"${proposal.title}\" (matches existing goal \"${dup}\")`);\n continue;\n }\n // Overload gate\n if (isOverload && !isCleanupProposal(proposal.title)) {\n logger.info(COMPONENT, `Agent ${agentId} skipped proposal \"${proposal.title}\" — goal overload (${activeGoalCount} active). Only cleanup proposals allowed.`);\n continue;\n }\n try {\n const approval = requestGoalProposalApproval(agentId, proposal, type);\n approvals.push(approval);\n recordProposal(agentId);\n allGoalTitles.push(proposal.title); // prevent intra-batch dupes too\n logger.info(COMPONENT, `Agent ${agentId} filed proposal \"${proposal.title}\" (approval ${approval.id})`);\n } catch (err) {\n logger.warn(COMPONENT, `Failed to file proposal \"${proposal.title}\": ${(err as Error).message}`);\n }\n }\n\n return approvals;\n}\n\n/**\n * v4.5.6: simple title similarity for dedupe. Normalizes case, strips\n * filler words, compares token overlap (Jaccard). 0.72 threshold catches\n * \"Satiate Hunger\" vs \"Satiate hunger\" vs \"Satiate hunger backlog\"\n * but not \"Satiate Purpose\" vs \"Satiate hunger\" — which is what we want.\n */\nfunction titleSimilarity(a: string, b: string): number {\n const tokenize = (s: string) => new Set(\n s.toLowerCase()\n .replace(/[^\\w\\s]/g, ' ')\n .split(/\\s+/)\n .filter(w => w.length > 2 && !STOP_WORDS.has(w))\n );\n const ta = tokenize(a);\n const tb = tokenize(b);\n if (ta.size === 0 || tb.size === 0) return 0;\n let intersection = 0;\n for (const t of ta) if (tb.has(t)) intersection++;\n const union = ta.size + tb.size - intersection;\n return union === 0 ? 0 : intersection / union;\n}\n\nconst STOP_WORDS = new Set([\n 'the', 'and', 'for', 'with', 'new', 'novel', 'build', 'using', 'from',\n 'into', 'over', 'onto', 'that', 'this', 'some', 'any',\n]);\n\n// ── Context Helpers ──────────────────────────────────────────────\n\n/**\n * Build the default context for a goal proposer run from current TITAN state.\n * Extracted so tests can construct contexts deterministically.\n */\nexport function buildDefaultContext(): GoalProposerContext {\n const activeGoals = listGoals('active').map(g => g.title);\n const failedSubtasks: string[] = [];\n for (const g of listGoals()) {\n for (const st of g.subtasks || []) {\n if (st.status === 'failed') failedSubtasks.push(`${g.title} → ${st.title}`);\n }\n }\n const recentActivity: string[] = [];\n try {\n const feed = getActivity({ limit: 50 });\n for (const entry of feed) {\n recentActivity.push(`[${entry.type}] ${entry.message}`);\n }\n } catch { /* feed may be unavailable in early boot */ }\n\n return {\n activeGoals,\n failedSubtasks: failedSubtasks.slice(0, 20),\n recentActivity,\n };\n}\n"],"mappings":"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","names":["listGoals"]}
|
|
1
|
+
{"version":3,"sources":["../../src/agent/goalProposer.ts"],"sourcesContent":["/**\n * TITAN — Self-Directed Goal Proposer\n *\n * Runs during the nightly dreaming cycle (Phase 4: Dream) after memory\n * consolidation has happened. Each registered agent examines recent activity,\n * open issues, failed subtasks, and consolidation findings, then proposes\n * 0-3 new goals it thinks would be worth doing.\n *\n * Proposals go into the Command Post approval queue as `type: 'goal_proposal'`.\n * A human (or designated approver agent) accepts or rejects them. On accept,\n * the existing createGoal() pipeline fires and Initiative picks up the work.\n *\n * Opt-in via config.agent.autoProposeGoals (default false).\n * Rate-limited per-agent via config.agent.proposalRateLimitPerDay.\n */\nimport { existsSync, readFileSync, writeFileSync } from 'fs';\nimport { join } from 'path';\nimport { TITAN_HOME } from '../utils/constants.js';\nimport { mkdirIfNotExists } from '../utils/helpers.js';\nimport { loadConfig } from '../config/config.js';\nimport { chat } from '../providers/router.js';\nimport { auxChat, resolveAuxiliaryModel } from '../providers/auxiliary.js';\nimport { applyOutputGuardrails } from './outputGuardrails.js';\nimport { getActivity, requestGoalProposalApproval, type CPApproval } from './commandPost.js';\nimport { listGoals } from './goals.js';\nimport logger from '../utils/logger.js';\n\nconst COMPONENT = 'GoalProposer';\nconst RATE_STATE_PATH = join(TITAN_HOME, 'goal-proposer-state.json');\n\n// ── Types ────────────────────────────────────────────────────────\n\nexport interface ProposedGoal {\n title: string;\n description: string;\n rationale: string;\n priority?: number;\n tags?: string[];\n parentGoalId?: string;\n subtasks?: Array<{ title: string; description: string; dependsOn?: string[] }>;\n}\n\nexport interface GoalProposerContext {\n /** Recent activity feed entries — max last 50. */\n recentActivity?: string[];\n /** Titles of currently active goals so proposals don't duplicate. */\n activeGoals?: string[];\n /** Titles of recently failed subtasks worth retrying or reframing. */\n failedSubtasks?: string[];\n /** Free-form notes from the dreaming consolidation log. */\n consolidationNotes?: string;\n /**\n * v4.9.0-local.4: extra prompt blocks (episodic recall, experiment\n * history, identity) pre-loaded by the caller. Keeps buildPrompt\n * synchronous.\n */\n extraBlocks?: string[];\n}\n\ninterface RateLimitState {\n /** Map of agentId → ISO timestamps of proposals filed in the last 24h. */\n proposalsByAgent: Record<string, string[]>;\n}\n\n// ── Rate Limiting ────────────────────────────────────────────────\n\nfunction loadRateState(): RateLimitState {\n if (!existsSync(RATE_STATE_PATH)) return { proposalsByAgent: {} };\n try {\n const raw = readFileSync(RATE_STATE_PATH, 'utf-8');\n const parsed = JSON.parse(raw) as Partial<RateLimitState>;\n // v4.9.0-local.6: defensive normalize. A prior bug (+ the goal-\n // reset script) can write `{}` to this file, losing the\n // `proposalsByAgent` key. Without this, every\n // `state.proposalsByAgent[agentId]` access crashes with\n // \"Cannot read properties of undefined (reading '<agent>')\"\n // and proposals silently fail for hours.\n return {\n proposalsByAgent: parsed?.proposalsByAgent ?? {},\n };\n } catch {\n return { proposalsByAgent: {} };\n }\n}\n\nfunction saveRateState(state: RateLimitState): void {\n try {\n mkdirIfNotExists(TITAN_HOME);\n writeFileSync(RATE_STATE_PATH, JSON.stringify(state, null, 2), 'utf-8');\n } catch (err) {\n logger.warn(COMPONENT, `Failed to save rate state: ${(err as Error).message}`);\n }\n}\n\n/** Returns how many slots the agent has remaining in the current 24h window. */\nexport function remainingSlots(agentId: string, limitPerDay: number): number {\n const state = loadRateState();\n const now = Date.now();\n const dayMs = 24 * 3600 * 1000;\n const stamps = (state.proposalsByAgent[agentId] || []).filter(t => now - new Date(t).getTime() < dayMs);\n return Math.max(0, limitPerDay - stamps.length);\n}\n\nfunction recordProposal(agentId: string): void {\n const state = loadRateState();\n const now = Date.now();\n const dayMs = 24 * 3600 * 1000;\n const existing = (state.proposalsByAgent[agentId] || []).filter(t => now - new Date(t).getTime() < dayMs);\n existing.push(new Date().toISOString());\n state.proposalsByAgent[agentId] = existing;\n saveRateState(state);\n}\n\n// ── Prompt ───────────────────────────────────────────────────────\n\nfunction buildPrompt(agentId: string, slotsLeft: number, ctx: GoalProposerContext): string {\n const sections: string[] = [];\n sections.push(`You are agent \"${agentId}\". You have been given a quiet window to reflect on the system's current state and propose new goals that would meaningfully help.`);\n sections.push(`You may propose 0 to ${slotsLeft} goals. It is OK — often preferable — to propose zero if nothing is clearly worth doing.`);\n sections.push('');\n\n if (ctx.activeGoals && ctx.activeGoals.length) {\n sections.push('## Currently Active Goals (do not duplicate)');\n for (const title of ctx.activeGoals.slice(0, 20)) sections.push(`- ${title}`);\n sections.push('');\n }\n if (ctx.recentActivity && ctx.recentActivity.length) {\n sections.push('## Recent Activity (last ~50 events)');\n for (const line of ctx.recentActivity.slice(-50)) sections.push(`- ${line}`);\n sections.push('');\n }\n if (ctx.failedSubtasks && ctx.failedSubtasks.length) {\n sections.push('## Recently Failed Subtasks');\n for (const title of ctx.failedSubtasks.slice(0, 20)) sections.push(`- ${title}`);\n sections.push('');\n }\n if (ctx.consolidationNotes) {\n sections.push('## Memory Consolidation Notes');\n sections.push(ctx.consolidationNotes);\n sections.push('');\n }\n\n // v4.9.0-local.4: extra memory blocks (episodic, experiments,\n // identity) pre-loaded by the async caller and passed through ctx.\n // Keeps buildPrompt synchronous while still giving the proposer\n // full context of what TITAN has already done + who it is.\n if (ctx.extraBlocks && ctx.extraBlocks.length > 0) {\n for (const block of ctx.extraBlocks) {\n if (block && block.trim()) {\n sections.push(block);\n sections.push('');\n }\n }\n }\n\n sections.push('## Output Format');\n sections.push('Return ONLY a JSON array (no prose, no markdown fences). Each element:');\n sections.push('```');\n sections.push('{');\n sections.push(' \"title\": \"short imperative, under 80 chars\",');\n sections.push(' \"description\": \"what success looks like, 1-3 sentences\",');\n sections.push(' \"rationale\": \"why this goal is worth doing NOW\",');\n sections.push(' \"priority\": 1-5 (1 = highest),');\n sections.push(' \"tags\": [\"optional\", \"labels\"],');\n sections.push(' \"subtasks\": [{\"title\": \"...\", \"description\": \"...\"}]');\n sections.push('}');\n sections.push('```');\n sections.push('If nothing is worth proposing, return `[]`. Never return more than the slot limit.');\n\n return sections.join('\\n');\n}\n\n/** JSON schema passed to Ollama's native structured-outputs `format` field.\n * Constrains the model to emit an array of proposal objects matching the\n * fields normalizeProposal() accepts. Belt-and-suspenders — the downstream\n * defensive parser is still the authoritative validator. */\nconst PROPOSAL_ARRAY_SCHEMA: Record<string, unknown> = {\n type: 'array',\n items: {\n type: 'object',\n required: ['title', 'description', 'rationale'],\n properties: {\n title: { type: 'string' },\n description: { type: 'string' },\n rationale: { type: 'string' },\n priority: { type: 'number' },\n tags: { type: 'array', items: { type: 'string' } },\n subtasks: {\n type: 'array',\n items: {\n type: 'object',\n required: ['title', 'description'],\n properties: {\n title: { type: 'string' },\n description: { type: 'string' },\n dependsOn: { type: 'array', items: { type: 'string' } },\n },\n },\n },\n },\n },\n};\n\n// ── JSON Extraction ──────────────────────────────────────────────\n\n/** Defensively parse a JSON array from LLM output. Returns [] on failure. */\nfunction extractProposalArray(raw: string): unknown[] {\n const trimmed = raw.trim();\n // Try direct parse first.\n try {\n const parsed = JSON.parse(trimmed);\n if (Array.isArray(parsed)) return parsed;\n } catch { /* fall through */ }\n // Strip code fences.\n const fenceStripped = trimmed.replace(/^```(?:json)?\\s*/i, '').replace(/\\s*```$/, '');\n try {\n const parsed = JSON.parse(fenceStripped);\n if (Array.isArray(parsed)) return parsed;\n } catch { /* fall through */ }\n // Find the first `[...]` substring.\n const match = trimmed.match(/\\[[\\s\\S]*\\]/);\n if (match) {\n try {\n const parsed = JSON.parse(match[0]);\n if (Array.isArray(parsed)) return parsed;\n } catch { /* give up */ }\n }\n return [];\n}\n\n/**\n * Exported for tests — normalizes a single raw LLM proposal into the\n * canonical ProposedGoal shape, OR returns null if it's filtered out\n * (malformed, or classified as self-mod while\n * `autonomy.selfMod.autoCreateGoals` is off).\n */\nexport function normalizeProposal(raw: unknown): ProposedGoal | null {\n if (!raw || typeof raw !== 'object') return null;\n const r = raw as Record<string, unknown>;\n let title = typeof r.title === 'string' ? r.title.trim() : '';\n let description = typeof r.description === 'string' ? r.description.trim() : '';\n const rationale = typeof r.rationale === 'string' ? r.rationale.trim() : '';\n if (!title || !description || !rationale) return null;\n if (title.length > 200 || description.length > 2000 || rationale.length > 2000) return null;\n\n const priority = typeof r.priority === 'number' && r.priority >= 1 && r.priority <= 5\n ? Math.floor(r.priority)\n : undefined;\n let tags: string[] | undefined = Array.isArray(r.tags)\n ? r.tags.filter((t): t is string => typeof t === 'string' && t.length < 40).slice(0, 6)\n : undefined;\n const parentGoalId = typeof r.parentGoalId === 'string' ? r.parentGoalId : undefined;\n\n type Subtask = { title: string; description: string; dependsOn?: string[] };\n let subtasks: Subtask[] | undefined;\n if (Array.isArray(r.subtasks)) {\n const collected: Subtask[] = [];\n for (const s of r.subtasks) {\n if (!s || typeof s !== 'object') continue;\n const rec = s as Record<string, unknown>;\n const t = typeof rec.title === 'string' ? rec.title.trim() : '';\n const d = typeof rec.description === 'string' ? rec.description.trim() : '';\n if (!t || !d) continue;\n const deps = Array.isArray(rec.dependsOn)\n ? rec.dependsOn.filter((x): x is string => typeof x === 'string')\n : undefined;\n // Subtask-level rewrite happens after we know the parent goal's\n // self-mod status (below), so stash refs.\n void t; void d;\n collected.push({ title: t, description: d, dependsOn: deps });\n if (collected.length >= 12) break;\n }\n if (collected.length > 0) subtasks = collected;\n }\n\n // v4.9.0-local.8: self-mod disambiguation. When the proposer emits a\n // goal that sounds like it wants to modify \"the framework\" / \"core\" /\n // etc, the specialist picking it up historically interpreted this as\n // \"build something under ~/titan-saas\" because that's where Next.js\n // project scaffolding lives. We close the ambiguity at creation time:\n //\n // 1. Detect self-mod trigger words in title + description + tags\n // 2. If matched, ensure tags include 'self-mod' so the toolRunner\n // scope-lock + staging gate activates for work on this goal\n // 3. Append an explicit scope-lock note to the description pointing\n // at the actual target path\n // 4. Rewrite common ambiguous phrases in subtasks to spell out the\n // target path\n const selfModTriggers = [\n /\\bself[\\s-]?heal/i,\n /\\bself[\\s-]?repair/i,\n /\\bself[\\s-]?mod/i,\n /\\bcore[\\s-]framework/i,\n /\\bTITAN['’]?s?\\s+(own|core|framework|architecture|source|runtime)/i,\n /\\bframework\\s+(component|module|core|runtime)/i,\n ];\n const selfModTagValues = new Set([\n 'self-healing', 'self-repair', 'self-mod', 'self-modification',\n 'core-framework', 'framework', 'architecture', 'core', 'autonomy',\n ]);\n const tagsLower = new Set((tags || []).map(t => t.toLowerCase()));\n const haystack = `${title}\\n${description}\\n${(tags || []).join(' ')}`;\n const matchedByText = selfModTriggers.some(re => re.test(haystack));\n const matchedByTag = [...tagsLower].some(t => selfModTagValues.has(t));\n const isSelfMod = matchedByText || matchedByTag;\n\n if (isSelfMod) {\n const cfg = loadConfig();\n // v6.0.3 — gate autonomous self-mod goal creation. When the flag is\n // off (default), we drop the proposal here BEFORE it reaches the\n // approval queue. The self-repair daemon's findings still surface\n // via the custom self_repair approval path; what we're suppressing\n // is the autonomous \"let's spin up a goal to rewrite the framework\"\n // path from the dreaming/Soma proposer. See schema.ts\n // autonomy.selfMod.autoCreateGoals for full rationale.\n const selfModBlock = cfg.autonomy?.selfMod as { target?: string; autoCreateGoals?: boolean } | undefined;\n const autoCreateGoals = selfModBlock?.autoCreateGoals === true;\n if (!autoCreateGoals) {\n logger.info(\n COMPONENT,\n `Dropping self-mod proposal \"${title.slice(0, 60)}\" — autonomy.selfMod.autoCreateGoals is disabled.`\n );\n return null;\n }\n const target = selfModBlock?.target || '/opt/TITAN';\n // Ensure the canonical 'self-mod' tag is present so toolRunner sees it\n tags = tags ? [...tags] : [];\n if (!tagsLower.has('self-mod')) tags.push('self-mod');\n tags = tags.slice(0, 6);\n\n // Append an unmistakable scope-lock note to the description — the\n // specialist reading this goal sees the target path explicitly\n // instead of having to infer \"the framework\" from context.\n const scopeNote = `\\n\\n[SCOPE-LOCK] This is a self-modification goal. All file writes MUST target ${target} (TITAN's own source tree). Writes to any other path will be refused by the toolRunner scope-lock. When staging is enabled, writes are diverted to ${target}/../self-mod-staging/<goalId>/ and surface as a self_mod_pr approval for human review before applying.`;\n if (!/\\[SCOPE-LOCK\\]/.test(description)) {\n description = (description + scopeNote).slice(0, 2000);\n }\n\n // Rewrite common ambiguous phrases in title/subtasks so the\n // specialist-level prompt mentions the target explicitly.\n const rewrite = (s: string): string => s\n .replace(/\\b(the\\s+)?core\\s+framework\\b/gi, `${target} (TITAN core framework)`)\n .replace(/\\b(the\\s+)?(TITAN\\s+)?framework\\b(?!\\s+component)/gi, `${target} (TITAN framework)`);\n title = rewrite(title).slice(0, 200);\n if (subtasks) {\n subtasks = subtasks.map(s => ({\n title: rewrite(s.title).slice(0, 200),\n description: rewrite(s.description).slice(0, 2000),\n dependsOn: s.dependsOn,\n }));\n }\n }\n\n return { title, description, rationale, priority, tags, parentGoalId, subtasks };\n}\n\n// ── Main Entry Point ─────────────────────────────────────────────\n\n/**\n * Generate goal proposals for a single agent and file them as pending approvals.\n * Returns the list of CPApproval records created (may be empty).\n *\n * Called by the dreaming watcher's Phase 4 (Dream). Safe to call ad-hoc from\n * debug endpoints or tests.\n */\nexport async function generateGoalProposals(\n agentId: string,\n ctx: GoalProposerContext,\n type: 'goal_proposal' | 'soma_proposal' = 'goal_proposal'\n): Promise<CPApproval[]> {\n const config = loadConfig();\n const enabled = config.agent.autoProposeGoals;\n if (!enabled) {\n logger.debug(COMPONENT, `autoProposeGoals disabled — skipping for agent ${agentId}`);\n return [];\n }\n\n const limit = config.agent.proposalRateLimitPerDay;\n const slotsLeft = remainingSlots(agentId, limit);\n if (slotsLeft <= 0) {\n logger.info(COMPONENT, `Agent ${agentId} has hit daily proposal limit (${limit}) — skipping`);\n return [];\n }\n\n const modelAlias = config.agent.proposalModel || 'fast';\n const model = config.agent.modelAliases[modelAlias] || modelAlias;\n\n // v4.9.0-local.4: pre-load extra memory blocks (episodic, experiments,\n // identity) before building the proposer prompt. Closes the repeat-\n // task feedback loop — the proposer now sees what TITAN has recently\n // done and won't re-propose the same ant colony sim three times.\n // Each block is best-effort; silent fallthrough if a module isn't\n // available at proposer time.\n const extraBlocks: string[] = [];\n try {\n const { renderRecallBlock } = await import('../memory/episodic.js');\n const block = renderRecallBlock({ limit: 12, windowHours: 72 });\n if (block) extraBlocks.push(block);\n } catch { /* ok */ }\n try {\n const { renderRecentExperimentsBlock } = await import('../memory/experiments.js');\n const block = renderRecentExperimentsBlock(8);\n if (block) extraBlocks.push(block);\n } catch { /* ok */ }\n try {\n const { getIdentity } = await import('../memory/identity.js');\n const id = getIdentity();\n if (id) {\n extraBlocks.push([\n '## Your identity (persistent)',\n `Mission: ${id.core.mission}`,\n `Non-negotiables: ${id.core.nonNegotiables.slice(0, 3).join('; ')}`,\n 'Propose ONLY goals that align with the mission and never violate a non-negotiable.',\n ].join('\\n'));\n }\n } catch { /* ok */ }\n\n const ctxWithBlocks: GoalProposerContext = { ...ctx, extraBlocks };\n const prompt = buildPrompt(agentId, slotsLeft, ctxWithBlocks);\n\n // v4.13 ancestor-extraction: route goal-proposal JSON extraction through\n // the auxiliary model client. The main agent model (gemma4:31b on the\n // Titan PC default) produces empty arrays for structured JSON tasks; a\n // dedicated fast+cheap model (minimax-m2.7:cloud) reliably produces valid\n // proposals. Falls back to the main `model` when no auxiliary is\n // configured.\n const auxModel = resolveAuxiliaryModel('json_extraction');\n const effectiveModel = auxModel || model;\n const isOllamaEffective = effectiveModel.toLowerCase().startsWith('ollama/');\n\n let rawContent: string;\n try {\n const response = await auxChat(\n 'json_extraction',\n {\n messages: [\n { role: 'system', content: 'You are a careful autonomous agent proposing new work. Output ONLY valid JSON. No explanation, no prose.' },\n { role: 'user', content: prompt },\n ],\n temperature: 0.4,\n maxTokens: 1500,\n ...(isOllamaEffective ? { format: PROPOSAL_ARRAY_SCHEMA } : {}),\n },\n model, // fallback to main agent model if no aux is configured\n );\n if (!response) {\n logger.warn(COMPONENT, `Auxiliary call returned null for agent ${agentId} — treating as no proposals`);\n return [];\n }\n rawContent = response.content || '';\n if (auxModel && auxModel !== model) {\n logger.info(COMPONENT, `Agent ${agentId} goal-proposal routed via auxiliary model ${auxModel} (main: ${model})`);\n }\n } catch (err) {\n logger.warn(COMPONENT, `LLM call failed for agent ${agentId}: ${(err as Error).message}`);\n return [];\n }\n\n // Strip chain-of-thought leakage before parsing JSON.\n const guarded = applyOutputGuardrails(rawContent, { type: 'sub_agent' });\n const parsed = extractProposalArray(guarded.content);\n if (parsed.length === 0) {\n logger.info(COMPONENT, `Agent ${agentId} proposed no goals (parsed empty array)`);\n return [];\n }\n\n const proposals: ProposedGoal[] = [];\n for (const item of parsed) {\n const normalized = normalizeProposal(item);\n if (normalized) proposals.push(normalized);\n if (proposals.length >= slotsLeft) break;\n }\n\n // v5.0.0: dedupe against ALL recent goals (not just active) and enforce\n // goal-overload backoff. Prevents the runaway loops that produced 1000+\n // duplicate \"Publish content\" goals.\n let allGoalTitles: string[] = [];\n let activeGoalCount = 0;\n try {\n const { listGoals } = await import('./goals.js');\n const all = listGoals();\n allGoalTitles = all.map(g => g.title);\n activeGoalCount = all.filter(g => g.status === 'active').length;\n } catch { /* best-effort */ }\n\n // Overload backoff: if the system is already swamped, only allow\n // cleanup / meta proposals (titles containing \"resolve\", \"cancel\",\n // \"close\", \"audit\", \"clean\", \"dedupe\"). Everything else is deferred\n // until the backlog drops.\n const isOverload = activeGoalCount >= 25;\n const isCleanupProposal = (t: string) => /\\b(resolve|cancel|close|audit|clean|dedupe|consolidate|prune)\\b/i.test(t);\n\n const approvals: CPApproval[] = [];\n for (const proposal of proposals) {\n // Dedupe against ANY existing goal (active, paused, completed, failed)\n const dup = allGoalTitles.find(t => titleSimilarity(t, proposal.title) >= 0.72);\n if (dup) {\n logger.info(COMPONENT, `Agent ${agentId} skipped duplicate proposal \"${proposal.title}\" (matches existing goal \"${dup}\")`);\n continue;\n }\n // Overload gate\n if (isOverload && !isCleanupProposal(proposal.title)) {\n logger.info(COMPONENT, `Agent ${agentId} skipped proposal \"${proposal.title}\" — goal overload (${activeGoalCount} active). Only cleanup proposals allowed.`);\n continue;\n }\n try {\n const approval = requestGoalProposalApproval(agentId, proposal, type);\n approvals.push(approval);\n recordProposal(agentId);\n allGoalTitles.push(proposal.title); // prevent intra-batch dupes too\n logger.info(COMPONENT, `Agent ${agentId} filed proposal \"${proposal.title}\" (approval ${approval.id})`);\n } catch (err) {\n logger.warn(COMPONENT, `Failed to file proposal \"${proposal.title}\": ${(err as Error).message}`);\n }\n }\n\n return approvals;\n}\n\n/**\n * v4.5.6: simple title similarity for dedupe. Normalizes case, strips\n * filler words, compares token overlap (Jaccard). 0.72 threshold catches\n * \"Satiate Hunger\" vs \"Satiate hunger\" vs \"Satiate hunger backlog\"\n * but not \"Satiate Purpose\" vs \"Satiate hunger\" — which is what we want.\n */\nfunction titleSimilarity(a: string, b: string): number {\n const tokenize = (s: string) => new Set(\n s.toLowerCase()\n .replace(/[^\\w\\s]/g, ' ')\n .split(/\\s+/)\n .filter(w => w.length > 2 && !STOP_WORDS.has(w))\n );\n const ta = tokenize(a);\n const tb = tokenize(b);\n if (ta.size === 0 || tb.size === 0) return 0;\n let intersection = 0;\n for (const t of ta) if (tb.has(t)) intersection++;\n const union = ta.size + tb.size - intersection;\n return union === 0 ? 0 : intersection / union;\n}\n\nconst STOP_WORDS = new Set([\n 'the', 'and', 'for', 'with', 'new', 'novel', 'build', 'using', 'from',\n 'into', 'over', 'onto', 'that', 'this', 'some', 'any',\n]);\n\n// ── Context Helpers ──────────────────────────────────────────────\n\n/**\n * Build the default context for a goal proposer run from current TITAN state.\n * Extracted so tests can construct contexts deterministically.\n */\nexport function buildDefaultContext(): GoalProposerContext {\n const activeGoals = listGoals('active').map(g => g.title);\n const failedSubtasks: string[] = [];\n for (const g of listGoals()) {\n for (const st of g.subtasks || []) {\n if (st.status === 'failed') failedSubtasks.push(`${g.title} → ${st.title}`);\n }\n }\n const recentActivity: string[] = [];\n try {\n const feed = getActivity({ limit: 50 });\n for (const entry of feed) {\n recentActivity.push(`[${entry.type}] ${entry.message}`);\n }\n } catch { /* feed may be unavailable in early boot */ }\n\n return {\n activeGoals,\n failedSubtasks: failedSubtasks.slice(0, 20),\n recentActivity,\n };\n}\n"],"mappings":";AAeA,SAAS,YAAY,cAAc,qBAAqB;AACxD,SAAS,YAAY;AACrB,SAAS,kBAAkB;AAC3B,SAAS,wBAAwB;AACjC,SAAS,kBAAkB;AAE3B,SAAS,SAAS,6BAA6B;AAC/C,SAAS,6BAA6B;AACtC,SAAS,aAAa,mCAAoD;AAC1E,SAAS,iBAAiB;AAC1B,OAAO,YAAY;AAEnB,MAAM,YAAY;AAClB,MAAM,kBAAkB,KAAK,YAAY,0BAA0B;AAsCnE,SAAS,gBAAgC;AACrC,MAAI,CAAC,WAAW,eAAe,EAAG,QAAO,EAAE,kBAAkB,CAAC,EAAE;AAChE,MAAI;AACA,UAAM,MAAM,aAAa,iBAAiB,OAAO;AACjD,UAAM,SAAS,KAAK,MAAM,GAAG;AAO7B,WAAO;AAAA,MACH,kBAAkB,QAAQ,oBAAoB,CAAC;AAAA,IACnD;AAAA,EACJ,QAAQ;AACJ,WAAO,EAAE,kBAAkB,CAAC,EAAE;AAAA,EAClC;AACJ;AAEA,SAAS,cAAc,OAA6B;AAChD,MAAI;AACA,qBAAiB,UAAU;AAC3B,kBAAc,iBAAiB,KAAK,UAAU,OAAO,MAAM,CAAC,GAAG,OAAO;AAAA,EAC1E,SAAS,KAAK;AACV,WAAO,KAAK,WAAW,8BAA+B,IAAc,OAAO,EAAE;AAAA,EACjF;AACJ;AAGO,SAAS,eAAe,SAAiB,aAA6B;AACzE,QAAM,QAAQ,cAAc;AAC5B,QAAM,MAAM,KAAK,IAAI;AACrB,QAAM,QAAQ,KAAK,OAAO;AAC1B,QAAM,UAAU,MAAM,iBAAiB,OAAO,KAAK,CAAC,GAAG,OAAO,OAAK,MAAM,IAAI,KAAK,CAAC,EAAE,QAAQ,IAAI,KAAK;AACtG,SAAO,KAAK,IAAI,GAAG,cAAc,OAAO,MAAM;AAClD;AAEA,SAAS,eAAe,SAAuB;AAC3C,QAAM,QAAQ,cAAc;AAC5B,QAAM,MAAM,KAAK,IAAI;AACrB,QAAM,QAAQ,KAAK,OAAO;AAC1B,QAAM,YAAY,MAAM,iBAAiB,OAAO,KAAK,CAAC,GAAG,OAAO,OAAK,MAAM,IAAI,KAAK,CAAC,EAAE,QAAQ,IAAI,KAAK;AACxG,WAAS,MAAK,oBAAI,KAAK,GAAE,YAAY,CAAC;AACtC,QAAM,iBAAiB,OAAO,IAAI;AAClC,gBAAc,KAAK;AACvB;AAIA,SAAS,YAAY,SAAiB,WAAmB,KAAkC;AACvF,QAAM,WAAqB,CAAC;AAC5B,WAAS,KAAK,kBAAkB,OAAO,oIAAoI;AAC3K,WAAS,KAAK,wBAAwB,SAAS,oGAA0F;AACzI,WAAS,KAAK,EAAE;AAEhB,MAAI,IAAI,eAAe,IAAI,YAAY,QAAQ;AAC3C,aAAS,KAAK,8CAA8C;AAC5D,eAAW,SAAS,IAAI,YAAY,MAAM,GAAG,EAAE,EAAG,UAAS,KAAK,KAAK,KAAK,EAAE;AAC5E,aAAS,KAAK,EAAE;AAAA,EACpB;AACA,MAAI,IAAI,kBAAkB,IAAI,eAAe,QAAQ;AACjD,aAAS,KAAK,sCAAsC;AACpD,eAAW,QAAQ,IAAI,eAAe,MAAM,GAAG,EAAG,UAAS,KAAK,KAAK,IAAI,EAAE;AAC3E,aAAS,KAAK,EAAE;AAAA,EACpB;AACA,MAAI,IAAI,kBAAkB,IAAI,eAAe,QAAQ;AACjD,aAAS,KAAK,6BAA6B;AAC3C,eAAW,SAAS,IAAI,eAAe,MAAM,GAAG,EAAE,EAAG,UAAS,KAAK,KAAK,KAAK,EAAE;AAC/E,aAAS,KAAK,EAAE;AAAA,EACpB;AACA,MAAI,IAAI,oBAAoB;AACxB,aAAS,KAAK,+BAA+B;AAC7C,aAAS,KAAK,IAAI,kBAAkB;AACpC,aAAS,KAAK,EAAE;AAAA,EACpB;AAMA,MAAI,IAAI,eAAe,IAAI,YAAY,SAAS,GAAG;AAC/C,eAAW,SAAS,IAAI,aAAa;AACjC,UAAI,SAAS,MAAM,KAAK,GAAG;AACvB,iBAAS,KAAK,KAAK;AACnB,iBAAS,KAAK,EAAE;AAAA,MACpB;AAAA,IACJ;AAAA,EACJ;AAEA,WAAS,KAAK,kBAAkB;AAChC,WAAS,KAAK,wEAAwE;AACtF,WAAS,KAAK,KAAK;AACnB,WAAS,KAAK,GAAG;AACjB,WAAS,KAAK,gDAAgD;AAC9D,WAAS,KAAK,4DAA4D;AAC1E,WAAS,KAAK,oDAAoD;AAClE,WAAS,KAAK,kCAAkC;AAChD,WAAS,KAAK,mCAAmC;AACjD,WAAS,KAAK,wDAAwD;AACtE,WAAS,KAAK,GAAG;AACjB,WAAS,KAAK,KAAK;AACnB,WAAS,KAAK,oFAAoF;AAElG,SAAO,SAAS,KAAK,IAAI;AAC7B;AAMA,MAAM,wBAAiD;AAAA,EACnD,MAAM;AAAA,EACN,OAAO;AAAA,IACH,MAAM;AAAA,IACN,UAAU,CAAC,SAAS,eAAe,WAAW;AAAA,IAC9C,YAAY;AAAA,MACR,OAAO,EAAE,MAAM,SAAS;AAAA,MACxB,aAAa,EAAE,MAAM,SAAS;AAAA,MAC9B,WAAW,EAAE,MAAM,SAAS;AAAA,MAC5B,UAAU,EAAE,MAAM,SAAS;AAAA,MAC3B,MAAM,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,SAAS,EAAE;AAAA,MACjD,UAAU;AAAA,QACN,MAAM;AAAA,QACN,OAAO;AAAA,UACH,MAAM;AAAA,UACN,UAAU,CAAC,SAAS,aAAa;AAAA,UACjC,YAAY;AAAA,YACR,OAAO,EAAE,MAAM,SAAS;AAAA,YACxB,aAAa,EAAE,MAAM,SAAS;AAAA,YAC9B,WAAW,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,SAAS,EAAE;AAAA,UAC1D;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AACJ;AAKA,SAAS,qBAAqB,KAAwB;AAClD,QAAM,UAAU,IAAI,KAAK;AAEzB,MAAI;AACA,UAAM,SAAS,KAAK,MAAM,OAAO;AACjC,QAAI,MAAM,QAAQ,MAAM,EAAG,QAAO;AAAA,EACtC,QAAQ;AAAA,EAAqB;AAE7B,QAAM,gBAAgB,QAAQ,QAAQ,qBAAqB,EAAE,EAAE,QAAQ,WAAW,EAAE;AACpF,MAAI;AACA,UAAM,SAAS,KAAK,MAAM,aAAa;AACvC,QAAI,MAAM,QAAQ,MAAM,EAAG,QAAO;AAAA,EACtC,QAAQ;AAAA,EAAqB;AAE7B,QAAM,QAAQ,QAAQ,MAAM,aAAa;AACzC,MAAI,OAAO;AACP,QAAI;AACA,YAAM,SAAS,KAAK,MAAM,MAAM,CAAC,CAAC;AAClC,UAAI,MAAM,QAAQ,MAAM,EAAG,QAAO;AAAA,IACtC,QAAQ;AAAA,IAAgB;AAAA,EAC5B;AACA,SAAO,CAAC;AACZ;AAQO,SAAS,kBAAkB,KAAmC;AACjE,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,QAAM,IAAI;AACV,MAAI,QAAQ,OAAO,EAAE,UAAU,WAAW,EAAE,MAAM,KAAK,IAAI;AAC3D,MAAI,cAAc,OAAO,EAAE,gBAAgB,WAAW,EAAE,YAAY,KAAK,IAAI;AAC7E,QAAM,YAAY,OAAO,EAAE,cAAc,WAAW,EAAE,UAAU,KAAK,IAAI;AACzE,MAAI,CAAC,SAAS,CAAC,eAAe,CAAC,UAAW,QAAO;AACjD,MAAI,MAAM,SAAS,OAAO,YAAY,SAAS,OAAQ,UAAU,SAAS,IAAM,QAAO;AAEvF,QAAM,WAAW,OAAO,EAAE,aAAa,YAAY,EAAE,YAAY,KAAK,EAAE,YAAY,IAC9E,KAAK,MAAM,EAAE,QAAQ,IACrB;AACN,MAAI,OAA6B,MAAM,QAAQ,EAAE,IAAI,IAC/C,EAAE,KAAK,OAAO,CAAC,MAAmB,OAAO,MAAM,YAAY,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,IACpF;AACN,QAAM,eAAe,OAAO,EAAE,iBAAiB,WAAW,EAAE,eAAe;AAG3E,MAAI;AACJ,MAAI,MAAM,QAAQ,EAAE,QAAQ,GAAG;AAC3B,UAAM,YAAuB,CAAC;AAC9B,eAAW,KAAK,EAAE,UAAU;AACxB,UAAI,CAAC,KAAK,OAAO,MAAM,SAAU;AACjC,YAAM,MAAM;AACZ,YAAM,IAAI,OAAO,IAAI,UAAU,WAAW,IAAI,MAAM,KAAK,IAAI;AAC7D,YAAM,IAAI,OAAO,IAAI,gBAAgB,WAAW,IAAI,YAAY,KAAK,IAAI;AACzE,UAAI,CAAC,KAAK,CAAC,EAAG;AACd,YAAM,OAAO,MAAM,QAAQ,IAAI,SAAS,IAClC,IAAI,UAAU,OAAO,CAAC,MAAmB,OAAO,MAAM,QAAQ,IAC9D;AAGN,WAAK;AAAG,WAAK;AACb,gBAAU,KAAK,EAAE,OAAO,GAAG,aAAa,GAAG,WAAW,KAAK,CAAC;AAC5D,UAAI,UAAU,UAAU,GAAI;AAAA,IAChC;AACA,QAAI,UAAU,SAAS,EAAG,YAAW;AAAA,EACzC;AAeA,QAAM,kBAAkB;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACJ;AACA,QAAM,mBAAmB,oBAAI,IAAI;AAAA,IAC7B;AAAA,IAAgB;AAAA,IAAe;AAAA,IAAY;AAAA,IAC3C;AAAA,IAAkB;AAAA,IAAa;AAAA,IAAgB;AAAA,IAAQ;AAAA,EAC3D,CAAC;AACD,QAAM,YAAY,IAAI,KAAK,QAAQ,CAAC,GAAG,IAAI,OAAK,EAAE,YAAY,CAAC,CAAC;AAChE,QAAM,WAAW,GAAG,KAAK;AAAA,EAAK,WAAW;AAAA,GAAM,QAAQ,CAAC,GAAG,KAAK,GAAG,CAAC;AACpE,QAAM,gBAAgB,gBAAgB,KAAK,QAAM,GAAG,KAAK,QAAQ,CAAC;AAClE,QAAM,eAAe,CAAC,GAAG,SAAS,EAAE,KAAK,OAAK,iBAAiB,IAAI,CAAC,CAAC;AACrE,QAAM,YAAY,iBAAiB;AAEnC,MAAI,WAAW;AACX,UAAM,MAAM,WAAW;AAQvB,UAAM,eAAe,IAAI,UAAU;AACnC,UAAM,kBAAkB,cAAc,oBAAoB;AAC1D,QAAI,CAAC,iBAAiB;AAClB,aAAO;AAAA,QACH;AAAA,QACA,+BAA+B,MAAM,MAAM,GAAG,EAAE,CAAC;AAAA,MACrD;AACA,aAAO;AAAA,IACX;AACA,UAAM,SAAS,cAAc,UAAU;AAEvC,WAAO,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC;AAC3B,QAAI,CAAC,UAAU,IAAI,UAAU,EAAG,MAAK,KAAK,UAAU;AACpD,WAAO,KAAK,MAAM,GAAG,CAAC;AAKtB,UAAM,YAAY;AAAA;AAAA,6EAAkF,MAAM,sJAAsJ,MAAM;AACtQ,QAAI,CAAC,iBAAiB,KAAK,WAAW,GAAG;AACrC,qBAAe,cAAc,WAAW,MAAM,GAAG,GAAI;AAAA,IACzD;AAIA,UAAM,UAAU,CAAC,MAAsB,EAClC,QAAQ,mCAAmC,GAAG,MAAM,yBAAyB,EAC7E,QAAQ,uDAAuD,GAAG,MAAM,oBAAoB;AACjG,YAAQ,QAAQ,KAAK,EAAE,MAAM,GAAG,GAAG;AACnC,QAAI,UAAU;AACV,iBAAW,SAAS,IAAI,QAAM;AAAA,QAC1B,OAAO,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG;AAAA,QACpC,aAAa,QAAQ,EAAE,WAAW,EAAE,MAAM,GAAG,GAAI;AAAA,QACjD,WAAW,EAAE;AAAA,MACjB,EAAE;AAAA,IACN;AAAA,EACJ;AAEA,SAAO,EAAE,OAAO,aAAa,WAAW,UAAU,MAAM,cAAc,SAAS;AACnF;AAWA,eAAsB,sBAClB,SACA,KACA,OAA0C,iBACrB;AACrB,QAAM,SAAS,WAAW;AAC1B,QAAM,UAAU,OAAO,MAAM;AAC7B,MAAI,CAAC,SAAS;AACV,WAAO,MAAM,WAAW,uDAAkD,OAAO,EAAE;AACnF,WAAO,CAAC;AAAA,EACZ;AAEA,QAAM,QAAQ,OAAO,MAAM;AAC3B,QAAM,YAAY,eAAe,SAAS,KAAK;AAC/C,MAAI,aAAa,GAAG;AAChB,WAAO,KAAK,WAAW,SAAS,OAAO,kCAAkC,KAAK,mBAAc;AAC5F,WAAO,CAAC;AAAA,EACZ;AAEA,QAAM,aAAa,OAAO,MAAM,iBAAiB;AACjD,QAAM,QAAQ,OAAO,MAAM,aAAa,UAAU,KAAK;AAQvD,QAAM,cAAwB,CAAC;AAC/B,MAAI;AACA,UAAM,EAAE,kBAAkB,IAAI,MAAM,OAAO,uBAAuB;AAClE,UAAM,QAAQ,kBAAkB,EAAE,OAAO,IAAI,aAAa,GAAG,CAAC;AAC9D,QAAI,MAAO,aAAY,KAAK,KAAK;AAAA,EACrC,QAAQ;AAAA,EAAW;AACnB,MAAI;AACA,UAAM,EAAE,6BAA6B,IAAI,MAAM,OAAO,0BAA0B;AAChF,UAAM,QAAQ,6BAA6B,CAAC;AAC5C,QAAI,MAAO,aAAY,KAAK,KAAK;AAAA,EACrC,QAAQ;AAAA,EAAW;AACnB,MAAI;AACA,UAAM,EAAE,YAAY,IAAI,MAAM,OAAO,uBAAuB;AAC5D,UAAM,KAAK,YAAY;AACvB,QAAI,IAAI;AACJ,kBAAY,KAAK;AAAA,QACb;AAAA,QACA,YAAY,GAAG,KAAK,OAAO;AAAA,QAC3B,oBAAoB,GAAG,KAAK,eAAe,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,QACjE;AAAA,MACJ,EAAE,KAAK,IAAI,CAAC;AAAA,IAChB;AAAA,EACJ,QAAQ;AAAA,EAAW;AAEnB,QAAM,gBAAqC,EAAE,GAAG,KAAK,YAAY;AACjE,QAAM,SAAS,YAAY,SAAS,WAAW,aAAa;AAQ5D,QAAM,WAAW,sBAAsB,iBAAiB;AACxD,QAAM,iBAAiB,YAAY;AACnC,QAAM,oBAAoB,eAAe,YAAY,EAAE,WAAW,SAAS;AAE3E,MAAI;AACJ,MAAI;AACA,UAAM,WAAW,MAAM;AAAA,MACnB;AAAA,MACA;AAAA,QACI,UAAU;AAAA,UACN,EAAE,MAAM,UAAU,SAAS,2GAA2G;AAAA,UACtI,EAAE,MAAM,QAAQ,SAAS,OAAO;AAAA,QACpC;AAAA,QACA,aAAa;AAAA,QACb,WAAW;AAAA,QACX,GAAI,oBAAoB,EAAE,QAAQ,sBAAsB,IAAI,CAAC;AAAA,MACjE;AAAA,MACA;AAAA;AAAA,IACJ;AACA,QAAI,CAAC,UAAU;AACX,aAAO,KAAK,WAAW,0CAA0C,OAAO,kCAA6B;AACrG,aAAO,CAAC;AAAA,IACZ;AACA,iBAAa,SAAS,WAAW;AACjC,QAAI,YAAY,aAAa,OAAO;AAChC,aAAO,KAAK,WAAW,SAAS,OAAO,6CAA6C,QAAQ,WAAW,KAAK,GAAG;AAAA,IACnH;AAAA,EACJ,SAAS,KAAK;AACV,WAAO,KAAK,WAAW,6BAA6B,OAAO,KAAM,IAAc,OAAO,EAAE;AACxF,WAAO,CAAC;AAAA,EACZ;AAGA,QAAM,UAAU,sBAAsB,YAAY,EAAE,MAAM,YAAY,CAAC;AACvE,QAAM,SAAS,qBAAqB,QAAQ,OAAO;AACnD,MAAI,OAAO,WAAW,GAAG;AACrB,WAAO,KAAK,WAAW,SAAS,OAAO,yCAAyC;AAChF,WAAO,CAAC;AAAA,EACZ;AAEA,QAAM,YAA4B,CAAC;AACnC,aAAW,QAAQ,QAAQ;AACvB,UAAM,aAAa,kBAAkB,IAAI;AACzC,QAAI,WAAY,WAAU,KAAK,UAAU;AACzC,QAAI,UAAU,UAAU,UAAW;AAAA,EACvC;AAKA,MAAI,gBAA0B,CAAC;AAC/B,MAAI,kBAAkB;AACtB,MAAI;AACA,UAAM,EAAE,WAAAA,WAAU,IAAI,MAAM,OAAO,YAAY;AAC/C,UAAM,MAAMA,WAAU;AACtB,oBAAgB,IAAI,IAAI,OAAK,EAAE,KAAK;AACpC,sBAAkB,IAAI,OAAO,OAAK,EAAE,WAAW,QAAQ,EAAE;AAAA,EAC7D,QAAQ;AAAA,EAAoB;AAM5B,QAAM,aAAa,mBAAmB;AACtC,QAAM,oBAAoB,CAAC,MAAc,mEAAmE,KAAK,CAAC;AAElH,QAAM,YAA0B,CAAC;AACjC,aAAW,YAAY,WAAW;AAE9B,UAAM,MAAM,cAAc,KAAK,OAAK,gBAAgB,GAAG,SAAS,KAAK,KAAK,IAAI;AAC9E,QAAI,KAAK;AACL,aAAO,KAAK,WAAW,SAAS,OAAO,gCAAgC,SAAS,KAAK,6BAA6B,GAAG,IAAI;AACzH;AAAA,IACJ;AAEA,QAAI,cAAc,CAAC,kBAAkB,SAAS,KAAK,GAAG;AAClD,aAAO,KAAK,WAAW,SAAS,OAAO,sBAAsB,SAAS,KAAK,2BAAsB,eAAe,2CAA2C;AAC3J;AAAA,IACJ;AACA,QAAI;AACA,YAAM,WAAW,4BAA4B,SAAS,UAAU,IAAI;AACpE,gBAAU,KAAK,QAAQ;AACvB,qBAAe,OAAO;AACtB,oBAAc,KAAK,SAAS,KAAK;AACjC,aAAO,KAAK,WAAW,SAAS,OAAO,oBAAoB,SAAS,KAAK,eAAe,SAAS,EAAE,GAAG;AAAA,IAC1G,SAAS,KAAK;AACV,aAAO,KAAK,WAAW,4BAA4B,SAAS,KAAK,MAAO,IAAc,OAAO,EAAE;AAAA,IACnG;AAAA,EACJ;AAEA,SAAO;AACX;AAQA,SAAS,gBAAgB,GAAW,GAAmB;AACnD,QAAM,WAAW,CAAC,MAAc,IAAI;AAAA,IAChC,EAAE,YAAY,EACT,QAAQ,YAAY,GAAG,EACvB,MAAM,KAAK,EACX,OAAO,OAAK,EAAE,SAAS,KAAK,CAAC,WAAW,IAAI,CAAC,CAAC;AAAA,EACvD;AACA,QAAM,KAAK,SAAS,CAAC;AACrB,QAAM,KAAK,SAAS,CAAC;AACrB,MAAI,GAAG,SAAS,KAAK,GAAG,SAAS,EAAG,QAAO;AAC3C,MAAI,eAAe;AACnB,aAAW,KAAK,GAAI,KAAI,GAAG,IAAI,CAAC,EAAG;AACnC,QAAM,QAAQ,GAAG,OAAO,GAAG,OAAO;AAClC,SAAO,UAAU,IAAI,IAAI,eAAe;AAC5C;AAEA,MAAM,aAAa,oBAAI,IAAI;AAAA,EACvB;AAAA,EAAO;AAAA,EAAO;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAS;AAAA,EAAS;AAAA,EAAS;AAAA,EAC/D;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAQ;AACpD,CAAC;AAQM,SAAS,sBAA2C;AACvD,QAAM,cAAc,UAAU,QAAQ,EAAE,IAAI,OAAK,EAAE,KAAK;AACxD,QAAM,iBAA2B,CAAC;AAClC,aAAW,KAAK,UAAU,GAAG;AACzB,eAAW,MAAM,EAAE,YAAY,CAAC,GAAG;AAC/B,UAAI,GAAG,WAAW,SAAU,gBAAe,KAAK,GAAG,EAAE,KAAK,WAAM,GAAG,KAAK,EAAE;AAAA,IAC9E;AAAA,EACJ;AACA,QAAM,iBAA2B,CAAC;AAClC,MAAI;AACA,UAAM,OAAO,YAAY,EAAE,OAAO,GAAG,CAAC;AACtC,eAAW,SAAS,MAAM;AACtB,qBAAe,KAAK,IAAI,MAAM,IAAI,KAAK,MAAM,OAAO,EAAE;AAAA,IAC1D;AAAA,EACJ,QAAQ;AAAA,EAA8C;AAEtD,SAAO;AAAA,IACH;AAAA,IACA,gBAAgB,eAAe,MAAM,GAAG,EAAE;AAAA,IAC1C;AAAA,EACJ;AACJ;","names":["listGoals"]}
|
package/dist/config/schema.js
CHANGED
|
@@ -768,6 +768,27 @@ const TitanConfigSchema = z.object({
|
|
|
768
768
|
* directly (scope-lock still enforces target prefix).
|
|
769
769
|
*/
|
|
770
770
|
staging: z.boolean().default(true),
|
|
771
|
+
/**
|
|
772
|
+
* v6.0.3 — Self-repair goal-creation gate.
|
|
773
|
+
*
|
|
774
|
+
* When false (default), the goal proposer drops any autonomously
|
|
775
|
+
* generated proposal that classifies as self-mod / self-repair /
|
|
776
|
+
* framework-modification work before it reaches the approval
|
|
777
|
+
* queue. The self-repair daemon still surfaces *findings* via
|
|
778
|
+
* `custom`-type `self_repair` approvals (so Tony sees what's
|
|
779
|
+
* wrong), but TITAN will not spin up new active goals to "fix
|
|
780
|
+
* itself" without explicit opt-in.
|
|
781
|
+
*
|
|
782
|
+
* Why off by default: in v6.0.2 we observed the Soma pressure
|
|
783
|
+
* loop + dreaming proposer cooperating to spawn 7 simultaneous
|
|
784
|
+
* "rewrite the framework" goals that recursed on each other,
|
|
785
|
+
* filling the active mission queue with self-referential
|
|
786
|
+
* busywork. This was real autonomy, but in the wrong direction.
|
|
787
|
+
*
|
|
788
|
+
* Set true to restore prior behavior (autonomous self-repair
|
|
789
|
+
* goal creation enabled).
|
|
790
|
+
*/
|
|
791
|
+
autoCreateGoals: z.boolean().default(false),
|
|
771
792
|
/**
|
|
772
793
|
* Directory for staged self-mod bundles. Each approved goal
|
|
773
794
|
* gets its own subdir. Relative paths resolve under TITAN_HOME.
|