@automaton-labs/aib 0.0.7 → 0.0.9
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/README.md +21 -578
- package/config/agent-dx-policy.default.json +31 -0
- package/config/control-plane-client.default.json +3 -0
- package/dist/agent-dx/agent-dx.js +805 -0
- package/dist/agent-dx/presentation.js +32 -0
- package/dist/alias-advisor/analyze.js +982 -0
- package/dist/alias-advisor/exact-text-cost.js +74 -0
- package/dist/alias-advisor/lexical.js +240 -0
- package/dist/alias-advisor/model.js +2 -0
- package/dist/alias-advisor/path-identity.js +49 -0
- package/dist/alias-advisor/ranking.js +171 -0
- package/dist/alias-advisor/token-estimator.js +85 -0
- package/dist/bin/aib.js +5 -1
- package/dist/bin/cli.js +811 -4
- package/dist/commands/add-missing-imports-preview-cache.js +99 -2
- package/dist/commands/add-missing-imports.js +241 -2
- package/dist/commands/apply-module-plan.js +1319 -3
- package/dist/commands/background-command.js +378 -2
- package/dist/commands/captured-input.js +74 -1
- package/dist/commands/config-command.js +314 -2
- package/dist/commands/config-output.js +357 -10
- package/dist/commands/control-plane-command.js +183 -1
- package/dist/commands/declaration-command.js +1209 -7
- package/dist/commands/declaration-execution-cache.js +79 -1
- package/dist/commands/declaration-format.js +221 -1
- package/dist/commands/declaration-preview-cache.js +114 -2
- package/dist/commands/diagnostics-command.js +70 -3
- package/dist/commands/doctor.js +137 -3
- package/dist/commands/execution-command.js +117 -1
- package/dist/commands/exports-star-collapse-command.js +178 -0
- package/dist/commands/exports-star-command.js +252 -0
- package/dist/commands/exports-star-preview-cache.js +84 -0
- package/dist/commands/feedback-command.js +176 -3
- package/dist/commands/file-move-to-dir-execution-cache.js +92 -1
- package/dist/commands/file-move-to-dir-preview-cache.js +125 -2
- package/dist/commands/file-move-to-dir-worker.js +54 -0
- package/dist/commands/file-move-to-dir.js +1073 -5
- package/dist/commands/file-mutation-runtime.js +102 -1
- package/dist/commands/file-mutation-worker-apply.js +180 -0
- package/dist/commands/file-refactor-batch-execution-cache.js +90 -1
- package/dist/commands/file-refactor-batch-preview-cache.js +125 -2
- package/dist/commands/file-refactor-batch-worker.js +54 -0
- package/dist/commands/file-refactor-batch.js +1154 -5
- package/dist/commands/file-rename-execution-cache.js +92 -1
- package/dist/commands/file-rename-preview-cache.js +125 -2
- package/dist/commands/file-rename-worker.js +54 -0
- package/dist/commands/file-rename.js +1053 -5
- package/dist/commands/file-text-edit-executor.js +205 -0
- package/dist/commands/find-importers.js +52 -1
- package/dist/commands/find-unused-imports.js +55 -1
- package/dist/commands/generate-docs-command.js +244 -6
- package/dist/commands/help-command.js +460 -7
- package/dist/commands/import-specifier-policy.js +391 -0
- package/dist/commands/imports-command.js +68 -1
- package/dist/commands/imports-rebase.js +1138 -0
- package/dist/commands/init-skill-usage.js +92 -3
- package/dist/commands/init-workspace.js +30 -1
- package/dist/commands/inspect-alias-candidates.js +413 -0
- package/dist/commands/inspect-cycles.js +811 -5
- package/dist/commands/inspect-direct-usages.js +98 -0
- package/dist/commands/inspect-duplicates-format.js +229 -0
- package/dist/commands/inspect-format-primitives.js +127 -0
- package/dist/commands/inspect-format.js +1590 -18
- package/dist/commands/inspect-graph.js +1553 -9
- package/dist/commands/inspect-imports.js +339 -2
- package/dist/commands/inspect-mixed-format.js +524 -0
- package/dist/commands/inspect-module-plan-format.js +216 -0
- package/dist/commands/inspect-module-plan-serialization.js +402 -0
- package/dist/commands/inspect-reference-path-format.js +157 -0
- package/dist/commands/inspect-request-values.js +599 -0
- package/dist/commands/inspect-selector-kind.js +21 -0
- package/dist/commands/inspect-selector.js +50 -0
- package/dist/commands/inspect-symbol-format.js +90 -0
- package/dist/commands/inspect-topology.js +435 -0
- package/dist/commands/inspect-tree.js +827 -5
- package/dist/commands/inspect-usages-detail.js +793 -0
- package/dist/commands/inspect-usages-evidence.js +31 -0
- package/dist/commands/inspect-usages-format.js +367 -0
- package/dist/commands/inspect.js +1450 -16
- package/dist/commands/internal-command.js +64 -0
- package/dist/commands/json-file-input.js +60 -1
- package/dist/commands/module-plan-cache.js +156 -2
- package/dist/commands/module-plan-standalone.js +208 -0
- package/dist/commands/module-plan-timeout.js +77 -1
- package/dist/commands/move-preview-cache.js +101 -2
- package/dist/commands/mutate-aggregate-output.js +996 -0
- package/dist/commands/mutate-child-execution.js +374 -0
- package/dist/commands/mutate-command.js +1394 -0
- package/dist/commands/mutate-declaration-output.js +313 -0
- package/dist/commands/mutate-domain-adapters.js +638 -0
- package/dist/commands/mutate-execution-cache.js +114 -0
- package/dist/commands/mutate-execution-status.js +598 -0
- package/dist/commands/mutate-failure-output.js +531 -0
- package/dist/commands/mutate-file-view.js +151 -0
- package/dist/commands/mutate-object-output.js +91 -0
- package/dist/commands/mutate-output-values.js +97 -0
- package/dist/commands/mutate-preview-cache.js +86 -0
- package/dist/commands/mutate-response-replay.js +153 -0
- package/dist/commands/mutate-result-projection.js +818 -0
- package/dist/commands/mutation-eta.js +28 -0
- package/dist/commands/mutation-execution-cache.js +140 -3
- package/dist/commands/mutation-recovery-journal.js +195 -0
- package/dist/commands/normalize-imports.js +1120 -4
- package/dist/commands/object-pack-command.js +546 -0
- package/dist/commands/object-pack-preview-cache.js +88 -0
- package/dist/commands/observability-command.js +47 -3
- package/dist/commands/ota-command.js +403 -2
- package/dist/commands/print-config.js +10 -1
- package/dist/commands/quick-read.js +1113 -11
- package/dist/commands/refactor-batch-builder.js +265 -1
- package/dist/commands/refactor-batch-execution-cache.js +85 -1
- package/dist/commands/refactor-batch-preview-cache.js +96 -2
- package/dist/commands/refactor-batch.js +461 -4
- package/dist/commands/rename-entities.js +794 -4
- package/dist/commands/rename-execution-cache.js +49 -1
- package/dist/commands/rename-input.js +22 -1
- package/dist/commands/rename-polling-policy.js +68 -0
- package/dist/commands/rename-preview-cache.js +96 -2
- package/dist/commands/result-view.js +993 -7
- package/dist/commands/reveal-command.js +445 -5
- package/dist/commands/selector-suggestions.js +93 -0
- package/dist/commands/session-workspace.js +1836 -31
- package/dist/commands/shared.js +2 -1
- package/dist/commands/skills-command.js +315 -0
- package/dist/commands/sync-command.js +59 -2
- package/dist/commands/worker-command.js +173 -1
- package/dist/commands/workspace-cache.js +55 -1
- package/dist/config/defaults.js +26 -1
- package/dist/config/env-vars.js +77 -1
- package/dist/config/glob-match.js +44 -1
- package/dist/config/import-rules.js +165 -1
- package/dist/config/local-config.js +293 -3
- package/dist/config/mutation-comments.js +51 -1
- package/dist/config/path-aliases.js +165 -1
- package/dist/config/path-display.js +84 -1
- package/dist/config/product-storage.js +37 -1
- package/dist/config/request-env.js +21 -0
- package/dist/config/request-routing-context.js +23 -0
- package/dist/config/resolve-command-alias.js +74 -1
- package/dist/config/resolve.js +24 -1
- package/dist/config/tsconfig-discovery.js +113 -1
- package/dist/config/typescript-preferences.js +131 -0
- package/dist/config/workspace-root.js +310 -3
- package/dist/config/workspace-state.js +254 -1
- package/dist/content/content-bundle.js +88 -1
- package/dist/diagnostics/module-plan-timeline.js +75 -2
- package/dist/diagnostics/readiness-text.js +45 -8
- package/dist/dsl/aib-dsl.js +838 -1
- package/dist/dsl/declaration-dsl.js +264 -1
- package/dist/dsl/file-move-to-dir-dsl.js +123 -1
- package/dist/dsl/file-refactor-batch-dsl.js +203 -1
- package/dist/dsl/file-rename-dsl.js +135 -1
- package/dist/dsl/mutate-dsl.js +746 -0
- package/dist/help/bootstrap.bash.md +176 -341
- package/dist/help/bootstrap.md +175 -340
- package/dist/help/bootstrap.pwsh.md +176 -341
- package/dist/help/docs/basics.md +1 -1
- package/dist/help/docs/config-setup.import-normalize.md +65 -65
- package/dist/help/docs/config-setup.import-rules.md +6 -5
- package/dist/help/docs/first-setup.md +6 -5
- package/dist/help/docs/help-protocol.md +4 -3
- package/dist/help/docs/import.base.md +38 -0
- package/dist/help/docs/import.rebase.md +85 -0
- package/dist/help/docs/inspect.aliasCandidates.md +39 -0
- package/dist/help/docs/inspect.code.md +1 -7
- package/dist/help/docs/inspect.file.md +10 -19
- package/dist/help/docs/inspect.graph.md +3 -17
- package/dist/help/{dsl/docs/inspect.md → docs/inspect.shared.md} +13 -12
- package/dist/help/docs/modulePlan.md +24 -28
- package/dist/help/docs/move.md +19 -22
- package/dist/help/{dsl/topics/file.move.md → docs/moveToDir.md} +36 -34
- package/dist/help/docs/mutate.mixed.md +34 -0
- package/dist/help/docs/mutation.shared.md +55 -0
- package/dist/help/docs/patterns.md +3 -12
- package/dist/help/docs/qr.md +12 -6
- package/dist/help/docs/quick-map.md +36 -24
- package/dist/help/docs/recipe.file-layout.md +10 -10
- package/dist/help/docs/recipe.import-boundary.md +92 -0
- package/dist/help/docs/recipe.safe-artifact-probing.md +68 -0
- package/dist/help/docs/recipe.unfamiliar-area.md +64 -0
- package/dist/help/docs/recipes.md +20 -0
- package/dist/help/docs/rename.md +19 -27
- package/dist/help/docs/renameFile.md +36 -0
- package/dist/help/docs/rules.md +26 -0
- package/dist/help/dsl/bootstrap.bash.md +176 -341
- package/dist/help/dsl/bootstrap.md +175 -340
- package/dist/help/dsl/bootstrap.pwsh.md +176 -341
- package/dist/help/dsl/docs/basics.md +1 -1
- package/dist/help/dsl/docs/config-setup.import-normalize.md +65 -65
- package/dist/help/dsl/docs/config-setup.import-rules.md +6 -5
- package/dist/help/dsl/docs/first-setup.md +6 -5
- package/dist/help/dsl/docs/help-protocol.md +4 -3
- package/dist/help/dsl/docs/import.base.md +38 -0
- package/dist/help/dsl/docs/import.rebase.md +85 -0
- package/dist/help/dsl/docs/inspect.aliasCandidates.md +39 -0
- package/dist/help/dsl/docs/inspect.code.md +1 -7
- package/dist/help/dsl/docs/inspect.file.md +10 -19
- package/dist/help/dsl/docs/inspect.graph.md +3 -17
- package/dist/help/{docs/inspect.md → dsl/docs/inspect.shared.md} +13 -12
- package/dist/help/dsl/docs/modulePlan.md +24 -28
- package/dist/help/dsl/docs/move.md +19 -22
- package/dist/help/{topics/file.move.md → dsl/docs/moveToDir.md} +36 -34
- package/dist/help/dsl/docs/mutate.mixed.md +34 -0
- package/dist/help/dsl/docs/mutation.shared.md +55 -0
- package/dist/help/dsl/docs/patterns.md +3 -12
- package/dist/help/dsl/docs/qr.md +12 -6
- package/dist/help/dsl/docs/quick-map.md +36 -24
- package/dist/help/dsl/docs/recipe.file-layout.md +10 -10
- package/dist/help/dsl/docs/recipe.import-boundary.md +92 -0
- package/dist/help/dsl/docs/recipe.safe-artifact-probing.md +68 -0
- package/dist/help/dsl/docs/recipe.unfamiliar-area.md +64 -0
- package/dist/help/dsl/docs/recipes.md +20 -0
- package/dist/help/dsl/docs/rename.md +19 -27
- package/dist/help/dsl/docs/renameFile.md +36 -0
- package/dist/help/dsl/docs/rules.md +26 -0
- package/dist/help/dsl/full.md +175 -340
- package/dist/help/dsl/help-index.md +48 -43
- package/dist/help/dsl/snippets/agents.md +2 -2
- package/dist/help/dsl/tokens/qr.inline.examples.md +1 -1
- package/dist/help/dsl/topics/basics.md +1 -1
- package/dist/help/dsl/topics/config-setup.import-normalize.md +65 -65
- package/dist/help/dsl/topics/config-setup.import-rules.md +6 -5
- package/dist/help/dsl/topics/first-setup.md +6 -5
- package/dist/help/dsl/topics/help-protocol.md +4 -3
- package/dist/help/dsl/topics/import.base.md +36 -0
- package/dist/help/dsl/topics/import.rebase.md +83 -0
- package/dist/help/dsl/topics/inspect.aliasCandidates.md +37 -0
- package/dist/help/dsl/topics/inspect.code.md +1 -7
- package/dist/help/dsl/topics/inspect.file.md +10 -19
- package/dist/help/dsl/topics/inspect.graph.md +3 -17
- package/dist/help/dsl/topics/{inspect.md → inspect.shared.md} +13 -12
- package/dist/help/dsl/topics/modulePlan.md +21 -26
- package/dist/help/dsl/topics/move.md +17 -18
- package/dist/help/{docs/file.move.md → dsl/topics/moveToDir.md} +33 -35
- package/dist/help/dsl/topics/mutate.mixed.md +32 -0
- package/dist/help/dsl/topics/mutation.shared.md +53 -0
- package/dist/help/dsl/topics/patterns.md +3 -12
- package/dist/help/dsl/topics/qr.md +12 -6
- package/dist/help/dsl/topics/quick-map.md +36 -24
- package/dist/help/dsl/topics/recipe.file-layout.md +10 -10
- package/dist/help/dsl/topics/recipe.import-boundary.md +90 -0
- package/dist/help/dsl/topics/recipe.safe-artifact-probing.md +66 -0
- package/dist/help/dsl/topics/recipe.unfamiliar-area.md +62 -0
- package/dist/help/dsl/topics/recipes.md +18 -0
- package/dist/help/dsl/topics/rename.md +15 -15
- package/dist/help/dsl/topics/renameFile.md +34 -0
- package/dist/help/dsl/topics/rules.md +24 -0
- package/dist/help/full.md +175 -340
- package/dist/help/help-index.md +48 -43
- package/dist/help/help-meta.json +98 -48
- package/dist/help/index.md +52 -20
- package/dist/help/snippets/agents.md +2 -2
- package/dist/help/tokens/qr.inline.examples.md +1 -1
- package/dist/help/topics/basics.md +1 -1
- package/dist/help/topics/config-setup.import-normalize.md +65 -65
- package/dist/help/topics/config-setup.import-rules.md +6 -5
- package/dist/help/topics/first-setup.md +6 -5
- package/dist/help/topics/help-protocol.md +4 -3
- package/dist/help/topics/import.base.md +36 -0
- package/dist/help/topics/import.rebase.md +83 -0
- package/dist/help/topics/inspect.aliasCandidates.md +37 -0
- package/dist/help/topics/inspect.code.md +1 -7
- package/dist/help/topics/inspect.file.md +10 -19
- package/dist/help/topics/inspect.graph.md +3 -17
- package/dist/help/topics/{inspect.md → inspect.shared.md} +13 -12
- package/dist/help/topics/modulePlan.md +21 -26
- package/dist/help/topics/move.md +17 -18
- package/dist/help/{dsl/docs/file.move.md → topics/moveToDir.md} +33 -35
- package/dist/help/topics/mutate.mixed.md +32 -0
- package/dist/help/topics/mutation.shared.md +53 -0
- package/dist/help/topics/patterns.md +3 -12
- package/dist/help/topics/qr.md +12 -6
- package/dist/help/topics/quick-map.md +36 -24
- package/dist/help/topics/recipe.file-layout.md +10 -10
- package/dist/help/topics/recipe.import-boundary.md +90 -0
- package/dist/help/topics/recipe.safe-artifact-probing.md +66 -0
- package/dist/help/topics/recipe.unfamiliar-area.md +62 -0
- package/dist/help/topics/recipes.md +18 -0
- package/dist/help/topics/rename.md +15 -15
- package/dist/help/topics/renameFile.md +34 -0
- package/dist/help/topics/rules.md +24 -0
- package/dist/host/capabilities.js +56 -1
- package/dist/imports/standalone-import-analysis.js +602 -0
- package/dist/imports/standalone-import-model.js +2 -0
- package/dist/imports/standalone-import-process.js +66 -0
- package/dist/imports/standalone-import-worker.js +27 -0
- package/dist/imports/standalone-ts-project.js +147 -0
- package/dist/inspect/inspect-duplicates-service.js +526 -0
- package/dist/inspect/inspect-reverse-module-closure.js +338 -0
- package/dist/inspect/inspect-source-ranges.js +82 -0
- package/dist/inspect/inspect-source-shape.js +649 -0
- package/dist/inspect/standalone-inspect-analysis.js +319 -0
- package/dist/inspect/standalone-inspect-model.js +9 -0
- package/dist/inspect/standalone-inspect-process.js +55 -0
- package/dist/inspect/standalone-inspect-usages.js +274 -0
- package/dist/inspect/standalone-inspect-worker.js +13 -0
- package/dist/metrics/central-metrics.js +101 -2
- package/dist/mutation/concrete-edit-plan.js +157 -0
- package/dist/mutation/exports-star-collapse-preview.js +361 -0
- package/dist/mutation/exports-star-expand-apply.js +373 -0
- package/dist/mutation/exports-star-expand-preview.js +807 -0
- package/dist/mutation/file-impact-scan.js +182 -0
- package/dist/mutation/file-mutation-discovery.js +674 -0
- package/dist/mutation/file-mutation-eta.js +99 -0
- package/dist/mutation/file-mutation-standalone-apply.js +584 -0
- package/dist/mutation/file-mutation-standalone-planner.js +500 -0
- package/dist/mutation/file-mutation-tsserver-session.js +473 -0
- package/dist/mutation/mutation-estimate.js +45 -0
- package/dist/mutation/mutation-plan.js +467 -0
- package/dist/mutation/object-mutation-foundation.js +2 -0
- package/dist/mutation/object-mutation-partition.js +148 -0
- package/dist/mutation/object-pack-semantic-apply.js +507 -0
- package/dist/mutation/object-pack-semantic-preview.js +984 -0
- package/dist/mutation/object-unpack-semantic-preview.js +993 -0
- package/dist/mutation/package-manifest-impact.js +176 -0
- package/dist/mutation/rename-owner-worker-child.js +37 -0
- package/dist/mutation/rename-owner-worker.js +122 -0
- package/dist/mutation/runtime-cycle-query.js +66 -0
- package/dist/mutation/semantic-execution-progress.js +63 -0
- package/dist/mutation/semantic-export-index.js +474 -0
- package/dist/mutation/semantic-impact-scan.js +434 -0
- package/dist/mutation/semantic-model.js +2 -0
- package/dist/mutation/semantic-move-best-effort-planner.js +209 -0
- package/dist/mutation/semantic-move-config-worker-child.js +61 -0
- package/dist/mutation/semantic-move-config-worker.js +449 -0
- package/dist/mutation/semantic-move-declarations.js +94 -0
- package/dist/mutation/semantic-move-metrics.js +119 -0
- package/dist/mutation/semantic-move-model.js +2 -0
- package/dist/mutation/semantic-move-owner-authority.js +122 -0
- package/dist/mutation/semantic-move-owner-candidates.js +300 -0
- package/dist/mutation/semantic-move-owner-divergence-harness.js +474 -0
- package/dist/mutation/semantic-move-owner-divergence-runner.js +162 -0
- package/dist/mutation/semantic-move-plan-hash.js +56 -0
- package/dist/mutation/semantic-move-policy.js +360 -0
- package/dist/mutation/semantic-move-process.js +218 -0
- package/dist/mutation/semantic-move-provider-diagnostics.js +27 -0
- package/dist/mutation/semantic-move-standalone-engine.js +919 -0
- package/dist/mutation/semantic-move-standalone-planner.js +1553 -0
- package/dist/mutation/semantic-move-transaction.js +639 -0
- package/dist/mutation/semantic-mutation-engine.js +478 -0
- package/dist/mutation/semantic-mutation-runtime.js +521 -0
- package/dist/mutation/semantic-planner-retry.js +26 -0
- package/dist/mutation/semantic-program-roots.js +69 -0
- package/dist/mutation/semantic-rename-commonjs.js +229 -0
- package/dist/mutation/semantic-rename-config-worker-child.js +46 -0
- package/dist/mutation/semantic-rename-config-worker.js +498 -0
- package/dist/mutation/semantic-rename-locations.js +192 -0
- package/dist/mutation/semantic-rename-model.js +2 -0
- package/dist/mutation/semantic-rename-process.js +217 -0
- package/dist/mutation/semantic-rename-standalone-engine.js +302 -0
- package/dist/mutation/semantic-rename-standalone-planner.js +567 -0
- package/dist/mutation/semantic-rename-transaction.js +333 -0
- package/dist/mutation/semantic-unused-import-cleanup.js +248 -0
- package/dist/mutation/semantic-worker-retry.js +40 -0
- package/dist/mutation/semantic-workspace.js +804 -0
- package/dist/mutation/targeted-import-canonicalizer.js +359 -0
- package/dist/observability/config.js +206 -1
- package/dist/observability/context.js +59 -1
- package/dist/observability/failure-snapshot.js +124 -2
- package/dist/observability/recent.js +63 -2
- package/dist/payloads/read-stdin-json.js +212 -1
- package/dist/rg-wrapper/core.js +714 -6
- package/dist/rg-wrapper/options.js +125 -1
- package/dist/rtk-wrapper/core.js +144 -2
- package/dist/rtk-wrapper/git-safety.js +203 -0
- package/dist/rtk-wrapper/output-adapter.js +106 -0
- package/dist/runtime/buffered-process.js +114 -0
- package/dist/runtime/bundled-node.js +97 -1
- package/dist/runtime/command-lifecycle.js +2 -0
- package/dist/runtime/input-source.js +238 -1
- package/dist/runtime/node-cli-identity.js +37 -0
- package/dist/runtime/run-command.js +191 -1
- package/dist/selectors/parse-entities.js +84 -1
- package/dist/semantic/semantic-context-pool.js +830 -0
- package/dist/semantic/semantic-context-provider.js +416 -0
- package/dist/semantic/semantic-resident-admission.js +38 -0
- package/dist/semantic/semantic-worker-child.js +40 -0
- package/dist/semantic/semantic-worker-manager.js +460 -0
- package/dist/semantic/semantic-worker-protocol.js +2 -0
- package/dist/semantic/semantic-worker-runtime.js +38 -0
- package/dist/semantic/workspace-semantic-context-pools.js +136 -0
- package/dist/session/client.js +359 -1
- package/dist/session/daemon-state.js +185 -2
- package/dist/session/external-tool-coordinator.js +88 -0
- package/dist/session/external-tool-request.js +52 -0
- package/dist/session/lane-owner.js +116 -0
- package/dist/session/paths.js +71 -1
- package/dist/session/runtime-lifecycle.js +225 -0
- package/dist/session/runtime-shutdown.js +95 -0
- package/dist/session/server.js +1194 -7
- package/dist/session/session-health.js +27 -0
- package/dist/shared/agent-text.js +29 -1
- package/dist/shared/errors.js +496 -30
- package/dist/shared/event-loop.js +6 -1
- package/dist/shared/hints.js +37 -1
- package/dist/shared/metrics.js +43 -1
- package/dist/shared/presentation.js +69 -4
- package/dist/shared/stdin-examples.js +77 -1
- package/dist/shared/stdout.js +6 -2
- package/dist/shared/types.js +23 -1
- package/dist/tool-runtime/runtime-tools.js +120 -1
- package/dist/topology/availability.js +663 -0
- package/dist/topology/cache.js +130 -0
- package/dist/topology/candidates.js +372 -0
- package/dist/topology/core.js +903 -0
- package/dist/topology/dependency-snapshot.js +189 -0
- package/dist/topology/model.js +2 -0
- package/dist/topology/scope.js +100 -0
- package/dist/topology/ts-oracle-batch.js +529 -0
- package/dist/topology/ts-oracle-host.js +69 -0
- package/dist/topology/ts-oracle-model.js +2 -0
- package/dist/topology/ts-oracle.js +224 -0
- package/dist/topology/tsconfig-loader.js +105 -0
- package/dist/topology/workspace-project-index.js +542 -0
- package/dist/tracing/config.js +192 -2
- package/dist/tracing/failure-summary.js +100 -0
- package/dist/tracing/trace.js +318 -5
- package/dist/tsc-wrapper/core.js +697 -0
- package/dist/workers/control-plane/aib-control-plane-worker.cjs +32 -32
- package/dist/workers/control-plane/client-config.default.json +3 -3
- package/dist/workers/lexical-worker-child.js +27 -0
- package/dist/workers/lexical-worker-manager.js +394 -0
- package/dist/workers/lexical-worker-protocol.js +2 -0
- package/dist/workers/lexical-worker-runtime.js +25 -0
- package/dist/workers/owned-one-shot-process.js +115 -0
- package/dist/workers/product-storage.js +23 -1
- package/dist/workers/registry.js +241 -1
- package/package.json +8 -13
- package/scripts/postinstall.cjs +29 -29
- package/scripts/provision-runtime.cjs +411 -459
- package/dist/client/http-client.js +0 -1
- package/dist/client/transport-options.js +0 -1
- package/dist/client/websocket-client.js +0 -1
- package/dist/commands/entity-resolution.js +0 -1
- package/dist/commands/file-command.js +0 -1
- package/dist/commands/host-command.js +0 -1
- package/dist/commands/inspect-symbol-query.js +0 -1
- package/dist/commands/list-instances.js +0 -1
- package/dist/commands/module-plan-command.js +0 -1
- package/dist/commands/move-command.js +0 -1
- package/dist/commands/move-to-file.js +0 -2
- package/dist/commands/ping.js +0 -1
- package/dist/commands/refactor-command.js +0 -1
- package/dist/commands/rename-command.js +0 -1
- package/dist/commands/runtime-command.js +0 -4
- package/dist/commands/runtime-info.js +0 -1
- package/dist/commands/validate-module-plan.js +0 -2
- package/dist/compatibility/policy.js +0 -1
- package/dist/config/auto-start-ide.js +0 -1
- package/dist/discovery/registry.js +0 -1
- package/dist/discovery/select-instance.js +0 -1
- package/dist/help/docs/file.rename.md +0 -35
- package/dist/help/docs/mutation.md +0 -60
- package/dist/help/docs/refactor.batch.md +0 -44
- package/dist/help/dsl/docs/file.rename.md +0 -35
- package/dist/help/dsl/docs/mutation.md +0 -60
- package/dist/help/dsl/docs/refactor.batch.md +0 -44
- package/dist/help/dsl/topics/file.rename.md +0 -33
- package/dist/help/dsl/topics/mutation.md +0 -58
- package/dist/help/dsl/topics/refactor.batch.md +0 -33
- package/dist/help/topics/file.rename.md +0 -33
- package/dist/help/topics/mutation.md +0 -58
- package/dist/help/topics/refactor.batch.md +0 -33
- package/dist/ide-launch/common.cjs +0 -162
- package/dist/managed-host/extension-vsix-resolver.js +0 -1
- package/dist/managed-host/manage-serve-web-host.cjs +0 -141
- package/dist/managed-host/serve-web-autostart.js +0 -1
- package/dist/managed-host/serve-web-host.cjs +0 -2115
- package/dist/runtime/managed-runtime-provisioning.js +0 -1
- package/dist/shared/diagnostic-catalog.js +0 -1
- package/dist/shared/diagnostics.js +0 -1
- package/dist/shared/operations.js +0 -1
- package/dist/shared/protocol.js +0 -1
- package/dist/shared/routes.js +0 -1
- package/extension/vscode-refactor-bridge-extension.vsix +0 -0
- package/runtimes/launcher/linux-x64/aib +0 -0
- package/runtimes/launcher/win-x64/aib.exe +0 -0
|
@@ -1,31 +1,1836 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.isSessionHandle = isSessionHandle;
|
|
37
|
+
exports.runWithSessionOverride = runWithSessionOverride;
|
|
38
|
+
exports.runSessionWorkspaceCommand = runSessionWorkspaceCommand;
|
|
39
|
+
exports.resolveSessionFileArgument = resolveSessionFileArgument;
|
|
40
|
+
exports.saveSessionOutputJson = saveSessionOutputJson;
|
|
41
|
+
exports.saveSessionOutputText = saveSessionOutputText;
|
|
42
|
+
exports.saveSessionResultJson = saveSessionResultJson;
|
|
43
|
+
exports.saveSessionResultViewJson = saveSessionResultViewJson;
|
|
44
|
+
exports.readSessionResultViewJson = readSessionResultViewJson;
|
|
45
|
+
exports.readSessionResultJson = readSessionResultJson;
|
|
46
|
+
exports.captureSessionInputJson = captureSessionInputJson;
|
|
47
|
+
exports.captureSessionInput = captureSessionInput;
|
|
48
|
+
exports.sessionWorkspaceExists = sessionWorkspaceExists;
|
|
49
|
+
exports.useSessionGuidance = useSessionGuidance;
|
|
50
|
+
exports.readSessionBooleanPref = readSessionBooleanPref;
|
|
51
|
+
exports.readSessionNumberPref = readSessionNumberPref;
|
|
52
|
+
exports.readSessionStringPref = readSessionStringPref;
|
|
53
|
+
exports.readEffectiveSessionPathAliases = readEffectiveSessionPathAliases;
|
|
54
|
+
exports.readSessionPathAliasOverrides = readSessionPathAliasOverrides;
|
|
55
|
+
exports.tryResolveCurrentSessionId = tryResolveCurrentSessionId;
|
|
56
|
+
const fs = __importStar(require("node:fs"));
|
|
57
|
+
const path = __importStar(require("node:path"));
|
|
58
|
+
const node_async_hooks_1 = require("node:async_hooks");
|
|
59
|
+
const env_vars_1 = require("../config/env-vars");
|
|
60
|
+
const workspace_root_1 = require("../config/workspace-root");
|
|
61
|
+
const path_aliases_1 = require("../config/path-aliases");
|
|
62
|
+
const agent_text_1 = require("../shared/agent-text");
|
|
63
|
+
const errors_1 = require("../shared/errors");
|
|
64
|
+
const DEFAULT_SESSION_ROOT = path.join(".tmp", "aib");
|
|
65
|
+
const SESSION_DIR_CONFIG_KEY = "sessionDir";
|
|
66
|
+
const SESSION_REGISTRY_FILE_NAME = "session.json";
|
|
67
|
+
const ACTIVE_SESSION_FILE_NAME = "active.json";
|
|
68
|
+
const HANDLE_PREFIX = "aib:";
|
|
69
|
+
const SESSION_ID_PREFIX = "s_";
|
|
70
|
+
const DEFAULT_AUTO_SESSION_ID = "_default";
|
|
71
|
+
const LAST_INPUT_NAME = "last";
|
|
72
|
+
const LAST_INPUT_FILE_NAME = "_last.json";
|
|
73
|
+
const sessionOverrideStorage = new node_async_hooks_1.AsyncLocalStorage();
|
|
74
|
+
const OUTPUT_KINDS = [
|
|
75
|
+
"graph",
|
|
76
|
+
"inspect",
|
|
77
|
+
"code",
|
|
78
|
+
"slice",
|
|
79
|
+
"members",
|
|
80
|
+
"exports",
|
|
81
|
+
"deps",
|
|
82
|
+
"usages",
|
|
83
|
+
"duplicates",
|
|
84
|
+
"mutate",
|
|
85
|
+
"execution",
|
|
86
|
+
"imports"
|
|
87
|
+
];
|
|
88
|
+
const INPUT_KINDS = [
|
|
89
|
+
"inspect",
|
|
90
|
+
"graph",
|
|
91
|
+
"mutate",
|
|
92
|
+
"imports",
|
|
93
|
+
"generic"
|
|
94
|
+
];
|
|
95
|
+
const SESSION_PREF_DEFS = {
|
|
96
|
+
"guidance.nextLimit": { type: "number", default: 2, min: 0, max: 100, hidden: true },
|
|
97
|
+
"diagnostics.hintLimit": { type: "number", default: 2, min: 0, max: 100, hidden: true },
|
|
98
|
+
"inspect.code.show": { type: "boolean", default: true, hidden: true },
|
|
99
|
+
"inspect.code.maxNonEmptyLines": { type: "number", default: 120, min: 1, max: 10000 },
|
|
100
|
+
"inspect.code.meta": { type: "boolean", default: true, hidden: true },
|
|
101
|
+
"inspect.members.maxItems": { type: "number", default: 20, min: 1, max: 1000 },
|
|
102
|
+
"inspect.members.all": { type: "boolean", default: false, hidden: true },
|
|
103
|
+
"inspect.exports.ranges": { type: "boolean", default: false, hidden: true },
|
|
104
|
+
"inspect.exports.resolveStar": { type: "boolean", default: false, hidden: true },
|
|
105
|
+
"inspect.graph.hubs": { type: "boolean", default: true },
|
|
106
|
+
"inspect.graph.entrypoints": { type: "boolean", default: true },
|
|
107
|
+
"inspect.graph.leaves": { type: "boolean", default: true },
|
|
108
|
+
"inspect.graph.edges": { type: "boolean", default: true },
|
|
109
|
+
"inspect.graph.symbols": { type: "boolean", default: false, hidden: true },
|
|
110
|
+
"inspect.graph.symbolUsage": { type: "boolean", default: false },
|
|
111
|
+
"inspect.usages.detail": { type: "string", default: "locations", values: ["summary", "locations", "code"], hidden: true },
|
|
112
|
+
"inspect.usages.maxLocations": { type: "number", default: 12, min: 1, max: 10000 },
|
|
113
|
+
"inspect.usages.maxCodeBlocks": { type: "number", default: 8, min: 1, max: 10000 },
|
|
114
|
+
"inspect.usages.excludeTarget": { type: "boolean", default: false, hidden: true }
|
|
115
|
+
};
|
|
116
|
+
function isSessionHandle(value) {
|
|
117
|
+
return value.startsWith(HANDLE_PREFIX);
|
|
118
|
+
}
|
|
119
|
+
function runWithSessionOverride(sessionId, callback) {
|
|
120
|
+
if (!sessionId) {
|
|
121
|
+
return callback();
|
|
122
|
+
}
|
|
123
|
+
return sessionOverrideStorage.run(sessionId, callback);
|
|
124
|
+
}
|
|
125
|
+
function runSessionWorkspaceCommand(cwd, restArgs, stdinPayload) {
|
|
126
|
+
const command = restArgs[0] ?? "status";
|
|
127
|
+
const resolvedWorkspace = (0, workspace_root_1.resolveWorkspaceRoot)(cwd);
|
|
128
|
+
if (!resolvedWorkspace) {
|
|
129
|
+
if (command === "status") {
|
|
130
|
+
return (0, agent_text_1.attachAgentText)({
|
|
131
|
+
initialized: false,
|
|
132
|
+
active: null,
|
|
133
|
+
source: "none",
|
|
134
|
+
available: [],
|
|
135
|
+
next: "Run aib help first-setup"
|
|
136
|
+
}, [
|
|
137
|
+
"session not ready",
|
|
138
|
+
"",
|
|
139
|
+
"No aib.json was found.",
|
|
140
|
+
"",
|
|
141
|
+
"If you are a user:",
|
|
142
|
+
"ask your agent to set up AIB for this repo:",
|
|
143
|
+
"aib help first-setup",
|
|
144
|
+
"",
|
|
145
|
+
"If you are an agent:",
|
|
146
|
+
"run:",
|
|
147
|
+
"aib help first-setup",
|
|
148
|
+
"",
|
|
149
|
+
"Then follow the setup from the intended repository root."
|
|
150
|
+
].join("\n"));
|
|
151
|
+
}
|
|
152
|
+
(0, workspace_root_1.resolveRequiredWorkspaceRoot)(cwd);
|
|
153
|
+
}
|
|
154
|
+
const workspaceRoot = resolvedWorkspace?.root ?? cwd;
|
|
155
|
+
cleanupExpiredSessions(workspaceRoot);
|
|
156
|
+
if (command === "init") {
|
|
157
|
+
return initSessionWorkspace(workspaceRoot, restArgs.slice(1));
|
|
158
|
+
}
|
|
159
|
+
if (command === "status") {
|
|
160
|
+
return sessionWorkspaceStatus(workspaceRoot);
|
|
161
|
+
}
|
|
162
|
+
if (command === "list") {
|
|
163
|
+
return sessionWorkspaceList(workspaceRoot);
|
|
164
|
+
}
|
|
165
|
+
if (command === "use") {
|
|
166
|
+
return sessionWorkspaceUse(workspaceRoot, restArgs.slice(1));
|
|
167
|
+
}
|
|
168
|
+
if (command === "where") {
|
|
169
|
+
return sessionWorkspaceWhere(workspaceRoot, restArgs.slice(1));
|
|
170
|
+
}
|
|
171
|
+
if (command === "read") {
|
|
172
|
+
return sessionWorkspaceRead(workspaceRoot, restArgs.slice(1), stdinPayload);
|
|
173
|
+
}
|
|
174
|
+
if (command === "write") {
|
|
175
|
+
return sessionWorkspaceWrite(workspaceRoot, restArgs.slice(1), stdinPayload);
|
|
176
|
+
}
|
|
177
|
+
if (command === "prefs") {
|
|
178
|
+
return sessionWorkspacePrefs(workspaceRoot, restArgs.slice(1), stdinPayload);
|
|
179
|
+
}
|
|
180
|
+
if (command === "aliases") {
|
|
181
|
+
return sessionWorkspaceAliases(workspaceRoot, restArgs.slice(1), stdinPayload);
|
|
182
|
+
}
|
|
183
|
+
if (command === "clear") {
|
|
184
|
+
return clearSessionWorkspace(workspaceRoot);
|
|
185
|
+
}
|
|
186
|
+
throw new errors_1.CliError("UNKNOWN_SESSION_WORKSPACE_COMMAND", `Unknown session workspace command: ${command}`);
|
|
187
|
+
}
|
|
188
|
+
function sessionWorkspaceAliases(cwd, args, stdinPayload) {
|
|
189
|
+
const command = args[0] ?? "get";
|
|
190
|
+
if (command === "get") {
|
|
191
|
+
const workspace = readRequiredWorkspace(cwd);
|
|
192
|
+
const config = (0, path_aliases_1.readConfigPathAliases)(cwd);
|
|
193
|
+
const session = (0, path_aliases_1.normalizePathAliasMap)(workspace.pathAliases ?? {}, "session path aliases");
|
|
194
|
+
const response = {
|
|
195
|
+
aliases: (0, path_aliases_1.effectivePathAliases)(cwd, session),
|
|
196
|
+
config,
|
|
197
|
+
session
|
|
198
|
+
};
|
|
199
|
+
return (0, agent_text_1.attachAgentText)(response, formatSessionAliasesAgentText(response));
|
|
200
|
+
}
|
|
201
|
+
if (command === "set") {
|
|
202
|
+
const workspace = readRequiredWorkspace(cwd);
|
|
203
|
+
const updates = args.includes("--stdin")
|
|
204
|
+
? readAliasesStdinPayload(stdinPayload)
|
|
205
|
+
: readAliasesPairArgs(args.slice(1));
|
|
206
|
+
const aliases = (0, path_aliases_1.normalizePathAliasMap)(workspace.pathAliases ?? {}, "session path aliases");
|
|
207
|
+
const updated = {};
|
|
208
|
+
for (const [name, target] of Object.entries(updates)) {
|
|
209
|
+
const alias = (0, path_aliases_1.normalizePathAliasName)(name, "session path aliases");
|
|
210
|
+
if (typeof target !== "string" || target.trim() === "") {
|
|
211
|
+
throw new errors_1.CliError("INVALID_PATH_ALIAS_TARGET", `session path alias ${name} must be a non-empty path string.`);
|
|
212
|
+
}
|
|
213
|
+
aliases[alias] = target.trim().replace(/\\/g, "/");
|
|
214
|
+
updated[alias] = aliases[alias];
|
|
215
|
+
}
|
|
216
|
+
workspace.pathAliases = aliases;
|
|
217
|
+
writeWorkspace(cwd, workspace);
|
|
218
|
+
const response = {
|
|
219
|
+
updated,
|
|
220
|
+
aliases: (0, path_aliases_1.effectivePathAliases)(cwd, aliases)
|
|
221
|
+
};
|
|
222
|
+
return (0, agent_text_1.attachAgentText)(response, formatSessionAliasesAgentText(response));
|
|
223
|
+
}
|
|
224
|
+
if (command === "clear") {
|
|
225
|
+
const workspace = readRequiredWorkspace(cwd);
|
|
226
|
+
const keys = args.slice(1).filter((item) => !item.startsWith("--"));
|
|
227
|
+
const aliases = (0, path_aliases_1.normalizePathAliasMap)(workspace.pathAliases ?? {}, "session path aliases");
|
|
228
|
+
const cleared = [];
|
|
229
|
+
if (keys.length === 0) {
|
|
230
|
+
cleared.push(...Object.keys(aliases).sort());
|
|
231
|
+
delete workspace.pathAliases;
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
for (const key of keys) {
|
|
235
|
+
const alias = (0, path_aliases_1.normalizePathAliasName)(key, "session path aliases");
|
|
236
|
+
if (Object.prototype.hasOwnProperty.call(aliases, alias)) {
|
|
237
|
+
cleared.push(alias);
|
|
238
|
+
delete aliases[alias];
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
if (Object.keys(aliases).length > 0) {
|
|
242
|
+
workspace.pathAliases = aliases;
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
delete workspace.pathAliases;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
writeWorkspace(cwd, workspace);
|
|
249
|
+
const response = {
|
|
250
|
+
cleared,
|
|
251
|
+
aliases: (0, path_aliases_1.effectivePathAliases)(cwd, workspace.pathAliases ?? {})
|
|
252
|
+
};
|
|
253
|
+
return (0, agent_text_1.attachAgentText)(response, formatSessionAliasesAgentText(response));
|
|
254
|
+
}
|
|
255
|
+
throw new errors_1.CliError("UNKNOWN_SESSION_ALIASES_COMMAND", `Unknown session aliases command: ${command}`, {
|
|
256
|
+
expected: "aib session aliases get | set | clear"
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
function readAliasesStdinPayload(stdinPayload) {
|
|
260
|
+
if (!isObject(stdinPayload)) {
|
|
261
|
+
throw new errors_1.CliError("INVALID_SESSION_ALIASES_STDIN", "session aliases set --stdin expects a JSON object.");
|
|
262
|
+
}
|
|
263
|
+
const rawAliases = isObject(stdinPayload.aliases) ? stdinPayload.aliases : stdinPayload;
|
|
264
|
+
const aliases = {};
|
|
265
|
+
for (const [key, value] of Object.entries(rawAliases)) {
|
|
266
|
+
if (typeof value === "string") {
|
|
267
|
+
aliases[key] = value;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return aliases;
|
|
271
|
+
}
|
|
272
|
+
function readAliasesPairArgs(args) {
|
|
273
|
+
if (args.length === 0 || args.length % 2 !== 0) {
|
|
274
|
+
throw new errors_1.CliError("SESSION_ALIASES_SET_USAGE", "Usage: aib session aliases set <name> <path> [<name> <path>...] or session aliases set --stdin");
|
|
275
|
+
}
|
|
276
|
+
const aliases = {};
|
|
277
|
+
for (let index = 0; index < args.length; index += 2) {
|
|
278
|
+
aliases[args[index] ?? ""] = args[index + 1] ?? "";
|
|
279
|
+
}
|
|
280
|
+
return aliases;
|
|
281
|
+
}
|
|
282
|
+
function formatSessionAliasesAgentText(response) {
|
|
283
|
+
if (isObject(response.updated)) {
|
|
284
|
+
return formatAliasesMap("aliases.updated", response.updated);
|
|
285
|
+
}
|
|
286
|
+
if (Array.isArray(response.cleared)) {
|
|
287
|
+
const cleared = response.cleared.filter((item) => typeof item === "string");
|
|
288
|
+
return cleared.length > 0 ? ["aliases.cleared", ...cleared].join("\n") : "aliases.cleared none";
|
|
289
|
+
}
|
|
290
|
+
if (isObject(response.aliases)) {
|
|
291
|
+
const lines = formatAliasesMap("aliases", response.aliases).split("\n");
|
|
292
|
+
if (lines.length === 1) {
|
|
293
|
+
lines.push("none");
|
|
294
|
+
}
|
|
295
|
+
return lines.join("\n");
|
|
296
|
+
}
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
function formatAliasesMap(title, aliases) {
|
|
300
|
+
const lines = [title];
|
|
301
|
+
for (const [key, value] of Object.entries(aliases).sort(([left], [right]) => left.localeCompare(right))) {
|
|
302
|
+
lines.push(`@${key}/=${String(value)}`);
|
|
303
|
+
}
|
|
304
|
+
return lines.join("\n");
|
|
305
|
+
}
|
|
306
|
+
function sessionWorkspaceWrite(cwd, args, stdinPayload) {
|
|
307
|
+
const kind = args[0] ?? "";
|
|
308
|
+
const name = args[1] ?? "";
|
|
309
|
+
if (!kind || !name) {
|
|
310
|
+
throw new errors_1.CliError("SESSION_WRITE_USAGE", "Usage: aib session write <kind> <name> --stdin");
|
|
311
|
+
}
|
|
312
|
+
if (stdinPayload === undefined) {
|
|
313
|
+
throw new errors_1.CliError("STDIN_REQUIRED", "session write expects JSON on stdin and the --stdin flag.");
|
|
314
|
+
}
|
|
315
|
+
const workspace = readRequiredWorkspace(cwd);
|
|
316
|
+
const file = sessionInputPath(workspace, kind, name);
|
|
317
|
+
writeJsonFile(file, stdinPayload);
|
|
318
|
+
const artifact = registerArtifact(workspace, "inputs", kind, name, file);
|
|
319
|
+
registerLastInputArtifact(workspace, kind, stdinPayload);
|
|
320
|
+
writeWorkspace(cwd, workspace);
|
|
321
|
+
const result = {
|
|
322
|
+
written: artifact.handle,
|
|
323
|
+
file: toDisplayPath(cwd, file)
|
|
324
|
+
};
|
|
325
|
+
const next = useSessionGuidance(cwd, "session.write.from", `Use with --from ${artifact.handle}`);
|
|
326
|
+
if (next) {
|
|
327
|
+
result.next = next;
|
|
328
|
+
}
|
|
329
|
+
return result;
|
|
330
|
+
}
|
|
331
|
+
function sessionWorkspacePrefs(cwd, args, stdinPayload) {
|
|
332
|
+
const command = args[0] ?? "get";
|
|
333
|
+
if (command === "get") {
|
|
334
|
+
const workspace = readRequiredWorkspace(cwd);
|
|
335
|
+
const full = args.includes("--all");
|
|
336
|
+
const prefix = args.slice(1).find((item) => !item.startsWith("--"));
|
|
337
|
+
const prefs = full ? effectivePrefs(workspace) : visiblePrefs(workspace.prefs ?? {});
|
|
338
|
+
const selected = selectPrefs(prefs, prefix);
|
|
339
|
+
const response = full
|
|
340
|
+
? {
|
|
341
|
+
prefs: selected
|
|
342
|
+
}
|
|
343
|
+
: {
|
|
344
|
+
overrides: selected,
|
|
345
|
+
defaults: "omitted; use session prefs get --all"
|
|
346
|
+
};
|
|
347
|
+
return (0, agent_text_1.attachAgentText)(response, formatSessionPrefsAgentText(response));
|
|
348
|
+
}
|
|
349
|
+
if (command === "set") {
|
|
350
|
+
const workspace = readRequiredWorkspace(cwd);
|
|
351
|
+
const updates = args.includes("--stdin")
|
|
352
|
+
? readPrefsStdinPayload(stdinPayload)
|
|
353
|
+
: readPrefsPairArgs(args.slice(1));
|
|
354
|
+
const prefs = workspace.prefs ?? {};
|
|
355
|
+
const updated = {};
|
|
356
|
+
for (const [key, value] of Object.entries(updates)) {
|
|
357
|
+
const normalizedKey = normalizeSessionPrefKey(key);
|
|
358
|
+
const parsed = parseSessionPrefValue(normalizedKey, value);
|
|
359
|
+
prefs[normalizedKey] = parsed;
|
|
360
|
+
updated[normalizedKey] = parsed;
|
|
361
|
+
}
|
|
362
|
+
workspace.prefs = prefs;
|
|
363
|
+
writeWorkspace(cwd, workspace);
|
|
364
|
+
const response = { updated };
|
|
365
|
+
return (0, agent_text_1.attachAgentText)(response, formatSessionPrefsAgentText(response));
|
|
366
|
+
}
|
|
367
|
+
if (command === "clear") {
|
|
368
|
+
const workspace = readRequiredWorkspace(cwd);
|
|
369
|
+
const keys = args.slice(1).filter((item) => !item.startsWith("--"));
|
|
370
|
+
const currentPrefs = workspace.prefs ?? {};
|
|
371
|
+
const cleared = [];
|
|
372
|
+
if (keys.length === 0) {
|
|
373
|
+
cleared.push(...Object.keys(currentPrefs).sort());
|
|
374
|
+
delete workspace.prefs;
|
|
375
|
+
}
|
|
376
|
+
else {
|
|
377
|
+
for (const key of keys) {
|
|
378
|
+
const normalizedKey = normalizeSessionPrefKey(key);
|
|
379
|
+
if (Object.prototype.hasOwnProperty.call(currentPrefs, normalizedKey)) {
|
|
380
|
+
cleared.push(normalizedKey);
|
|
381
|
+
delete currentPrefs[normalizedKey];
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
if (Object.keys(currentPrefs).length > 0) {
|
|
385
|
+
workspace.prefs = currentPrefs;
|
|
386
|
+
}
|
|
387
|
+
else {
|
|
388
|
+
delete workspace.prefs;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
writeWorkspace(cwd, workspace);
|
|
392
|
+
const response = {
|
|
393
|
+
cleared
|
|
394
|
+
};
|
|
395
|
+
return (0, agent_text_1.attachAgentText)(response, formatSessionPrefsAgentText(response));
|
|
396
|
+
}
|
|
397
|
+
throw new errors_1.CliError("UNKNOWN_SESSION_PREFS_COMMAND", `Unknown session prefs command: ${command}`, {
|
|
398
|
+
expected: "aib session prefs get | set | clear"
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
function selectPrefs(prefs, prefix) {
|
|
402
|
+
if (!prefix) {
|
|
403
|
+
return prefs;
|
|
404
|
+
}
|
|
405
|
+
const selected = {};
|
|
406
|
+
for (const [key, value] of Object.entries(prefs)) {
|
|
407
|
+
if (key === prefix || key.startsWith(`${prefix}.`)) {
|
|
408
|
+
selected[key] = value;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
return selected;
|
|
412
|
+
}
|
|
413
|
+
function formatSessionPrefsAgentText(response) {
|
|
414
|
+
if (isObject(response.updated)) {
|
|
415
|
+
return formatPrefsMap("prefs.updated", response.updated);
|
|
416
|
+
}
|
|
417
|
+
if (Array.isArray(response.cleared)) {
|
|
418
|
+
const cleared = response.cleared.filter((item) => typeof item === "string");
|
|
419
|
+
return cleared.length > 0 ? ["prefs.cleared", ...cleared].join("\n") : "prefs.cleared none";
|
|
420
|
+
}
|
|
421
|
+
if (isObject(response.overrides)) {
|
|
422
|
+
const lines = formatPrefsMap("prefs", response.overrides).split("\n");
|
|
423
|
+
if (lines.length === 1) {
|
|
424
|
+
lines.push("no overrides");
|
|
425
|
+
}
|
|
426
|
+
if (typeof response.defaults === "string") {
|
|
427
|
+
lines.push(response.defaults);
|
|
428
|
+
}
|
|
429
|
+
return lines.join("\n");
|
|
430
|
+
}
|
|
431
|
+
if (isObject(response.prefs)) {
|
|
432
|
+
return formatPrefsMap("prefs", response.prefs);
|
|
433
|
+
}
|
|
434
|
+
return null;
|
|
435
|
+
}
|
|
436
|
+
function formatPrefsMap(title, prefs) {
|
|
437
|
+
const lines = [title];
|
|
438
|
+
for (const [key, value] of Object.entries(prefs).sort(([left], [right]) => left.localeCompare(right))) {
|
|
439
|
+
lines.push(`${key}=${String(value)}`);
|
|
440
|
+
}
|
|
441
|
+
return lines.join("\n");
|
|
442
|
+
}
|
|
443
|
+
function readPrefsStdinPayload(stdinPayload) {
|
|
444
|
+
if (!isObject(stdinPayload)) {
|
|
445
|
+
throw new errors_1.CliError("INVALID_SESSION_PREFS_STDIN", "session prefs set --stdin expects a JSON object.");
|
|
446
|
+
}
|
|
447
|
+
const rawPrefs = isObject(stdinPayload.prefs) ? stdinPayload.prefs : stdinPayload;
|
|
448
|
+
const prefs = {};
|
|
449
|
+
for (const [key, value] of Object.entries(rawPrefs)) {
|
|
450
|
+
prefs[key] = value;
|
|
451
|
+
}
|
|
452
|
+
return prefs;
|
|
453
|
+
}
|
|
454
|
+
function readPrefsPairArgs(args) {
|
|
455
|
+
if (args.length === 0 || args.length % 2 !== 0) {
|
|
456
|
+
throw new errors_1.CliError("SESSION_PREFS_SET_USAGE", "Usage: aib session prefs set <key> <value> [<key> <value>...] or session prefs set --stdin");
|
|
457
|
+
}
|
|
458
|
+
const prefs = {};
|
|
459
|
+
for (let index = 0; index < args.length; index += 2) {
|
|
460
|
+
const key = args[index] ?? "";
|
|
461
|
+
const value = args[index + 1] ?? "";
|
|
462
|
+
prefs[key] = value;
|
|
463
|
+
}
|
|
464
|
+
return prefs;
|
|
465
|
+
}
|
|
466
|
+
function normalizeSessionPrefKey(key) {
|
|
467
|
+
if (Object.prototype.hasOwnProperty.call(SESSION_PREF_DEFS, key)) {
|
|
468
|
+
return key;
|
|
469
|
+
}
|
|
470
|
+
throw new errors_1.CliError("UNKNOWN_SESSION_PREF", `Unknown session preference: ${key}`, {
|
|
471
|
+
available: Object.keys(SESSION_PREF_DEFS)
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
function parseSessionPrefValue(key, value) {
|
|
475
|
+
const definition = SESSION_PREF_DEFS[key];
|
|
476
|
+
if (definition.type === "boolean") {
|
|
477
|
+
if (typeof value === "boolean") {
|
|
478
|
+
return value;
|
|
479
|
+
}
|
|
480
|
+
if (typeof value === "string") {
|
|
481
|
+
const normalized = value.trim().toLowerCase();
|
|
482
|
+
if (normalized === "true") {
|
|
483
|
+
return true;
|
|
484
|
+
}
|
|
485
|
+
if (normalized === "false") {
|
|
486
|
+
return false;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
throw new errors_1.CliError("INVALID_SESSION_PREF_VALUE", `${key} expects true or false.`);
|
|
490
|
+
}
|
|
491
|
+
if (definition.type === "string") {
|
|
492
|
+
if (typeof value !== "string") {
|
|
493
|
+
throw new errors_1.CliError("INVALID_SESSION_PREF_VALUE", `${key} expects one of: ${definition.values.join(", ")}.`);
|
|
494
|
+
}
|
|
495
|
+
const normalized = value.trim();
|
|
496
|
+
if (!definition.values.includes(normalized)) {
|
|
497
|
+
throw new errors_1.CliError("INVALID_SESSION_PREF_VALUE", `${key} expects one of: ${definition.values.join(", ")}.`);
|
|
498
|
+
}
|
|
499
|
+
return normalized;
|
|
500
|
+
}
|
|
501
|
+
const parsed = typeof value === "number" ? value : typeof value === "string" ? Number(value) : NaN;
|
|
502
|
+
if (!Number.isInteger(parsed) || parsed < definition.min || parsed > definition.max) {
|
|
503
|
+
throw new errors_1.CliError("INVALID_SESSION_PREF_VALUE", `${key} expects an integer from ${definition.min} to ${definition.max}.`);
|
|
504
|
+
}
|
|
505
|
+
return parsed;
|
|
506
|
+
}
|
|
507
|
+
function effectivePrefs(workspace) {
|
|
508
|
+
const prefs = {};
|
|
509
|
+
for (const key of Object.keys(SESSION_PREF_DEFS)) {
|
|
510
|
+
const definition = SESSION_PREF_DEFS[key];
|
|
511
|
+
if ("hidden" in definition && definition.hidden) {
|
|
512
|
+
continue;
|
|
513
|
+
}
|
|
514
|
+
if (definition.type === "boolean") {
|
|
515
|
+
prefs[key] = readWorkspaceBooleanPref(workspace, key, definition.default);
|
|
516
|
+
}
|
|
517
|
+
else if (definition.type === "number") {
|
|
518
|
+
prefs[key] = readWorkspaceNumberPref(workspace, key, definition.default);
|
|
519
|
+
}
|
|
520
|
+
else {
|
|
521
|
+
prefs[key] = readWorkspaceStringPref(workspace, key, definition.default);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
return prefs;
|
|
525
|
+
}
|
|
526
|
+
function visiblePrefs(prefs) {
|
|
527
|
+
const visible = {};
|
|
528
|
+
for (const [key, value] of Object.entries(prefs)) {
|
|
529
|
+
if (!isHiddenSessionPrefKey(key)) {
|
|
530
|
+
visible[key] = value;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
return visible;
|
|
534
|
+
}
|
|
535
|
+
function isHiddenSessionPrefKey(key) {
|
|
536
|
+
if (!Object.prototype.hasOwnProperty.call(SESSION_PREF_DEFS, key)) {
|
|
537
|
+
return false;
|
|
538
|
+
}
|
|
539
|
+
const definition = SESSION_PREF_DEFS[key];
|
|
540
|
+
return "hidden" in definition && definition.hidden === true;
|
|
541
|
+
}
|
|
542
|
+
function resolveSessionFileArgument(cwd, value) {
|
|
543
|
+
if (!isSessionHandle(value)) {
|
|
544
|
+
return value;
|
|
545
|
+
}
|
|
546
|
+
const workspace = readRequiredWorkspace(cwd);
|
|
547
|
+
const parsed = parseSessionHandle(value);
|
|
548
|
+
const bucketGroup = parsed.scope === "input" ? workspace.inputs : workspace.outputs;
|
|
549
|
+
const kind = parsed.scope === "input" ? parsed.kind : parsed.scope;
|
|
550
|
+
const bucket = bucketGroup[kind];
|
|
551
|
+
const name = parsed.name === "last" ? bucket?.last : parsed.name;
|
|
552
|
+
const artifact = name ? bucket?.items[name] : undefined;
|
|
553
|
+
if (!artifact) {
|
|
554
|
+
throw new errors_1.CliError("SESSION_HANDLE_NOT_FOUND", `Session handle not found: ${value}`, {
|
|
555
|
+
handle: value,
|
|
556
|
+
sessionDir: toDisplayPath(cwd, workspace.rootDir)
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
return artifact.file;
|
|
560
|
+
}
|
|
561
|
+
function saveSessionOutputJson(cwd, kind, name, value) {
|
|
562
|
+
const workspace = readRequiredWorkspaceForSave(cwd);
|
|
563
|
+
const file = sessionOutputPath(workspace, kind, name, ".json");
|
|
564
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
565
|
+
fs.writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`);
|
|
566
|
+
const artifact = registerArtifact(workspace, "outputs", kind, name, file);
|
|
567
|
+
writeWorkspace(cwd, workspace);
|
|
568
|
+
return {
|
|
569
|
+
saved: artifact.handle,
|
|
570
|
+
last: `aib:${kind}:last`,
|
|
571
|
+
file: toDisplayPath(cwd, file)
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
function saveSessionOutputText(cwd, kind, name, value, extension = ".txt") {
|
|
575
|
+
const workspace = readRequiredWorkspaceForSave(cwd);
|
|
576
|
+
const file = sessionOutputPath(workspace, kind, name, extension);
|
|
577
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
578
|
+
fs.writeFileSync(file, value);
|
|
579
|
+
const artifact = registerArtifact(workspace, "outputs", kind, name, file);
|
|
580
|
+
writeWorkspace(cwd, workspace);
|
|
581
|
+
return {
|
|
582
|
+
saved: artifact.handle,
|
|
583
|
+
last: `aib:${kind}:last`,
|
|
584
|
+
file: toDisplayPath(cwd, file)
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
function saveSessionResultJson(cwd, kind, id, value) {
|
|
588
|
+
const workspace = readWorkspaceForSave(cwd);
|
|
589
|
+
if (!workspace) {
|
|
590
|
+
return null;
|
|
591
|
+
}
|
|
592
|
+
const normalizedKind = sanitizePathSegment(kind);
|
|
593
|
+
const normalizedId = sanitizePathSegment(id);
|
|
594
|
+
const file = path.join(workspace.rootDir, "outputs", "result", normalizedKind, `${normalizedId}.json`);
|
|
595
|
+
writeJsonFile(file, value);
|
|
596
|
+
return {
|
|
597
|
+
saved: `aib:result:${normalizedKind}:${normalizedId}`,
|
|
598
|
+
file: toDisplayPath(cwd, file)
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
function saveSessionResultViewJson(cwd, id, value) {
|
|
602
|
+
const workspace = readWorkspaceForSave(cwd);
|
|
603
|
+
if (!workspace) {
|
|
604
|
+
return null;
|
|
605
|
+
}
|
|
606
|
+
const normalizedId = sanitizePathSegment(id);
|
|
607
|
+
const file = path.join(workspace.rootDir, "outputs", "result", `${normalizedId}.json`);
|
|
608
|
+
writeJsonFile(file, value);
|
|
609
|
+
return {
|
|
610
|
+
saved: `aib:${normalizedId}`,
|
|
611
|
+
file: toDisplayPath(cwd, file)
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
function readSessionResultViewJson(cwd, id) {
|
|
615
|
+
const workspace = readRequiredWorkspace(cwd);
|
|
616
|
+
const normalizedId = sanitizePathSegment(id);
|
|
617
|
+
const file = path.join(workspace.rootDir, "outputs", "result", `${normalizedId}.json`);
|
|
618
|
+
if (!fs.existsSync(file)) {
|
|
619
|
+
throw new errors_1.CliError("SESSION_RESULT_NOT_FOUND", `Result handle not found: aib:${normalizedId}`, {
|
|
620
|
+
handle: `aib:${normalizedId}`,
|
|
621
|
+
sessionDir: toDisplayPath(cwd, workspace.rootDir)
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
const parsed = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
625
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
626
|
+
throw new errors_1.CliError("INVALID_SESSION_RESULT", `Result artifact is not a JSON object: aib:${normalizedId}`);
|
|
627
|
+
}
|
|
628
|
+
return parsed;
|
|
629
|
+
}
|
|
630
|
+
function readSessionResultJson(cwd, kind, id) {
|
|
631
|
+
const workspace = readRequiredWorkspace(cwd);
|
|
632
|
+
const normalizedKind = sanitizePathSegment(kind);
|
|
633
|
+
const normalizedId = sanitizePathSegment(id);
|
|
634
|
+
const file = path.join(workspace.rootDir, "outputs", "result", normalizedKind, `${normalizedId}.json`);
|
|
635
|
+
if (!fs.existsSync(file)) {
|
|
636
|
+
throw new errors_1.CliError("SESSION_RESULT_NOT_FOUND", `Result handle not found: aib:result:${normalizedKind}:${normalizedId}`, {
|
|
637
|
+
handle: `aib:result:${normalizedKind}:${normalizedId}`,
|
|
638
|
+
sessionDir: toDisplayPath(cwd, workspace.rootDir)
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
const parsed = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
642
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
643
|
+
throw new errors_1.CliError("INVALID_SESSION_RESULT", `Result artifact is not a JSON object: aib:result:${normalizedKind}:${normalizedId}`);
|
|
644
|
+
}
|
|
645
|
+
return parsed;
|
|
646
|
+
}
|
|
647
|
+
function captureSessionInputJson(cwd, kind, name, value) {
|
|
648
|
+
return captureSessionInput(cwd, kind, name, value, { format: "json", text: JSON.stringify(value, null, 2) });
|
|
649
|
+
}
|
|
650
|
+
function captureSessionInput(cwd, kind, name, value, source) {
|
|
651
|
+
const workspace = readWorkspaceForSave(cwd);
|
|
652
|
+
if (!workspace) {
|
|
653
|
+
return null;
|
|
654
|
+
}
|
|
655
|
+
const inputSource = source ?? { format: "json", text: JSON.stringify(value, null, 2) };
|
|
656
|
+
const file = inputSource.format === "dsl"
|
|
657
|
+
? sessionInputPath(workspace, kind, name, ".dsl")
|
|
658
|
+
: sessionInputPath(workspace, kind, name, ".json");
|
|
659
|
+
if (inputSource.format === "dsl") {
|
|
660
|
+
writeTextFile(file, inputSource.text);
|
|
661
|
+
writeJsonFile(sessionCompiledInputPath(workspace, kind, name), value);
|
|
662
|
+
}
|
|
663
|
+
else {
|
|
664
|
+
writeJsonFile(file, value);
|
|
665
|
+
}
|
|
666
|
+
const artifact = registerArtifact(workspace, "inputs", kind, name, file);
|
|
667
|
+
registerLastInputArtifact(workspace, kind, value, inputSource);
|
|
668
|
+
writeWorkspace(cwd, workspace);
|
|
669
|
+
return {
|
|
670
|
+
handle: artifact.handle,
|
|
671
|
+
file: toDisplayPath(cwd, file)
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
function sessionWorkspaceExists(cwd) {
|
|
675
|
+
return fs.existsSync(workspaceMarkerPath(cwd));
|
|
676
|
+
}
|
|
677
|
+
function useSessionGuidance(cwd, key, message, limit = -1) {
|
|
678
|
+
const workspace = readWorkspace(cwd);
|
|
679
|
+
if (!workspace) {
|
|
680
|
+
return message;
|
|
681
|
+
}
|
|
682
|
+
const configuredLimit = limit >= 0 ? limit : readWorkspaceNumberPref(workspace, "guidance.nextLimit", 2);
|
|
683
|
+
const guidance = workspace.guidance ?? {};
|
|
684
|
+
const state = guidance[key] ?? { shown: 0, limit: configuredLimit };
|
|
685
|
+
state.limit = configuredLimit;
|
|
686
|
+
if (state.shown >= state.limit) {
|
|
687
|
+
guidance[key] = state;
|
|
688
|
+
workspace.guidance = guidance;
|
|
689
|
+
writeWorkspace(cwd, workspace);
|
|
690
|
+
return undefined;
|
|
691
|
+
}
|
|
692
|
+
state.shown += 1;
|
|
693
|
+
guidance[key] = state;
|
|
694
|
+
workspace.guidance = guidance;
|
|
695
|
+
writeWorkspace(cwd, workspace);
|
|
696
|
+
return message;
|
|
697
|
+
}
|
|
698
|
+
function readSessionBooleanPref(cwd, key, fallback) {
|
|
699
|
+
const workspace = readWorkspace(cwd);
|
|
700
|
+
const definition = SESSION_PREF_DEFS[key];
|
|
701
|
+
const defaultValue = typeof fallback === "boolean" ? fallback : definition.type === "boolean" ? definition.default : false;
|
|
702
|
+
return workspace ? readWorkspaceBooleanPref(workspace, key, defaultValue) : defaultValue;
|
|
703
|
+
}
|
|
704
|
+
function readSessionNumberPref(cwd, key, fallback) {
|
|
705
|
+
const workspace = readWorkspace(cwd);
|
|
706
|
+
const definition = SESSION_PREF_DEFS[key];
|
|
707
|
+
const defaultValue = typeof fallback === "number" ? fallback : definition.type === "number" ? definition.default : 0;
|
|
708
|
+
const configValue = (0, workspace_root_1.readWorkspaceNumberConfig)(cwd, key, defaultValue);
|
|
709
|
+
return workspace ? readWorkspaceNumberPref(workspace, key, configValue) : configValue;
|
|
710
|
+
}
|
|
711
|
+
function readSessionStringPref(cwd, key, fallback) {
|
|
712
|
+
const workspace = readWorkspace(cwd);
|
|
713
|
+
const definition = SESSION_PREF_DEFS[key];
|
|
714
|
+
const defaultValue = typeof fallback === "string" ? fallback : definition.type === "string" ? definition.default : "";
|
|
715
|
+
return workspace ? readWorkspaceStringPref(workspace, key, defaultValue) : defaultValue;
|
|
716
|
+
}
|
|
717
|
+
function readEffectiveSessionPathAliases(cwd) {
|
|
718
|
+
try {
|
|
719
|
+
const workspace = readWorkspace(cwd);
|
|
720
|
+
return (0, path_aliases_1.effectivePathAliases)(cwd, workspace?.pathAliases ?? {});
|
|
721
|
+
}
|
|
722
|
+
catch (error) {
|
|
723
|
+
if (error instanceof errors_1.CliError && error.code === "MULTIPLE_AIB_SESSIONS") {
|
|
724
|
+
return (0, path_aliases_1.effectivePathAliases)(cwd, {});
|
|
725
|
+
}
|
|
726
|
+
throw error;
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
function readSessionPathAliasOverrides(cwd) {
|
|
730
|
+
try {
|
|
731
|
+
const workspace = readWorkspace(cwd);
|
|
732
|
+
return (0, path_aliases_1.normalizePathAliasMap)(workspace?.pathAliases ?? {}, "session path aliases");
|
|
733
|
+
}
|
|
734
|
+
catch (error) {
|
|
735
|
+
if (error instanceof errors_1.CliError && error.code === "MULTIPLE_AIB_SESSIONS") {
|
|
736
|
+
return {};
|
|
737
|
+
}
|
|
738
|
+
throw error;
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
function readWorkspaceBooleanPref(workspace, key, fallback) {
|
|
742
|
+
const value = workspace.prefs?.[key];
|
|
743
|
+
return typeof value === "boolean" ? value : fallback;
|
|
744
|
+
}
|
|
745
|
+
function readWorkspaceNumberPref(workspace, key, fallback) {
|
|
746
|
+
const value = workspace.prefs?.[key];
|
|
747
|
+
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
748
|
+
}
|
|
749
|
+
function readWorkspaceStringPref(workspace, key, fallback) {
|
|
750
|
+
const value = workspace.prefs?.[key];
|
|
751
|
+
return typeof value === "string" ? value : fallback;
|
|
752
|
+
}
|
|
753
|
+
function initSessionWorkspace(cwd, args) {
|
|
754
|
+
const requestedDir = readFlagValue(args, "--dir");
|
|
755
|
+
const explicitName = readFlagValue(args, "--name");
|
|
756
|
+
const sessionId = sanitizeSessionId(explicitName ?? currentSessionId() ?? createSessionId());
|
|
757
|
+
if (explicitName && sessionId === DEFAULT_AUTO_SESSION_ID) {
|
|
758
|
+
throw new errors_1.CliError("SESSION_ID_RESERVED", `${DEFAULT_AUTO_SESSION_ID} is reserved for AIB's automatic default session.`, {
|
|
759
|
+
session: sessionId,
|
|
760
|
+
next: "Use aib session init --name <name>"
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
const sessionRoot = resolveSessionRoot(cwd, requestedDir, true);
|
|
764
|
+
const rootDir = path.join(sessionRoot.rootDir, sessionId);
|
|
765
|
+
const now = new Date().toISOString();
|
|
766
|
+
const existing = readWorkspaceById(cwd, sessionId);
|
|
767
|
+
const workspace = existing ?? {
|
|
768
|
+
version: 1,
|
|
769
|
+
sessionId,
|
|
770
|
+
cwd: path.resolve(cwd),
|
|
771
|
+
rootDir,
|
|
772
|
+
createdAt: now,
|
|
773
|
+
updatedAt: now,
|
|
774
|
+
outputs: {},
|
|
775
|
+
inputs: {},
|
|
776
|
+
guidance: {}
|
|
777
|
+
};
|
|
778
|
+
workspace.sessionId = sessionId;
|
|
779
|
+
workspace.rootDir = rootDir;
|
|
780
|
+
workspace.updatedAt = now;
|
|
781
|
+
ensureWorkspaceDirs(workspace);
|
|
782
|
+
writeWorkspace(cwd, workspace);
|
|
783
|
+
upsertRegistrySession(cwd, workspace, true);
|
|
784
|
+
const registry = readRegistry(cwd);
|
|
785
|
+
const sessionCount = registry ? Object.keys(registry.sessions).length : 1;
|
|
786
|
+
const result = {
|
|
787
|
+
session: sessionId,
|
|
788
|
+
dir: toDisplayPath(cwd, workspace.rootDir),
|
|
789
|
+
sessionDir: toDisplayPath(cwd, sessionRoot.rootDir),
|
|
790
|
+
sessionDirSource: sessionRoot.source,
|
|
791
|
+
sessionCount,
|
|
792
|
+
bind: `${env_vars_1.CLI_ENV.session}=${sessionId}`,
|
|
793
|
+
next: sessionCount === 1
|
|
794
|
+
? "Run AIB commands without -s for now. AIB will tell you if multiple sessions exist."
|
|
795
|
+
: `Use aib -s ${sessionId} <command> or set ${env_vars_1.CLI_ENV.session}=${sessionId}.`
|
|
796
|
+
};
|
|
797
|
+
if (sessionRoot.ignoredRequestedDir) {
|
|
798
|
+
result.note = `${SESSION_DIR_CONFIG_KEY} from aib.json is in effect; --dir was ignored.`;
|
|
799
|
+
result.requestedDir = sessionRoot.ignoredRequestedDir;
|
|
800
|
+
}
|
|
801
|
+
return (0, agent_text_1.attachAgentText)(result, formatSessionInitAgentText(result));
|
|
802
|
+
}
|
|
803
|
+
function formatSessionInitAgentText(result) {
|
|
804
|
+
const sessionId = String(result.session ?? "");
|
|
805
|
+
const sessionCount = typeof result.sessionCount === "number" ? result.sessionCount : 1;
|
|
806
|
+
const lines = [`session ready: ${sessionId}`, ""];
|
|
807
|
+
if (typeof result.note === "string" && result.note) {
|
|
808
|
+
lines.push("aib.json sessionDir is in effect; --dir was ignored.");
|
|
809
|
+
lines.push("");
|
|
810
|
+
}
|
|
811
|
+
if (sessionCount === 1) {
|
|
812
|
+
lines.push("Only one AIB session exists in this repo.");
|
|
813
|
+
lines.push("You can run AIB commands without -s for now.");
|
|
814
|
+
lines.push("AIB will tell you if multiple sessions exist and you need to choose one.");
|
|
815
|
+
}
|
|
816
|
+
else {
|
|
817
|
+
lines.push("Multiple AIB sessions exist in this repo.");
|
|
818
|
+
lines.push("Use this session explicitly:");
|
|
819
|
+
lines.push(`aib -s ${sessionId} <command>`);
|
|
820
|
+
lines.push("");
|
|
821
|
+
lines.push("Or bind it in this shell:");
|
|
822
|
+
lines.push(`${env_vars_1.CLI_ENV.session}=${sessionId}`);
|
|
823
|
+
}
|
|
824
|
+
return lines.join("\n");
|
|
825
|
+
}
|
|
826
|
+
function sessionWorkspaceList(cwd) {
|
|
827
|
+
const registry = readRegistry(cwd);
|
|
828
|
+
const selected = resolveSelectedSessionForList(cwd);
|
|
829
|
+
return {
|
|
830
|
+
active: selected.sessionId ?? registry?.activeSessionId ?? null,
|
|
831
|
+
source: selected.source,
|
|
832
|
+
sessions: registry
|
|
833
|
+
? Object.values(registry.sessions)
|
|
834
|
+
.sort((left, right) => left.sessionId.localeCompare(right.sessionId))
|
|
835
|
+
.map((session) => `${session.sessionId} -> ${toDisplayPath(cwd, session.rootDir)}`)
|
|
836
|
+
: []
|
|
837
|
+
};
|
|
838
|
+
}
|
|
839
|
+
function sessionWorkspaceUse(cwd, args) {
|
|
840
|
+
const rawSessionId = args[0] ?? "";
|
|
841
|
+
if (!rawSessionId) {
|
|
842
|
+
throw new errors_1.CliError("SESSION_USE_ID_REQUIRED", "Usage: aib session use <sessionId>");
|
|
843
|
+
}
|
|
844
|
+
const sessionId = sanitizeSessionId(rawSessionId);
|
|
845
|
+
const registry = readRegistry(cwd);
|
|
846
|
+
const entry = registry?.sessions[sessionId];
|
|
847
|
+
if (!entry) {
|
|
848
|
+
throw new errors_1.CliError("SESSION_NOT_FOUND", `Session not found: ${sessionId}`, {
|
|
849
|
+
available: registry ? Object.keys(registry.sessions).sort() : []
|
|
850
|
+
});
|
|
851
|
+
}
|
|
852
|
+
writeRegistry(cwd, {
|
|
853
|
+
...(registry ?? createEmptyRegistry(cwd)),
|
|
854
|
+
activeSessionId: sessionId
|
|
855
|
+
});
|
|
856
|
+
return {
|
|
857
|
+
session: sessionId,
|
|
858
|
+
dir: toDisplayPath(cwd, entry.rootDir),
|
|
859
|
+
bind: `${env_vars_1.CLI_ENV.session}=${sessionId}`,
|
|
860
|
+
next: `Use aib -s ${sessionId} <command> or set ${env_vars_1.CLI_ENV.session}=${sessionId}.`
|
|
861
|
+
};
|
|
862
|
+
}
|
|
863
|
+
function sessionWorkspaceWhere(cwd, args) {
|
|
864
|
+
const handle = args[0] ?? "";
|
|
865
|
+
if (!handle) {
|
|
866
|
+
throw new errors_1.CliError("SESSION_WHERE_HANDLE_REQUIRED", "Usage: aib session where <handle>");
|
|
867
|
+
}
|
|
868
|
+
const file = resolveSessionFileArgument(cwd, handle);
|
|
869
|
+
const response = {
|
|
870
|
+
handle,
|
|
871
|
+
file: toDisplayPath(cwd, file)
|
|
872
|
+
};
|
|
873
|
+
return (0, agent_text_1.attachAgentText)(response, [
|
|
874
|
+
handle,
|
|
875
|
+
response.file
|
|
876
|
+
].join("\n"));
|
|
877
|
+
}
|
|
878
|
+
function sessionWorkspaceRead(cwd, args, stdinPayload) {
|
|
879
|
+
if (args.includes("--stdin")) {
|
|
880
|
+
if (!isObject(stdinPayload)) {
|
|
881
|
+
throw new errors_1.CliError("INVALID_SESSION_READ_STDIN", "session read --stdin expects a JSON object payload.");
|
|
882
|
+
}
|
|
883
|
+
const readRequests = parseSessionReadBatchPayload(stdinPayload);
|
|
884
|
+
if (readRequests.length === 1) {
|
|
885
|
+
const result = readSessionArtifact(cwd, readRequests[0]);
|
|
886
|
+
return (0, agent_text_1.attachAgentText)(result, formatSessionReadAgentText(result));
|
|
887
|
+
}
|
|
888
|
+
const result = {
|
|
889
|
+
reads: readRequests.map((request) => readSessionArtifactRow(cwd, request))
|
|
890
|
+
};
|
|
891
|
+
return (0, agent_text_1.attachAgentText)(result, formatSessionReadAgentText(result));
|
|
892
|
+
}
|
|
893
|
+
const handle = args[0] ?? "";
|
|
894
|
+
if (!handle) {
|
|
895
|
+
throw new errors_1.CliError("SESSION_READ_HANDLE_REQUIRED", "Usage: aib session read <handle> [--head <n> | --offset <n> --limit <n>]");
|
|
896
|
+
}
|
|
897
|
+
const result = readSessionArtifact(cwd, {
|
|
898
|
+
handle,
|
|
899
|
+
...readSessionReadOptions(args.slice(1))
|
|
900
|
+
});
|
|
901
|
+
return (0, agent_text_1.attachAgentText)(result, formatSessionReadAgentText(result));
|
|
902
|
+
}
|
|
903
|
+
function parseSessionReadBatchPayload(payload) {
|
|
904
|
+
if (Array.isArray(payload.reads)) {
|
|
905
|
+
return payload.reads.map((row, index) => {
|
|
906
|
+
if (typeof row === "string") {
|
|
907
|
+
if (!isSessionHandle(row)) {
|
|
908
|
+
throw new errors_1.CliError("INVALID_SESSION_READ_ROW", `session read row at index ${index} must be an aib: handle string or an object.`);
|
|
909
|
+
}
|
|
910
|
+
return { handle: row };
|
|
911
|
+
}
|
|
912
|
+
if (!isObject(row)) {
|
|
913
|
+
throw new errors_1.CliError("INVALID_SESSION_READ_ROW", `session read row at index ${index} must be an aib: handle string or an object.`);
|
|
914
|
+
}
|
|
915
|
+
return parseSessionReadRow(row, index);
|
|
916
|
+
});
|
|
917
|
+
}
|
|
918
|
+
if (typeof payload.handle === "string" || typeof payload.read === "string") {
|
|
919
|
+
return [parseSessionReadRow(payload, 0)];
|
|
920
|
+
}
|
|
921
|
+
throw new errors_1.CliError("INVALID_SESSION_READ_STDIN", "Expected { reads: [{ handle }] } or { handle }.");
|
|
922
|
+
}
|
|
923
|
+
function parseSessionReadRow(row, index) {
|
|
924
|
+
const handle = readString(row.handle) ?? readString(row.read);
|
|
925
|
+
if (!handle) {
|
|
926
|
+
throw new errors_1.CliError("SESSION_READ_HANDLE_REQUIRED", `session read row at index ${index} requires handle.`);
|
|
927
|
+
}
|
|
928
|
+
return {
|
|
929
|
+
handle,
|
|
930
|
+
...(row.rawInput === true ? { rawInput: true } : {}),
|
|
931
|
+
...readSessionReadObjectOptions(row, index)
|
|
932
|
+
};
|
|
933
|
+
}
|
|
934
|
+
function readSessionArtifactRow(cwd, request) {
|
|
935
|
+
try {
|
|
936
|
+
return readSessionArtifact(cwd, request);
|
|
937
|
+
}
|
|
938
|
+
catch (error) {
|
|
939
|
+
if (error instanceof errors_1.CliError) {
|
|
940
|
+
const details = isObject(error.details) ? error.details : {};
|
|
941
|
+
return {
|
|
942
|
+
read: request.handle,
|
|
943
|
+
error: error.code,
|
|
944
|
+
...(typeof details.next === "string" ? { next: details.next } : {})
|
|
945
|
+
};
|
|
946
|
+
}
|
|
947
|
+
return {
|
|
948
|
+
read: request.handle,
|
|
949
|
+
error: "UNEXPECTED_ERROR"
|
|
950
|
+
};
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
function readSessionArtifact(cwd, request) {
|
|
954
|
+
validateSessionReadOptions(request);
|
|
955
|
+
const parsed = parseSessionHandle(request.handle);
|
|
956
|
+
const file = resolveSessionFileArgument(cwd, request.handle);
|
|
957
|
+
if (parsed.scope === "input" && !request.rawInput) {
|
|
958
|
+
const rerun = buildInputRerunCommand(parsed.kind, request.handle);
|
|
959
|
+
return {
|
|
960
|
+
read: request.handle,
|
|
961
|
+
file: toDisplayPath(cwd, file),
|
|
962
|
+
next: rerun
|
|
963
|
+
? `Edit file, then rerun: ${rerun}`
|
|
964
|
+
: "Edit file, then rerun the command with --from <handle>."
|
|
965
|
+
};
|
|
966
|
+
}
|
|
967
|
+
if (parsed.scope === "graph" || parsed.scope === "usages") {
|
|
968
|
+
const next = parsed.scope === "graph"
|
|
969
|
+
? `aib inspect graph --from-file ${request.handle} --focus <file>`
|
|
970
|
+
: `aib inspect usages --from-file ${request.handle} --focus <name>`;
|
|
971
|
+
throw new errors_1.CliError("SESSION_ARTIFACT_NOT_READABLE", `${parsed.scope} artifacts are reusable indexes, not agent-readable context.`, {
|
|
972
|
+
handle: request.handle,
|
|
973
|
+
kind: parsed.scope,
|
|
974
|
+
next
|
|
975
|
+
});
|
|
976
|
+
}
|
|
977
|
+
if (parsed.scope === "duplicates") {
|
|
978
|
+
const content = fs.readFileSync(file, "utf8");
|
|
979
|
+
return {
|
|
980
|
+
read: request.handle,
|
|
981
|
+
content: readSavedDuplicatesContent(cwd, request.handle, file, content, request)
|
|
982
|
+
};
|
|
983
|
+
}
|
|
984
|
+
const content = fs.readFileSync(file, "utf8");
|
|
985
|
+
return {
|
|
986
|
+
read: request.handle,
|
|
987
|
+
content: readSessionArtifactContent(file, content, request)
|
|
988
|
+
};
|
|
989
|
+
}
|
|
990
|
+
function readSavedDuplicatesContent(cwd, handle, file, content, request) {
|
|
991
|
+
const text = formatSavedDuplicatesContent(cwd, handle, file, content);
|
|
992
|
+
return request.head !== undefined || request.offset !== undefined || request.limit !== undefined
|
|
993
|
+
? applyReadWindow(text, request)
|
|
994
|
+
: text;
|
|
995
|
+
}
|
|
996
|
+
function formatSavedDuplicatesContent(cwd, handle, file, content) {
|
|
997
|
+
let payload;
|
|
998
|
+
try {
|
|
999
|
+
payload = JSON.parse(content);
|
|
1000
|
+
}
|
|
1001
|
+
catch {
|
|
1002
|
+
return applySavedArtifactFallback(handle, file, content);
|
|
1003
|
+
}
|
|
1004
|
+
if (!isObject(payload)) {
|
|
1005
|
+
return applySavedArtifactFallback(handle, file, content);
|
|
1006
|
+
}
|
|
1007
|
+
const lines = [];
|
|
1008
|
+
const targets = Array.isArray(payload.targetPaths)
|
|
1009
|
+
? payload.targetPaths.filter((item) => typeof item === "string" && item !== "")
|
|
1010
|
+
: [];
|
|
1011
|
+
const targetLabel = targets.length === 1
|
|
1012
|
+
? toDisplayPath(cwd, targets[0])
|
|
1013
|
+
: targets.length > 1 ? `${targets.length} scopes` : "";
|
|
1014
|
+
lines.push(targetLabel ? `duplicates ${targetLabel}` : "duplicates");
|
|
1015
|
+
const summary = typeof payload.summary === "string"
|
|
1016
|
+
? payload.summary
|
|
1017
|
+
: `${numberOrZero(payload.itemCount)} ${plural(numberOrZero(payload.itemCount), "name")}`;
|
|
1018
|
+
lines.push(summary);
|
|
1019
|
+
const items = Array.isArray(payload.items) ? payload.items.filter(isObject) : [];
|
|
1020
|
+
for (const item of items) {
|
|
1021
|
+
const name = typeof item.name === "string" ? item.name : "";
|
|
1022
|
+
const count = numberOrZero(item.declarationCount);
|
|
1023
|
+
const variants = numberOrZero(item.variantCount);
|
|
1024
|
+
const exactCopies = numberOrZero(item.exactCopyCount);
|
|
1025
|
+
if (name) {
|
|
1026
|
+
lines.push(`${name} x${count}, ${variants} ${plural(variants, "variant")}${exactCopies > 0 ? `, exact x${exactCopies}` : ""}`);
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
const hidden = numberOrZero(payload.hiddenItemCount);
|
|
1030
|
+
if (hidden > 0) {
|
|
1031
|
+
lines.push(`+ ${hidden} ${plural(hidden, "name")}`);
|
|
1032
|
+
}
|
|
1033
|
+
lines.push(`raw: aib session where ${handle}`);
|
|
1034
|
+
return lines.join("\n");
|
|
1035
|
+
}
|
|
1036
|
+
function applySavedArtifactFallback(handle, file, content) {
|
|
1037
|
+
return [
|
|
1038
|
+
`saved artifact ${handle}`,
|
|
1039
|
+
`${content.length} bytes`,
|
|
1040
|
+
`raw: ${file}`
|
|
1041
|
+
].join("\n");
|
|
1042
|
+
}
|
|
1043
|
+
function readSessionArtifactContent(file, content, request) {
|
|
1044
|
+
if (request.head !== undefined || request.offset !== undefined || request.limit !== undefined) {
|
|
1045
|
+
return applyReadWindow(content, request);
|
|
1046
|
+
}
|
|
1047
|
+
if (path.extname(file).toLowerCase() !== ".json") {
|
|
1048
|
+
return content;
|
|
1049
|
+
}
|
|
1050
|
+
try {
|
|
1051
|
+
return JSON.parse(content);
|
|
1052
|
+
}
|
|
1053
|
+
catch {
|
|
1054
|
+
return content;
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
function formatSessionReadAgentText(response) {
|
|
1058
|
+
const rows = Array.isArray(response.reads) ? response.reads.filter(isObject) : [response];
|
|
1059
|
+
if (rows.length === 0) {
|
|
1060
|
+
return null;
|
|
1061
|
+
}
|
|
1062
|
+
const parts = [];
|
|
1063
|
+
const includeHeaders = rows.length > 1;
|
|
1064
|
+
for (const row of rows) {
|
|
1065
|
+
const handle = typeof row.read === "string" ? row.read : "";
|
|
1066
|
+
const content = row.content;
|
|
1067
|
+
const formattedContent = formatSessionReadContent(content);
|
|
1068
|
+
if (formattedContent !== null) {
|
|
1069
|
+
if (includeHeaders && handle) {
|
|
1070
|
+
parts.push(`// ${handle}`);
|
|
1071
|
+
}
|
|
1072
|
+
parts.push(formattedContent.trimEnd());
|
|
1073
|
+
continue;
|
|
1074
|
+
}
|
|
1075
|
+
if (typeof row.file === "string") {
|
|
1076
|
+
if (includeHeaders && handle) {
|
|
1077
|
+
parts.push(`// ${handle}`);
|
|
1078
|
+
}
|
|
1079
|
+
else if (handle) {
|
|
1080
|
+
parts.push(`input ${handle}`);
|
|
1081
|
+
}
|
|
1082
|
+
parts.push(`file: ${row.file}`);
|
|
1083
|
+
if (typeof row.next === "string") {
|
|
1084
|
+
parts.push(`next: ${row.next}`);
|
|
1085
|
+
}
|
|
1086
|
+
continue;
|
|
1087
|
+
}
|
|
1088
|
+
const error = typeof row.error === "string" ? row.error : "";
|
|
1089
|
+
if (error) {
|
|
1090
|
+
if (includeHeaders && handle) {
|
|
1091
|
+
parts.push(`// ${handle}`);
|
|
1092
|
+
}
|
|
1093
|
+
parts.push(`error: ${error}`);
|
|
1094
|
+
if (typeof row.next === "string") {
|
|
1095
|
+
parts.push(`next: ${row.next}`);
|
|
1096
|
+
}
|
|
1097
|
+
continue;
|
|
1098
|
+
}
|
|
1099
|
+
return null;
|
|
1100
|
+
}
|
|
1101
|
+
return parts.join("\n");
|
|
1102
|
+
}
|
|
1103
|
+
function formatSessionReadContent(content) {
|
|
1104
|
+
if (typeof content === "string") {
|
|
1105
|
+
return content;
|
|
1106
|
+
}
|
|
1107
|
+
if (content === undefined) {
|
|
1108
|
+
return null;
|
|
1109
|
+
}
|
|
1110
|
+
return JSON.stringify(content, null, 2);
|
|
1111
|
+
}
|
|
1112
|
+
function buildInputRerunCommand(kind, handle) {
|
|
1113
|
+
if (kind === "inspect") {
|
|
1114
|
+
return `aib inspect --from ${handle}`;
|
|
1115
|
+
}
|
|
1116
|
+
if (kind === "graph") {
|
|
1117
|
+
return `aib inspect graph --from ${handle}`;
|
|
1118
|
+
}
|
|
1119
|
+
if (kind === "rename") {
|
|
1120
|
+
return `aib mutate preview --from ${handle}`;
|
|
1121
|
+
}
|
|
1122
|
+
if (kind === "move") {
|
|
1123
|
+
return `aib mutate preview --from ${handle}`;
|
|
1124
|
+
}
|
|
1125
|
+
if (kind === "refactor") {
|
|
1126
|
+
return `aib mutate preview --from ${handle}`;
|
|
1127
|
+
}
|
|
1128
|
+
if (kind === "modulePlan") {
|
|
1129
|
+
return `aib mutate preview --from ${handle}`;
|
|
1130
|
+
}
|
|
1131
|
+
if (kind === "imports") {
|
|
1132
|
+
return `aib mutate preview --from ${handle}`;
|
|
1133
|
+
}
|
|
1134
|
+
return null;
|
|
1135
|
+
}
|
|
1136
|
+
function validateSessionReadOptions(options) {
|
|
1137
|
+
if (options.head !== undefined && (options.offset !== undefined || options.limit !== undefined)) {
|
|
1138
|
+
throw new errors_1.CliError("SESSION_READ_RANGE_CONFLICT", "Use either head or offset/limit, not both.");
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
function readSessionReadOptions(args) {
|
|
1142
|
+
const row = {};
|
|
1143
|
+
const head = readFlagValue(args, "--head");
|
|
1144
|
+
const offset = readFlagValue(args, "--offset");
|
|
1145
|
+
const limit = readFlagValue(args, "--limit");
|
|
1146
|
+
if (head !== undefined) {
|
|
1147
|
+
row.head = head;
|
|
1148
|
+
}
|
|
1149
|
+
if (offset !== undefined) {
|
|
1150
|
+
row.offset = offset;
|
|
1151
|
+
}
|
|
1152
|
+
if (limit !== undefined) {
|
|
1153
|
+
row.limit = limit;
|
|
1154
|
+
}
|
|
1155
|
+
return {
|
|
1156
|
+
...(args.includes("--raw-input") ? { rawInput: true } : {}),
|
|
1157
|
+
...readSessionReadObjectOptions(row, 0)
|
|
1158
|
+
};
|
|
1159
|
+
}
|
|
1160
|
+
function readSessionReadObjectOptions(row, index) {
|
|
1161
|
+
const head = readOptionalNonNegativeInteger(row.head, `session read row at index ${index} has invalid head.`);
|
|
1162
|
+
const offset = readOptionalNonNegativeInteger(row.offset, `session read row at index ${index} has invalid offset.`);
|
|
1163
|
+
const limit = readOptionalPositiveInteger(row.limit, `session read row at index ${index} has invalid limit.`);
|
|
1164
|
+
return {
|
|
1165
|
+
...(head !== undefined ? { head } : {}),
|
|
1166
|
+
...(offset !== undefined ? { offset } : {}),
|
|
1167
|
+
...(limit !== undefined ? { limit } : {})
|
|
1168
|
+
};
|
|
1169
|
+
}
|
|
1170
|
+
function applyReadWindow(content, options) {
|
|
1171
|
+
if (options.head === undefined && options.offset === undefined && options.limit === undefined) {
|
|
1172
|
+
return content;
|
|
1173
|
+
}
|
|
1174
|
+
const lines = content.split(/\r?\n/);
|
|
1175
|
+
const start = options.head !== undefined ? 0 : options.offset ?? 0;
|
|
1176
|
+
const end = options.head !== undefined ? options.head : options.limit !== undefined ? start + options.limit : undefined;
|
|
1177
|
+
return lines.slice(start, end).join("\n");
|
|
1178
|
+
}
|
|
1179
|
+
function sessionWorkspaceStatus(cwd) {
|
|
1180
|
+
const registry = readRegistry(cwd);
|
|
1181
|
+
const selected = resolveSelectedSessionForList(cwd);
|
|
1182
|
+
const available = registry ? Object.keys(registry.sessions).sort() : [];
|
|
1183
|
+
if (selected.source === "ambiguous") {
|
|
1184
|
+
return (0, agent_text_1.attachAgentText)({
|
|
1185
|
+
ok: false,
|
|
1186
|
+
code: "MULTIPLE_AIB_SESSIONS",
|
|
1187
|
+
error: "Multiple AIB sessions exist. Select one explicitly.",
|
|
1188
|
+
available,
|
|
1189
|
+
next: `Use aib -s <session> <command> or set ${env_vars_1.CLI_ENV.session}=<session>.`
|
|
1190
|
+
}, formatMultipleSessionsStatusText(available));
|
|
1191
|
+
}
|
|
1192
|
+
const workspace = selected.sessionId ? readWorkspaceById(cwd, selected.sessionId) : null;
|
|
1193
|
+
if (!workspace) {
|
|
1194
|
+
const response = {
|
|
1195
|
+
initialized: false,
|
|
1196
|
+
active: selected.sessionId ?? null,
|
|
1197
|
+
source: selected.source,
|
|
1198
|
+
available,
|
|
1199
|
+
next: selected.sessionId
|
|
1200
|
+
? `Run aib session init --name ${selected.sessionId}`
|
|
1201
|
+
: "Run aib session init --name <name>"
|
|
1202
|
+
};
|
|
1203
|
+
return (0, agent_text_1.attachAgentText)(response, formatSessionNotReadyStatusText(response));
|
|
1204
|
+
}
|
|
1205
|
+
writeWorkspace(cwd, workspace);
|
|
1206
|
+
const response = {
|
|
1207
|
+
initialized: true,
|
|
1208
|
+
session: workspace.sessionId ?? selected.sessionId,
|
|
1209
|
+
active: workspace.sessionId ?? selected.sessionId,
|
|
1210
|
+
source: selected.source,
|
|
1211
|
+
available,
|
|
1212
|
+
sessionDir: toDisplayPath(cwd, workspace.rootDir),
|
|
1213
|
+
aliases: (0, path_aliases_1.effectivePathAliases)(cwd, workspace.pathAliases ?? {}),
|
|
1214
|
+
latest: latestHandles(workspace),
|
|
1215
|
+
dirs: sessionDirsPayload(cwd, workspace)
|
|
1216
|
+
};
|
|
1217
|
+
return (0, agent_text_1.attachAgentText)(response, formatSessionStatusText(response));
|
|
1218
|
+
}
|
|
1219
|
+
function formatSessionNotReadyStatusText(response) {
|
|
1220
|
+
const active = typeof response.active === "string" && response.active ? response.active : null;
|
|
1221
|
+
if (active) {
|
|
1222
|
+
return [
|
|
1223
|
+
"session not ready",
|
|
1224
|
+
"",
|
|
1225
|
+
`Session ${active} was not found.`,
|
|
1226
|
+
"Create it:",
|
|
1227
|
+
`aib session init --name ${active}`
|
|
1228
|
+
].join("\n");
|
|
1229
|
+
}
|
|
1230
|
+
return [
|
|
1231
|
+
"session not ready",
|
|
1232
|
+
"",
|
|
1233
|
+
"No AIB sessions exist in this repo.",
|
|
1234
|
+
"Create one:",
|
|
1235
|
+
"aib session init --name <name>"
|
|
1236
|
+
].join("\n");
|
|
1237
|
+
}
|
|
1238
|
+
function formatSessionStatusText(response) {
|
|
1239
|
+
const sessionId = String(response.session ?? "");
|
|
1240
|
+
const aliases = response.aliases && typeof response.aliases === "object" && !Array.isArray(response.aliases)
|
|
1241
|
+
? response.aliases
|
|
1242
|
+
: {};
|
|
1243
|
+
const lines = [`session: ${sessionId}`];
|
|
1244
|
+
const aliasLines = Object.entries(aliases)
|
|
1245
|
+
.filter(([, target]) => typeof target === "string" && target.trim() !== "")
|
|
1246
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
1247
|
+
.map(([name, target]) => `@${name} -> ${String(target)}`);
|
|
1248
|
+
if (aliasLines.length > 0) {
|
|
1249
|
+
lines.push("", "aliases:", ...aliasLines);
|
|
1250
|
+
}
|
|
1251
|
+
if (response.source === "single") {
|
|
1252
|
+
lines.push("", "Only one AIB session exists in this repo.", "You can run AIB commands without -s.");
|
|
1253
|
+
}
|
|
1254
|
+
return lines.join("\n");
|
|
1255
|
+
}
|
|
1256
|
+
function formatMultipleSessionsStatusText(available) {
|
|
1257
|
+
return [
|
|
1258
|
+
"multiple AIB sessions",
|
|
1259
|
+
"",
|
|
1260
|
+
"available:",
|
|
1261
|
+
...available,
|
|
1262
|
+
"",
|
|
1263
|
+
"Choose one:",
|
|
1264
|
+
"aib -s <session> <command>",
|
|
1265
|
+
"",
|
|
1266
|
+
"Or bind it in this shell:",
|
|
1267
|
+
`${env_vars_1.CLI_ENV.session}=<session>`,
|
|
1268
|
+
"",
|
|
1269
|
+
"If none of these sessions is yours, create a new one:",
|
|
1270
|
+
"aib session init --name <name>"
|
|
1271
|
+
].join("\n");
|
|
1272
|
+
}
|
|
1273
|
+
function clearSessionWorkspace(cwd) {
|
|
1274
|
+
const selected = resolveSelectedSessionForList(cwd);
|
|
1275
|
+
const registry = readRegistry(cwd);
|
|
1276
|
+
const available = registry ? Object.keys(registry.sessions).sort() : [];
|
|
1277
|
+
if (selected.source === "ambiguous") {
|
|
1278
|
+
return (0, agent_text_1.attachAgentText)({
|
|
1279
|
+
ok: false,
|
|
1280
|
+
code: "MULTIPLE_AIB_SESSIONS",
|
|
1281
|
+
error: "Multiple AIB sessions exist. Select one explicitly.",
|
|
1282
|
+
available,
|
|
1283
|
+
next: "Use aib -s <session> session clear."
|
|
1284
|
+
}, formatMultipleSessionsClearText(available));
|
|
1285
|
+
}
|
|
1286
|
+
const workspace = selected.sessionId ? readWorkspaceById(cwd, selected.sessionId) : null;
|
|
1287
|
+
if (!workspace) {
|
|
1288
|
+
return (0, agent_text_1.attachAgentText)({
|
|
1289
|
+
cleared: false,
|
|
1290
|
+
reason: "session-not-initialized"
|
|
1291
|
+
}, [
|
|
1292
|
+
"No AIB sessions exist in this repo.",
|
|
1293
|
+
"",
|
|
1294
|
+
"Create one:",
|
|
1295
|
+
"aib session init --name <name>"
|
|
1296
|
+
].join("\n"));
|
|
1297
|
+
}
|
|
1298
|
+
pruneSessionWorkspaceData(workspace, { touch: true });
|
|
1299
|
+
writeWorkspace(cwd, workspace);
|
|
1300
|
+
const sessionId = workspace.sessionId ?? selected.sessionId ?? "";
|
|
1301
|
+
return (0, agent_text_1.attachAgentText)({
|
|
1302
|
+
cleared: true,
|
|
1303
|
+
session: sessionId,
|
|
1304
|
+
dir: toDisplayPath(cwd, workspace.rootDir)
|
|
1305
|
+
}, [
|
|
1306
|
+
`session cleared: ${sessionId}`,
|
|
1307
|
+
"",
|
|
1308
|
+
"Inputs and outputs were pruned.",
|
|
1309
|
+
"You can keep using this session."
|
|
1310
|
+
].join("\n"));
|
|
1311
|
+
}
|
|
1312
|
+
function pruneSessionWorkspaceData(workspace, options) {
|
|
1313
|
+
fs.rmSync(path.join(workspace.rootDir, "inputs"), { recursive: true, force: true });
|
|
1314
|
+
fs.rmSync(path.join(workspace.rootDir, "outputs"), { recursive: true, force: true });
|
|
1315
|
+
workspace.inputs = {};
|
|
1316
|
+
workspace.outputs = {};
|
|
1317
|
+
workspace.guidance = {};
|
|
1318
|
+
if (options.touch) {
|
|
1319
|
+
workspace.updatedAt = new Date().toISOString();
|
|
1320
|
+
}
|
|
1321
|
+
ensureWorkspaceDirs(workspace);
|
|
1322
|
+
}
|
|
1323
|
+
function formatMultipleSessionsClearText(available) {
|
|
1324
|
+
return [
|
|
1325
|
+
"multiple AIB sessions",
|
|
1326
|
+
"",
|
|
1327
|
+
"available:",
|
|
1328
|
+
...available,
|
|
1329
|
+
"",
|
|
1330
|
+
"Clear one explicitly only if it is yours:",
|
|
1331
|
+
"aib -s <session> session clear",
|
|
1332
|
+
"",
|
|
1333
|
+
"If none of these sessions is yours, create a new one:",
|
|
1334
|
+
"aib session init --name <name>"
|
|
1335
|
+
].join("\n");
|
|
1336
|
+
}
|
|
1337
|
+
function cleanupExpiredSessions(cwd) {
|
|
1338
|
+
const policy = readSessionTtlPolicy(cwd);
|
|
1339
|
+
const registry = readRegistry(cwd);
|
|
1340
|
+
if (!registry) {
|
|
1341
|
+
return;
|
|
1342
|
+
}
|
|
1343
|
+
const now = Date.now();
|
|
1344
|
+
let changed = false;
|
|
1345
|
+
for (const [sessionId, entry] of Object.entries(registry.sessions)) {
|
|
1346
|
+
const sessionFile = workspaceFilePath(entry.rootDir);
|
|
1347
|
+
if (!fs.existsSync(sessionFile)) {
|
|
1348
|
+
delete registry.sessions[sessionId];
|
|
1349
|
+
changed = true;
|
|
1350
|
+
if (registry.activeSessionId === sessionId) {
|
|
1351
|
+
delete registry.activeSessionId;
|
|
1352
|
+
}
|
|
1353
|
+
continue;
|
|
1354
|
+
}
|
|
1355
|
+
const updatedAt = Date.parse(entry.updatedAt);
|
|
1356
|
+
if (!Number.isFinite(updatedAt)) {
|
|
1357
|
+
continue;
|
|
1358
|
+
}
|
|
1359
|
+
const inactiveMs = now - updatedAt;
|
|
1360
|
+
if (policy.autoDelete && policy.ttlDeleteMs > 0 && inactiveMs > policy.ttlDeleteMs) {
|
|
1361
|
+
fs.rmSync(entry.rootDir, { recursive: true, force: true });
|
|
1362
|
+
delete registry.sessions[sessionId];
|
|
1363
|
+
changed = true;
|
|
1364
|
+
if (registry.activeSessionId === sessionId) {
|
|
1365
|
+
delete registry.activeSessionId;
|
|
1366
|
+
}
|
|
1367
|
+
continue;
|
|
1368
|
+
}
|
|
1369
|
+
if (policy.autoClean && policy.ttlCleanMs > 0 && inactiveMs > policy.ttlCleanMs) {
|
|
1370
|
+
const workspace = readWorkspaceFile(cwd, entry.rootDir, sessionId);
|
|
1371
|
+
if (workspace) {
|
|
1372
|
+
pruneSessionWorkspaceData(workspace, { touch: false });
|
|
1373
|
+
writeWorkspacePreservingTimestamp(workspace);
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
if (!changed) {
|
|
1378
|
+
return;
|
|
1379
|
+
}
|
|
1380
|
+
if (!registry.activeSessionId) {
|
|
1381
|
+
const nextSessionId = Object.keys(registry.sessions).sort()[0];
|
|
1382
|
+
if (nextSessionId) {
|
|
1383
|
+
registry.activeSessionId = nextSessionId;
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
writeRegistry(cwd, registry);
|
|
1387
|
+
}
|
|
1388
|
+
function readSessionTtlPolicy(cwd) {
|
|
1389
|
+
const legacyTtlMinutes = (0, workspace_root_1.readWorkspaceNumberConfig)(cwd, "session.ttlMinutes", 60);
|
|
1390
|
+
const ttlDeleteMinutes = (0, workspace_root_1.readWorkspaceNumberConfig)(cwd, "session.ttlDeleteMinutes", legacyTtlMinutes);
|
|
1391
|
+
const ttlCleanMinutes = (0, workspace_root_1.readWorkspaceNumberConfig)(cwd, "session.ttlCleanMinutes", legacyTtlMinutes);
|
|
1392
|
+
return {
|
|
1393
|
+
autoDelete: (0, workspace_root_1.readWorkspaceBooleanConfig)(cwd, "session.autoDelete", true),
|
|
1394
|
+
ttlDeleteMs: ttlDeleteMinutes > 0 ? ttlDeleteMinutes * 60_000 : 0,
|
|
1395
|
+
autoClean: (0, workspace_root_1.readWorkspaceBooleanConfig)(cwd, "session.autoClean", true),
|
|
1396
|
+
ttlCleanMs: ttlCleanMinutes > 0 ? ttlCleanMinutes * 60_000 : 0
|
|
1397
|
+
};
|
|
1398
|
+
}
|
|
1399
|
+
function ensureWorkspaceDirs(workspace) {
|
|
1400
|
+
for (const kind of OUTPUT_KINDS) {
|
|
1401
|
+
fs.mkdirSync(path.join(workspace.rootDir, "outputs", kind), { recursive: true });
|
|
1402
|
+
}
|
|
1403
|
+
for (const kind of INPUT_KINDS) {
|
|
1404
|
+
fs.mkdirSync(path.join(workspace.rootDir, "inputs", kind), { recursive: true });
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
function readWorkspaceById(cwd, sessionId) {
|
|
1408
|
+
const registry = readRegistry(cwd);
|
|
1409
|
+
const entry = registry?.sessions[sessionId];
|
|
1410
|
+
if (!entry) {
|
|
1411
|
+
return null;
|
|
1412
|
+
}
|
|
1413
|
+
return readWorkspaceFile(cwd, entry.rootDir, sessionId);
|
|
1414
|
+
}
|
|
1415
|
+
function readWorkspace(cwd) {
|
|
1416
|
+
const selected = resolveSelectedSession(cwd);
|
|
1417
|
+
return selected.sessionId ? readWorkspaceById(cwd, selected.sessionId) : null;
|
|
1418
|
+
}
|
|
1419
|
+
function readWorkspaceForSave(cwd) {
|
|
1420
|
+
cleanupExpiredSessions(cwd);
|
|
1421
|
+
const workspace = readWorkspace(cwd);
|
|
1422
|
+
return workspace ?? createDefaultSessionWorkspace(cwd);
|
|
1423
|
+
}
|
|
1424
|
+
function createDefaultSessionWorkspace(cwd) {
|
|
1425
|
+
const workspaceRoot = (0, workspace_root_1.resolveWorkspaceRoot)(cwd);
|
|
1426
|
+
if (!workspaceRoot) {
|
|
1427
|
+
return null;
|
|
1428
|
+
}
|
|
1429
|
+
const sessionRoot = resolveSessionRoot(workspaceRoot.root, undefined, false);
|
|
1430
|
+
const rootDir = path.join(sessionRoot.rootDir, DEFAULT_AUTO_SESSION_ID);
|
|
1431
|
+
const now = new Date().toISOString();
|
|
1432
|
+
const existing = readWorkspaceFile(workspaceRoot.root, rootDir, DEFAULT_AUTO_SESSION_ID);
|
|
1433
|
+
const workspace = existing ?? {
|
|
1434
|
+
version: 1,
|
|
1435
|
+
sessionId: DEFAULT_AUTO_SESSION_ID,
|
|
1436
|
+
auto: true,
|
|
1437
|
+
cwd: path.resolve(workspaceRoot.root),
|
|
1438
|
+
rootDir,
|
|
1439
|
+
createdAt: now,
|
|
1440
|
+
updatedAt: now,
|
|
1441
|
+
outputs: {},
|
|
1442
|
+
inputs: {},
|
|
1443
|
+
guidance: {}
|
|
1444
|
+
};
|
|
1445
|
+
workspace.sessionId = DEFAULT_AUTO_SESSION_ID;
|
|
1446
|
+
workspace.auto = true;
|
|
1447
|
+
workspace.cwd = path.resolve(workspaceRoot.root);
|
|
1448
|
+
workspace.rootDir = rootDir;
|
|
1449
|
+
workspace.updatedAt = now;
|
|
1450
|
+
ensureWorkspaceDirs(workspace);
|
|
1451
|
+
writeWorkspace(workspaceRoot.root, workspace);
|
|
1452
|
+
return workspace;
|
|
1453
|
+
}
|
|
1454
|
+
function readWorkspaceFile(cwd, rootDir, sessionId) {
|
|
1455
|
+
try {
|
|
1456
|
+
const parsed = JSON.parse(fs.readFileSync(workspaceFilePath(rootDir), "utf8"));
|
|
1457
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
1458
|
+
return null;
|
|
1459
|
+
}
|
|
1460
|
+
const candidate = parsed;
|
|
1461
|
+
if (candidate.version !== 1 || typeof candidate.rootDir !== "string") {
|
|
1462
|
+
return null;
|
|
1463
|
+
}
|
|
1464
|
+
candidate.sessionId = candidate.sessionId ?? sessionId;
|
|
1465
|
+
return candidate;
|
|
1466
|
+
}
|
|
1467
|
+
catch {
|
|
1468
|
+
return null;
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
function readRequiredWorkspace(cwd) {
|
|
1472
|
+
const workspace = readWorkspace(cwd);
|
|
1473
|
+
if (!workspace) {
|
|
1474
|
+
throw new errors_1.CliError("SESSION_WORKSPACE_NOT_INITIALIZED", "Session workspace is not initialized.", {
|
|
1475
|
+
session: currentSessionId() ?? null,
|
|
1476
|
+
next: "Run aib session init --name <name>",
|
|
1477
|
+
help: "aib help session"
|
|
1478
|
+
});
|
|
1479
|
+
}
|
|
1480
|
+
writeWorkspace(cwd, workspace);
|
|
1481
|
+
return workspace;
|
|
1482
|
+
}
|
|
1483
|
+
function readRequiredWorkspaceForSave(cwd) {
|
|
1484
|
+
const workspace = readWorkspaceForSave(cwd);
|
|
1485
|
+
if (!workspace) {
|
|
1486
|
+
throw new errors_1.CliError("SESSION_WORKSPACE_NOT_INITIALIZED", "Session workspace is not initialized.", {
|
|
1487
|
+
session: currentSessionId() ?? null,
|
|
1488
|
+
next: "Run aib session init --name <name>",
|
|
1489
|
+
help: "aib help session"
|
|
1490
|
+
});
|
|
1491
|
+
}
|
|
1492
|
+
return workspace;
|
|
1493
|
+
}
|
|
1494
|
+
function writeWorkspace(cwd, workspace) {
|
|
1495
|
+
workspace.updatedAt = new Date().toISOString();
|
|
1496
|
+
fs.mkdirSync(workspace.rootDir, { recursive: true });
|
|
1497
|
+
fs.writeFileSync(workspaceFilePath(workspace.rootDir), `${JSON.stringify(workspace, null, 2)}\n`);
|
|
1498
|
+
upsertRegistrySession(cwd, workspace, false);
|
|
1499
|
+
}
|
|
1500
|
+
function writeWorkspacePreservingTimestamp(workspace) {
|
|
1501
|
+
fs.mkdirSync(workspace.rootDir, { recursive: true });
|
|
1502
|
+
fs.writeFileSync(workspaceFilePath(workspace.rootDir), `${JSON.stringify(workspace, null, 2)}\n`);
|
|
1503
|
+
}
|
|
1504
|
+
function resolveSessionRoot(cwd, requestedDir, persistDefault = false) {
|
|
1505
|
+
const workspace = (0, workspace_root_1.resolveWorkspaceRoot)(cwd);
|
|
1506
|
+
const workspaceRoot = workspace?.root ?? cwd;
|
|
1507
|
+
const configuredDir = workspace ? readString(workspace.config[SESSION_DIR_CONFIG_KEY]) : undefined;
|
|
1508
|
+
if (configuredDir) {
|
|
1509
|
+
return {
|
|
1510
|
+
rootDir: normalizeSessionRootDir(workspaceRoot, configuredDir),
|
|
1511
|
+
source: "aib.json",
|
|
1512
|
+
...(requestedDir ? { ignoredRequestedDir: requestedDir } : {})
|
|
1513
|
+
};
|
|
1514
|
+
}
|
|
1515
|
+
const rawDir = requestedDir ?? DEFAULT_SESSION_ROOT;
|
|
1516
|
+
const rootDir = normalizeSessionRootDir(workspaceRoot, rawDir);
|
|
1517
|
+
if (persistDefault && workspace) {
|
|
1518
|
+
(0, workspace_root_1.updateWorkspaceConfig)(workspaceRoot, {
|
|
1519
|
+
[SESSION_DIR_CONFIG_KEY]: toConfigRelativePath(workspaceRoot, rootDir)
|
|
1520
|
+
});
|
|
1521
|
+
}
|
|
1522
|
+
return {
|
|
1523
|
+
rootDir,
|
|
1524
|
+
source: requestedDir ? "request" : "default"
|
|
1525
|
+
};
|
|
1526
|
+
}
|
|
1527
|
+
function normalizeSessionRootDir(workspaceRoot, rawDir) {
|
|
1528
|
+
const resolved = path.resolve(workspaceRoot, rawDir);
|
|
1529
|
+
return path.basename(resolved).toLowerCase() === "aib" ? resolved : path.join(resolved, "aib");
|
|
1530
|
+
}
|
|
1531
|
+
function toConfigRelativePath(workspaceRoot, filePath) {
|
|
1532
|
+
const relative = path.relative(workspaceRoot, filePath);
|
|
1533
|
+
return relative && !relative.startsWith("..") && !path.isAbsolute(relative)
|
|
1534
|
+
? relative.replace(/\\/g, "/")
|
|
1535
|
+
: filePath.replace(/\\/g, "/");
|
|
1536
|
+
}
|
|
1537
|
+
function workspaceMarkerPath(cwd) {
|
|
1538
|
+
return path.join(resolveSessionRoot(cwd).rootDir, SESSION_REGISTRY_FILE_NAME);
|
|
1539
|
+
}
|
|
1540
|
+
function activeSessionPath(cwd) {
|
|
1541
|
+
return path.join(resolveSessionRoot(cwd).rootDir, ACTIVE_SESSION_FILE_NAME);
|
|
1542
|
+
}
|
|
1543
|
+
function workspaceFilePath(rootDir) {
|
|
1544
|
+
return path.join(rootDir, "session.json");
|
|
1545
|
+
}
|
|
1546
|
+
function readRegistry(cwd) {
|
|
1547
|
+
try {
|
|
1548
|
+
const parsed = JSON.parse(fs.readFileSync(workspaceMarkerPath(cwd), "utf8"));
|
|
1549
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
1550
|
+
return null;
|
|
1551
|
+
}
|
|
1552
|
+
const candidate = parsed;
|
|
1553
|
+
if (candidate.version !== 1 || !candidate.sessions || typeof candidate.sessions !== "object") {
|
|
1554
|
+
return null;
|
|
1555
|
+
}
|
|
1556
|
+
return {
|
|
1557
|
+
version: 1,
|
|
1558
|
+
cwd: typeof candidate.cwd === "string" ? candidate.cwd : path.resolve(cwd),
|
|
1559
|
+
...(typeof candidate.activeSessionId === "string" ? { activeSessionId: candidate.activeSessionId } : {}),
|
|
1560
|
+
sessions: candidate.sessions
|
|
1561
|
+
};
|
|
1562
|
+
}
|
|
1563
|
+
catch {
|
|
1564
|
+
return null;
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
function writeRegistry(cwd, registry) {
|
|
1568
|
+
registry.cwd = path.resolve((0, workspace_root_1.resolveWorkspaceRoot)(cwd)?.root ?? cwd);
|
|
1569
|
+
fs.mkdirSync(path.dirname(workspaceMarkerPath(cwd)), { recursive: true });
|
|
1570
|
+
fs.writeFileSync(workspaceMarkerPath(cwd), `${JSON.stringify(registry, null, 2)}\n`);
|
|
1571
|
+
writeActiveSession(cwd, registry.activeSessionId);
|
|
1572
|
+
}
|
|
1573
|
+
function createEmptyRegistry(cwd) {
|
|
1574
|
+
return {
|
|
1575
|
+
version: 1,
|
|
1576
|
+
cwd: path.resolve(cwd),
|
|
1577
|
+
sessions: {}
|
|
1578
|
+
};
|
|
1579
|
+
}
|
|
1580
|
+
function writeActiveSession(cwd, sessionId) {
|
|
1581
|
+
const file = activeSessionPath(cwd);
|
|
1582
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
1583
|
+
if (!sessionId) {
|
|
1584
|
+
fs.rmSync(file, { force: true });
|
|
1585
|
+
return;
|
|
1586
|
+
}
|
|
1587
|
+
fs.writeFileSync(file, `${JSON.stringify({ sessionId, updatedAt: new Date().toISOString() }, null, 2)}\n`);
|
|
1588
|
+
}
|
|
1589
|
+
function upsertRegistrySession(cwd, workspace, makeActive) {
|
|
1590
|
+
const sessionId = workspace.sessionId ?? currentSessionId() ?? "";
|
|
1591
|
+
if (!sessionId) {
|
|
1592
|
+
return;
|
|
1593
|
+
}
|
|
1594
|
+
const registry = readRegistry(cwd) ?? createEmptyRegistry(cwd);
|
|
1595
|
+
registry.sessions[sessionId] = {
|
|
1596
|
+
sessionId,
|
|
1597
|
+
...(workspace.auto ? { auto: true } : {}),
|
|
1598
|
+
rootDir: workspace.rootDir,
|
|
1599
|
+
createdAt: registry.sessions[sessionId]?.createdAt ?? workspace.createdAt,
|
|
1600
|
+
updatedAt: workspace.updatedAt
|
|
1601
|
+
};
|
|
1602
|
+
if (makeActive || !registry.activeSessionId) {
|
|
1603
|
+
registry.activeSessionId = sessionId;
|
|
1604
|
+
}
|
|
1605
|
+
writeRegistry(cwd, registry);
|
|
1606
|
+
}
|
|
1607
|
+
function removeRegistrySession(cwd, sessionId) {
|
|
1608
|
+
const registry = readRegistry(cwd);
|
|
1609
|
+
if (!registry || !sessionId) {
|
|
1610
|
+
return;
|
|
1611
|
+
}
|
|
1612
|
+
delete registry.sessions[sessionId];
|
|
1613
|
+
if (registry.activeSessionId === sessionId) {
|
|
1614
|
+
const nextSessionId = Object.keys(registry.sessions).sort()[0];
|
|
1615
|
+
if (nextSessionId) {
|
|
1616
|
+
registry.activeSessionId = nextSessionId;
|
|
1617
|
+
}
|
|
1618
|
+
else {
|
|
1619
|
+
delete registry.activeSessionId;
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
writeRegistry(cwd, registry);
|
|
1623
|
+
}
|
|
1624
|
+
function resolveSelectedSession(cwd) {
|
|
1625
|
+
const override = sessionOverrideStorage.getStore();
|
|
1626
|
+
if (override) {
|
|
1627
|
+
return { sessionId: sanitizeSessionId(override), source: "override" };
|
|
1628
|
+
}
|
|
1629
|
+
const envSession = process.env[env_vars_1.CLI_ENV.session];
|
|
1630
|
+
if (envSession && envSession.trim()) {
|
|
1631
|
+
return { sessionId: sanitizeSessionId(envSession), source: "env" };
|
|
1632
|
+
}
|
|
1633
|
+
const legacyEnvSession = process.env[env_vars_1.CLI_ENV.legacySession];
|
|
1634
|
+
if (legacyEnvSession && legacyEnvSession.trim()) {
|
|
1635
|
+
return { sessionId: sanitizeSessionId(legacyEnvSession), source: "legacy-env" };
|
|
1636
|
+
}
|
|
1637
|
+
const registry = readRegistry(cwd);
|
|
1638
|
+
const sessions = registry ? Object.keys(registry.sessions).sort() : [];
|
|
1639
|
+
if (sessions.length === 1) {
|
|
1640
|
+
return { sessionId: sessions[0], source: "single" };
|
|
1641
|
+
}
|
|
1642
|
+
if (sessions.length > 1) {
|
|
1643
|
+
throw new errors_1.CliError("MULTIPLE_AIB_SESSIONS", "Multiple AIB sessions exist. Select one explicitly.", {
|
|
1644
|
+
available: sessions,
|
|
1645
|
+
next: `Use aib -s <session> <command> or set ${env_vars_1.CLI_ENV.session}=<session>.`
|
|
1646
|
+
});
|
|
1647
|
+
}
|
|
1648
|
+
return { sessionId: null, source: "none" };
|
|
1649
|
+
}
|
|
1650
|
+
function resolveSelectedSessionForList(cwd) {
|
|
1651
|
+
try {
|
|
1652
|
+
return resolveSelectedSession(cwd);
|
|
1653
|
+
}
|
|
1654
|
+
catch (error) {
|
|
1655
|
+
if (error instanceof errors_1.CliError && error.code === "MULTIPLE_AIB_SESSIONS") {
|
|
1656
|
+
return { sessionId: null, source: "ambiguous" };
|
|
1657
|
+
}
|
|
1658
|
+
throw error;
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
function tryResolveCurrentSessionId(cwd) {
|
|
1662
|
+
const selected = resolveSelectedSessionForList(cwd);
|
|
1663
|
+
return {
|
|
1664
|
+
sessionId: selected.sessionId,
|
|
1665
|
+
sessionSource: selected.source
|
|
1666
|
+
};
|
|
1667
|
+
}
|
|
1668
|
+
function currentSessionId() {
|
|
1669
|
+
const override = sessionOverrideStorage.getStore();
|
|
1670
|
+
if (override) {
|
|
1671
|
+
return sanitizeSessionId(override);
|
|
1672
|
+
}
|
|
1673
|
+
const envSession = process.env[env_vars_1.CLI_ENV.session];
|
|
1674
|
+
if (envSession && envSession.trim()) {
|
|
1675
|
+
return sanitizeSessionId(envSession);
|
|
1676
|
+
}
|
|
1677
|
+
const legacyEnvSession = process.env[env_vars_1.CLI_ENV.legacySession];
|
|
1678
|
+
return legacyEnvSession && legacyEnvSession.trim() ? sanitizeSessionId(legacyEnvSession) : null;
|
|
1679
|
+
}
|
|
1680
|
+
function sessionOutputPath(workspace, kind, name, extension) {
|
|
1681
|
+
return path.join(workspace.rootDir, "outputs", sanitizePathSegment(kind), `${sanitizePathSegment(name)}${sanitizeExtension(extension)}`);
|
|
1682
|
+
}
|
|
1683
|
+
function sessionInputPath(workspace, kind, name, extension = ".json") {
|
|
1684
|
+
return path.join(workspace.rootDir, "inputs", sanitizePathSegment(kind), `${sanitizePathSegment(name)}${sanitizeExtension(extension)}`);
|
|
1685
|
+
}
|
|
1686
|
+
function sessionCompiledInputPath(workspace, kind, name) {
|
|
1687
|
+
return path.join(workspace.rootDir, "inputs", sanitizePathSegment(kind), `${sanitizePathSegment(name)}.compiled.json`);
|
|
1688
|
+
}
|
|
1689
|
+
function sessionLastInputPath(workspace, kind, extension = ".json") {
|
|
1690
|
+
return path.join(workspace.rootDir, "inputs", sanitizePathSegment(kind), extension === ".json" ? LAST_INPUT_FILE_NAME : `_last${sanitizeExtension(extension)}`);
|
|
1691
|
+
}
|
|
1692
|
+
function writeJsonFile(file, value) {
|
|
1693
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
1694
|
+
fs.writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`);
|
|
1695
|
+
}
|
|
1696
|
+
function writeTextFile(file, value) {
|
|
1697
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
1698
|
+
fs.writeFileSync(file, value.endsWith("\n") ? value : `${value}\n`, "utf8");
|
|
1699
|
+
}
|
|
1700
|
+
function registerLastInputArtifact(workspace, kind, value, source) {
|
|
1701
|
+
const normalizedKind = sanitizePathSegment(kind);
|
|
1702
|
+
const inputSource = source ?? { format: "json", text: JSON.stringify(value, null, 2) };
|
|
1703
|
+
const file = inputSource.format === "dsl"
|
|
1704
|
+
? sessionLastInputPath(workspace, normalizedKind, ".dsl")
|
|
1705
|
+
: sessionLastInputPath(workspace, normalizedKind, ".json");
|
|
1706
|
+
if (inputSource.format === "dsl") {
|
|
1707
|
+
writeTextFile(file, inputSource.text);
|
|
1708
|
+
writeJsonFile(path.join(workspace.rootDir, "inputs", normalizedKind, "_last.compiled.json"), value);
|
|
1709
|
+
fs.rmSync(sessionLastInputPath(workspace, normalizedKind, ".json"), { force: true });
|
|
1710
|
+
}
|
|
1711
|
+
else {
|
|
1712
|
+
writeJsonFile(file, value);
|
|
1713
|
+
fs.rmSync(sessionLastInputPath(workspace, normalizedKind, ".dsl"), { force: true });
|
|
1714
|
+
fs.rmSync(path.join(workspace.rootDir, "inputs", normalizedKind, "_last.compiled.json"), { force: true });
|
|
1715
|
+
}
|
|
1716
|
+
registerArtifact(workspace, "inputs", normalizedKind, LAST_INPUT_NAME, file);
|
|
1717
|
+
}
|
|
1718
|
+
function registerArtifact(workspace, group, kind, name, file) {
|
|
1719
|
+
const normalizedKind = sanitizePathSegment(kind);
|
|
1720
|
+
const normalizedName = sanitizePathSegment(name);
|
|
1721
|
+
const handle = group === "inputs"
|
|
1722
|
+
? `aib:input:${normalizedKind}:${normalizedName}`
|
|
1723
|
+
: `aib:${normalizedKind}:${normalizedName}`;
|
|
1724
|
+
const now = new Date().toISOString();
|
|
1725
|
+
const buckets = workspace[group];
|
|
1726
|
+
const bucket = buckets[normalizedKind] ?? { items: {} };
|
|
1727
|
+
const artifact = {
|
|
1728
|
+
handle,
|
|
1729
|
+
file,
|
|
1730
|
+
createdAt: bucket.items[normalizedName]?.createdAt ?? now,
|
|
1731
|
+
updatedAt: now
|
|
1732
|
+
};
|
|
1733
|
+
bucket.items[normalizedName] = artifact;
|
|
1734
|
+
bucket.last = normalizedName;
|
|
1735
|
+
buckets[normalizedKind] = bucket;
|
|
1736
|
+
return artifact;
|
|
1737
|
+
}
|
|
1738
|
+
function parseSessionHandle(handle) {
|
|
1739
|
+
const parts = handle.split(":");
|
|
1740
|
+
if (parts[0] !== "aib") {
|
|
1741
|
+
throw new errors_1.CliError("INVALID_SESSION_HANDLE", `Invalid session handle: ${handle}`);
|
|
1742
|
+
}
|
|
1743
|
+
if (parts[1] === "input" && parts.length === 4) {
|
|
1744
|
+
return { scope: "input", kind: parts[2] ?? "", name: parts[3] ?? "" };
|
|
1745
|
+
}
|
|
1746
|
+
if (parts.length === 3) {
|
|
1747
|
+
return { scope: parts[1] ?? "", kind: parts[1] ?? "", name: parts[2] ?? "" };
|
|
1748
|
+
}
|
|
1749
|
+
throw new errors_1.CliError("INVALID_SESSION_HANDLE", `Invalid session handle: ${handle}`, {
|
|
1750
|
+
expected: "aib:<kind>:<name> or aib:input:<kind>:<name>"
|
|
1751
|
+
});
|
|
1752
|
+
}
|
|
1753
|
+
function latestHandles(workspace) {
|
|
1754
|
+
const latest = {};
|
|
1755
|
+
for (const [kind, bucket] of Object.entries(workspace.outputs)) {
|
|
1756
|
+
if (bucket.last) {
|
|
1757
|
+
latest[kind] = `aib:${kind}:${bucket.last}`;
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
for (const [kind, bucket] of Object.entries(workspace.inputs)) {
|
|
1761
|
+
if (bucket.last) {
|
|
1762
|
+
latest[`input:${kind}`] = `aib:input:${kind}:${bucket.last}`;
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
return latest;
|
|
1766
|
+
}
|
|
1767
|
+
function sessionDirsPayload(cwd, workspace) {
|
|
1768
|
+
return {
|
|
1769
|
+
outputs: toDisplayPath(cwd, path.join(workspace.rootDir, "outputs")),
|
|
1770
|
+
inputs: toDisplayPath(cwd, path.join(workspace.rootDir, "inputs"))
|
|
1771
|
+
};
|
|
1772
|
+
}
|
|
1773
|
+
function readFlagValue(args, flag) {
|
|
1774
|
+
const index = args.indexOf(flag);
|
|
1775
|
+
return index >= 0 ? args[index + 1] : undefined;
|
|
1776
|
+
}
|
|
1777
|
+
function readString(value) {
|
|
1778
|
+
return typeof value === "string" && value.trim() !== "" ? value.trim() : undefined;
|
|
1779
|
+
}
|
|
1780
|
+
function readOptionalNonNegativeInteger(value, message) {
|
|
1781
|
+
if (value === undefined) {
|
|
1782
|
+
return undefined;
|
|
1783
|
+
}
|
|
1784
|
+
const parsed = typeof value === "number" ? value : typeof value === "string" ? Number(value) : Number.NaN;
|
|
1785
|
+
if (!Number.isInteger(parsed) || parsed < 0) {
|
|
1786
|
+
throw new errors_1.CliError("INVALID_SESSION_READ_RANGE", message);
|
|
1787
|
+
}
|
|
1788
|
+
return parsed;
|
|
1789
|
+
}
|
|
1790
|
+
function readOptionalPositiveInteger(value, message) {
|
|
1791
|
+
if (value === undefined) {
|
|
1792
|
+
return undefined;
|
|
1793
|
+
}
|
|
1794
|
+
const parsed = readOptionalNonNegativeInteger(value, message);
|
|
1795
|
+
if (parsed === undefined) {
|
|
1796
|
+
return undefined;
|
|
1797
|
+
}
|
|
1798
|
+
if (parsed <= 0) {
|
|
1799
|
+
throw new errors_1.CliError("INVALID_SESSION_READ_RANGE", message);
|
|
1800
|
+
}
|
|
1801
|
+
return parsed;
|
|
1802
|
+
}
|
|
1803
|
+
function isObject(value) {
|
|
1804
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1805
|
+
}
|
|
1806
|
+
function sanitizePathSegment(value) {
|
|
1807
|
+
const sanitized = value.trim().replace(/[^A-Za-z0-9._-]/g, "-").replace(/^-+|-+$/g, "");
|
|
1808
|
+
if (!sanitized) {
|
|
1809
|
+
throw new errors_1.CliError("INVALID_SESSION_ARTIFACT_NAME", `Invalid session artifact name: ${value}`);
|
|
1810
|
+
}
|
|
1811
|
+
return sanitized;
|
|
1812
|
+
}
|
|
1813
|
+
function sanitizeSessionId(value) {
|
|
1814
|
+
const sanitized = value.trim().replace(/[^A-Za-z0-9._-]/g, "-").replace(/^-+|-+$/g, "");
|
|
1815
|
+
if (!sanitized) {
|
|
1816
|
+
throw new errors_1.CliError("INVALID_SESSION_ID", `Invalid session id: ${value}`);
|
|
1817
|
+
}
|
|
1818
|
+
return sanitized;
|
|
1819
|
+
}
|
|
1820
|
+
function createSessionId() {
|
|
1821
|
+
return `${SESSION_ID_PREFIX}${Math.random().toString(16).slice(2, 8)}`;
|
|
1822
|
+
}
|
|
1823
|
+
function sanitizeExtension(value) {
|
|
1824
|
+
const extension = value.startsWith(".") ? value : `.${value}`;
|
|
1825
|
+
return extension.replace(/[^A-Za-z0-9.]/g, "") || ".txt";
|
|
1826
|
+
}
|
|
1827
|
+
function numberOrZero(value) {
|
|
1828
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
1829
|
+
}
|
|
1830
|
+
function plural(count, singular) {
|
|
1831
|
+
return count === 1 ? singular : `${singular}s`;
|
|
1832
|
+
}
|
|
1833
|
+
function toDisplayPath(cwd, filePath) {
|
|
1834
|
+
const relative = path.relative(cwd, filePath);
|
|
1835
|
+
return relative && !relative.startsWith("..") ? relative.replace(/\\/g, "/") : filePath;
|
|
1836
|
+
}
|