@bevel-software/platform-core-backend 0.25.0 → 0.26.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/agent-guide/access-control.md +234 -0
- package/agent-guide/conventions.md +27 -0
- package/agent-guide/directory-structure.md +145 -0
- package/agent-guide/finding-things.md +7 -0
- package/agent-guide/introduction.md +27 -0
- package/agent-guide/skills.md +47 -0
- package/agent-guide/tool-manuals.md +217 -0
- package/agent-guide/where-a-new-file-goes.md +36 -0
- package/dist/assets.d.ts +7 -0
- package/dist/assets.d.ts.map +1 -1
- package/dist/assets.js +9 -0
- package/dist/assets.js.map +1 -1
- package/dist/core/core-ports.d.ts +11 -0
- package/dist/core/core-ports.d.ts.map +1 -1
- package/dist/core/core-ports.js.map +1 -1
- package/dist/core/create-core-server.d.ts.map +1 -1
- package/dist/core/create-core-server.js +13 -2
- package/dist/core/create-core-server.js.map +1 -1
- package/dist/core/create-core-services.d.ts +9 -0
- package/dist/core/create-core-services.d.ts.map +1 -1
- package/dist/core/create-core-services.js +14 -4
- package/dist/core/create-core-services.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/modules/access/access-control.interface.d.ts +9 -0
- package/dist/modules/access/access-control.interface.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.d.ts +1 -0
- package/dist/modules/access/access-control.service.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.js +16 -0
- package/dist/modules/access/access-control.service.js.map +1 -1
- package/dist/modules/agent-guide/agent-guide.d.ts +139 -0
- package/dist/modules/agent-guide/agent-guide.d.ts.map +1 -0
- package/dist/modules/agent-guide/agent-guide.js +191 -0
- package/dist/modules/agent-guide/agent-guide.js.map +1 -0
- package/dist/modules/agent-guide/agent-guide.tools.d.ts +24 -0
- package/dist/modules/agent-guide/agent-guide.tools.d.ts.map +1 -0
- package/dist/modules/agent-guide/agent-guide.tools.js +100 -0
- package/dist/modules/agent-guide/agent-guide.tools.js.map +1 -0
- package/dist/modules/agent-guide/index.d.ts +4 -0
- package/dist/modules/agent-guide/index.d.ts.map +1 -0
- package/dist/modules/agent-guide/index.js +4 -0
- package/dist/modules/agent-guide/index.js.map +1 -0
- package/dist/modules/agent-instructions/agent-instructions.routes.d.ts +3 -2
- package/dist/modules/agent-instructions/agent-instructions.routes.d.ts.map +1 -1
- package/dist/modules/agent-instructions/agent-instructions.routes.js +3 -2
- package/dist/modules/agent-instructions/agent-instructions.routes.js.map +1 -1
- package/dist/modules/agent-instructions/compose.d.ts +9 -6
- package/dist/modules/agent-instructions/compose.d.ts.map +1 -1
- package/dist/modules/agent-instructions/compose.js +9 -6
- package/dist/modules/agent-instructions/compose.js.map +1 -1
- package/dist/modules/agent-instructions/index.d.ts +1 -1
- package/dist/modules/agent-instructions/index.d.ts.map +1 -1
- package/dist/modules/agent-instructions/index.js +1 -1
- package/dist/modules/agent-instructions/index.js.map +1 -1
- package/dist/modules/agent-instructions/shared-file-rules.d.ts +10 -50
- package/dist/modules/agent-instructions/shared-file-rules.d.ts.map +1 -1
- package/dist/modules/agent-instructions/shared-file-rules.js +32 -85
- package/dist/modules/agent-instructions/shared-file-rules.js.map +1 -1
- package/dist/modules/mcp/mcp.service.d.ts +29 -2
- package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
- package/dist/modules/mcp/mcp.service.js +113 -16
- package/dist/modules/mcp/mcp.service.js.map +1 -1
- package/dist/modules/mcp/tool-schema-guard.d.ts +105 -0
- package/dist/modules/mcp/tool-schema-guard.d.ts.map +1 -0
- package/dist/modules/mcp/tool-schema-guard.js +171 -0
- package/dist/modules/mcp/tool-schema-guard.js.map +1 -0
- package/dist/modules/plugins/plugins.tools.d.ts +36 -2
- package/dist/modules/plugins/plugins.tools.d.ts.map +1 -1
- package/dist/modules/plugins/plugins.tools.js +71 -14
- package/dist/modules/plugins/plugins.tools.js.map +1 -1
- package/dist/modules/settings/deployment-settings.service.d.ts +0 -7
- package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
- package/dist/modules/settings/deployment-settings.service.js +14 -53
- package/dist/modules/settings/deployment-settings.service.js.map +1 -1
- package/dist/modules/settings/setup.routes.d.ts.map +1 -1
- package/dist/modules/settings/setup.routes.js +3 -6
- package/dist/modules/settings/setup.routes.js.map +1 -1
- package/dist/modules/skills/skills.tools.d.ts.map +1 -1
- package/dist/modules/skills/skills.tools.js +58 -16
- package/dist/modules/skills/skills.tools.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +23 -4
- package/dist/modules/tool-manuals/tool-manuals.contract.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.contract.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts +4 -0
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.js +14 -0
- package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.d.ts +7 -0
- package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.js +66 -36
- package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
- package/dist/modules/tool-registry/description-length.d.ts +14 -14
- package/dist/modules/tool-registry/description-length.d.ts.map +1 -1
- package/dist/modules/tool-registry/description-length.js +24 -26
- package/dist/modules/tool-registry/description-length.js.map +1 -1
- package/dist/modules/tool-registry/guide-first.d.ts +23 -0
- package/dist/modules/tool-registry/guide-first.d.ts.map +1 -0
- package/dist/modules/tool-registry/guide-first.js +32 -0
- package/dist/modules/tool-registry/guide-first.js.map +1 -0
- package/dist/modules/tool-registry/tool-registry.d.ts +6 -0
- package/dist/modules/tool-registry/tool-registry.d.ts.map +1 -1
- package/dist/modules/tool-registry/tool-registry.js +9 -2
- package/dist/modules/tool-registry/tool-registry.js.map +1 -1
- package/dist/modules/workflow/agent-tools/change-request-read-shape.d.ts +449 -0
- package/dist/modules/workflow/agent-tools/change-request-read-shape.d.ts.map +1 -0
- package/dist/modules/workflow/agent-tools/change-request-read-shape.js +481 -0
- package/dist/modules/workflow/agent-tools/change-request-read-shape.js.map +1 -0
- package/dist/modules/workflow/agent-tools/change-request-read.tools.d.ts +73 -0
- package/dist/modules/workflow/agent-tools/change-request-read.tools.d.ts.map +1 -0
- package/dist/modules/workflow/agent-tools/change-request-read.tools.js +582 -0
- package/dist/modules/workflow/agent-tools/change-request-read.tools.js.map +1 -0
- package/dist/modules/workflow/agent-tools/change-request-summary.d.ts +12 -1
- package/dist/modules/workflow/agent-tools/change-request-summary.d.ts.map +1 -1
- package/dist/modules/workflow/agent-tools/change-request-summary.js +5 -1
- package/dist/modules/workflow/agent-tools/change-request-summary.js.map +1 -1
- package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
- package/dist/modules/workflow/agent-tools/workflow.tools.js +9 -0
- package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
- package/dist/modules/workflow/git/git.service.d.ts +210 -13
- package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/git.service.js +456 -91
- package/dist/modules/workflow/git/git.service.js.map +1 -1
- package/dist/modules/workflow/git/merge-commit.d.ts +73 -0
- package/dist/modules/workflow/git/merge-commit.d.ts.map +1 -0
- package/dist/modules/workflow/git/merge-commit.js +89 -0
- package/dist/modules/workflow/git/merge-commit.js.map +1 -0
- package/dist/modules/workflow/git/pull-request.service.d.ts +94 -1
- package/dist/modules/workflow/git/pull-request.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/pull-request.service.js +332 -37
- package/dist/modules/workflow/git/pull-request.service.js.map +1 -1
- package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts +35 -0
- package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/review-workflow/review-workflow.service.js +178 -12
- package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -1
- package/dist/modules/workflow/workflow.routes.d.ts +6 -2
- package/dist/modules/workflow/workflow.routes.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.routes.js +7 -2
- package/dist/modules/workflow/workflow.routes.js.map +1 -1
- package/dist/modules/workflow/workflow.service.d.ts +4 -0
- package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.service.js +3 -0
- package/dist/modules/workflow/workflow.service.js.map +1 -1
- package/dist/modules/workspace/startup/kb-startup-runner.d.ts +70 -0
- package/dist/modules/workspace/startup/kb-startup-runner.d.ts.map +1 -1
- package/dist/modules/workspace/startup/kb-startup-runner.js +213 -20
- package/dist/modules/workspace/startup/kb-startup-runner.js.map +1 -1
- package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/seed-tree.js +22 -27
- package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
- package/dist/modules/workspace/startup/steps/template-files.step.d.ts +58 -52
- package/dist/modules/workspace/startup/steps/template-files.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/template-files.step.js +209 -223
- package/dist/modules/workspace/startup/steps/template-files.step.js.map +1 -1
- package/dist/modules/workspace/startup/steps/template-source.d.ts +5 -3
- package/dist/modules/workspace/startup/steps/template-source.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/template-source.js +5 -3
- package/dist/modules/workspace/startup/steps/template-source.js.map +1 -1
- package/dist/modules/workspace/workspace.tools.d.ts +10 -1
- package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.tools.js +211 -18
- package/dist/modules/workspace/workspace.tools.js.map +1 -1
- package/dist/shared/domain-errors.d.ts +11 -0
- package/dist/shared/domain-errors.d.ts.map +1 -1
- package/dist/shared/domain-errors.js +14 -0
- package/dist/shared/domain-errors.js.map +1 -1
- package/dist/shared/hidden-tools.d.ts +44 -0
- package/dist/shared/hidden-tools.d.ts.map +1 -0
- package/dist/shared/hidden-tools.js +13 -0
- package/dist/shared/hidden-tools.js.map +1 -0
- package/kb-template/.bevelignore +0 -5
- package/package.json +4 -3
- package/src/__tests__/kb-layout-config.test.ts +10 -100
- package/src/__tests__/packaged-assets-ship.test.ts +54 -0
- package/src/assets.ts +10 -0
- package/src/core/core-ports.ts +11 -0
- package/src/core/create-core-server.ts +13 -2
- package/src/core/create-core-services.ts +28 -4
- package/src/index.ts +2 -2
- package/src/modules/access/__tests__/access-control.atref-batch.test.ts +58 -0
- package/src/modules/access/__tests__/access-control.platform-restore.test.ts +8 -7
- package/src/modules/access/__tests__/access-personal-plugin.test.ts +1 -18
- package/src/modules/access/access-control.interface.ts +15 -0
- package/src/modules/access/access-control.service.ts +21 -0
- package/src/modules/agent-guide/__tests__/agent-guide.test.ts +328 -0
- package/src/modules/agent-guide/__tests__/agent-guide.tools.test.ts +189 -0
- package/src/modules/agent-guide/agent-guide.tools.ts +122 -0
- package/src/modules/agent-guide/agent-guide.ts +291 -0
- package/src/modules/agent-guide/index.ts +21 -0
- package/src/modules/agent-instructions/__tests__/shared-file-rules.test.ts +28 -121
- package/src/modules/agent-instructions/agent-instructions.routes.ts +3 -2
- package/src/modules/agent-instructions/compose.ts +9 -6
- package/src/modules/agent-instructions/index.ts +0 -3
- package/src/modules/agent-instructions/shared-file-rules.ts +31 -93
- package/src/modules/mcp/__tests__/fake-downstream-mcp-server.ts +14 -3
- package/src/modules/mcp/__tests__/mcp.e2e.test.ts +250 -0
- package/src/modules/mcp/__tests__/mcp.service.test.ts +31 -23
- package/src/modules/mcp/__tests__/tool-schema-guard.test.ts +266 -0
- package/src/modules/mcp/mcp.service.ts +137 -19
- package/src/modules/mcp/tool-schema-guard.ts +196 -0
- package/src/modules/plugins/__tests__/plugins.tools.test.ts +154 -4
- package/src/modules/plugins/plugins.tools.ts +75 -15
- package/src/modules/settings/__tests__/deployment-settings.service.test.ts +26 -55
- package/src/modules/settings/deployment-settings.service.ts +13 -54
- package/src/modules/settings/setup.routes.ts +3 -6
- package/src/modules/skills/__tests__/skills.tools.description.test.ts +91 -0
- package/src/modules/skills/skills.tools.ts +62 -16
- package/src/modules/tool-manuals/__tests__/tool-manuals.detail.route.test.ts +57 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +73 -4
- package/src/modules/tool-manuals/tool-manuals.contract.ts +24 -4
- package/src/modules/tool-manuals/tool-manuals.service.ts +17 -0
- package/src/modules/tool-manuals/tool-manuals.tools.ts +74 -36
- package/src/modules/tool-registry/__tests__/own-tool-schemas.test.ts +160 -0
- package/src/modules/tool-registry/__tests__/tool-description-length.test.ts +61 -59
- package/src/modules/tool-registry/description-length.ts +24 -26
- package/src/modules/tool-registry/guide-first.ts +34 -0
- package/src/modules/tool-registry/tool-registry.ts +9 -2
- package/src/modules/workflow/__tests__/apply-failure.test.ts +6 -1
- package/src/modules/workflow/agent-tools/__tests__/change-request-read-shape.test.ts +705 -0
- package/src/modules/workflow/agent-tools/__tests__/change-request-read.tools.test.ts +1518 -0
- package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +23 -2
- package/src/modules/workflow/agent-tools/change-request-read-shape.ts +712 -0
- package/src/modules/workflow/agent-tools/change-request-read.tools.ts +724 -0
- package/src/modules/workflow/agent-tools/change-request-summary.ts +5 -1
- package/src/modules/workflow/agent-tools/workflow.tools.ts +8 -0
- package/src/modules/workflow/git/__tests__/git.service.appliedChange.test.ts +285 -0
- package/src/modules/workflow/git/__tests__/git.service.changedFilesForPr.test.ts +124 -0
- package/src/modules/workflow/git/__tests__/git.service.mergeChangeRequest.test.ts +334 -0
- package/src/modules/workflow/git/__tests__/pull-request.service.list-fetch.test.ts +72 -2
- package/src/modules/workflow/git/__tests__/pull-request.service.placeholder.test.ts +24 -2
- package/src/modules/workflow/git/__tests__/pull-request.service.test.ts +620 -1
- package/src/modules/workflow/git/git.service.ts +537 -94
- package/src/modules/workflow/git/merge-commit.ts +88 -0
- package/src/modules/workflow/git/pull-request.service.ts +380 -54
- package/src/modules/workflow/review-workflow/__tests__/approval-states.test.ts +7 -1
- package/src/modules/workflow/review-workflow/__tests__/merge-records-own-commit.test.ts +407 -0
- package/src/modules/workflow/review-workflow/review-workflow.service.ts +189 -11
- package/src/modules/workflow/workflow.routes.ts +7 -2
- package/src/modules/workflow/workflow.service.ts +7 -0
- package/src/modules/workspace/__tests__/escape-sequences.routes.test.ts +4 -3
- package/src/modules/workspace/__tests__/workspace.routes.move-platform-files.test.ts +21 -10
- package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +33 -55
- package/src/modules/workspace/__tests__/workspace.tools.test.ts +255 -22
- package/src/modules/workspace/startup/__tests__/kb-startup-runner.test.ts +231 -1
- package/src/modules/workspace/startup/kb-startup-runner.ts +216 -19
- package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +191 -489
- package/src/modules/workspace/startup/steps/seed-tree.ts +21 -27
- package/src/modules/workspace/startup/steps/template-files.step.ts +217 -249
- package/src/modules/workspace/startup/steps/template-source.ts +5 -3
- package/src/modules/workspace/workspace.tools.ts +226 -16
- package/src/shared/domain-errors.ts +15 -0
- package/src/shared/hidden-tools.ts +45 -0
- package/kb-template/AGENTS.md +0 -730
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { LEGACY_AGENTS_FILE,
|
|
3
|
+
import { LEGACY_AGENTS_FILE, validateKbRootName, } from '@bevel-software/platform-shared';
|
|
4
4
|
import { IGNORE_FILENAME, isAbsence } from '../../../../shared/fs.contract.js';
|
|
5
5
|
import { PREAMBLE_FILE } from '../../../agent-instructions/compose.js';
|
|
6
|
+
import { isManagedGuide } from '../../../agent-guide/agent-guide.js';
|
|
6
7
|
import { TemplateSource } from './template-source.js';
|
|
7
8
|
import { hasGitInternalsSegment } from '../../../../shared/git-internals.js';
|
|
9
|
+
export { isManagedGuide };
|
|
8
10
|
/** Root-anchored so a knowledge folder may still contain an ordinary namesake. */
|
|
9
11
|
const PREAMBLE_IGNORE_PATTERN = `/${PREAMBLE_FILE}`;
|
|
12
|
+
/**
|
|
13
|
+
* The guide's name before it was `AGENTS.md`, back when it was a file. A copy
|
|
14
|
+
* the platform wrote under it is taken out of the repository like one under
|
|
15
|
+
* the current name (see {@link TemplateFilesStep.retireGuideCopies}).
|
|
16
|
+
*/
|
|
17
|
+
const PRE_RENAME_AGENTS_FILE = 'CLAUDE.md';
|
|
10
18
|
/**
|
|
11
19
|
* The **required scaffolding** — the minimum an operational KB needs. Any of
|
|
12
20
|
* these missing from a protected branch are added at the startup phase; the
|
|
@@ -22,16 +30,14 @@ const PREAMBLE_IGNORE_PATTERN = `/${PREAMBLE_FILE}`;
|
|
|
22
30
|
*
|
|
23
31
|
* `roles.yaml` is in neither, and is not part of the template at all: it is
|
|
24
32
|
* generated from `ADMIN_EMAIL` (see roles-yaml.step.ts), so a repo can't be
|
|
25
|
-
* seeded with a stale hard-coded Admin list.
|
|
33
|
+
* seeded with a stale hard-coded Admin list. The agent guide is in neither
|
|
34
|
+
* either, any more: it is served from code (see modules/agent-guide), and the
|
|
35
|
+
* copies earlier releases wrote are REMOVED here, not refreshed.
|
|
26
36
|
*/
|
|
27
|
-
|
|
37
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- the list is a function of the layout to its callers, though no name in it is configurable today
|
|
38
|
+
export function requiredFiles(_layout) {
|
|
28
39
|
return [
|
|
29
40
|
'access.md',
|
|
30
|
-
// The managed agent guide, under whatever this deployment calls it. The
|
|
31
|
-
// PACKAGED template still carries it as `AGENTS.md` — one file, one
|
|
32
|
-
// spelling in the tarball — so the write target and the template source
|
|
33
|
-
// part company here and nowhere else (see {@link templateNameOf}).
|
|
34
|
-
layout.agentsFile,
|
|
35
41
|
'.bevelignore',
|
|
36
42
|
'.gitignore',
|
|
37
43
|
// The deployment preamble every connected agent is told at session start
|
|
@@ -41,30 +47,6 @@ export function requiredFiles(layout) {
|
|
|
41
47
|
PREAMBLE_FILE,
|
|
42
48
|
];
|
|
43
49
|
}
|
|
44
|
-
/**
|
|
45
|
-
* The template's own name for a required file. The guide is the one file whose
|
|
46
|
-
* name on disk is a deployment's choice while its name in the template is
|
|
47
|
-
* fixed; everything else is spelled the same on both sides.
|
|
48
|
-
*/
|
|
49
|
-
function templateNameOf(repoRel, agentsFile) {
|
|
50
|
-
return repoRel === agentsFile ? LEGACY_AGENTS_FILE : repoRel;
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* The sentence the managed guide carries about itself, and the ONLY thing that
|
|
54
|
-
* makes a root `AGENTS.md` provably the platform's rather than the customer's.
|
|
55
|
-
*
|
|
56
|
-
* Matched on this one phrase rather than on the whole header: the lines around
|
|
57
|
-
* it have changed between releases (they name the configured file now), and a
|
|
58
|
-
* knowledge base seeded by any of those releases is still ours to remove. A
|
|
59
|
-
* customer file would have to quote the platform's own claim about itself
|
|
60
|
-
* verbatim to be mistaken for one, and the consequence of the mistake is a
|
|
61
|
-
* deletion — which is why nothing looser will do.
|
|
62
|
-
*/
|
|
63
|
-
const MANAGED_GUIDE_MARKER = '**This file is managed by the platform.**';
|
|
64
|
-
/** Whether `text` is a copy of the platform's managed guide, of any vintage. */
|
|
65
|
-
export function isManagedGuide(text) {
|
|
66
|
-
return text.includes(MANAGED_GUIDE_MARKER);
|
|
67
|
-
}
|
|
68
50
|
/**
|
|
69
51
|
* Repo-root files the startup phase GENERATES rather than copies — today just
|
|
70
52
|
* `roles.yaml`, rendered from `ADMIN_EMAIL` (see roles-yaml.step.ts and
|
|
@@ -139,13 +121,16 @@ export function reservedRootDirs(extraRootDirs, layout) {
|
|
|
139
121
|
}
|
|
140
122
|
/**
|
|
141
123
|
* The template top-up as an {@link OnServerStart} step: add any missing base
|
|
142
|
-
* scaffolding to every PROTECTED branch, and
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
124
|
+
* scaffolding to every PROTECTED branch, and take the agent guide copies
|
|
125
|
+
* earlier releases wrote OUT of them — the guide is served from code now, and
|
|
126
|
+
* a copy left on disk would be read as the organisation's own conventions
|
|
127
|
+
* file, stale and under a header that says the platform owns it. Drafts are
|
|
128
|
+
* deliberately out of scope — whatever the protected branches gain, drafts
|
|
129
|
+
* fork from; a scaffolding addition on a draft would surface as noise in its
|
|
130
|
+
* change request's diff. (Unlike the Groups→Plugins rename, a missing file
|
|
131
|
+
* diffs as one file, not the whole tree — so the uniform-application argument
|
|
132
|
+
* does not bite here. A stale guide copy on a draft is recognised by its
|
|
133
|
+
* header and never served, see `modules/agent-guide`.)
|
|
149
134
|
*
|
|
150
135
|
* Everything is DECLARED on the branch handle; reads go against the pre-step
|
|
151
136
|
* tree via `repoDir()`. Fail-open behavior from the lazy top-up (best-effort,
|
|
@@ -157,7 +142,6 @@ export class TemplateFilesStep {
|
|
|
157
142
|
disk;
|
|
158
143
|
kb;
|
|
159
144
|
extraRootDirs;
|
|
160
|
-
agentsFileLink;
|
|
161
145
|
name = 'template-files';
|
|
162
146
|
/**
|
|
163
147
|
* @param extraRootDirs Additional root folders this distribution reserves,
|
|
@@ -166,23 +150,16 @@ export class TemplateFilesStep {
|
|
|
166
150
|
* claim a root without also shipping a template entry
|
|
167
151
|
* for it.
|
|
168
152
|
*/
|
|
169
|
-
/**
|
|
170
|
-
* @param agentsFileLink Whether to keep the platform's pointer sentence in a
|
|
171
|
-
* customer-owned root `AGENTS.md` — a GETTER, because
|
|
172
|
-
* the setting behind it may be saved by the very
|
|
173
|
-
* first-run save that then runs this phase.
|
|
174
|
-
*/
|
|
175
153
|
constructor(disk,
|
|
176
154
|
/**
|
|
177
155
|
* Read per run, never captured: the save that completes first-run setup
|
|
178
156
|
* applies the admin's names after this step was built. A snapshot taken
|
|
179
157
|
* here scaffolded `Skills/` beside the `skills/` they had just chosen.
|
|
180
158
|
*/
|
|
181
|
-
kb, extraRootDirs = []
|
|
159
|
+
kb, extraRootDirs = []) {
|
|
182
160
|
this.disk = disk;
|
|
183
161
|
this.kb = kb;
|
|
184
162
|
this.extraRootDirs = extraRootDirs;
|
|
185
|
-
this.agentsFileLink = agentsFileLink;
|
|
186
163
|
// Validated NOW, so a bad extra fails at boot beside the rest of the
|
|
187
164
|
// wiring — but the list itself is NOT kept, for the reason `kb` says.
|
|
188
165
|
reservedRootDirs(extraRootDirs, kb.layout);
|
|
@@ -203,8 +180,6 @@ export class TemplateFilesStep {
|
|
|
203
180
|
// Read ONCE per branch: a value re-read between the write and the ignore
|
|
204
181
|
// rule could disagree with itself.
|
|
205
182
|
const layout = this.kb.layout;
|
|
206
|
-
const agentsFile = layout.agentsFile;
|
|
207
|
-
const renamed = agentsFile !== LEGACY_AGENTS_FILE;
|
|
208
183
|
for (const rel of requiredFiles(layout)) {
|
|
209
184
|
// `lstat`, not `exists`: a DIRECTORY or SYMLINK squatting a required
|
|
210
185
|
// file's name would read as "present", and a skip-if-present check
|
|
@@ -219,48 +194,35 @@ export class TemplateFilesStep {
|
|
|
219
194
|
`(${found.isSymbolicLink() ? 'symlink' : found.isDirectory() ? 'directory' : 'special file'}). ` +
|
|
220
195
|
'Remove or rename it — the platform requires this name to be a readable file.');
|
|
221
196
|
}
|
|
222
|
-
let content = await templates.read(
|
|
197
|
+
let content = await templates.read(rel);
|
|
223
198
|
// The on-disk merge below only runs against an EXISTING ignore file; a
|
|
224
|
-
// freshly-declared one
|
|
225
|
-
//
|
|
226
|
-
//
|
|
227
|
-
//
|
|
228
|
-
//
|
|
229
|
-
//
|
|
230
|
-
//
|
|
231
|
-
//
|
|
232
|
-
// it: the on-disk reconciliation below never sees a file that was
|
|
233
|
-
// absent, so the declared content is reconciled here instead.
|
|
199
|
+
// freshly-declared one is reconciled here instead, so a distribution's
|
|
200
|
+
// custom template that predates a rule — or still ships one an earlier
|
|
201
|
+
// release had — declares the same file the merge would have produced.
|
|
202
|
+
// The deployment preamble is edited through External agent access, not
|
|
203
|
+
// as an ordinary knowledge-base document, so its rule is guaranteed;
|
|
204
|
+
// the rules that hid the skills root, the plugins root and the guide
|
|
205
|
+
// copies the platform used to write are taken out (see the merge below
|
|
206
|
+
// for why each).
|
|
234
207
|
if (rel === IGNORE_FILENAME) {
|
|
235
208
|
// A template still shipping the unanchored preamble rule an earlier
|
|
236
209
|
// release had is respelled first, so the guarantee below adds nothing
|
|
237
210
|
// beside it.
|
|
238
211
|
content = withPlatformIgnorePatternRespelled(content, PREAMBLE_FILE, PREAMBLE_IGNORE_PATTERN);
|
|
239
|
-
content = withoutIgnoreLine(withoutPlatformIgnorePattern(withIgnorePattern(
|
|
240
|
-
// …and a template (a distribution's, a stale packaged one) still
|
|
241
|
-
// hiding `AGENTS.md` while this deployment's guide is called something
|
|
242
|
-
// else would hide the CUSTOMER'S file from the first boot — the exact
|
|
243
|
-
// thing the rename exists to prevent.
|
|
244
|
-
if (renamed)
|
|
245
|
-
content = withoutPlatformAgentsRule(content);
|
|
212
|
+
content = withoutPlatformGuideRules(withoutIgnoreLine(withoutPlatformIgnorePattern(withIgnorePattern(content, PREAMBLE_IGNORE_PATTERN), `${layout.skillsDir}/`), `${layout.pluginsDir}/`), [LEGACY_AGENTS_FILE, PRE_RENAME_AGENTS_FILE]);
|
|
246
213
|
}
|
|
247
214
|
branch.write(rel, content);
|
|
248
215
|
added.push(rel);
|
|
249
216
|
}
|
|
250
|
-
//
|
|
251
|
-
//
|
|
252
|
-
// UNCONDITIONALLY, not only when the file was just added: a KB whose
|
|
253
|
-
// guide predates the CLAUDE.md→AGENTS.md rename has an ignore file
|
|
254
|
-
// that lists the old name and knows nothing of the new one, so the
|
|
255
|
-
// conventions doc shows up in the file tree and the agent view. A KB
|
|
256
|
-
// whose deployment has just RENAMED the guide is the same story one
|
|
257
|
-
// rename later: the rule names a file that is now the customer's.
|
|
217
|
+
// mcp-description.md left VISIBLE by a stale `.bevelignore` is closed
|
|
218
|
+
// here — and UNCONDITIONALLY, not only when the file was just added.
|
|
258
219
|
// Idempotent: an ignore file already carrying the rule — or absent, in
|
|
259
220
|
// which case the template's copy declared above arrives with the rule in
|
|
260
221
|
// it — changes nothing and produces no note. Deliberately checked by
|
|
261
|
-
// LINE PRESENCE, not effective outcome: a later
|
|
262
|
-
// the operator explicitly choosing to SHOW the file, and
|
|
263
|
-
// default this step provides, not a mandate it re-imposes
|
|
222
|
+
// LINE PRESENCE, not effective outcome: a later `!/mcp-description.md`
|
|
223
|
+
// negation is the operator explicitly choosing to SHOW the file, and
|
|
224
|
+
// hiding it is a default this step provides, not a mandate it re-imposes
|
|
225
|
+
// every boot.
|
|
264
226
|
//
|
|
265
227
|
// The shared-skills root goes the OTHER way. An earlier release hid it
|
|
266
228
|
// like `Plugins/`; the Skills & Tools sidebar now renders it as a file
|
|
@@ -277,144 +239,101 @@ export class TemplateFilesStep {
|
|
|
277
239
|
// it as a file tree too, so the rule that hid it since the first seed
|
|
278
240
|
// comes out. That one has no comment to know it by — it was in the
|
|
279
241
|
// template body from the start — so every line spelling it goes,
|
|
280
|
-
// whoever wrote it (see `withoutIgnoreLine`).
|
|
281
|
-
//
|
|
282
|
-
//
|
|
242
|
+
// whoever wrote it (see `withoutIgnoreLine`).
|
|
243
|
+
//
|
|
244
|
+
// And the guide's rules go the same way as the skills root's. Every
|
|
245
|
+
// release that wrote the guide to disk hid it with a rule of its own —
|
|
246
|
+
// under `AGENTS.md`, under the name a deployment gave the guide (any
|
|
247
|
+
// name it ever gave it: the copies found at the root say which), and
|
|
248
|
+
// under `CLAUDE.md` for the copy that predates the rename. The guide is
|
|
249
|
+
// not on disk any more, so a root file under any of those names is the
|
|
250
|
+
// organisation's own conventions page, which they must be able to see
|
|
251
|
+
// and edit in the app. The platform's own lines come out, recognised by
|
|
252
|
+
// the comment or the template slot each release wrote them in (see
|
|
253
|
+
// {@link withoutPlatformGuideRules}); a rule an operator wrote by hand
|
|
254
|
+
// is theirs and stays. ONE read-modify-write for all the rules: separate
|
|
255
|
+
// passes would each read the on-disk file and a later declared write
|
|
256
|
+
// would lose an earlier one's.
|
|
257
|
+
//
|
|
258
|
+
// The copies come out first only so the one commit this step makes can
|
|
259
|
+
// name them in its subject; the rule pass below does not read the names
|
|
260
|
+
// — a guide rule is known by the platform's comment above it, whatever
|
|
261
|
+
// name it spells.
|
|
262
|
+
const retired = await this.retireGuideCopies(repoDir, branch);
|
|
263
|
+
added.push(...retired);
|
|
283
264
|
added.push(...(await this.reconcileIgnoreRules(repoDir, branch, {
|
|
284
265
|
// The preamble rule is respelled before it is added: a knowledge base
|
|
285
266
|
// that booted the release shipping the unanchored spelling carries the
|
|
286
267
|
// platform's own line, and that line hides a nested namesake too.
|
|
287
268
|
respell: [[PREAMBLE_FILE, PREAMBLE_IGNORE_PATTERN]],
|
|
288
|
-
|
|
289
|
-
// escaped, or the rule would hide nothing.
|
|
290
|
-
add: [gitignoreLiteral(agentsFile), PREAMBLE_IGNORE_PATTERN],
|
|
269
|
+
add: [PREAMBLE_IGNORE_PATTERN],
|
|
291
270
|
drop: [`${this.kb.layout.skillsDir}/`],
|
|
292
271
|
dropEvery: [`${this.kb.layout.pluginsDir}/`],
|
|
293
|
-
// The
|
|
294
|
-
//
|
|
295
|
-
//
|
|
296
|
-
|
|
297
|
-
// (see {@link withoutPlatformAgentsRule}); a rule an operator wrote by
|
|
298
|
-
// hand is theirs and stays.
|
|
299
|
-
dropAgentsRule: renamed,
|
|
272
|
+
// The two names the template itself shipped a rule for. A rule under
|
|
273
|
+
// any other name — a retired copy's, or a name no copy is left to
|
|
274
|
+
// tell — is known by the platform's comment above it instead.
|
|
275
|
+
guideNames: [LEGACY_AGENTS_FILE, PRE_RENAME_AGENTS_FILE],
|
|
300
276
|
})));
|
|
301
|
-
// The guide is MANAGED, not merely seeded: the platform owns its content,
|
|
302
|
-
// and a stale copy is replaced with the packaged template's every startup
|
|
303
|
-
// phase. The file's own header says so, which is what makes overwriting
|
|
304
|
-
// edits a stated contract instead of a surprise.
|
|
305
|
-
let agentsRefreshed = false;
|
|
306
|
-
if (!added.includes(agentsFile) &&
|
|
307
|
-
(await templates.differsFrom(repoDir, agentsFile, LEGACY_AGENTS_FILE))) {
|
|
308
|
-
branch.write(agentsFile, await templates.read(LEGACY_AGENTS_FILE));
|
|
309
|
-
added.push(agentsFile);
|
|
310
|
-
agentsRefreshed = true;
|
|
311
|
-
}
|
|
312
|
-
// What becomes of the `AGENTS.md` the platform used to own, now that the
|
|
313
|
-
// guide lives somewhere else. Nothing at all while the name is the default.
|
|
314
|
-
if (renamed) {
|
|
315
|
-
added.push(...(await this.reconcileLegacyGuide(repoDir, branch, {
|
|
316
|
-
agentsFile,
|
|
317
|
-
// Only on the boot the rename lands — the boot that first writes the
|
|
318
|
-
// guide under its new name. Said every boot after, the "kept" note
|
|
319
|
-
// would caption commits about other things forever.
|
|
320
|
-
announceKept: added.includes(agentsFile),
|
|
321
|
-
})));
|
|
322
|
-
}
|
|
323
277
|
added.push(...this.ensureRequiredDirs(repoDir, branch, await this.missingDirs(repoDir)));
|
|
324
278
|
if (added.length === 0)
|
|
325
279
|
return;
|
|
326
280
|
// One honest line; it becomes the commit subject when this step is the
|
|
327
281
|
// first to dirty the branch.
|
|
328
|
-
|
|
329
|
-
|
|
282
|
+
const others = added.filter((rel) => !retired.includes(rel));
|
|
283
|
+
branch.note(retired.length > 0
|
|
284
|
+
? `Remove the platform-written ${retired.join(' and ')} — the agent guide is served by the platform now` +
|
|
285
|
+
(others.length > 0 ? `; update ${others.join(', ')}` : '')
|
|
330
286
|
: `Add missing KB scaffolding: ${added.join(', ')}`);
|
|
331
287
|
}
|
|
332
288
|
/**
|
|
333
|
-
* The
|
|
334
|
-
*
|
|
335
|
-
*
|
|
336
|
-
*
|
|
337
|
-
*
|
|
338
|
-
* Removal is gated on the managed header and nothing else. An admin who
|
|
339
|
-
* renames the guide on a knowledge base the platform seeded would otherwise
|
|
340
|
-
* be left with stale platform content sitting under the very name they
|
|
341
|
-
* wanted for their own file; an admin who renames it on a repository whose
|
|
342
|
-
* `AGENTS.md` is their own must find that file byte-for-byte untouched. The
|
|
343
|
-
* header is the one fact that tells the two apart, so it is the one thing
|
|
344
|
-
* asked.
|
|
289
|
+
* The copies of the guide the platform wrote to the repository root while
|
|
290
|
+
* the guide was a file — under `AGENTS.md`, under `CLAUDE.md` from before
|
|
291
|
+
* the rename, and under every name a deployment ever gave the guide —
|
|
292
|
+
* removed when the platform can PROVE it wrote them, and otherwise left
|
|
293
|
+
* exactly alone.
|
|
345
294
|
*
|
|
346
|
-
*
|
|
347
|
-
*
|
|
348
|
-
*
|
|
349
|
-
*
|
|
350
|
-
*
|
|
351
|
-
*
|
|
295
|
+
* Found by SCANNING the root's markdown files rather than by the names the
|
|
296
|
+
* deployment knows today: a deployment that renamed the guide more than
|
|
297
|
+
* once left a copy under each earlier name, and the current setting
|
|
298
|
+
* remembers only the last. The header is what makes a scan safe, and the
|
|
299
|
+
* one fact that tells a copy of ours from a file of theirs: the
|
|
300
|
+
* organisation's own `AGENTS.md`, a `CLAUDE.md` its people edited, a note
|
|
301
|
+
* of theirs that happens to sit at the root, must all be found byte for
|
|
302
|
+
* byte untouched. A SYMLINK or a directory is left as it is: reading a link
|
|
303
|
+
* follows it, so a link pointing at a copy of the guide — or at any other
|
|
304
|
+
* file carrying the header — would read as ours and the removal would take
|
|
305
|
+
* the organisation's entry. Links are never followed anywhere else in the
|
|
306
|
+
* platform, and they are not followed here.
|
|
352
307
|
*
|
|
353
|
-
* Returns the
|
|
308
|
+
* Returns the names removed, in name order, for the note and for the
|
|
309
|
+
* ignore rules that hid them.
|
|
354
310
|
*/
|
|
355
|
-
async
|
|
356
|
-
const
|
|
357
|
-
|
|
358
|
-
//
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
// Gone between the probe and the read — a concurrent delete reads as the
|
|
380
|
-
// absence it is, on the same terms as the probe above.
|
|
381
|
-
if (isAbsence(err))
|
|
382
|
-
return [];
|
|
383
|
-
throw err;
|
|
384
|
-
}
|
|
385
|
-
if (isManagedGuide(current)) {
|
|
386
|
-
branch.remove(LEGACY_AGENTS_FILE);
|
|
387
|
-
branch.note(`Remove the platform-written AGENTS.md — the agent guide is now ${opts.agentsFile}`);
|
|
388
|
-
return [LEGACY_AGENTS_FILE];
|
|
389
|
-
}
|
|
390
|
-
if (opts.announceKept) {
|
|
391
|
-
branch.note('Keep AGENTS.md — it is not a platform template, so it is the knowledge base\'s own');
|
|
392
|
-
}
|
|
393
|
-
// The admin's consent gates every write below, this file being theirs.
|
|
394
|
-
if (!this.agentsFileLink())
|
|
395
|
-
return [];
|
|
396
|
-
// A sentence of OURS already in the file is updated rather than joined by
|
|
397
|
-
// a second one. The guide's name can be changed again, and after a second
|
|
398
|
-
// rename the sentence this step wrote last time points at a file that is
|
|
399
|
-
// no longer there — which asking "is the new name mentioned?" cannot see,
|
|
400
|
-
// because the old sentence does not mention it.
|
|
401
|
-
const retargeted = retargetAgentsFilePointer(current, opts.agentsFile);
|
|
402
|
-
if (retargeted !== null) {
|
|
403
|
-
if (retargeted === current)
|
|
404
|
-
return [];
|
|
405
|
-
branch.write(LEGACY_AGENTS_FILE, retargeted);
|
|
406
|
-
branch.note(`Point the sentence in AGENTS.md at ${opts.agentsFile}`);
|
|
407
|
-
return [LEGACY_AGENTS_FILE];
|
|
311
|
+
async retireGuideCopies(repoDir, branch) {
|
|
312
|
+
const removed = [];
|
|
313
|
+
const entries = await fs.readdir(repoDir, { withFileTypes: true });
|
|
314
|
+
// `isFile` is false for a link, which is the point (see above).
|
|
315
|
+
const candidates = entries
|
|
316
|
+
.filter((entry) => entry.isFile() && entry.name.toLowerCase().endsWith('.md'))
|
|
317
|
+
.map((entry) => entry.name)
|
|
318
|
+
.sort();
|
|
319
|
+
for (const name of candidates) {
|
|
320
|
+
let current;
|
|
321
|
+
try {
|
|
322
|
+
current = await this.disk.readTextFile(path.join(repoDir, name));
|
|
323
|
+
}
|
|
324
|
+
catch (err) {
|
|
325
|
+
// Gone between the listing and the read — a concurrent delete reads
|
|
326
|
+
// as the absence it is.
|
|
327
|
+
if (isAbsence(err))
|
|
328
|
+
continue;
|
|
329
|
+
throw err;
|
|
330
|
+
}
|
|
331
|
+
if (!isManagedGuide(current))
|
|
332
|
+
continue;
|
|
333
|
+
branch.remove(name);
|
|
334
|
+
removed.push(name);
|
|
408
335
|
}
|
|
409
|
-
|
|
410
|
-
// Asked through the shared reading, not a raw `includes`: the sentence
|
|
411
|
-
// spells the name escaped and percent-encoded, so on a punctuated name the
|
|
412
|
-
// copy written last boot need not carry the raw name at all.
|
|
413
|
-
if (mentionsAgentsFile(current, opts.agentsFile))
|
|
414
|
-
return [];
|
|
415
|
-
branch.write(LEGACY_AGENTS_FILE, withPointerSentence(current, opts.agentsFile));
|
|
416
|
-
branch.note(`Add a pointer to ${opts.agentsFile} at the end of AGENTS.md`);
|
|
417
|
-
return [LEGACY_AGENTS_FILE];
|
|
336
|
+
return removed;
|
|
418
337
|
}
|
|
419
338
|
/**
|
|
420
339
|
* Which reserved roots are absent — and which are SQUATTED. `lstat`, not
|
|
@@ -488,9 +407,9 @@ export class TemplateFilesStep {
|
|
|
488
407
|
return [];
|
|
489
408
|
}
|
|
490
409
|
const respelled = (rules.respell ?? []).reduce((text, [from, to]) => withPlatformIgnorePatternRespelled(text, from, to), current);
|
|
491
|
-
const added = rules.add.reduce((text, pattern) => withIgnorePattern(text, pattern
|
|
410
|
+
const added = rules.add.reduce((text, pattern) => withIgnorePattern(text, pattern), respelled);
|
|
492
411
|
const dropped = (rules.dropEvery ?? []).reduce((text, pattern) => withoutIgnoreLine(text, pattern), rules.drop.reduce((text, pattern) => withoutPlatformIgnorePattern(text, pattern), added));
|
|
493
|
-
const merged = rules.
|
|
412
|
+
const merged = withoutPlatformGuideRules(dropped, rules.guideNames);
|
|
494
413
|
if (merged === current)
|
|
495
414
|
return [];
|
|
496
415
|
branch.write(IGNORE_FILENAME, merged);
|
|
@@ -565,15 +484,99 @@ function followsTemplateHygieneBlock(kept) {
|
|
|
565
484
|
return false;
|
|
566
485
|
return kept.slice(-block.length).every((line, i) => line.trim() === block[i]);
|
|
567
486
|
}
|
|
487
|
+
/**
|
|
488
|
+
* `text` without the rules THE PLATFORM WROTE to hide the guide while it was a
|
|
489
|
+
* file. Under WHATEVER name: every rule sitting directly under one of the two
|
|
490
|
+
* comments the platform wrote above the guide's rule
|
|
491
|
+
* ({@link withoutPlatformConventionsRules}) — the name a deployment saved for
|
|
492
|
+
* the guide is not read any more, so the rule for it is known by its comment
|
|
493
|
+
* and by nothing else. Then the two names the template itself shipped a rule
|
|
494
|
+
* for, under each of `names`: the `AGENTS.md` line in the slot at the end of
|
|
495
|
+
* the template's own repo-hygiene block
|
|
496
|
+
* ({@link TEMPLATE_HYGIENE_BLOCK_ABOVE_AGENTS_RULE}) and the `CLAUDE.md` line
|
|
497
|
+
* under the two-line comment the template carried it with. Each goes with
|
|
498
|
+
* its comment.
|
|
499
|
+
*
|
|
500
|
+
* The guide is not on disk any more, which is what makes every one of these
|
|
501
|
+
* lines wrong: it hides a file the platform never writes, which is therefore
|
|
502
|
+
* the organisation's own. A `!AGENTS.md` negation is not the rule and stays,
|
|
503
|
+
* as everywhere else here, and so does a bare rule an operator wrote by hand.
|
|
504
|
+
*/
|
|
505
|
+
export function withoutPlatformGuideRules(text, names) {
|
|
506
|
+
let out = withoutPlatformConventionsRules(text);
|
|
507
|
+
for (const name of new Set(names)) {
|
|
508
|
+
if (name === LEGACY_AGENTS_FILE)
|
|
509
|
+
out = withoutPlatformAgentsRule(out);
|
|
510
|
+
else if (name === PRE_RENAME_AGENTS_FILE)
|
|
511
|
+
out = withoutPlatformClaudeRule(out);
|
|
512
|
+
}
|
|
513
|
+
return out;
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* `text` without every rule line that sits DIRECTLY under one of the two
|
|
517
|
+
* comments the platform wrote above the guide's rule while the guide was a
|
|
518
|
+
* file ({@link PLATFORM_RULE_COMMENT}, {@link AGENTS_RULE_COMMENT}), whatever
|
|
519
|
+
* name the rule spells — `AGENTS.md`, `CLAUDE.md`, or the escaped form of a
|
|
520
|
+
* name a deployment chose — and without that comment, plus the blank line
|
|
521
|
+
* that opened the appended block. Those two comments were written above
|
|
522
|
+
* nothing else, so the comment is the whole provenance: a rule for a name
|
|
523
|
+
* nobody remembers is retired exactly like one for a name still known. A
|
|
524
|
+
* `!negation`, a blank or a further comment under the comment is not a rule
|
|
525
|
+
* and stays, comment included.
|
|
526
|
+
*/
|
|
527
|
+
function withoutPlatformConventionsRules(text) {
|
|
528
|
+
const lines = text.split('\n');
|
|
529
|
+
const kept = [];
|
|
530
|
+
for (const line of lines) {
|
|
531
|
+
const above = kept[kept.length - 1]?.trim();
|
|
532
|
+
const rule = line.trim();
|
|
533
|
+
const ours = (above === PLATFORM_RULE_COMMENT || above === AGENTS_RULE_COMMENT) &&
|
|
534
|
+
rule !== '' &&
|
|
535
|
+
!rule.startsWith('#') &&
|
|
536
|
+
!rule.startsWith('!');
|
|
537
|
+
if (!ours) {
|
|
538
|
+
kept.push(line);
|
|
539
|
+
continue;
|
|
540
|
+
}
|
|
541
|
+
kept.pop();
|
|
542
|
+
if (kept.length > 1 && kept[kept.length - 1]?.trim() === '')
|
|
543
|
+
kept.pop();
|
|
544
|
+
}
|
|
545
|
+
return kept.join('\n');
|
|
546
|
+
}
|
|
547
|
+
/** The two comment lines the packaged template carried above its `CLAUDE.md` rule, in order. */
|
|
548
|
+
const TEMPLATE_CLAUDE_RULE_COMMENT = [
|
|
549
|
+
'# The pre-rename name. Listed so a knowledge base carrying both files hides',
|
|
550
|
+
'# both — top-up adds AGENTS.md but never deletes the CLAUDE.md beside it.',
|
|
551
|
+
];
|
|
552
|
+
/**
|
|
553
|
+
* `text` without the `CLAUDE.md` line the packaged template wrote, and without
|
|
554
|
+
* the two comment lines it wrote above it. Provenance is that comment, as
|
|
555
|
+
* everywhere else here: a bare `CLAUDE.md` an operator wrote is theirs.
|
|
556
|
+
*/
|
|
557
|
+
function withoutPlatformClaudeRule(text) {
|
|
558
|
+
const lines = text.split('\n');
|
|
559
|
+
const kept = [];
|
|
560
|
+
for (const line of lines) {
|
|
561
|
+
const [first, second] = TEMPLATE_CLAUDE_RULE_COMMENT;
|
|
562
|
+
const ours = line.trim() === PRE_RENAME_AGENTS_FILE &&
|
|
563
|
+
kept.length >= 2 &&
|
|
564
|
+
kept[kept.length - 1].trim() === second &&
|
|
565
|
+
kept[kept.length - 2].trim() === first;
|
|
566
|
+
if (!ours) {
|
|
567
|
+
kept.push(line);
|
|
568
|
+
continue;
|
|
569
|
+
}
|
|
570
|
+
kept.splice(-2, 2);
|
|
571
|
+
}
|
|
572
|
+
return kept.join('\n');
|
|
573
|
+
}
|
|
568
574
|
/**
|
|
569
575
|
* `text` without the `AGENTS.md` line THE PLATFORM WROTE — under its own
|
|
570
576
|
* comment (either spelling), or in the slot at the end of the template's own
|
|
571
577
|
* repo-hygiene block ({@link TEMPLATE_HYGIENE_BLOCK_ABOVE_AGENTS_RULE}) — and
|
|
572
|
-
* without that comment.
|
|
573
|
-
*
|
|
574
|
-
* Called only when the guide has been renamed, which is what makes the line
|
|
575
|
-
* wrong: it hides a file the platform no longer owns. A `!AGENTS.md` negation
|
|
576
|
-
* is not the rule and stays, as everywhere else here.
|
|
578
|
+
* without that comment. A `!AGENTS.md` negation is not the rule and stays, as
|
|
579
|
+
* everywhere else here.
|
|
577
580
|
*/
|
|
578
581
|
export function withoutPlatformAgentsRule(text) {
|
|
579
582
|
const lines = text.split('\n');
|
|
@@ -601,17 +604,6 @@ export function withoutPlatformAgentsRule(text) {
|
|
|
601
604
|
}
|
|
602
605
|
return kept.join('\n');
|
|
603
606
|
}
|
|
604
|
-
/**
|
|
605
|
-
* `text` with the platform's pointer sentence appended as its own paragraph.
|
|
606
|
-
*
|
|
607
|
-
* One blank line between the customer's last line and ours, whether or not
|
|
608
|
-
* their file ended in a newline: a sentence glued onto the end of their last
|
|
609
|
-
* paragraph would read as a continuation of something they wrote.
|
|
610
|
-
*/
|
|
611
|
-
export function withPointerSentence(text, agentsFile) {
|
|
612
|
-
const body = text.replace(/\n+$/, '');
|
|
613
|
-
return `${body}\n\n${agentsFilePointerSentence(agentsFile)}\n`;
|
|
614
|
-
}
|
|
615
607
|
/** The comment written above the preamble rule on an existing knowledge base. */
|
|
616
608
|
const PREAMBLE_RULE_COMMENT = '# Added by the platform: agent instructions are edited from External agent access.';
|
|
617
609
|
/**
|
|
@@ -719,20 +711,14 @@ function withPlatformIgnorePatternRespelled(text, from, to) {
|
|
|
719
711
|
* still standing here is the operator's: it already hides the file, and
|
|
720
712
|
* appending the anchored rule beside it would say nothing they have not.
|
|
721
713
|
*/
|
|
722
|
-
function withIgnorePattern(text, pattern
|
|
714
|
+
function withIgnorePattern(text, pattern) {
|
|
723
715
|
const lines = text.split('\n').map((l) => l.trim());
|
|
724
716
|
const operatorPreambleRule = pattern === PREAMBLE_IGNORE_PATTERN &&
|
|
725
717
|
(lines.includes(PREAMBLE_FILE) || lines.includes(`!${PREAMBLE_FILE}`));
|
|
726
718
|
if (lines.includes(pattern) || lines.includes(`!${pattern}`) || operatorPreambleRule)
|
|
727
719
|
return text;
|
|
728
720
|
const separator = text.endsWith('\n') ? '' : '\n';
|
|
729
|
-
|
|
730
|
-
// needs it), so it is recognised in that spelling.
|
|
731
|
-
const comment = pattern === PREAMBLE_IGNORE_PATTERN
|
|
732
|
-
? PREAMBLE_RULE_COMMENT
|
|
733
|
-
: pattern === gitignoreLiteral(agentsFile)
|
|
734
|
-
? AGENTS_RULE_COMMENT
|
|
735
|
-
: PLATFORM_RULE_COMMENT;
|
|
721
|
+
const comment = pattern === PREAMBLE_IGNORE_PATTERN ? PREAMBLE_RULE_COMMENT : PLATFORM_RULE_COMMENT;
|
|
736
722
|
return `${text}${separator}\n${comment}\n${pattern}\n`;
|
|
737
723
|
}
|
|
738
724
|
//# sourceMappingURL=template-files.step.js.map
|