@jaimevalasek/aioson 1.4.0 → 1.6.0
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/CHANGELOG.md +31 -1
- package/LICENSE +661 -21
- package/README.md +9 -1
- package/docs/design-previews/aurora-command-ui-website.html +884 -0
- package/docs/design-previews/aurora-command-ui.html +682 -0
- package/docs/design-previews/bold-editorial-ui-website.html +658 -0
- package/docs/design-previews/bold-editorial-ui.html +717 -0
- package/docs/design-previews/clean-saas-ui-website.html +1202 -0
- package/docs/design-previews/clean-saas-ui.html +549 -0
- package/docs/design-previews/cognitive-core-ui-website.html +1009 -0
- package/docs/design-previews/cognitive-core-ui.html +463 -0
- package/docs/design-previews/glassmorphism-ui-website.html +572 -0
- package/docs/design-previews/glassmorphism-ui.html +886 -0
- package/docs/design-previews/index.html +699 -0
- package/docs/design-previews/interface-design-website.html +1187 -0
- package/docs/design-previews/interface-design.html +513 -0
- package/docs/design-previews/neo-brutalist-ui-website.html +621 -0
- package/docs/design-previews/neo-brutalist-ui.html +797 -0
- package/docs/design-previews/premium-command-center-ui-website.html +1217 -0
- package/docs/design-previews/premium-command-center-ui.html +552 -0
- package/docs/design-previews/warm-craft-ui-website.html +684 -0
- package/docs/design-previews/warm-craft-ui.html +739 -0
- package/docs/en/cli-reference.md +20 -9
- package/docs/en/squad-dashboard.md +372 -0
- package/docs/openclaw-bridge.md +308 -0
- package/docs/pt/README.md +7 -0
- package/docs/pt/agent-sharding.md +132 -0
- package/docs/pt/agentes.md +131 -11
- package/docs/pt/busca-de-contexto.md +129 -0
- package/docs/pt/cache-de-contexto.md +156 -0
- package/docs/pt/cenarios.md +46 -2
- package/docs/pt/comandos-cli.md +88 -1
- package/docs/pt/design-hybrid-forge.md +107 -0
- package/docs/pt/inicio-rapido.md +72 -5
- package/docs/pt/inteligencia-adaptativa.md +324 -0
- package/docs/pt/monitor-de-contexto.md +104 -0
- package/docs/pt/recuperacao-de-sessao.md +125 -0
- package/docs/pt/sandbox.md +125 -0
- package/docs/pt/skills.md +98 -6
- package/docs/pt/squad-dashboard.md +373 -0
- package/docs/testing/genome-2.0-matrix.md +5 -5
- package/docs/testing/genome-2.0-rollout.md +9 -9
- package/package.json +2 -2
- package/src/agent-loader.js +280 -0
- package/src/backup-local.js +74 -0
- package/src/cli.js +192 -0
- package/src/commands/agent-loader.js +85 -0
- package/src/commands/backup-local-cmd.js +25 -0
- package/src/commands/context-cache.js +90 -0
- package/src/commands/context-monitor.js +92 -0
- package/src/commands/context-search.js +66 -0
- package/src/commands/design-hybrid-options.js +385 -0
- package/src/commands/health.js +214 -0
- package/src/commands/init.js +54 -13
- package/src/commands/install.js +52 -13
- package/src/commands/learning-evolve.js +355 -0
- package/src/commands/live.js +34 -0
- package/src/commands/recovery.js +43 -0
- package/src/commands/runtime.js +242 -0
- package/src/commands/sandbox.js +37 -0
- package/src/commands/setup-context.js +29 -4
- package/src/commands/setup.js +178 -0
- package/src/commands/skill.js +79 -32
- package/src/commands/squad-daemon.js +209 -0
- package/src/commands/squad-dashboard.js +39 -0
- package/src/commands/squad-deploy.js +64 -0
- package/src/commands/squad-doctor.js +52 -0
- package/src/commands/squad-mcp.js +270 -0
- package/src/commands/squad-processes.js +56 -0
- package/src/commands/squad-recovery.js +42 -0
- package/src/commands/squad-roi.js +291 -0
- package/src/commands/squad-score.js +250 -0
- package/src/commands/squad-status.js +37 -1
- package/src/commands/squad-validate.js +62 -1
- package/src/commands/squad-webhook.js +160 -0
- package/src/commands/squad-worker.js +191 -0
- package/src/commands/squad-worktrees.js +75 -0
- package/src/commands/tool-registry-cmd.js +232 -0
- package/src/commands/update.js +7 -0
- package/src/commands/web-map.js +70 -0
- package/src/commands/web-scrape.js +71 -0
- package/src/constants.js +17 -0
- package/src/context-cache.js +159 -0
- package/src/context-search.js +326 -0
- package/src/context-writer.js +45 -1
- package/src/design-variation-catalog.js +503 -0
- package/src/i18n/messages/en.js +159 -3
- package/src/i18n/messages/es.js +147 -2
- package/src/i18n/messages/fr.js +147 -2
- package/src/i18n/messages/pt-BR.js +158 -3
- package/src/install-animation.js +260 -0
- package/src/install-profile.js +143 -0
- package/src/install-wizard.js +474 -0
- package/src/installer.js +38 -10
- package/src/lib/webhook-server.js +328 -0
- package/src/mcp-connectors/registry.js +602 -0
- package/src/parser.js +7 -1
- package/src/recovery-context-session.js +154 -0
- package/src/runtime-store.js +355 -2
- package/src/sandbox.js +177 -0
- package/src/squad/external-session.js +180 -0
- package/src/squad/inter-squad.js +74 -0
- package/src/squad/recovery-context.js +201 -0
- package/src/squad/worktree-manager.js +114 -0
- package/src/squad-daemon.js +490 -0
- package/src/squad-dashboard/api.js +223 -0
- package/src/squad-dashboard/attachment-handler.js +93 -0
- package/src/squad-dashboard/context-monitor.js +157 -0
- package/src/squad-dashboard/execution-logs.js +115 -0
- package/src/squad-dashboard/hunk-review.js +209 -0
- package/src/squad-dashboard/metrics.js +133 -0
- package/src/squad-dashboard/process-monitor.js +125 -0
- package/src/squad-dashboard/renderer.js +858 -0
- package/src/squad-dashboard/server.js +232 -0
- package/src/squad-dashboard/styles.js +525 -0
- package/src/squad-dashboard/token-tracker.js +99 -0
- package/src/tool-executor.js +94 -0
- package/src/updater.js +11 -3
- package/src/web.js +284 -0
- package/src/worker-runner.js +339 -0
- package/template/.aioson/agents/analyst.md +62 -3
- package/template/.aioson/agents/architect.md +42 -0
- package/template/.aioson/agents/design-hybrid-forge.md +127 -0
- package/template/.aioson/agents/dev.md +223 -11
- package/template/.aioson/agents/deyvin.md +65 -0
- package/template/.aioson/agents/neo.md +152 -0
- package/template/.aioson/agents/orache.md +17 -0
- package/template/.aioson/agents/orchestrator.md +26 -0
- package/template/.aioson/agents/pm.md +58 -0
- package/template/.aioson/agents/product.md +88 -12
- package/template/.aioson/agents/qa.md +80 -0
- package/template/.aioson/agents/setup.md +128 -22
- package/template/.aioson/agents/sheldon.md +704 -0
- package/template/.aioson/agents/squad.md +191 -0
- package/template/.aioson/agents/tester.md +410 -0
- package/template/.aioson/agents/ux-ui.md +12 -0
- package/template/.aioson/config.md +21 -0
- package/template/.aioson/context/forensics/.gitkeep +0 -0
- package/template/.aioson/context/seeds/seed-example.md +27 -0
- package/template/.aioson/context/user-profile.md +42 -0
- package/template/.aioson/locales/en/agents/analyst.md +8 -0
- package/template/.aioson/locales/en/agents/architect.md +8 -0
- package/template/.aioson/locales/en/agents/dev.md +66 -7
- package/template/.aioson/locales/en/agents/deyvin.md +8 -0
- package/template/.aioson/locales/en/agents/neo.md +8 -0
- package/template/.aioson/locales/en/agents/orchestrator.md +26 -0
- package/template/.aioson/locales/en/agents/qa.md +49 -0
- package/template/.aioson/locales/en/agents/setup.md +35 -2
- package/template/.aioson/locales/en/agents/sheldon.md +340 -0
- package/template/.aioson/locales/en/agents/ux-ui.md +8 -0
- package/template/.aioson/locales/es/agents/analyst.md +8 -0
- package/template/.aioson/locales/es/agents/architect.md +8 -0
- package/template/.aioson/locales/es/agents/dev.md +66 -7
- package/template/.aioson/locales/es/agents/deyvin.md +8 -0
- package/template/.aioson/locales/es/agents/neo.md +48 -0
- package/template/.aioson/locales/es/agents/orchestrator.md +26 -0
- package/template/.aioson/locales/es/agents/qa.md +26 -0
- package/template/.aioson/locales/es/agents/setup.md +35 -2
- package/template/.aioson/locales/es/agents/sheldon.md +192 -0
- package/template/.aioson/locales/es/agents/squad.md +63 -0
- package/template/.aioson/locales/es/agents/ux-ui.md +8 -0
- package/template/.aioson/locales/fr/agents/analyst.md +8 -0
- package/template/.aioson/locales/fr/agents/architect.md +8 -0
- package/template/.aioson/locales/fr/agents/dev.md +66 -7
- package/template/.aioson/locales/fr/agents/deyvin.md +8 -0
- package/template/.aioson/locales/fr/agents/neo.md +48 -0
- package/template/.aioson/locales/fr/agents/orchestrator.md +26 -0
- package/template/.aioson/locales/fr/agents/qa.md +26 -0
- package/template/.aioson/locales/fr/agents/setup.md +35 -2
- package/template/.aioson/locales/fr/agents/sheldon.md +192 -0
- package/template/.aioson/locales/fr/agents/squad.md +63 -0
- package/template/.aioson/locales/fr/agents/ux-ui.md +8 -0
- package/template/.aioson/locales/pt-BR/agents/analyst.md +19 -0
- package/template/.aioson/locales/pt-BR/agents/architect.md +19 -0
- package/template/.aioson/locales/pt-BR/agents/dev.md +75 -12
- package/template/.aioson/locales/pt-BR/agents/deyvin.md +8 -0
- package/template/.aioson/locales/pt-BR/agents/neo.md +147 -0
- package/template/.aioson/locales/pt-BR/agents/orchestrator.md +26 -0
- package/template/.aioson/locales/pt-BR/agents/product.md +8 -3
- package/template/.aioson/locales/pt-BR/agents/qa.md +60 -0
- package/template/.aioson/locales/pt-BR/agents/setup.md +35 -2
- package/template/.aioson/locales/pt-BR/agents/sheldon.md +192 -0
- package/template/.aioson/locales/pt-BR/agents/squad.md +105 -0
- package/template/.aioson/locales/pt-BR/agents/ux-ui.md +8 -0
- package/template/.aioson/schemas/squad-blueprint.schema.json +21 -0
- package/template/.aioson/schemas/squad-manifest.schema.json +178 -1
- package/template/.aioson/skills/design/aurora-command-ui/SKILL.md +243 -0
- package/template/.aioson/skills/design/aurora-command-ui/references/art-direction.md +293 -0
- package/template/.aioson/skills/design/aurora-command-ui/references/components.md +827 -0
- package/template/.aioson/skills/design/aurora-command-ui/references/dashboards.md +250 -0
- package/template/.aioson/skills/design/aurora-command-ui/references/design-tokens.md +585 -0
- package/template/.aioson/skills/design/aurora-command-ui/references/motion.md +365 -0
- package/template/.aioson/skills/design/aurora-command-ui/references/patterns.md +482 -0
- package/template/.aioson/skills/design/aurora-command-ui/references/websites.md +387 -0
- package/template/.aioson/skills/design/bold-editorial-ui/SKILL.md +205 -0
- package/template/.aioson/skills/design/bold-editorial-ui/references/art-direction.md +338 -0
- package/template/.aioson/skills/design/bold-editorial-ui/references/components.md +977 -0
- package/template/.aioson/skills/design/bold-editorial-ui/references/dashboards.md +218 -0
- package/template/.aioson/skills/design/bold-editorial-ui/references/design-tokens.md +326 -0
- package/template/.aioson/skills/design/bold-editorial-ui/references/motion.md +461 -0
- package/template/.aioson/skills/design/bold-editorial-ui/references/patterns.md +293 -0
- package/template/.aioson/skills/design/bold-editorial-ui/references/websites.md +352 -0
- package/template/.aioson/skills/design/clean-saas-ui/SKILL.md +210 -0
- package/template/.aioson/skills/design/clean-saas-ui/references/art-direction.md +319 -0
- package/template/.aioson/skills/design/clean-saas-ui/references/components.md +365 -0
- package/template/.aioson/skills/design/clean-saas-ui/references/dashboards.md +196 -0
- package/template/.aioson/skills/design/clean-saas-ui/references/design-tokens.md +244 -0
- package/template/.aioson/skills/design/clean-saas-ui/references/motion.md +235 -0
- package/template/.aioson/skills/design/clean-saas-ui/references/patterns.md +215 -0
- package/template/.aioson/skills/design/clean-saas-ui/references/websites.md +295 -0
- package/template/.aioson/skills/design/cognitive-core-ui/SKILL.md +55 -9
- package/template/.aioson/skills/design/cognitive-core-ui/references/art-direction.md +339 -0
- package/template/.aioson/skills/design/cognitive-core-ui/references/components.md +1 -1
- package/template/.aioson/skills/design/cognitive-core-ui/references/dashboards.md +100 -0
- package/template/.aioson/skills/design/cognitive-core-ui/references/design-tokens.md +43 -9
- package/template/.aioson/skills/design/cognitive-core-ui/references/motion.md +40 -0
- package/template/.aioson/skills/design/cognitive-core-ui/references/patterns.md +1 -1
- package/template/.aioson/skills/design/cognitive-core-ui/references/websites.md +99 -12
- package/template/.aioson/skills/design/glassmorphism-ui/SKILL.md +222 -0
- package/template/.aioson/skills/design/glassmorphism-ui/references/art-direction.md +159 -0
- package/template/.aioson/skills/design/glassmorphism-ui/references/components.md +498 -0
- package/template/.aioson/skills/design/glassmorphism-ui/references/dashboards.md +236 -0
- package/template/.aioson/skills/design/glassmorphism-ui/references/design-tokens.md +274 -0
- package/template/.aioson/skills/design/glassmorphism-ui/references/motion.md +355 -0
- package/template/.aioson/skills/design/glassmorphism-ui/references/patterns.md +198 -0
- package/template/.aioson/skills/design/glassmorphism-ui/references/websites.md +307 -0
- package/template/.aioson/skills/design/neo-brutalist-ui/SKILL.md +213 -0
- package/template/.aioson/skills/design/neo-brutalist-ui/references/art-direction.md +228 -0
- package/template/.aioson/skills/design/neo-brutalist-ui/references/components.md +855 -0
- package/template/.aioson/skills/design/neo-brutalist-ui/references/dashboards.md +334 -0
- package/template/.aioson/skills/design/neo-brutalist-ui/references/design-tokens.md +342 -0
- package/template/.aioson/skills/design/neo-brutalist-ui/references/motion.md +286 -0
- package/template/.aioson/skills/design/neo-brutalist-ui/references/patterns.md +458 -0
- package/template/.aioson/skills/design/neo-brutalist-ui/references/websites.md +723 -0
- package/template/.aioson/skills/design/warm-craft-ui/SKILL.md +209 -0
- package/template/.aioson/skills/design/warm-craft-ui/references/art-direction.md +324 -0
- package/template/.aioson/skills/design/warm-craft-ui/references/components.md +508 -0
- package/template/.aioson/skills/design/warm-craft-ui/references/dashboards.md +223 -0
- package/template/.aioson/skills/design/warm-craft-ui/references/design-tokens.md +374 -0
- package/template/.aioson/skills/design/warm-craft-ui/references/motion.md +356 -0
- package/template/.aioson/skills/design/warm-craft-ui/references/patterns.md +288 -0
- package/template/.aioson/skills/design/warm-craft-ui/references/websites.md +289 -0
- package/template/.aioson/skills/premium-visual-design/SKILL.md +83 -0
- package/template/.aioson/skills/premium-visual-design/components/agent-badge.md +92 -0
- package/template/.aioson/skills/premium-visual-design/components/dependency-node.md +102 -0
- package/template/.aioson/skills/premium-visual-design/components/mention-autocomplete.md +136 -0
- package/template/.aioson/skills/premium-visual-design/components/notification-center.md +136 -0
- package/template/.aioson/skills/premium-visual-design/components/review-action-bar.md +188 -0
- package/template/.aioson/skills/premium-visual-design/components/team-switcher.md +131 -0
- package/template/.aioson/skills/premium-visual-design/patterns/agent-message-thread.md +198 -0
- package/template/.aioson/skills/premium-visual-design/patterns/notification-panel.md +275 -0
- package/template/.aioson/skills/premium-visual-design/patterns/review-workflow-ui.md +234 -0
- package/template/.aioson/skills/premium-visual-design/patterns/task-dependency-graph.md +147 -0
- package/template/.aioson/skills/premium-visual-design/tokens/status-extended.md +142 -0
- package/template/.aioson/skills/process/aioson-spec-driven/SKILL.md +45 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/approval-gates.md +109 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/artifact-map.md +44 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/classification-map.md +37 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/hardening-lane.md +49 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/maintenance-and-state.md +66 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/ui-language.md +75 -0
- package/template/.aioson/skills/process/design-hybrid-forge/SKILL.md +144 -0
- package/template/.aioson/skills/process/design-hybrid-forge/references/crossover-protocol.md +221 -0
- package/template/.aioson/skills/process/design-hybrid-forge/references/naming-registry.md +88 -0
- package/template/.aioson/skills/process/design-hybrid-forge/references/output-contract.md +291 -0
- package/template/.aioson/skills/process/design-hybrid-forge/references/pair-compatibility.md +117 -0
- package/template/.aioson/skills/process/design-hybrid-forge/references/quality-gates.md +188 -0
- package/template/.aioson/skills/process/design-hybrid-forge/references/variation-library.md +125 -0
- package/template/.aioson/skills/squad/formats/catalog.json +15 -0
- package/template/.aioson/skills/squad/formats/content/blog-post.md +47 -0
- package/template/.aioson/skills/squad/formats/content/newsletter.md +47 -0
- package/template/.aioson/skills/squad/formats/creative/podcast-script.md +43 -0
- package/template/.aioson/skills/squad/formats/creative/video-script.md +41 -0
- package/template/.aioson/skills/squad/formats/social/instagram-feed.md +42 -0
- package/template/.aioson/skills/squad/formats/social/linkedin-post.md +42 -0
- package/template/.aioson/skills/squad/formats/social/tiktok.md +39 -0
- package/template/.aioson/skills/squad/formats/social/twitter-thread.md +39 -0
- package/template/.aioson/skills/squad/formats/social/youtube-long.md +47 -0
- package/template/.aioson/skills/squad/formats/social/youtube-shorts.md +39 -0
- package/template/.aioson/skills/squad/patterns/multi-platform-pattern.md +108 -0
- package/template/.aioson/skills/squad/patterns/persona-based-pattern.md +98 -0
- package/template/.aioson/skills/squad/patterns/pipeline-pattern.md +106 -0
- package/template/.aioson/skills/squad/patterns/review-loop-pattern.md +81 -0
- package/template/.aioson/skills/squad/references/checklist-templates.md +122 -0
- package/template/.aioson/skills/squad/references/executor-archetypes.md +123 -0
- package/template/.aioson/skills/squad/references/workflow-templates.md +169 -0
- package/template/.aioson/skills/static/debugging-protocol.md +42 -0
- package/template/.aioson/skills/static/git-worktrees.md +36 -0
- package/template/.aioson/tasks/implementation-plan.md +19 -0
- package/template/.aioson/tasks/squad-design.md +28 -0
- package/template/.aioson/tasks/squad-profile.md +48 -0
- package/template/.aioson/tasks/squad-review.md +61 -0
- package/template/.aioson/tasks/squad-task-decompose.md +66 -0
- package/template/.claude/commands/aioson/agent/neo.md +5 -0
- package/template/.claude/commands/aioson/agent/tester.md +5 -0
- package/template/.gemini/GEMINI.md +1 -0
- package/template/.gemini/commands/aios-neo.toml +4 -0
- package/template/.gemini/commands/aios-tester.toml +6 -0
- package/template/AGENTS.md +26 -1
- package/template/CLAUDE.md +6 -2
- package/template/OPENCODE.md +2 -0
package/src/commands/runtime.js
CHANGED
|
@@ -20,6 +20,7 @@ const {
|
|
|
20
20
|
} = require('../runtime-store');
|
|
21
21
|
const { runAutoDelivery } = require('../delivery-runner');
|
|
22
22
|
const { writeHandoff, buildRuntimeLogHandoff } = require('../session-handoff');
|
|
23
|
+
const { backupAiosonDocs, isDocCreatingAgent } = require('../backup-local');
|
|
23
24
|
|
|
24
25
|
const ALLOWED_LAYOUTS = new Set(['document', 'tabs', 'accordion', 'stack', 'mixed']);
|
|
25
26
|
const DEFAULT_TEXT_FIELDS = ['content', 'text', 'body', 'lyrics', 'markdown'];
|
|
@@ -1159,6 +1160,80 @@ async function runRuntimeLog({ args, options = {}, logger, t }) {
|
|
|
1159
1160
|
}
|
|
1160
1161
|
|
|
1161
1162
|
|
|
1163
|
+
/**
|
|
1164
|
+
* aioson agent:done . --agent=<name> --summary="..." [--title="..."] [--status=completed|failed]
|
|
1165
|
+
*
|
|
1166
|
+
* Safe self-registration for official agents invoked directly (not via workflow:next or live:start).
|
|
1167
|
+
* - If an active live session exists for the agent: appends a completion event without closing the session.
|
|
1168
|
+
* - If no session exists: creates a standalone task+run and immediately marks it completed.
|
|
1169
|
+
*
|
|
1170
|
+
* Intended to be called ONCE at the very end of an agent session, after delivering the main artifact.
|
|
1171
|
+
*/
|
|
1172
|
+
async function runAgentDone({ args, options = {}, logger, t }) {
|
|
1173
|
+
const targetDir = resolveTargetDir(args);
|
|
1174
|
+
const agentName = String(options.agent || '').trim();
|
|
1175
|
+
if (!agentName) {
|
|
1176
|
+
throw new Error('--agent is required');
|
|
1177
|
+
}
|
|
1178
|
+
const normalizedAgent = agentName.startsWith('@') ? agentName : `@${agentName}`;
|
|
1179
|
+
const summary = String(options.summary || options.message || `${normalizedAgent} session completed`).trim();
|
|
1180
|
+
const title = options.title ? String(options.title).trim() : null;
|
|
1181
|
+
const status = options.status || 'completed';
|
|
1182
|
+
|
|
1183
|
+
const { db, dbPath, runtimeDir } = await openRuntimeDb(targetDir);
|
|
1184
|
+
|
|
1185
|
+
try {
|
|
1186
|
+
const session = await readAgentSession(runtimeDir, normalizedAgent);
|
|
1187
|
+
const hasActiveSession = session && !session.finished && session.runKey;
|
|
1188
|
+
|
|
1189
|
+
if (hasActiveSession) {
|
|
1190
|
+
// Live or tracked session is already open — only append a completion note.
|
|
1191
|
+
// Do NOT close the session: live:handoff or live:close owns the lifecycle.
|
|
1192
|
+
appendRunEvent(db, {
|
|
1193
|
+
runKey: session.runKey,
|
|
1194
|
+
eventType: 'agent_done',
|
|
1195
|
+
phase: 'live',
|
|
1196
|
+
status: 'running',
|
|
1197
|
+
message: summary
|
|
1198
|
+
});
|
|
1199
|
+
|
|
1200
|
+
if (!options.json) {
|
|
1201
|
+
logger.log(`agent:done — ${normalizedAgent} | live session active, event logged | run: ${session.runKey} (${dbPath})`);
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
if (isDocCreatingAgent(normalizedAgent)) {
|
|
1205
|
+
backupAiosonDocs(targetDir).catch(() => {});
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
return { ok: true, targetDir, dbPath, agent: normalizedAgent, mode: 'live_event', runKey: session.runKey };
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
// No active session — create a standalone task+run and immediately complete it.
|
|
1212
|
+
const { runKey, taskKey } = await logAgentEvent(db, runtimeDir, {
|
|
1213
|
+
agentName: normalizedAgent,
|
|
1214
|
+
message: summary,
|
|
1215
|
+
type: 'completed',
|
|
1216
|
+
taskTitle: title || normalizedAgent,
|
|
1217
|
+
finish: true,
|
|
1218
|
+
status,
|
|
1219
|
+
summary
|
|
1220
|
+
});
|
|
1221
|
+
|
|
1222
|
+
if (!options.json) {
|
|
1223
|
+
logger.log(`agent:done — ${normalizedAgent} | task: ${taskKey} | run: ${runKey} (${dbPath})`);
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
if (isDocCreatingAgent(normalizedAgent)) {
|
|
1227
|
+
backupAiosonDocs(targetDir).catch(() => {});
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
return { ok: true, targetDir, dbPath, agent: normalizedAgent, mode: 'standalone', runKey, taskKey };
|
|
1231
|
+
} finally {
|
|
1232
|
+
db.close();
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
|
|
1162
1237
|
async function runRuntimeSessionStart({ args, options = {}, logger, t }) {
|
|
1163
1238
|
const targetDir = resolveTargetDir(args);
|
|
1164
1239
|
const { db, dbPath, runtimeDir } = await openRuntimeDb(targetDir);
|
|
@@ -1683,6 +1758,171 @@ function parseFrontmatter(content) {
|
|
|
1683
1758
|
return result;
|
|
1684
1759
|
}
|
|
1685
1760
|
|
|
1761
|
+
/**
|
|
1762
|
+
* Parses a duration string like "24h", "30m", "7d" into milliseconds.
|
|
1763
|
+
* Falls back to treating the raw value as hours.
|
|
1764
|
+
*/
|
|
1765
|
+
function parseDurationMs(value, defaultHours = 24) {
|
|
1766
|
+
const text = String(value || '').trim().toLowerCase();
|
|
1767
|
+
if (!text) return defaultHours * 60 * 60 * 1000;
|
|
1768
|
+
|
|
1769
|
+
const match = text.match(/^(\d+(?:\.\d+)?)\s*([hmd]?)$/);
|
|
1770
|
+
if (!match) return defaultHours * 60 * 60 * 1000;
|
|
1771
|
+
|
|
1772
|
+
const n = parseFloat(match[1]);
|
|
1773
|
+
const unit = match[2] || 'h';
|
|
1774
|
+
if (unit === 'd') return n * 24 * 60 * 60 * 1000;
|
|
1775
|
+
if (unit === 'm') return n * 60 * 1000;
|
|
1776
|
+
return n * 60 * 60 * 1000; // hours (default)
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
/**
|
|
1780
|
+
* aioson agent:recover [targetDir] [--older-than=<duration>] [--dry-run]
|
|
1781
|
+
*
|
|
1782
|
+
* Detects and closes agent sessions that were abandoned (Claude Code closed before
|
|
1783
|
+
* agent:done was called, or live:start session was never closed).
|
|
1784
|
+
*
|
|
1785
|
+
* Sources checked:
|
|
1786
|
+
* 1. Session files in .aioson/.sessions/ with finished=false older than threshold.
|
|
1787
|
+
* 2. agent_runs rows with status='running'/'queued' and started_at older than threshold
|
|
1788
|
+
* that have no corresponding live session file (orphaned DB records).
|
|
1789
|
+
*
|
|
1790
|
+
* --older-than Duration threshold. Accepts: 24h (default), 8h, 30m, 7d.
|
|
1791
|
+
* --dry-run Report what would be recovered without making any changes.
|
|
1792
|
+
* --json Output JSON result.
|
|
1793
|
+
*/
|
|
1794
|
+
async function runAgentRecover({ args, options = {}, logger }) {
|
|
1795
|
+
const targetDir = resolveTargetDir(args);
|
|
1796
|
+
const dryRun = Boolean(options['dry-run'] || options.dryRun);
|
|
1797
|
+
const olderThanMs = parseDurationMs(options['older-than'] || options.olderThan, 24);
|
|
1798
|
+
const cutoffMs = Date.now() - olderThanMs;
|
|
1799
|
+
const cutoffIso = new Date(cutoffMs).toISOString();
|
|
1800
|
+
const now = new Date().toISOString();
|
|
1801
|
+
|
|
1802
|
+
const { db, dbPath, runtimeDir } = await openRuntimeDb(targetDir);
|
|
1803
|
+
|
|
1804
|
+
const recovered = [];
|
|
1805
|
+
const skipped = [];
|
|
1806
|
+
|
|
1807
|
+
try {
|
|
1808
|
+
// ── 1. Scan session files ─────────────────────────────────────────────────
|
|
1809
|
+
const sessionsDir = path.join(runtimeDir, '.sessions');
|
|
1810
|
+
let sessionFiles = [];
|
|
1811
|
+
try {
|
|
1812
|
+
const entries = await fs.readdir(sessionsDir);
|
|
1813
|
+
sessionFiles = entries.filter((f) => f.endsWith('.json'));
|
|
1814
|
+
} catch {
|
|
1815
|
+
// .sessions dir may not exist — that's fine
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1818
|
+
for (const file of sessionFiles) {
|
|
1819
|
+
const filePath = path.join(sessionsDir, file);
|
|
1820
|
+
let session;
|
|
1821
|
+
try {
|
|
1822
|
+
session = JSON.parse(await fs.readFile(filePath, 'utf8'));
|
|
1823
|
+
} catch {
|
|
1824
|
+
continue;
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
if (session.finished) continue;
|
|
1828
|
+
|
|
1829
|
+
const startedAt = session.startedAt ? new Date(session.startedAt).getTime() : 0;
|
|
1830
|
+
if (startedAt > cutoffMs) {
|
|
1831
|
+
skipped.push({ source: 'session_file', file, reason: 'within_threshold', startedAt: session.startedAt });
|
|
1832
|
+
continue;
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
const agentName = file.replace(/\.json$/, '');
|
|
1836
|
+
const runKey = session.runKey || null;
|
|
1837
|
+
const taskKey = session.taskKey || null;
|
|
1838
|
+
|
|
1839
|
+
if (!dryRun) {
|
|
1840
|
+
// Mark run as abandoned
|
|
1841
|
+
if (runKey) {
|
|
1842
|
+
const runRow = db.prepare('SELECT run_key, status FROM agent_runs WHERE run_key = ?').get(runKey);
|
|
1843
|
+
if (runRow && (runRow.status === 'running' || runRow.status === 'queued')) {
|
|
1844
|
+
db.prepare(`
|
|
1845
|
+
UPDATE agent_runs
|
|
1846
|
+
SET status = 'abandoned', summary = 'Recovered: session abandoned without close', updated_at = ?, finished_at = ?
|
|
1847
|
+
WHERE run_key = ?
|
|
1848
|
+
`).run(now, now, runKey);
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
// Mark task as abandoned
|
|
1852
|
+
if (taskKey) {
|
|
1853
|
+
const taskRow = db.prepare('SELECT task_key, status FROM tasks WHERE task_key = ?').get(taskKey);
|
|
1854
|
+
if (taskRow && (taskRow.status === 'running' || taskRow.status === 'queued')) {
|
|
1855
|
+
db.prepare(`
|
|
1856
|
+
UPDATE tasks
|
|
1857
|
+
SET status = 'abandoned', updated_at = ?, finished_at = ?
|
|
1858
|
+
WHERE task_key = ?
|
|
1859
|
+
`).run(now, now, taskKey);
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
// Remove session file
|
|
1863
|
+
try { await fs.unlink(filePath); } catch { /* noop */ }
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1866
|
+
recovered.push({ source: 'session_file', agent: agentName, runKey, taskKey, startedAt: session.startedAt });
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
// ── 2. Scan DB for orphaned running runs (no session file) ────────────────
|
|
1870
|
+
const orphanedRuns = db.prepare(`
|
|
1871
|
+
SELECT run_key, task_key, agent_name, started_at
|
|
1872
|
+
FROM agent_runs
|
|
1873
|
+
WHERE status IN ('running', 'queued')
|
|
1874
|
+
AND source = 'direct'
|
|
1875
|
+
AND started_at < ?
|
|
1876
|
+
`).all(cutoffIso);
|
|
1877
|
+
|
|
1878
|
+
for (const run of orphanedRuns) {
|
|
1879
|
+
// Skip if already recovered via session file
|
|
1880
|
+
if (recovered.some((r) => r.runKey === run.run_key)) continue;
|
|
1881
|
+
|
|
1882
|
+
if (!dryRun) {
|
|
1883
|
+
db.prepare(`
|
|
1884
|
+
UPDATE agent_runs
|
|
1885
|
+
SET status = 'abandoned', summary = 'Recovered: orphaned run with no session file', updated_at = ?, finished_at = ?
|
|
1886
|
+
WHERE run_key = ?
|
|
1887
|
+
`).run(now, now, run.run_key);
|
|
1888
|
+
|
|
1889
|
+
if (run.task_key) {
|
|
1890
|
+
const taskRow = db.prepare('SELECT task_key, status FROM tasks WHERE task_key = ?').get(run.task_key);
|
|
1891
|
+
if (taskRow && (taskRow.status === 'running' || taskRow.status === 'queued')) {
|
|
1892
|
+
db.prepare(`
|
|
1893
|
+
UPDATE tasks
|
|
1894
|
+
SET status = 'abandoned', updated_at = ?, finished_at = ?
|
|
1895
|
+
WHERE task_key = ?
|
|
1896
|
+
`).run(now, now, run.task_key);
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1901
|
+
recovered.push({ source: 'orphaned_run', agent: run.agent_name, runKey: run.run_key, taskKey: run.task_key, startedAt: run.started_at });
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1904
|
+
// ── Output ────────────────────────────────────────────────────────────────
|
|
1905
|
+
const olderThanLabel = options['older-than'] || options.olderThan || '24h';
|
|
1906
|
+
if (recovered.length === 0) {
|
|
1907
|
+
logger.log(`agent:recover — no abandoned sessions found older than ${olderThanLabel} (${dbPath})`);
|
|
1908
|
+
} else {
|
|
1909
|
+
const verb = dryRun ? '[dry-run] would recover' : 'recovered';
|
|
1910
|
+
logger.log(`agent:recover — ${verb} ${recovered.length} abandoned session(s) older than ${olderThanLabel} (${dbPath})`);
|
|
1911
|
+
for (const r of recovered) {
|
|
1912
|
+
logger.log(` ${r.agent} started: ${r.startedAt || '?'} run: ${r.runKey || '—'} [${r.source}]`);
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
if (skipped.length > 0) {
|
|
1916
|
+
logger.log(` skipped ${skipped.length} session(s) within threshold.`);
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1919
|
+
return { ok: true, targetDir, dbPath, dryRun, cutoff: cutoffIso, recovered, skipped };
|
|
1920
|
+
} finally {
|
|
1921
|
+
db.close();
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
|
|
1686
1926
|
/**
|
|
1687
1927
|
* aioson runtime:prune [targetDir] --older-than=<days>
|
|
1688
1928
|
*
|
|
@@ -1767,6 +2007,8 @@ module.exports = {
|
|
|
1767
2007
|
runRuntimeFail,
|
|
1768
2008
|
runRuntimeStatus,
|
|
1769
2009
|
runRuntimeLog,
|
|
2010
|
+
runAgentDone,
|
|
2011
|
+
runAgentRecover,
|
|
1770
2012
|
runRuntimeSessionStart,
|
|
1771
2013
|
runRuntimeSessionLog,
|
|
1772
2014
|
runRuntimeSessionFinish,
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const { executeInSandbox } = require('../sandbox');
|
|
5
|
+
|
|
6
|
+
async function runSandboxExec({ args, options, logger }) {
|
|
7
|
+
const command = args[0] || options.command || '';
|
|
8
|
+
const cwd = path.resolve(process.cwd(), options.cwd || '.');
|
|
9
|
+
const timeout = Number(options.timeout) || 30_000;
|
|
10
|
+
const intent = options.intent || undefined;
|
|
11
|
+
|
|
12
|
+
if (!command) {
|
|
13
|
+
logger.error('Usage: aioson sandbox:exec "<command>" [--timeout=30000] [--cwd=.]');
|
|
14
|
+
return { ok: false, error: 'missing_command' };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const result = await executeInSandbox(command, { cwd, timeout, intent });
|
|
18
|
+
|
|
19
|
+
if (options.json) {
|
|
20
|
+
return { ok: result.ok, ...result };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (result.stdout) {
|
|
24
|
+
logger.log(result.stdout);
|
|
25
|
+
}
|
|
26
|
+
if (result.stderr) {
|
|
27
|
+
logger.error(result.stderr);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (result.timedOut) {
|
|
31
|
+
logger.error(`Command timed out after ${timeout}ms`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return { ok: result.ok, ...result };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = { runSandboxExec };
|
|
@@ -3,12 +3,32 @@
|
|
|
3
3
|
const path = require('node:path');
|
|
4
4
|
const readline = require('node:readline/promises');
|
|
5
5
|
const { detectFramework, isMonorepoDetection } = require('../detector');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Infer conversation language from the OS locale environment variables.
|
|
9
|
+
* Supports LANGUAGE, LANG, and LC_ALL in priority order.
|
|
10
|
+
* Maps POSIX locale codes (e.g. pt_BR.UTF-8) to AIOSON locale codes (e.g. pt-BR).
|
|
11
|
+
*/
|
|
12
|
+
function detectSystemLanguage() {
|
|
13
|
+
const raw = process.env.LANGUAGE || process.env.LANG || process.env.LC_ALL || '';
|
|
14
|
+
const base = raw.split(':')[0].split('.')[0].trim();
|
|
15
|
+
if (!base || base === 'C' || base === 'POSIX') return 'en';
|
|
16
|
+
const normalized = base.replace('_', '-');
|
|
17
|
+
const supported = ['en', 'pt-BR', 'es', 'fr'];
|
|
18
|
+
if (supported.includes(normalized)) return normalized;
|
|
19
|
+
const lang = normalized.split('-')[0].toLowerCase();
|
|
20
|
+
if (lang === 'pt') return 'pt-BR';
|
|
21
|
+
if (lang === 'es') return 'es';
|
|
22
|
+
if (lang === 'fr') return 'fr';
|
|
23
|
+
return 'en';
|
|
24
|
+
}
|
|
6
25
|
const { getCliVersionSync } = require('../version');
|
|
7
26
|
const {
|
|
8
27
|
calculateClassification,
|
|
9
28
|
normalizeBoolean,
|
|
10
29
|
renderProjectContext,
|
|
11
|
-
writeProjectContext
|
|
30
|
+
writeProjectContext,
|
|
31
|
+
renderSquadApiSection
|
|
12
32
|
} = require('../context-writer');
|
|
13
33
|
const { applyAgentLocale } = require('../locales');
|
|
14
34
|
const { openRuntimeDb, logAgentEvent } = require('../runtime-store');
|
|
@@ -208,6 +228,7 @@ function applyExplicitOverrides(data, options, detectedInstalled) {
|
|
|
208
228
|
const langValue = options.language ?? options.lang;
|
|
209
229
|
if (langValue !== undefined) output.conversationLanguage = String(langValue);
|
|
210
230
|
if (hasOption(options, 'design-skill')) output.designSkill = String(options['design-skill']);
|
|
231
|
+
if (hasOption(options, 'test-runner')) output.testRunner = String(options['test-runner']);
|
|
211
232
|
if (hasOption(options, 'web3-enabled')) {
|
|
212
233
|
output.web3Enabled = normalizeBoolean(options['web3-enabled'], output.web3Enabled);
|
|
213
234
|
}
|
|
@@ -467,8 +488,9 @@ async function runSetupContext({ args, options, logger, t }) {
|
|
|
467
488
|
profile: 'developer',
|
|
468
489
|
framework: detectedFramework,
|
|
469
490
|
frameworkInstalled: detectedInstalled,
|
|
470
|
-
conversationLanguage:
|
|
491
|
+
conversationLanguage: detectSystemLanguage(),
|
|
471
492
|
designSkill: '',
|
|
493
|
+
testRunner: '',
|
|
472
494
|
web3Enabled: inferredWeb3Enabled,
|
|
473
495
|
web3Networks: inferredWeb3Enabled ? inferWeb3Network(detectedFramework) : '',
|
|
474
496
|
contractFramework: inferredWeb3Enabled ? detectedFramework : '',
|
|
@@ -616,7 +638,9 @@ async function runSetupContext({ args, options, logger, t }) {
|
|
|
616
638
|
}
|
|
617
639
|
|
|
618
640
|
const content = renderProjectContext(data);
|
|
619
|
-
const
|
|
641
|
+
const squadApiSection = await renderSquadApiSection(targetDir);
|
|
642
|
+
const fullContent = squadApiSection ? content + '\n' + squadApiSection + '\n' : content;
|
|
643
|
+
const filePath = await writeProjectContext(targetDir, fullContent);
|
|
620
644
|
const localeApplyResult = await applyAgentLocale(targetDir, data.conversationLanguage, {
|
|
621
645
|
dryRun: false
|
|
622
646
|
});
|
|
@@ -669,5 +693,6 @@ module.exports = {
|
|
|
669
693
|
runSetupContext,
|
|
670
694
|
servicesToContextFields,
|
|
671
695
|
mergeProfileData,
|
|
672
|
-
applyExplicitOverrides
|
|
696
|
+
applyExplicitOverrides,
|
|
697
|
+
detectSystemLanguage
|
|
673
698
|
};
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const readline = require('node:readline/promises');
|
|
5
|
+
const { installTemplate, readInstallProfile } = require('../installer');
|
|
6
|
+
const { detectFramework } = require('../detector');
|
|
7
|
+
const { detectSystemLanguage } = require('./setup-context');
|
|
8
|
+
const { runSetupContext } = require('./setup-context');
|
|
9
|
+
const { resolvePromptTool } = require('../prompt-tool');
|
|
10
|
+
const { normalizeBoolean } = require('../context-writer');
|
|
11
|
+
const { runInstallWizard } = require('../install-wizard');
|
|
12
|
+
|
|
13
|
+
async function ask(rl, question, fallback = '') {
|
|
14
|
+
const suffix = fallback ? ` (${fallback})` : '';
|
|
15
|
+
const value = await rl.question(`${question}${suffix}: `);
|
|
16
|
+
const cleaned = String(value || '').trim();
|
|
17
|
+
if (!cleaned) return fallback;
|
|
18
|
+
return cleaned;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function runSetup({ args, options, logger, t }) {
|
|
22
|
+
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
23
|
+
const dryRun = Boolean(options['dry-run']);
|
|
24
|
+
const force = Boolean(options.force);
|
|
25
|
+
const defaultsMode = Boolean(options.defaults);
|
|
26
|
+
const promptTool = resolvePromptTool(options.tool);
|
|
27
|
+
|
|
28
|
+
// Step 1 — detect install profile (wizard if first time in TTY)
|
|
29
|
+
const isTTY = process.stdin.isTTY && process.stdout.isTTY;
|
|
30
|
+
let installProfile = null;
|
|
31
|
+
|
|
32
|
+
if (!dryRun && isTTY) {
|
|
33
|
+
const existingProfile = await readInstallProfile(targetDir);
|
|
34
|
+
if (!existingProfile) {
|
|
35
|
+
installProfile = await runInstallWizard({});
|
|
36
|
+
} else {
|
|
37
|
+
installProfile = existingProfile;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Step 2 — install template
|
|
42
|
+
logger.log(t('setup.installing'));
|
|
43
|
+
const installResult = await installTemplate(targetDir, {
|
|
44
|
+
overwrite: force,
|
|
45
|
+
dryRun,
|
|
46
|
+
mode: 'install',
|
|
47
|
+
installProfile
|
|
48
|
+
});
|
|
49
|
+
logger.log(t('setup.installed', { count: installResult.copied.length }));
|
|
50
|
+
|
|
51
|
+
// Step 3 — detect framework and system language
|
|
52
|
+
const detection = await detectFramework(targetDir);
|
|
53
|
+
const detectedFramework = detection.framework;
|
|
54
|
+
const detectedInstalled = detection.installed;
|
|
55
|
+
const systemLang = detectSystemLanguage();
|
|
56
|
+
|
|
57
|
+
// Build setup:context options by merging detected state with explicit flags
|
|
58
|
+
const contextOptions = { defaults: true };
|
|
59
|
+
|
|
60
|
+
// Propagate any explicit overrides the user passed to `setup`
|
|
61
|
+
const passthroughFlags = [
|
|
62
|
+
'project-name', 'project-type', 'framework', 'framework-installed',
|
|
63
|
+
'classification', 'lang', 'language', 'profile', 'backend', 'frontend',
|
|
64
|
+
'database', 'auth', 'uiux', 'design-skill', 'test-runner',
|
|
65
|
+
'web3-enabled', 'web3-networks', 'contract-framework',
|
|
66
|
+
'wallet-provider', 'indexer', 'rpc-provider',
|
|
67
|
+
'queues', 'storage', 'websockets', 'payments', 'email', 'cache', 'search'
|
|
68
|
+
];
|
|
69
|
+
for (const flag of passthroughFlags) {
|
|
70
|
+
if (Object.prototype.hasOwnProperty.call(options, flag)) {
|
|
71
|
+
contextOptions[flag] = options[flag];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Apply language: explicit flag > system detection
|
|
76
|
+
if (!contextOptions.lang && !contextOptions.language) {
|
|
77
|
+
contextOptions.lang = systemLang;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// For greenfield projects (nothing detected), ask minimal interactive questions
|
|
81
|
+
// unless --defaults is set or the user already passed --framework
|
|
82
|
+
const isGreenfield = !detectedFramework;
|
|
83
|
+
const frameworkProvided = Object.prototype.hasOwnProperty.call(options, 'framework');
|
|
84
|
+
|
|
85
|
+
if (!defaultsMode && isGreenfield && !frameworkProvided) {
|
|
86
|
+
const rl = readline.createInterface({
|
|
87
|
+
input: process.stdin,
|
|
88
|
+
output: process.stdout
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
logger.log(t('setup.no_framework_detected'));
|
|
93
|
+
|
|
94
|
+
const projectName = await ask(
|
|
95
|
+
rl,
|
|
96
|
+
t('setup.q_project_name'),
|
|
97
|
+
path.basename(targetDir) || 'my-project'
|
|
98
|
+
);
|
|
99
|
+
if (projectName !== path.basename(targetDir)) {
|
|
100
|
+
contextOptions['project-name'] = projectName;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const framework = await ask(rl, t('setup.q_framework'), '');
|
|
104
|
+
if (framework) {
|
|
105
|
+
contextOptions.framework = framework;
|
|
106
|
+
contextOptions['framework-installed'] = 'false';
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const detectedLang = contextOptions.lang || systemLang;
|
|
110
|
+
const lang = await ask(rl, t('setup.q_lang'), detectedLang);
|
|
111
|
+
contextOptions.lang = lang;
|
|
112
|
+
} finally {
|
|
113
|
+
rl.close();
|
|
114
|
+
}
|
|
115
|
+
} else if (!defaultsMode && detectedFramework) {
|
|
116
|
+
// Existing project with detected framework — confirm before proceeding
|
|
117
|
+
const rl = readline.createInterface({
|
|
118
|
+
input: process.stdin,
|
|
119
|
+
output: process.stdout
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
try {
|
|
123
|
+
logger.log(
|
|
124
|
+
t('setup.framework_detected', {
|
|
125
|
+
framework: detectedFramework,
|
|
126
|
+
installed: String(detectedInstalled)
|
|
127
|
+
})
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
const confirmed = normalizeBoolean(
|
|
131
|
+
await ask(rl, t('setup.q_confirm_framework'), 'true'),
|
|
132
|
+
true
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
if (!confirmed) {
|
|
136
|
+
const override = await ask(rl, t('setup.q_override_framework'), detectedFramework);
|
|
137
|
+
contextOptions.framework = override;
|
|
138
|
+
contextOptions['framework-installed'] = await ask(
|
|
139
|
+
rl,
|
|
140
|
+
t('setup.q_framework_installed'),
|
|
141
|
+
'false'
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const detectedLang = contextOptions.lang || systemLang;
|
|
146
|
+
const lang = await ask(rl, t('setup.q_lang'), detectedLang);
|
|
147
|
+
contextOptions.lang = lang;
|
|
148
|
+
} finally {
|
|
149
|
+
rl.close();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Step 4 — run setup:context with fully resolved options
|
|
154
|
+
logger.log(t('setup.writing_context'));
|
|
155
|
+
const contextResult = await runSetupContext({
|
|
156
|
+
args: [targetDir],
|
|
157
|
+
options: contextOptions,
|
|
158
|
+
logger,
|
|
159
|
+
t
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
if (!dryRun) {
|
|
163
|
+
logger.log('');
|
|
164
|
+
logger.log(t('setup.done'));
|
|
165
|
+
logger.log(t('setup.step_agents'));
|
|
166
|
+
logger.log(t('setup.step_agent_prompt', { tool: promptTool }));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
ok: true,
|
|
171
|
+
targetDir,
|
|
172
|
+
installResult,
|
|
173
|
+
contextResult,
|
|
174
|
+
detection
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
module.exports = { runSetup };
|