@event4u/agent-config 17.2.0 → 17.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.augment-plugin/marketplace.json +3 -3
- package/.augment-plugin/plugin.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/skills/install-agent-config/SKILL.md +9 -9
- package/CHANGELOG.md +174 -0
- package/dist/agent-src/skills/code-intelligence/SKILL.md +13 -12
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/scripts/check_memory.ts +1 -1
- package/dist/cli/commands/recordTriggerEval.js +1 -1
- package/dist/cli-delegate/{chunk-KR5ZIFPO.js → chunk-DHSSP7V3.js} +1 -1
- package/dist/cli-delegate/chunk-E7ACTJTJ.js +6792 -0
- package/dist/cli-delegate/{chunk-BZJ4Y3CI.js → chunk-MT2WOOCY.js} +1 -1
- package/dist/cli-delegate/{chunk-CMZEKSNN.js → chunk-ORJPBER2.js} +2 -2
- package/dist/cli-delegate/{chunk-VYZGJLCA.js → chunk-RKNT4LIK.js} +22 -1286
- package/dist/cli-delegate/cmd_conformance.js +20 -14
- package/dist/cli-delegate/cmd_doctor.js +3 -3
- package/dist/cli-delegate/cmd_doctor_neighbours.js +2 -2
- package/dist/cli-delegate/cmd_explain.js +1 -1
- package/dist/cli-delegate/cmd_export.js +2 -2
- package/dist/cli-delegate/cmd_prune.js +2 -2
- package/dist/cli-delegate/cmd_settings_migrate.js +2 -2
- package/dist/cli-delegate/cmd_settings_set.js +8 -4
- package/dist/cli-delegate/cmd_sync.js +2 -2
- package/dist/cli-delegate/cmd_uninstall.js +2 -2
- package/dist/cli-delegate/cmd_validate.js +2 -2
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +3 -3
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +1 -1
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +2 -2
- package/dist/discovery/trust-report.md +1 -1
- package/dist/discovery/workspaces.json +2 -2
- package/dist/hooks/code_graph_refresh.chunk.cjs +414 -0
- package/dist/hooks/code_graph_refresh.chunk.cjs.sha256 +1 -0
- package/dist/hooks/dispatch.js +21 -11
- package/dist/hooks/dispatch.sha256 +1 -1
- package/dist/hooks/egress_engine.chunk.cjs +1 -1
- package/dist/hooks/egress_engine.chunk.cjs.sha256 +1 -1
- package/dist/install/install.mjs +6974 -6037
- package/dist/mcp/mcp-cloudflare-catalogue.json +1 -0
- package/dist/mcp/registry-manifest.json +3 -2
- package/dist/mcp/server.json +13 -4
- package/dist/mcp/server.mjs +5561 -2463
- package/dist/scripts/_lib/egress_rules.js +8 -2
- package/dist/scripts/condense.js +9 -9
- package/dist/server/routes/discovery.js +1 -1
- package/dist/server/routes/install.js +1 -1
- package/dist/server/routes/ping.js +1 -1
- package/dist/server/routes/schema.js +4 -4
- package/dist/server/routes/settings.js +2 -6
- package/dist/server/routes/wizard.js +6 -6
- package/dist/server/schemas/settings.js +42 -42
- package/dist/shared/settingsSurface.js +1 -1
- package/dist/shared/userMd/schema.js +1 -1
- package/dist/shared/zodJsonSchema.js +47 -0
- package/dist/ui/assets/index-B0bcIgi0.js +77 -0
- package/dist/ui/index.html +1 -1
- package/package.json +3 -3
- package/src/agent-src/templates/scripts/check_memory.ts +1 -1
- package/src/config/ci-local-parity.yml +11 -0
- package/src/config/continuity-surface.json +9 -2
- package/src/config/gate-violation-baselines.json +3 -3
- package/src/config/gitignore-block.txt +6 -5
- package/src/config/hook-bundle-budget.json +16 -1
- package/src/config/pack-size-budget.json +12 -1
- package/src/config/packed-binary-manifest.json +9 -0
- package/src/scripts/_cli/cmd_settings_set.ts +3 -2
- package/src/scripts/_dispatch.bash +1 -1
- package/src/scripts/_lib/egress_rules.ts +8 -2
- package/src/scripts/_lib/listing_manifests.ts +85 -0
- package/src/scripts/_lib/neighbour_census.ts +1 -0
- package/src/scripts/_lib/release_settings_surface.ts +2 -6
- package/src/scripts/adoption_status.ts +231 -27
- package/src/scripts/build_mcp_registry_manifest.ts +23 -12
- package/src/scripts/check_dependency_floors.ts +7 -0
- package/src/scripts/check_release_manifest_content.ts +17 -2
- package/src/scripts/check_release_pr_shape.ts +5 -0
- package/src/scripts/code_graph/build.ts +80 -44
- package/src/scripts/code_graph/cli.ts +260 -16
- package/src/scripts/code_graph/conventions_default.ts +228 -0
- package/src/scripts/code_graph/extract.ts +5 -2
- package/src/scripts/code_graph/extract_more.ts +105 -1
- package/src/scripts/code_graph/loader.ts +10 -2
- package/src/scripts/code_graph/map.ts +174 -41
- package/src/scripts/code_graph/map_model.ts +53 -15
- package/src/scripts/code_graph/map_verify.ts +12 -0
- package/src/scripts/code_graph/map_viewer/viewer.css +6 -0
- package/src/scripts/code_graph/map_viewer/viewer.js +114 -13
- package/src/scripts/code_graph/passes.ts +173 -0
- package/src/scripts/code_graph/providers/angular.ts +55 -0
- package/src/scripts/code_graph/providers/aspnetcore.ts +182 -0
- package/src/scripts/code_graph/providers/catalog.ts +290 -0
- package/src/scripts/code_graph/providers/django.ts +163 -0
- package/src/scripts/code_graph/providers/express.ts +25 -0
- package/src/scripts/code_graph/providers/fastapi.ts +49 -0
- package/src/scripts/code_graph/providers/flask.ts +99 -0
- package/src/scripts/code_graph/providers/go_http.ts +121 -0
- package/src/scripts/code_graph/providers/index.ts +101 -0
- package/src/scripts/code_graph/{laravel_overlay.ts → providers/laravel.ts} +113 -7
- package/src/scripts/code_graph/providers/nestjs.ts +34 -0
- package/src/scripts/code_graph/providers/nextjs.ts +91 -0
- package/src/scripts/code_graph/providers/nuxt.ts +55 -0
- package/src/scripts/code_graph/providers/react-router.ts +58 -0
- package/src/scripts/code_graph/providers/shared/detect.ts +78 -0
- package/src/scripts/code_graph/providers/shared/extractors.ts +249 -0
- package/src/scripts/code_graph/providers/shared/js.ts +252 -0
- package/src/scripts/code_graph/providers/shared/kit.ts +210 -0
- package/src/scripts/code_graph/providers/shared/php.ts +64 -0
- package/src/scripts/code_graph/providers/shared/python.ts +223 -0
- package/src/scripts/code_graph/providers/spring.ts +138 -0
- package/src/scripts/code_graph/providers/sqlalchemy.ts +62 -0
- package/src/scripts/code_graph/providers/sveltekit.ts +59 -0
- package/src/scripts/code_graph/providers/symfony.ts +142 -0
- package/src/scripts/code_graph/providers/typeorm.ts +58 -0
- package/src/scripts/code_graph/providers/types.ts +56 -0
- package/src/scripts/code_graph/providers/vue-router.ts +21 -0
- package/src/scripts/code_graph/providers/wordpress.ts +128 -0
- package/src/scripts/code_graph/refresh_cli.ts +81 -0
- package/src/scripts/code_graph/refresh_lock.ts +193 -0
- package/src/scripts/code_graph/resolution_tiers.ts +19 -7
- package/src/scripts/code_graph/scip_reader.ts +2 -2
- package/src/scripts/code_graph/sqlite_store.ts +10 -4
- package/src/scripts/code_graph/types.ts +75 -41
- package/src/scripts/code_graph/validate.ts +6 -8
- package/src/scripts/condense.ts +9 -9
- package/src/scripts/generate_settings_reference.ts +2 -6
- package/src/scripts/hook_chunks.mjs +4 -0
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +24 -7
- package/src/scripts/hooks/code_graph_refresh_hook.ts +160 -0
- package/src/scripts/hooks/lazy_concern.ts +4 -0
- package/src/scripts/install-hooks.sh +54 -33
- package/src/scripts/install.ts +2 -6
- package/src/scripts/lint_hook_manifest.ts +2 -0
- package/src/scripts/lint_marketplace.ts +33 -0
- package/src/scripts/lint_mcp_registry_manifest.ts +36 -0
- package/src/scripts/mcp_server/consumer_tool_catalog.json +1 -0
- package/src/scripts/mcp_server/graph_tools.ts +5 -1
- package/src/scripts/release.ts +2 -5
- package/src/scripts/release_drill.ts +4 -1
- package/src/scripts/release_env.ts +17 -0
- package/src/scripts/release_mix_taxonomy.json +3 -0
- package/src/server/schemas/settings.ts +42 -42
- package/src/shared/settingsSurface.ts +1 -1
- package/src/shared/userMd/schema.ts +1 -1
- package/src/shared/zodJsonSchema.ts +41 -0
- package/src/vendor/grammars/README.md +6 -5
- package/src/vendor/grammars/tree-sitter-c_sharp.wasm +0 -0
- package/dist/cli-delegate/chunk-XIAPY44N.js +0 -4587
- package/dist/ui/assets/index-w70Ado09.js +0 -23
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
* - metadata.version must match package.json (single source of truth)
|
|
18
18
|
* - every version field in BOTH .augment-plugin/ manifests matches
|
|
19
19
|
* package.json too — see check_augment_manifests()
|
|
20
|
+
* - the Copilot plugin and Gemini extension match it in `version` and in the
|
|
21
|
+
* pinned `npx` argument — see check_listing_manifests()
|
|
20
22
|
* - the union of plugins[].skills[] must be EXACTLY the pointer skill
|
|
21
23
|
* (./.claude-plugin/skills/install-agent-config) — a repopulated
|
|
22
24
|
* content-skill list FAILS by design
|
|
@@ -29,6 +31,7 @@ import fs from "node:fs";
|
|
|
29
31
|
import path from "node:path";
|
|
30
32
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
31
33
|
|
|
34
|
+
import { LISTING_MANIFESTS, listingVersionFindings } from "./_lib/listing_manifests.js";
|
|
32
35
|
import { assertWatchlistResolves, DeadScopeError } from "./_lib/scan_scope.js";
|
|
33
36
|
|
|
34
37
|
const ROOT = ".";
|
|
@@ -149,6 +152,34 @@ export function check_augment_manifests(
|
|
|
149
152
|
}
|
|
150
153
|
}
|
|
151
154
|
|
|
155
|
+
/**
|
|
156
|
+
* The Copilot discovery plugin and the Gemini extension carry the package
|
|
157
|
+
* version AND pin it inside their `npx` arguments; a crawler installs from the
|
|
158
|
+
* default branch, so either copy drifting ships a stale server to every new
|
|
159
|
+
* install. Same sync rule as the Augment twins, plus the pin.
|
|
160
|
+
*/
|
|
161
|
+
export function check_listing_manifests(
|
|
162
|
+
pkgVersion: string,
|
|
163
|
+
errors: string[],
|
|
164
|
+
base: string = ROOT,
|
|
165
|
+
): void {
|
|
166
|
+
for (const rel of LISTING_MANIFESTS) {
|
|
167
|
+
const file = path.join(base, rel);
|
|
168
|
+
if (!_exists(file)) {
|
|
169
|
+
errors.push(`${file} not found (a listing manifest the release version-syncs)`);
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
let data: unknown;
|
|
173
|
+
try {
|
|
174
|
+
data = JSON.parse(fs.readFileSync(file, "utf-8"));
|
|
175
|
+
} catch (e) {
|
|
176
|
+
errors.push(`${file} is not valid JSON: ${e instanceof Error ? e.message : String(e)}`);
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
errors.push(...listingVersionFindings(file, data, pkgVersion));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
152
183
|
/** Resolve a key path, expanding `*` over array indices. Returns [label, value]. */
|
|
153
184
|
function _resolveVersionField(
|
|
154
185
|
data: JsonValue,
|
|
@@ -185,6 +216,7 @@ export function main(): number {
|
|
|
185
216
|
".claude-plugin/marketplace.json",
|
|
186
217
|
".augment-plugin/plugin.json",
|
|
187
218
|
".augment-plugin/marketplace.json",
|
|
219
|
+
...LISTING_MANIFESTS,
|
|
188
220
|
"package.json",
|
|
189
221
|
`${POINTER_SKILL_ENTRY.replace(/^\.\//, "")}/SKILL.md`,
|
|
190
222
|
],
|
|
@@ -248,6 +280,7 @@ export function main(): number {
|
|
|
248
280
|
}
|
|
249
281
|
if (typeof pkgVersion === "string") {
|
|
250
282
|
check_augment_manifests(pkgVersion, errors);
|
|
283
|
+
check_listing_manifests(pkgVersion, errors);
|
|
251
284
|
}
|
|
252
285
|
}
|
|
253
286
|
} else {
|
|
@@ -27,6 +27,7 @@ import * as path from 'node:path';
|
|
|
27
27
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
28
28
|
|
|
29
29
|
import { assertWatchlistResolves, DeadScopeError } from './_lib/scan_scope.js';
|
|
30
|
+
import { REGISTRY_DESCRIPTION_MAX, SERVER_SCHEMA_URL } from './build_mcp_registry_manifest.js';
|
|
30
31
|
|
|
31
32
|
const _HERE = path.resolve(fileURLToPath(import.meta.url));
|
|
32
33
|
// ROOT = Path(__file__).resolve().parents[2]
|
|
@@ -286,6 +287,37 @@ function _validateSchema(data: Json, schema: JsonObject): SchemaError | null {
|
|
|
286
287
|
return errors.length ? errors[0]! : null;
|
|
287
288
|
}
|
|
288
289
|
|
|
290
|
+
/**
|
|
291
|
+
* What the live registry rejects or mis-installs, checked before a release
|
|
292
|
+
* publishes it: the schema pin, the 100-character description cap, and the
|
|
293
|
+
* `mcp-server` argument without which a client starts the bare CLI.
|
|
294
|
+
*/
|
|
295
|
+
export function checkRegistryPayload(server: JsonObject): string | null {
|
|
296
|
+
if (server['$schema'] !== SERVER_SCHEMA_URL) {
|
|
297
|
+
return `$schema must be ${SERVER_SCHEMA_URL} (got ${String(server['$schema'])})`;
|
|
298
|
+
}
|
|
299
|
+
const description = server['description'];
|
|
300
|
+
if (typeof description !== 'string' || description.length === 0) {
|
|
301
|
+
return 'description is missing — set package.json agentConfig.registryDescription';
|
|
302
|
+
}
|
|
303
|
+
if (description.length > REGISTRY_DESCRIPTION_MAX) {
|
|
304
|
+
return `description is ${description.length} characters; the registry accepts at most ${REGISTRY_DESCRIPTION_MAX}`;
|
|
305
|
+
}
|
|
306
|
+
const packages = server['packages'];
|
|
307
|
+
const first = Array.isArray(packages) ? (packages[0] as JsonObject | undefined) : undefined;
|
|
308
|
+
const args = first?.['packageArguments'];
|
|
309
|
+
const startsServer =
|
|
310
|
+
Array.isArray(args) &&
|
|
311
|
+
args.some((a) => {
|
|
312
|
+
const arg = a as JsonObject;
|
|
313
|
+
return arg['type'] === 'positional' && arg['value'] === 'mcp-server';
|
|
314
|
+
});
|
|
315
|
+
if (!startsServer) {
|
|
316
|
+
return 'the npm package entry has no positional `mcp-server` argument, so a client would start the CLI';
|
|
317
|
+
}
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
|
|
289
321
|
function main(argv: readonly string[]): number {
|
|
290
322
|
let args: Args;
|
|
291
323
|
try {
|
|
@@ -369,6 +401,10 @@ function main(argv: readonly string[]): number {
|
|
|
369
401
|
`(${String(pkg_for_gate['mcpName'])})`,
|
|
370
402
|
);
|
|
371
403
|
}
|
|
404
|
+
const registryProblem = checkRegistryPayload(server_payload);
|
|
405
|
+
if (registryProblem !== null) {
|
|
406
|
+
return _fail(`server.json: ${registryProblem}`);
|
|
407
|
+
}
|
|
372
408
|
|
|
373
409
|
if (!args.quiet) {
|
|
374
410
|
const registries = (manifest as JsonObject)['registries'];
|
|
@@ -62,7 +62,7 @@ import {
|
|
|
62
62
|
testsFor,
|
|
63
63
|
untested,
|
|
64
64
|
} from '../code_graph/verbs.js';
|
|
65
|
-
import { areaReport, readMap } from '../code_graph/map.js';
|
|
65
|
+
import { areaReport, graphGeneration, readMap } from '../code_graph/map.js';
|
|
66
66
|
import type { BuiltinTool } from './tools.js';
|
|
67
67
|
|
|
68
68
|
/** The `no graph here` answer, in one place so all five agree on its shape. */
|
|
@@ -134,6 +134,7 @@ const RELATIONS = [
|
|
|
134
134
|
'migrates',
|
|
135
135
|
'persists',
|
|
136
136
|
'relates',
|
|
137
|
+
'injects',
|
|
137
138
|
'documents',
|
|
138
139
|
] as const;
|
|
139
140
|
|
|
@@ -399,11 +400,14 @@ export const GRAPH_TOOLS: Record<string, BuiltinTool> = {
|
|
|
399
400
|
map: 'present',
|
|
400
401
|
drawn_at_commit: map.meta.commit,
|
|
401
402
|
graph_state_when_drawn: map.meta.state,
|
|
403
|
+
// Same generation → the map shows exactly the graph the queries read.
|
|
404
|
+
map_matches_graph: map.meta.graph_generation !== undefined && map.meta.graph_generation === graphGeneration(path.join(root, NATIVE_CACHE_REL)),
|
|
402
405
|
files: m.files.length,
|
|
403
406
|
areas: m.areas.length,
|
|
404
407
|
trusted_links: m.analyses.trustedEdges,
|
|
405
408
|
guess_share: m.analyses.guessShare,
|
|
406
409
|
request_paths: m.analyses.requestPathsTotal,
|
|
410
|
+
providers: (m.providers ?? []).map((p) => `${p.id} (${p.status})`),
|
|
407
411
|
largest_areas: m.areas.slice(0, 5).map((a) => `${a.id} ${a.name} (${a.files.length})`),
|
|
408
412
|
map_md: 'agents/map/MAP.md',
|
|
409
413
|
index_html: 'agents/map/index.html',
|
package/src/scripts/release.ts
CHANGED
|
@@ -152,8 +152,6 @@ const _HERE = fileURLToPath(import.meta.url);
|
|
|
152
152
|
|
|
153
153
|
import {
|
|
154
154
|
ArgparseExit,
|
|
155
|
-
AUGMENT_MARKETPLACE_JSON,
|
|
156
|
-
AUGMENT_PLUGIN_JSON,
|
|
157
155
|
CHANGELOG,
|
|
158
156
|
_set_changelog_reader,
|
|
159
157
|
read_changelog_text,
|
|
@@ -169,7 +167,7 @@ import {
|
|
|
169
167
|
REPO_ROOT,
|
|
170
168
|
REPO_SLUG,
|
|
171
169
|
SystemExitError,
|
|
172
|
-
|
|
170
|
+
set_plugin_manifest_versions,
|
|
173
171
|
set_marketplace_version,
|
|
174
172
|
set_template_pin,
|
|
175
173
|
_rstrip,
|
|
@@ -939,8 +937,7 @@ function execute(
|
|
|
939
937
|
set_package_version(PACKAGE_JSON, plan.target, plan.commits);
|
|
940
938
|
set_lockfile_version(PACKAGE_LOCK_JSON, plan.target);
|
|
941
939
|
set_marketplace_version(MARKETPLACE_JSON, plan.target);
|
|
942
|
-
|
|
943
|
-
set_augment_manifest_version(AUGMENT_MARKETPLACE_JSON, plan.target);
|
|
940
|
+
set_plugin_manifest_versions(plan.target);
|
|
944
941
|
set_template_pin(PROJECT_TEMPLATE, plan.target);
|
|
945
942
|
writeReleasedSurface(plan.target);
|
|
946
943
|
prepend_changelog(CHANGELOG, plan.changelog_entry);
|
|
@@ -44,6 +44,7 @@ import { releaseHoldPreflight } from './_lib/release_holds.js';
|
|
|
44
44
|
import { SETTINGS_SURFACE_FIXTURE } from './_lib/release_settings_surface.js';
|
|
45
45
|
import { die } from './release_publication.js';
|
|
46
46
|
import { DERIVED_MARKER } from './_lib/release_highlights.js';
|
|
47
|
+
import { listingManifestPaths } from './_lib/listing_manifests.js';
|
|
47
48
|
import {
|
|
48
49
|
AUGMENT_MARKETPLACE_JSON,
|
|
49
50
|
AUGMENT_PLUGIN_JSON,
|
|
@@ -52,13 +53,14 @@ import {
|
|
|
52
53
|
PACKAGE_JSON,
|
|
53
54
|
PACKAGE_LOCK_JSON,
|
|
54
55
|
PROJECT_TEMPLATE,
|
|
56
|
+
REPO_ROOT as ENV_REPO_ROOT,
|
|
55
57
|
} from './release_env.js';
|
|
56
58
|
|
|
57
59
|
/**
|
|
58
60
|
* The files step 2 mutates on disk, diverted into memory for every scenario.
|
|
59
61
|
*
|
|
60
62
|
* The FakeWorld intercepts COMMANDS, not `fs` writes, and step 2's bump is
|
|
61
|
-
*
|
|
63
|
+
* ten direct writes. Every scenario before 2026-09-03 passed `--resume` with
|
|
62
64
|
* `package.json` already at the target, so step 2 short-circuited and nothing
|
|
63
65
|
* was ever written — the drill looked side-effect-free because no scenario had
|
|
64
66
|
* reached the writing arm. The first `resume: false` scenario appended twelve
|
|
@@ -83,6 +85,7 @@ const _MUTATED_BY_STEP_2: readonly string[] = [
|
|
|
83
85
|
MARKETPLACE_JSON,
|
|
84
86
|
AUGMENT_PLUGIN_JSON,
|
|
85
87
|
AUGMENT_MARKETPLACE_JSON,
|
|
88
|
+
...listingManifestPaths(ENV_REPO_ROOT),
|
|
86
89
|
PROJECT_TEMPLATE,
|
|
87
90
|
SETTINGS_SURFACE_FIXTURE,
|
|
88
91
|
];
|
|
@@ -24,6 +24,8 @@ import * as fs from 'node:fs';
|
|
|
24
24
|
import * as path from 'node:path';
|
|
25
25
|
import { fileURLToPath } from 'node:url';
|
|
26
26
|
|
|
27
|
+
import { listingManifestPaths, setListingManifestVersion } from './_lib/listing_manifests.js';
|
|
28
|
+
|
|
27
29
|
const _HERE = fileURLToPath(import.meta.url);
|
|
28
30
|
|
|
29
31
|
// ---------------------------------------------------------------------------
|
|
@@ -293,6 +295,20 @@ function set_augment_manifest_version(p: string, version: string): void {
|
|
|
293
295
|
fs.writeFileSync(p, jsonDumpsIndent(data, 2) + '\n', 'utf-8');
|
|
294
296
|
}
|
|
295
297
|
|
|
298
|
+
/**
|
|
299
|
+
* Every plugin and extension manifest the release keeps at the package
|
|
300
|
+
* version: the two `.augment-plugin/` twins and the two listing manifests that
|
|
301
|
+
* also pin the version inside their `npx` arguments. One entry point so
|
|
302
|
+
* `release.ts`, which sits past the source-size cap, spends one line on all four.
|
|
303
|
+
*/
|
|
304
|
+
function set_plugin_manifest_versions(version: string, root: string = REPO_ROOT): void {
|
|
305
|
+
set_augment_manifest_version(path.join(root, '.augment-plugin', 'plugin.json'), version);
|
|
306
|
+
set_augment_manifest_version(path.join(root, '.augment-plugin', 'marketplace.json'), version);
|
|
307
|
+
for (const p of listingManifestPaths(root)) {
|
|
308
|
+
setListingManifestVersion(p, version, (v) => jsonDumpsIndent(v, 2));
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
296
312
|
/** Update `metadata.version`; preserve 2-space indentation + UTF-8. */
|
|
297
313
|
function set_marketplace_version(p: string, version: string): void {
|
|
298
314
|
const data = JSON.parse(fs.readFileSync(p, 'utf-8')) as Record<string, unknown>;
|
|
@@ -374,6 +390,7 @@ export {
|
|
|
374
390
|
commaGroup,
|
|
375
391
|
jsonDumpsIndent,
|
|
376
392
|
set_augment_manifest_version,
|
|
393
|
+
set_plugin_manifest_versions,
|
|
377
394
|
set_marketplace_version,
|
|
378
395
|
set_template_pin,
|
|
379
396
|
pyLen,
|
|
@@ -117,6 +117,9 @@
|
|
|
117
117
|
{ "prefix": "LICENSE", "category": "consumer" },
|
|
118
118
|
{ "prefix": "NOTICE", "category": "consumer" },
|
|
119
119
|
{ "prefix": "llms.txt", "category": "consumer" },
|
|
120
|
+
{ "prefix": "gemini-extension.json", "category": "consumer" },
|
|
121
|
+
{ "prefix": "gemini-extension-context.md", "category": "consumer" },
|
|
122
|
+
{ "prefix": "assets/", "category": "consumer" },
|
|
120
123
|
|
|
121
124
|
{ "prefix": "AGENTS.md", "category": "governance" },
|
|
122
125
|
{ "prefix": "CLAUDE.md", "category": "governance" },
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* recurses one level into nested objects; deeper trees fail render-time.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import
|
|
14
|
+
import * as z from 'zod';
|
|
15
15
|
|
|
16
16
|
const ruleLoadingTier = z.enum(['minimal', 'balanced', 'full', 'custom']);
|
|
17
17
|
const disciplineProfile = z.enum(['auto', 'off', 'essential', 'full']);
|
|
@@ -42,7 +42,7 @@ export const settingsSchema = z.object({
|
|
|
42
42
|
id: profileId.default('developer').describe(
|
|
43
43
|
'Which experience you run — the audience identity that selects your default skill / command surface, README entry-path, and persona pre-selection (ADR-010, docs/contracts/profile-system.md). Six seed profiles: developer · content_creator · founder · agency · finance · ops. This is the first wizard question. In 6.0.0-A it records the choice only; pack-scoped surfacing (projection-time filtering, ADR-040) activates in 6.0.0-B behind a staged, opt-in rollout. Switch later with `agent-config use --profile=<id>`.',
|
|
44
44
|
),
|
|
45
|
-
}).
|
|
45
|
+
}).prefault({ id: 'developer' }),
|
|
46
46
|
projection: z.object({
|
|
47
47
|
mode: projectionMode.default('legacy-all').describe(
|
|
48
48
|
'Whether the per-tool projector writes EVERY artefact into the host-tool trees (.claude/ .cursor/ .windsurf/) or only the active profile + packs\' artefacts (ADR-040, docs/contracts/capability-packs.md). legacy-all = (default, non-breaking) project the full surface exactly as 5.x did. scoped = project only the active profile\'s packs unioned with the runtime.active_packs overlay, expanded over the requires graph — opt in with `agent-config use --profile=<id>`. A failed scoped projection restores the full tree.',
|
|
@@ -50,7 +50,7 @@ export const settingsSchema = z.object({
|
|
|
50
50
|
rule_packs: z.union([z.literal('auto'), z.array(z.string())]).default([]).describe(
|
|
51
51
|
'Scoping axis for the RULE layer beyond the derived workspace set, per pack ids (src/config/discovery/packs.yml). When set, a non-kernel rule also needs a packs frontmatter intersection to ship — e.g. deselecting frontend-design drops ui-audit-gate + design-fidelity. Opt-in, and an empty list is inactive; the workspace axis beside it is derived rather than configured (ADR-293 step 4.6). The literal "auto" derives the id list from the active-pack set (the same set the skill/command prune uses), so a domain safety floor stops shipping into installs that do not have the pack it guards; an explicit list stays supported and wins over the derivation.',
|
|
52
52
|
),
|
|
53
|
-
}).
|
|
53
|
+
}).prefault({ mode: 'legacy-all' }),
|
|
54
54
|
rule_loading_tier: ruleLoadingTier.default('balanced').describe(
|
|
55
55
|
'Master switch for which rule tiers load and how cautiously the agent spends tokens. minimal = only the 9 kernel rules (cheapest, fewest guardrails). balanced = kernel + tier-1 (recommended default). full = kernel + tier-1 + tier-2 (most guardrails, highest token cost). custom = roll your own in agents/overrides/. LEGACY: superseded by discipline_profile — when that key is set it wins (mapping: minimal→off, balanced→essential, full→full).',
|
|
56
56
|
),
|
|
@@ -78,7 +78,7 @@ export const settingsSchema = z.object({
|
|
|
78
78
|
strong: z.number().min(0).nullable().default(null).describe(
|
|
79
79
|
'USD ceiling for the strong model tier. null = no separate tier cap. The never-block-to-save-money relation this used to describe went with the archived budget-routing layer (docs/contracts/budget-routing.md); nothing routes between tiers today.',
|
|
80
80
|
),
|
|
81
|
-
}).
|
|
81
|
+
}).prefault({ cheap: null, medium: null, strong: null }),
|
|
82
82
|
}),
|
|
83
83
|
enforcement: enforcementMode.default('advisory').describe(
|
|
84
84
|
'What happens when a budget hits 100%. advisory = show a banner, keep working (default — never blocks an active task). hard-stop = refuse further model calls until the budget resets or you raise the ceiling.',
|
|
@@ -88,7 +88,7 @@ export const settingsSchema = z.object({
|
|
|
88
88
|
auto_switch: modelAutoSwitch.default('suggest').describe(
|
|
89
89
|
'Per-skill model auto-switch (ADR-035). Skills declare a vendor-neutral model_tier (lite/medium/high); the generator maps it to a native Claude model (high→opus, medium→sonnet, lite→haiku). suggest (default) = never emit a native Claude model: key; the model-recommendation rule names the tier as a one-question suggestion on every surface — your explicit /model choice is never silently overridden. auto = render a native Claude model: into lite/medium/high-tier skills so Claude Code switches automatically for that turn (reverts next prompt), and suggest on surfaces without a native override. off = inert, no native key and no suggestion.',
|
|
90
90
|
),
|
|
91
|
-
}).
|
|
91
|
+
}).prefault({ auto_switch: 'suggest' }),
|
|
92
92
|
personal: z.object({
|
|
93
93
|
ide: z.string().default('').describe(
|
|
94
94
|
'CLI binary your IDE registers (code, code-insiders, phpstorm, cursor, windsurf, idea, subl, …). Used by the file-editor skill to open edited files. Leave empty to disable IDE integration.',
|
|
@@ -133,7 +133,7 @@ export const settingsSchema = z.object({
|
|
|
133
133
|
update_strategy: gitUpdateStrategy.default('merge').describe(
|
|
134
134
|
'How a feature branch is brought up to date with its base. merge (default) = merge the base into the branch, as before this key existed. rebase = rebase the branch onto origin/<base> and publish with --force-with-lease, never a merge of the base into the branch. Rebase rewrites history, so the agent still asks for it unless the git-history-discipline rule already authorises the rewrite (the user asked this turn, an unrevoked standing instruction, or a pull --rebase the user started); this key decides which operation is proposed, never whether one is authorised.',
|
|
135
135
|
),
|
|
136
|
-
}).
|
|
136
|
+
}).prefault({}),
|
|
137
137
|
github: z.object({
|
|
138
138
|
pr_reply_method: replyMethod.default('create_review_comment').describe(
|
|
139
139
|
'How the agent replies to PR review comments. create_review_comment = post a new review comment (works on every GitHub plan). replies_endpoint = thread the reply under the original comment (needs the newer REST endpoint). auto = detect at runtime, prefer threaded replies when available.',
|
|
@@ -175,10 +175,10 @@ export const settingsSchema = z.object({
|
|
|
175
175
|
max_mcp_output_tokens: z.number().int().positive().nullable().default(null).describe(
|
|
176
176
|
'Token cap on a single MCP tool result the host places into a model request. null (default) = nothing written, host default 25000 applies. Same size-not-count caveat: it does not govern MCP connections, timeouts, or whether a tool runs.',
|
|
177
177
|
),
|
|
178
|
-
}).
|
|
178
|
+
}).prefault({}).describe(
|
|
179
179
|
'Request-size caps this package may write into the host env block. Both null by default. No traffic or auto-updater variable is expressible here, by construction — see the block comment.',
|
|
180
180
|
),
|
|
181
|
-
}).
|
|
181
|
+
}).prefault({}).describe(
|
|
182
182
|
'What this package may write into the host environment. ABSENT resolves to the all-null shape, which is the same thing as off — a settings file predating this section must not fail to parse, and "no section" and "both caps null" both mean write nothing.',
|
|
183
183
|
),
|
|
184
184
|
augment: z.object({
|
|
@@ -235,7 +235,7 @@ export const settingsSchema = z.object({
|
|
|
235
235
|
max_cost_per_rolling_7d_usd: z.number().min(0).nullable().default(null).describe(
|
|
236
236
|
'Rolling 7-day USD ceiling for class-1 gate execution, summed from the append-only receipt ledger at agents/runtime/state/gate-budget-ledger.jsonl. A run whose estimate would cross it renders instead of running. null (default) = no rolling ceiling, per ADR-279. A per-run cap alone bounds one mistake, not a week of them, which is why option (a) of b-gate-budget-preauth carries two numbers — but each cap now bounds on its own, so setting one and leaving the other null is supported.',
|
|
237
237
|
),
|
|
238
|
-
}).
|
|
238
|
+
}).prefault({ max_cost_per_run_usd: null, max_cost_per_rolling_7d_usd: null }),
|
|
239
239
|
}),
|
|
240
240
|
planning: z.object({
|
|
241
241
|
closure_pass: z.boolean().default(true).describe(
|
|
@@ -248,13 +248,13 @@ export const settingsSchema = z.object({
|
|
|
248
248
|
'Gate R2 — completion review at 100% roadmap completion / pre-PR. true (default) = a findings-before-fixes review by a fresh reviewer context must exist for the current diff hash (or an exact honest-null / skip declaration) before fix commits and PR creation, enforced by check_completion_review at pre-push + CI (CI authoritative; a crashed validator warns and allows). false = escape hatch, the validator skips.',
|
|
249
249
|
),
|
|
250
250
|
})
|
|
251
|
-
// `.
|
|
251
|
+
// `.prefault({})` is load-bearing, not cosmetic: without it the SECTION is
|
|
252
252
|
// required, so any settings payload that omits `planning` fails with
|
|
253
253
|
// `ZodError: planning Required` — which contradicts this gate family's own
|
|
254
254
|
// contract ("missing key = true" for all three) and reds every server
|
|
255
255
|
// test whose fixture predates the section. With the default, an absent
|
|
256
256
|
// section materialises as the three `true` leaves the contract promises.
|
|
257
|
-
.
|
|
257
|
+
.prefault({}),
|
|
258
258
|
execution: z.object({
|
|
259
259
|
fix_loop_max: z.number().int().min(1).default(10).describe(
|
|
260
260
|
'Consecutive failed fix attempts against one validation target before the escalation ladder reaches its terminal rung. Reaching the bound triggers a strategy change, never a question. Overridable globally, per project and per prompt.',
|
|
@@ -262,7 +262,7 @@ export const settingsSchema = z.object({
|
|
|
262
262
|
escalation: z.array(z.string()).default(['independent', 'council', 'team', 'owner_owned_check']).describe(
|
|
263
263
|
'The escalation rungs, in order, walked when the fix-loop bound is reached: independent (another session or a provider-diverse reviewer), council, team, then owner_owned_check — which asks whether the residue is owner-owned, not whether to ask the owner now.',
|
|
264
264
|
),
|
|
265
|
-
}).
|
|
265
|
+
}).prefault({}),
|
|
266
266
|
quality: z.object({
|
|
267
267
|
local_auto_run: z.boolean().default(false).describe(
|
|
268
268
|
'Run quality tools (linters, type-checks, formatters) and the local test suite autonomously after edits, IN CHAT. Off by default — in a chat turn a human is present and remote CI is the authoritative gate, so a local full-pipeline run duplicates it at wall-clock cost. The agent only runs a quality tool on an explicit ask, a concrete CI failure, or the new-gate carve-out. A mission is governed by local_auto_run_in_mission instead.',
|
|
@@ -289,10 +289,10 @@ export const settingsSchema = z.object({
|
|
|
289
289
|
'Length distance below which a value may be reconciled, in absolute CSS pixels. Ships null, same reasoning as color. GitHub Primer\'s ±1px spacing widening is recorded as an externally observed candidate in src/scripts/_lib/design_tolerance.ts and is deliberately not the shipped value; max(1px, 2%) was rejected for growing more permissive at large dimensions with no evidence that this is wanted.',
|
|
290
290
|
),
|
|
291
291
|
})
|
|
292
|
-
.
|
|
292
|
+
.prefault({ color: null, length: null }),
|
|
293
293
|
})
|
|
294
|
-
.
|
|
295
|
-
}).
|
|
294
|
+
.prefault({ enabled: false, tolerance: { color: null, length: null } }),
|
|
295
|
+
}).prefault({
|
|
296
296
|
fidelity_mode: 'strict',
|
|
297
297
|
approximation: { enabled: false, tolerance: { color: null, length: null } },
|
|
298
298
|
}),
|
|
@@ -300,7 +300,7 @@ export const settingsSchema = z.object({
|
|
|
300
300
|
consumer_index_paths: z.array(z.string()).default([]).describe(
|
|
301
301
|
"Extra project-relative paths where THIS project keeps a code-graph index another tool wrote. The built-in list is deliberately vendor-neutral (graph.json, code-graph.json, .code-graph/graph.json) and names no tool, so a tool that writes its index elsewhere is named here rather than waited for. A graph found this way LOADS and answers query and explain with every edge tagged read-from-elsewhere; the gate verbs (impact, untested, dead) refuse a graph made only of such edges and say so, because an empty answer from a gate must not read as 'nothing found' when it means 'nothing trusted'. Absolute paths and paths escaping the project root are ignored.",
|
|
302
302
|
),
|
|
303
|
-
}).
|
|
303
|
+
}).prefault({}),
|
|
304
304
|
screenshots: z.object({
|
|
305
305
|
identity_allowlist: z.array(z.string()).default([]).describe(
|
|
306
306
|
"Consumed by the doc-screenshot-hygiene rule and screenshot-hygiene skill. Public identity tokens SAFE to show unredacted in a documentation screenshot — the maintainer's own public handles plus well-known fake-data tokens. Not a general fake-data dictionary and not identity-resolution: everything not listed is treated as sensitive by default, and a public handle co-located with a real name does not whitelist the real name. Default [] = nothing auto-allowed.",
|
|
@@ -311,22 +311,22 @@ export const settingsSchema = z.object({
|
|
|
311
311
|
data_bearing_gate: z.enum(['on', 'off']).default('on').describe(
|
|
312
312
|
'Consumed by the doc-screenshot-hygiene rule. on (default) = a data-bearing screenshot embed is gated behind this-turn human confirmation; uncertain/unresolved regions redact-or-refuse, never ship-and-hope; illustrative/no-data screenshots may embed with a stated justification. off = no data-bearing gate (the anonymization taxonomy still applies).',
|
|
313
313
|
),
|
|
314
|
-
}).
|
|
314
|
+
}).prefault({ identity_allowlist: [], forbid_terminal_capture: true, data_bearing_gate: 'on' }),
|
|
315
315
|
verbosity: z.object({
|
|
316
316
|
offer_council_in_delivery: z.boolean().default(false).describe(
|
|
317
317
|
'Offer "run AI Council on this?" inside delivery commands (/feature-plan, /review-changes, /roadmap-create). Council commands themselves are unaffected.',
|
|
318
318
|
),
|
|
319
|
-
}).
|
|
319
|
+
}).prefault({ offer_council_in_delivery: false }),
|
|
320
320
|
code_style: z.object({
|
|
321
321
|
docblocks: z.enum(['minimal', 'full']).default('minimal').describe(
|
|
322
322
|
'Consumed by the code-comment-discipline rule. minimal (default) = no signature-mirroring docblocks; docblocks only for machine-relevant precision (generics, array shapes) or genuine why-context. full = the exported public surface of a library package may carry one-line summary docblocks; the redundancy ban still holds.',
|
|
323
323
|
),
|
|
324
|
-
}).
|
|
324
|
+
}).prefault({ docblocks: 'minimal' }),
|
|
325
325
|
reasoning: z.object({
|
|
326
326
|
enabled: z.boolean().default(true).describe(
|
|
327
327
|
'Master switch for the Reasoning Discipline Protocol (RDP). false = the whole layer is inert (zero overhead).',
|
|
328
328
|
),
|
|
329
|
-
}).
|
|
329
|
+
}).prefault({}),
|
|
330
330
|
subagents: z.object({
|
|
331
331
|
quota_arbitrage: z.boolean().default(true).describe(
|
|
332
332
|
'Prefer a separate quota-pool model for delegable sub-tasks where the host manifest reports one. Optional bonus only — identical behaviour (minus the quota win) where unsupported. Never load-bearing.',
|
|
@@ -335,7 +335,7 @@ export const settingsSchema = z.object({
|
|
|
335
335
|
lite: z.string().default('').describe('Model alias for lite-tier sub-tasks. Empty = the tier runtime default.'),
|
|
336
336
|
medium: z.string().default('').describe('Model alias for medium-tier sub-tasks. Empty = the tier runtime default.'),
|
|
337
337
|
high: z.string().default('').describe('Model alias for high-tier sub-tasks. Empty = the tier runtime default.'),
|
|
338
|
-
}).
|
|
338
|
+
}).prefault({}).describe(
|
|
339
339
|
'Per-tier model map for downshift routing. Each empty value uses the tier runtime default (no vendor model baked in).',
|
|
340
340
|
),
|
|
341
341
|
implementer_model: z.string().default('').describe(
|
|
@@ -362,7 +362,7 @@ export const settingsSchema = z.object({
|
|
|
362
362
|
cleanup: z.enum(['off', 'notify', 'auto']).default('notify').describe(
|
|
363
363
|
'What the agent may do about a worktree whose work is provably on the trunk (merged by merge commit, rebase or squash), that is clean, holds no ignored file a rebuild would not restore, and has no live session. notify (default, and what an absent key resolves to) says once a day how many exist and removes nothing; auto removes them right after /pr:merge and once a day on the first session start, without force, keeping local branches; off says nothing. The daily pass reads merged pull requests through your gh login (branch name and head commit only).',
|
|
364
364
|
),
|
|
365
|
-
}).
|
|
365
|
+
}).prefault({ cleanup: 'notify' }),
|
|
366
366
|
ai_team: z.object({
|
|
367
367
|
model: z.string().default('auto').describe(
|
|
368
368
|
"Model handed to the codex CLI. 'auto' (default) = pass no --model flag so the CLI's own default applies — tracks the subscription's current strongest model instead of pinning a stale ID. Any other value passes through verbatim as `--model <value>`.",
|
|
@@ -380,8 +380,8 @@ export const settingsSchema = z.object({
|
|
|
380
380
|
max_consecutive_blocks: z.number().int().min(1).default(3).describe(
|
|
381
381
|
'Circuit-breaker bound: after this many CONSECUTIVE BLOCK verdicts in one session, a visible notice is injected exactly once and the managed layer stops re-blocking — the user decides, never an infinite Claude↔Codex loop. An ALLOW verdict resets the counter. Positive integer.',
|
|
382
382
|
),
|
|
383
|
-
}).
|
|
384
|
-
}).
|
|
383
|
+
}).prefault({ managed: false, max_consecutive_blocks: 3 }),
|
|
384
|
+
}).prefault({ model: 'auto', allow_delegate: false, max_calls_per_day: 50, review_gate: { managed: false, max_consecutive_blocks: 3 } }),
|
|
385
385
|
emergency: z.object({
|
|
386
386
|
orchestration_halt: z.boolean().default(false).describe(
|
|
387
387
|
'The one audited incident switch over the always-on orchestration stack (subagents, council, team). NOT an activation gate: false (default) = the stack runs normally. true = halted; arming requires no ceremony. Disarming (returning to false) requires orchestration_halt_justification to be a non-empty string. Both transitions emit one telemetry line.',
|
|
@@ -389,7 +389,7 @@ export const settingsSchema = z.object({
|
|
|
389
389
|
orchestration_halt_justification: z.string().default('').describe(
|
|
390
390
|
'Required non-empty before orchestration_halt may return to false. Ignored while arming the halt.',
|
|
391
391
|
),
|
|
392
|
-
}).
|
|
392
|
+
}).prefault({ orchestration_halt: false, orchestration_halt_justification: '' }),
|
|
393
393
|
onboarding: z.object({
|
|
394
394
|
onboarded: z.boolean().default(false).describe(
|
|
395
395
|
'Set to true once the developer has completed `agent-config setup`. The onboarding-gate rule blocks the first turn of every chat until this is true. Toggle back to false to re-trigger the wizard.',
|
|
@@ -425,7 +425,7 @@ export const settingsSchema = z.object({
|
|
|
425
425
|
enabled: z.boolean().default(true).describe(
|
|
426
426
|
'Automatic retro after merged work (ADR-292, docs/contracts/retro-v1.md). true (default, owner directive 2026-10-12) = a merged PR and the first session of a new local day enqueue finished work; a deterministic triage picks what is worth one learning, and nothing behavior-changing is applied without a person. The one network read is the daily probe asking GitHub, through your own gh login, whether a pushed PR merged (repository and PR number only, three-second budget). false = no automatic path runs — no merge enqueue, no forge-merge marker, no daily probe and no network read; an explicit /retro still runs on request. Class C: an agent cannot set it; it cascades from the user-global file.',
|
|
427
427
|
),
|
|
428
|
-
}).
|
|
428
|
+
}).prefault({}),
|
|
429
429
|
memory: z.object({
|
|
430
430
|
redact_patterns: z.array(z.string()).default([]).describe(
|
|
431
431
|
'Regex patterns (one per line) that scrub matches from chat-history transcripts and memory before they hit disk. Use for secrets, customer names, internal URLs. Patterns are anchored and case-insensitive.',
|
|
@@ -445,15 +445,15 @@ export const settingsSchema = z.object({
|
|
|
445
445
|
allowed_tiers: z.array(z.string()).default(['public']).describe(
|
|
446
446
|
'Origin tiers auto-eligible to cross a project boundary. proprietary is manual-only regardless (the gate hard-codes it), so an in-house schema never auto-shares.',
|
|
447
447
|
),
|
|
448
|
-
}).
|
|
449
|
-
}).
|
|
448
|
+
}).prefault({}),
|
|
449
|
+
}).prefault({}),
|
|
450
450
|
egress: z.object({
|
|
451
451
|
placeholders: z.object({
|
|
452
452
|
mode: z.enum(['off', 'observe', 'protect', 'strict']).default('off').describe(
|
|
453
453
|
'Dispatcher egress stage (docs/contracts/egress-placeholders-v1.md). off (default) = nothing. observe = detect and count listed values in prompts and tool bodies, types and counts only, and change nothing a hook concern sees. protect = also give every recording and advisory concern a copy with each value replaced by a placeholder token, so local stores keep tokens; guards still see the original. strict = as protect until the host rewrite exists. No mode yet changes what reaches the model; the rule table holds credential rows and the validated identifier rows. Project layers only.',
|
|
454
454
|
),
|
|
455
|
-
}).
|
|
456
|
-
}).
|
|
455
|
+
}).prefault({}),
|
|
456
|
+
}).prefault({}),
|
|
457
457
|
hooks: z.object({
|
|
458
458
|
concern_budget: z.object({
|
|
459
459
|
tier1_concerns: z.array(z.string()).default([]).describe(
|
|
@@ -464,47 +464,47 @@ export const settingsSchema = z.object({
|
|
|
464
464
|
touched_file_quality: z.enum(['off', 'shadow', 'warn']).default('off').describe(
|
|
465
465
|
"Stop-slot pass that runs the project's OWN quality commands — the ones resolve_toolchain() already reports — over the files this turn edited. Default off. `shadow` records a per-run result and emits nothing; `warn` adds ONE advisory line of at most 200 bytes. Never blocks and never counts as verification: a command recorded here never reaches _lib/verification_command.ts, so a clean eslint run cannot let a turn claim it verified anything. A writing command runs only in its check form (pint --test) or not at all, and a command with no per-file form is skipped rather than run project-wide at every stop.",
|
|
466
466
|
),
|
|
467
|
-
}).
|
|
467
|
+
}).prefault({}),
|
|
468
468
|
injection_scan: z.object({
|
|
469
469
|
enabled: z.boolean().default(false).describe(
|
|
470
470
|
'PostToolUse prompt-injection scanner (road-to-security-pillar.md P3.2). Default off. When on, scans tool output (file reads, web fetches, MCP responses) for injection signatures and WARNS in context (never blocks). Runtime backstop on top of the always-on untrusted-input-defense rule; detection is probabilistic.',
|
|
471
471
|
),
|
|
472
|
-
}).
|
|
472
|
+
}).prefault({}),
|
|
473
473
|
runtime_journal: z.object({
|
|
474
474
|
enabled: z.boolean().default(false).describe(
|
|
475
475
|
'Runtime event journal (road-to-runtime-event-journal Phase 1). Default off. When on, one durable, episode-keyed record per dispatched hook event is appended to <git-common-dir>/agent-journal/journal.sqlite — a Class-A write that opens, writes and exits. It emits nothing to the model, never warns and never blocks: a locked database, a missing node:sqlite, a malformed envelope or a full disk all degrade to silence. Off rather than on because it CREATES a storage surface (a SQLite database under your .git/) rather than appending to a directory that already exists. The record type has no field able to hold free-form content — ids, an event name, a bounded capability identifier, repo-relative locators and two 12-hex digests; no prompt, no file body, no absolute path. Retention: a 30-day TTL anchored on episode close, plus explicit, time-bounded, human-only holds that themselves expire.',
|
|
476
476
|
),
|
|
477
|
-
}).
|
|
477
|
+
}).prefault({}),
|
|
478
478
|
rtk_wrap: z.object({
|
|
479
479
|
enabled: z.boolean().default(false).describe(
|
|
480
480
|
'PreToolUse RTK-wrap nudge (token-saving Phase 3). Default off. When on AND the binary on PATH is verified as Rust Token Killer (a live two-stage identity probe — not a self-reported flag, and never a colliding same-name binary), warns (never blocks) "re-run wrapped with rtk" before a single verbose CLI command (git/npm/cargo/docker/…) — upstream reports 60–90% output-token savings (their estimate). Skips completeness-critical / piped / compound commands and git diff. No-op when rtk is absent, unverified, or a different tool. Its own activation charge is one advisory line under the 1,024 B default concern cap in src/config/hook-token-budget.json; the per-fire distribution is UNMEASURED — stated rather than estimated, because the saving above is a third-party output-token claim and not a standing-payload reduction this package measured.',
|
|
481
481
|
),
|
|
482
|
-
}).
|
|
482
|
+
}).prefault({}),
|
|
483
483
|
design_slop: z.object({
|
|
484
484
|
enabled: z.boolean().default(false).describe(
|
|
485
485
|
'PreToolUse anti-slop nudge (road-to-anti-slop-detector Phase 3). Default off. When on, runs the lint_design_slop registry against about-to-be-written UI content and WARNS (never blocks) on P0/P1 aesthetic tells (side-stripe, gradient-text, magic z-index, …). Flags are rebuttable via DESIGN.md / design-slop-disable. Anti-loop: a file::rule signature surfaced 3x goes silent. Host-limited convenience layer; the universal gate is the lint_design_slop linter/CI.',
|
|
486
486
|
),
|
|
487
|
-
}).
|
|
487
|
+
}).prefault({}),
|
|
488
488
|
design_pass: z.object({
|
|
489
489
|
enabled: z.boolean().default(false).describe(
|
|
490
490
|
'PostToolUse + stop design pass (road-to-frontend-power E1.1/E1.2/E1.3). Default off. One concern on two slots: on post_tool_use a write to a UI surface delivers the design findings as context and never blocks; on stop the same pass runs over every UI file touched this session, deduped against what the post pass surfaced, and a P0 objective floor (contrast, font size, heading skip, focus) blocks with a continuation. P1-P3 never block. post_tool_use rather than pre_tool_use for two measured reasons: pre_tool_use is declared by three hosts and honoured by one while post_tool_use is declared by six, and _lib/ui_surface.ts is a path predicate, so a pre-write gate cannot fire on the first write of a new surface. A pass that could not fully run reports verification: degraded with a reason rather than passing silently. Does not replace design_slop: two design keys is the honest state until the tiering experiment has a number.',
|
|
491
491
|
),
|
|
492
|
-
}).
|
|
492
|
+
}).prefault({}),
|
|
493
493
|
ui_route_nudge: z.object({
|
|
494
494
|
enabled: z.boolean().default(false).describe(
|
|
495
495
|
'PreToolUse UI-route nudge (road-to-frontend-skill-application Phase 4). Default off. When on, a Write/Edit to a UI surface with no design consultation latched this session WARNS (never blocks) naming the route — run existing-ui-audit, then the fe-design loop. A read or search touching fe-design / existing-ui-audit / design-review / design-intelligence latches consultation and silences it for the session. Anti-loop: at most 2 nudges per session. It does not read the rules: the UI-surface decision comes from _lib/ui_surface.ts and no code parses rule frontmatter, so this runs parallel to the two UI rules rather than consuming their triggers, and a test keeps the sets from drifting. It is a nudge, so their enforced_by: none stays accurate.',
|
|
496
496
|
),
|
|
497
|
-
}).
|
|
497
|
+
}).prefault({}),
|
|
498
498
|
code_graph: z.object({
|
|
499
499
|
enabled: z.boolean().default(false).describe(
|
|
500
500
|
'PreToolUse code-graph nudge (ADR-124 Phase 4). Default off. When on AND a native code-graph cache or a consumer-shipped graph.json/SCIP index is present, warns once per session (never blocks) as the agent is about to Grep/Glob or Read a source file — query the graph first for who-calls/where-used/impact questions (or rebuild if stale, build if absent). Source G’s strict block-first-read mode is deliberately un-ported.',
|
|
501
501
|
),
|
|
502
|
-
}).
|
|
502
|
+
}).prefault({}),
|
|
503
503
|
suggestion_capture: z.object({
|
|
504
504
|
enabled: z.boolean().default(false).describe(
|
|
505
505
|
'Suggestion-block capture (road-to-suggestion-block-capture Phase 2). Default off. Two slots: `stop` reads `last_assistant_message` — a payload field, so no transcript file is read — and latches that the assistant turn carried a numbered-options block; `user_prompt_submit` CONSUMES that latch and classifies the answering turn as option_n / as_is / other / stale_block. Consume-once is the correctness guard: the latch is deleted on read, so a bare "1" three turns later meets no latch and classifies `other`, and a latch past its TTL or unparseable is `stale_block` rather than a guess. Writes COUNTS ONLY to agents/runtime/state/audit/suggestion-capture.jsonl — the record type has no field able to hold a prompt, an option label or a command name, and a test asserts the written key set against src/config/suggestion-capture.json. Off by default because this is an INSTRUMENT rather than a feature: it exists so a capture rate can be measured on a maintainer workspace over a fixed soak window, and there is nothing in it for a consumer to gain.',
|
|
506
506
|
),
|
|
507
|
-
}).
|
|
507
|
+
}).prefault({}),
|
|
508
508
|
// `turn_end_gate` is deliberately ABSENT. The stop-slot turn-end gate is
|
|
509
509
|
// always armed (2026-08-12) and has no settings surface: whether it
|
|
510
510
|
// fires is decided by each detector's own trigger conditions, not by a
|
|
@@ -544,12 +544,12 @@ export const settingsSchema = z.object({
|
|
|
544
544
|
kev: z.enum(['off', 'on']).default('on').describe(
|
|
545
545
|
'Whether a refresh reads the CISA known-exploited catalog. on (default) downloads the whole catalog and matches it locally, so nothing about the project is sent, and a finding in it is raised one tier in a runtime scope; off leaves tiers to the other sources. Runs only where egress is query.',
|
|
546
546
|
),
|
|
547
|
-
}).
|
|
547
|
+
}).prefault({ mode: 'notify', egress: 'query', kev: 'on' }),
|
|
548
548
|
update: z.object({
|
|
549
549
|
mode: z.enum(['off', 'notify', 'ask', 'auto']).default('notify').describe(
|
|
550
550
|
'What the agent may do about a newer release. notify tells you and installs nothing (the default, and what an absent key resolves to); ask behaves as notify until the ring-0 exit ships a prompt; auto installs a staged release at a session start when every gate passes and no other session is live; off says nothing at all. Read from the user-global layer only — a repository cannot set how your global install updates itself.',
|
|
551
551
|
),
|
|
552
|
-
}).
|
|
552
|
+
}).prefault({ mode: 'notify' }),
|
|
553
553
|
legal_review_prep: z.object({
|
|
554
554
|
acknowledged: z.boolean().default(false).describe(
|
|
555
555
|
'I understand the legal-review-prep pack provides templates and general information ONLY — it is NOT legal advice, creates no attorney-client relationship, and never replaces a licensed lawyer. Individual cases require an attorney. The pack stays inactive until this is checked.',
|
|
@@ -557,7 +557,7 @@ export const settingsSchema = z.object({
|
|
|
557
557
|
require_council: z.boolean().default(true).describe(
|
|
558
558
|
'Gate legal work-product behind a multi-model AI-council / deep-research pass (defense-in-depth: documented multi-stage review + audit trail; fail-closed when no council is configured). Leave on for the safest posture. Turning it off lets single-model legal output through — not recommended for a high-risk pack.',
|
|
559
559
|
),
|
|
560
|
-
}).
|
|
560
|
+
}).prefault({ acknowledged: false, require_council: true }),
|
|
561
561
|
});
|
|
562
562
|
|
|
563
563
|
export type Settings = z.infer<typeof settingsSchema>;
|
|
@@ -82,7 +82,7 @@ function unwrapRef(root: JsonSchemaNode): JsonSchemaNode {
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
|
-
* Flatten a `
|
|
85
|
+
* Flatten a `toJsonSchema7` output into dotted leaf entries. Objects with
|
|
86
86
|
* `properties` recurse; everything else (scalars, enums, arrays, free-form
|
|
87
87
|
* maps) is a leaf. Deterministic key order (sorted) so snapshots diff
|
|
88
88
|
* cleanly in git and across runs.
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* the same Zod schema. ESLint forbids Node-only imports in this tree.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import
|
|
14
|
+
import * as z from 'zod';
|
|
15
15
|
|
|
16
16
|
/** Hard cap on the optional `notes` block. Keeps the file loadable into every reply. */
|
|
17
17
|
export const USER_IDENTITY_NOTES_MAX_CHARS = 8_000;
|