Merge remote-tracking branch 'origin/master' into codex/invariant-service-seam

# Conflicts:
#	.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.i18n.yaml
#	.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.md
#	.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.zh.md
#	.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.md
#	.agents/notes/implemented/feature/2026-07-07-session-prefix.md
#	.agents/notes/implemented/process/2026-07-14-typescript-program-backed-semantic-gates.i18n.yaml
#	docs/architecture.md
#	docs/config-catalog.md
#	docs/core-data-structures/session.md
#	docs/rfc/INDEX.md
#	packages/examples/agent-spine-demo/README.md
#	packages/examples/agent-spine-demo/src/index.ts
#	packages/examples/agent-spine-demo/tests/agent-core.spec.ts
#	packages/support/invariants/README.md
#	packages/support/invariants/src/index.ts
#	packages/support/invariants/tests/invariants.spec.ts
This commit is contained in:
Tianyi Cui
2026-07-20 00:25:31 +08:00
676 changed files with 6946 additions and 2405 deletions
@@ -26,6 +26,7 @@ export class FeatureConfigurator {
* @param current - currently installed selection, when configuring.
* @param prefilledOptions - options already chosen by a tree picker.
* @param prefilledSecrets - non-interactive secret values supplied by creation.
* @param prefilledValues - non-interactive value inputs supplied by a headless spec.
* @returns normalized selection with captured values and secrets.
*/
async configure(
@@ -34,6 +35,7 @@ export class FeatureConfigurator {
current?: FeatureSelection,
prefilledOptions?: readonly string[],
prefilledSecrets: Readonly<Record<string, string>> = {},
prefilledValues: Readonly<Record<string, unknown>> = {},
): Promise<FeatureSelection> {
let options: readonly string[]
switch (feature.mode) {
@@ -69,6 +71,11 @@ export class FeatureConfigurator {
id: feature.id,
options,
}
const coercedPrefilled: Record<string, string> = {}
for (const [key, value] of Object.entries(prefilledValues)) {
if (typeof value !== 'string') throw new Error(`${feature.id}.${key} value must be a string`)
coercedPrefilled[key] = value
}
const values: Record<string, string> = {}
for (const input of feature.valueInputs(selected, profile)) {
const existing = current?.values?.[input.id]
@@ -81,7 +88,7 @@ export class FeatureConfigurator {
...existing === undefined ? {} : { initialValue: existing },
validate: value => value.trim().length === 0 ? 'A value is required' : undefined,
})
values[input.id] = requireAnswer(await question.resolve(this.port))
values[input.id] = requireAnswer(await question.resolve(this.port, coercedPrefilled[input.id]))
}
const base: FeatureSelection = Object.keys(values).length === 0
? selected