@seanmars/tospec 0.19.0-beta.6 → 0.19.0-beta.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +137 -0
- package/assets/dashboard/app.js +3 -3
- package/assets/rules/tospec/decision.md +3 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +205 -36
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +151 -23
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/dashboard.d.ts +34 -9
- package/dist/commands/dashboard.d.ts.map +1 -1
- package/dist/commands/dashboard.js +213 -21
- package/dist/commands/dashboard.js.map +1 -1
- package/dist/commands/decision.d.ts +11 -0
- package/dist/commands/decision.d.ts.map +1 -1
- package/dist/commands/decision.js +182 -20
- package/dist/commands/decision.js.map +1 -1
- package/dist/commands/shared-output.d.ts +12 -0
- package/dist/commands/shared-output.d.ts.map +1 -1
- package/dist/commands/shared-output.js +50 -1
- package/dist/commands/shared-output.js.map +1 -1
- package/dist/commands/show.d.ts +10 -0
- package/dist/commands/show.d.ts.map +1 -1
- package/dist/commands/show.js +23 -4
- package/dist/commands/show.js.map +1 -1
- package/dist/commands/validate.d.ts +41 -1
- package/dist/commands/validate.d.ts.map +1 -1
- package/dist/commands/validate.js +95 -17
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/workflow/index.d.ts +5 -5
- package/dist/commands/workflow/index.d.ts.map +1 -1
- package/dist/commands/workflow/index.js +5 -5
- package/dist/commands/workflow/index.js.map +1 -1
- package/dist/commands/workflow/instructions.d.ts +23 -0
- package/dist/commands/workflow/instructions.d.ts.map +1 -1
- package/dist/commands/workflow/instructions.js +84 -16
- package/dist/commands/workflow/instructions.js.map +1 -1
- package/dist/commands/workflow/new-change.d.ts +2 -0
- package/dist/commands/workflow/new-change.d.ts.map +1 -1
- package/dist/commands/workflow/new-change.js +32 -4
- package/dist/commands/workflow/new-change.js.map +1 -1
- package/dist/commands/workflow/schemas.d.ts +2 -0
- package/dist/commands/workflow/schemas.d.ts.map +1 -1
- package/dist/commands/workflow/schemas.js +38 -1
- package/dist/commands/workflow/schemas.js.map +1 -1
- package/dist/commands/workflow/shared.d.ts +34 -2
- package/dist/commands/workflow/shared.d.ts.map +1 -1
- package/dist/commands/workflow/shared.js +37 -3
- package/dist/commands/workflow/shared.js.map +1 -1
- package/dist/commands/workflow/status.d.ts +14 -0
- package/dist/commands/workflow/status.d.ts.map +1 -1
- package/dist/commands/workflow/status.js +65 -8
- package/dist/commands/workflow/status.js.map +1 -1
- package/dist/commands/workflow/templates.d.ts +7 -0
- package/dist/commands/workflow/templates.d.ts.map +1 -1
- package/dist/commands/workflow/templates.js +13 -0
- package/dist/commands/workflow/templates.js.map +1 -1
- package/dist/core/archive.d.ts +14 -0
- package/dist/core/archive.d.ts.map +1 -1
- package/dist/core/archive.js +169 -18
- package/dist/core/archive.js.map +1 -1
- package/dist/core/artifact-graph/graph.d.ts +13 -3
- package/dist/core/artifact-graph/graph.d.ts.map +1 -1
- package/dist/core/artifact-graph/graph.js +16 -6
- package/dist/core/artifact-graph/graph.js.map +1 -1
- package/dist/core/artifact-graph/index.d.ts +1 -1
- package/dist/core/artifact-graph/index.d.ts.map +1 -1
- package/dist/core/artifact-graph/index.js +1 -1
- package/dist/core/artifact-graph/index.js.map +1 -1
- package/dist/core/artifact-graph/instruction-loader.d.ts +74 -3
- package/dist/core/artifact-graph/instruction-loader.d.ts.map +1 -1
- package/dist/core/artifact-graph/instruction-loader.js +79 -31
- package/dist/core/artifact-graph/instruction-loader.js.map +1 -1
- package/dist/core/artifact-graph/resolver.d.ts +26 -0
- package/dist/core/artifact-graph/resolver.d.ts.map +1 -1
- package/dist/core/artifact-graph/resolver.js +44 -4
- package/dist/core/artifact-graph/resolver.js.map +1 -1
- package/dist/core/artifact-graph/stub-detection.d.ts +20 -0
- package/dist/core/artifact-graph/stub-detection.d.ts.map +1 -0
- package/dist/core/artifact-graph/stub-detection.js +42 -0
- package/dist/core/artifact-graph/stub-detection.js.map +1 -0
- package/dist/core/change-presenter.d.ts +16 -0
- package/dist/core/change-presenter.d.ts.map +1 -1
- package/dist/core/change-presenter.js +68 -9
- package/dist/core/change-presenter.js.map +1 -1
- package/dist/core/change-status-policy.d.ts +12 -1
- package/dist/core/change-status-policy.d.ts.map +1 -1
- package/dist/core/change-status-policy.js +33 -1
- package/dist/core/change-status-policy.js.map +1 -1
- package/dist/core/codex-residue.js +1 -1
- package/dist/core/config-schema.d.ts +1 -12
- package/dist/core/config-schema.d.ts.map +1 -1
- package/dist/core/config-schema.js +27 -1
- package/dist/core/config-schema.js.map +1 -1
- package/dist/core/config.d.ts +37 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +37 -0
- package/dist/core/config.js.map +1 -1
- package/dist/core/dashboard-activity.js +2 -2
- package/dist/core/dashboard-activity.js.map +1 -1
- package/dist/core/dashboard-data.d.ts +5 -0
- package/dist/core/dashboard-data.d.ts.map +1 -1
- package/dist/core/dashboard-data.js +15 -8
- package/dist/core/dashboard-data.js.map +1 -1
- package/dist/core/init.d.ts +22 -0
- package/dist/core/init.d.ts.map +1 -1
- package/dist/core/init.js +107 -45
- package/dist/core/init.js.map +1 -1
- package/dist/core/list.d.ts +1 -1
- package/dist/core/list.d.ts.map +1 -1
- package/dist/core/list.js +68 -17
- package/dist/core/list.js.map +1 -1
- package/dist/core/markdown-render.d.ts +33 -0
- package/dist/core/markdown-render.d.ts.map +1 -0
- package/dist/core/markdown-render.js +103 -0
- package/dist/core/markdown-render.js.map +1 -0
- package/dist/core/migrate.d.ts +20 -6
- package/dist/core/migrate.d.ts.map +1 -1
- package/dist/core/migrate.js +102 -6
- package/dist/core/migrate.js.map +1 -1
- package/dist/core/parsers/change-parser.js +1 -1
- package/dist/core/parsers/change-parser.js.map +1 -1
- package/dist/core/parsers/markdown-parser.d.ts.map +1 -1
- package/dist/core/parsers/markdown-parser.js +16 -0
- package/dist/core/parsers/markdown-parser.js.map +1 -1
- package/dist/core/parsers/requirement-blocks.js +32 -9
- package/dist/core/parsers/requirement-blocks.js.map +1 -1
- package/dist/core/root-selection.d.ts +11 -1
- package/dist/core/root-selection.d.ts.map +1 -1
- package/dist/core/root-selection.js +4 -2
- package/dist/core/root-selection.js.map +1 -1
- package/dist/core/rules.d.ts +6 -1
- package/dist/core/rules.d.ts.map +1 -1
- package/dist/core/rules.js +24 -2
- package/dist/core/rules.js.map +1 -1
- package/dist/core/schemas/base.schema.d.ts +3 -0
- package/dist/core/schemas/base.schema.d.ts.map +1 -1
- package/dist/core/schemas/base.schema.js +22 -0
- package/dist/core/schemas/base.schema.js.map +1 -1
- package/dist/core/schemas/change.schema.d.ts +8 -0
- package/dist/core/schemas/change.schema.d.ts.map +1 -1
- package/dist/core/schemas/spec.schema.d.ts +2 -0
- package/dist/core/schemas/spec.schema.d.ts.map +1 -1
- package/dist/core/shared/index.d.ts +1 -1
- package/dist/core/shared/index.d.ts.map +1 -1
- package/dist/core/shared/index.js +1 -1
- package/dist/core/shared/index.js.map +1 -1
- package/dist/core/shared/rules-generation.d.ts +27 -6
- package/dist/core/shared/rules-generation.d.ts.map +1 -1
- package/dist/core/shared/rules-generation.js +115 -44
- package/dist/core/shared/rules-generation.js.map +1 -1
- package/dist/core/shared/tool-detection.d.ts +19 -0
- package/dist/core/shared/tool-detection.d.ts.map +1 -1
- package/dist/core/shared/tool-detection.js +30 -2
- package/dist/core/shared/tool-detection.js.map +1 -1
- package/dist/core/spec-presenter.d.ts.map +1 -1
- package/dist/core/spec-presenter.js +5 -0
- package/dist/core/spec-presenter.js.map +1 -1
- package/dist/core/specs-apply.d.ts +15 -1
- package/dist/core/specs-apply.d.ts.map +1 -1
- package/dist/core/specs-apply.js +33 -11
- package/dist/core/specs-apply.js.map +1 -1
- package/dist/core/templates/workflows/apply.js +1 -1
- package/dist/core/templates/workflows/apply.js.map +1 -1
- package/dist/core/templates/workflows/archive.d.ts.map +1 -1
- package/dist/core/templates/workflows/archive.js +4 -2
- package/dist/core/templates/workflows/archive.js.map +1 -1
- package/dist/core/templates/workflows/decision.js +1 -1
- package/dist/core/templates/workflows/issue.d.ts.map +1 -1
- package/dist/core/templates/workflows/issue.js +3 -0
- package/dist/core/templates/workflows/issue.js.map +1 -1
- package/dist/core/update.d.ts +26 -0
- package/dist/core/update.d.ts.map +1 -1
- package/dist/core/update.js +111 -23
- package/dist/core/update.js.map +1 -1
- package/dist/core/validation/constants.d.ts +1 -1
- package/dist/core/validation/constants.d.ts.map +1 -1
- package/dist/core/validation/constants.js +6 -1
- package/dist/core/validation/constants.js.map +1 -1
- package/dist/core/validation/section-validator.d.ts.map +1 -1
- package/dist/core/validation/section-validator.js +21 -3
- package/dist/core/validation/section-validator.js.map +1 -1
- package/dist/core/validation/validator.d.ts +17 -4
- package/dist/core/validation/validator.d.ts.map +1 -1
- package/dist/core/validation/validator.js +120 -34
- package/dist/core/validation/validator.js.map +1 -1
- package/dist/utils/change-utils.d.ts +31 -2
- package/dist/utils/change-utils.d.ts.map +1 -1
- package/dist/utils/change-utils.js +127 -37
- package/dist/utils/change-utils.js.map +1 -1
- package/dist/utils/file-system.d.ts +1 -1
- package/dist/utils/file-system.js +1 -1
- package/dist/utils/item-discovery.d.ts +20 -5
- package/dist/utils/item-discovery.d.ts.map +1 -1
- package/dist/utils/item-discovery.js +28 -9
- package/dist/utils/item-discovery.js.map +1 -1
- package/dist/utils/spec-files.d.ts +12 -0
- package/dist/utils/spec-files.d.ts.map +1 -1
- package/dist/utils/spec-files.js +34 -0
- package/dist/utils/spec-files.js.map +1 -1
- package/dist/utils/task-progress.js +1 -1
- package/package.json +1 -1
- package/schemas/decision/templates/decision.md +3 -1
- package/schemas/decision/templates/index.md +2 -2
- package/schemas/issue/schema.yaml +4 -2
- package/schemas/issue/templates/spec.md +20 -2
- package/schemas/sdd/schema.yaml +4 -0
- package/schemas/sdd/templates/spec.md +20 -2
- /package/assets/rules/tospec/{single-sourc-of-truth.md → single-source-of-truth.md} +0 -0
package/dist/core/rules.js
CHANGED
|
@@ -3,20 +3,42 @@ import { FileSystemUtils } from '../utils/file-system.js';
|
|
|
3
3
|
import { TOSPEC_DIR_NAME } from './config.js';
|
|
4
4
|
import { getConfiguredTools } from './shared/tool-detection.js';
|
|
5
5
|
import { planWorkflowRules, writeWorkflowRules } from './shared/rules-generation.js';
|
|
6
|
+
import { emitSuccess } from '../commands/shared-output.js';
|
|
7
|
+
/** The `--json` null-shape; mirrors the success payload with `rules` nulled. */
|
|
8
|
+
export const RULES_FAILURE_PAYLOAD = { rules: null, root: null };
|
|
6
9
|
/** Refresh only the workflow rule files of agents already configured for tospec. */
|
|
7
10
|
export class RulesCommand {
|
|
8
|
-
async execute(targetPath) {
|
|
11
|
+
async execute(targetPath, options = {}) {
|
|
9
12
|
const projectPath = path.resolve(targetPath);
|
|
10
13
|
if (!await FileSystemUtils.directoryExists(path.join(projectPath, TOSPEC_DIR_NAME))) {
|
|
11
14
|
throw new Error("No Tospec directory found. Run 'tospec init' first.");
|
|
12
15
|
}
|
|
13
16
|
const tools = getConfiguredTools(projectPath);
|
|
14
17
|
if (tools.length === 0) {
|
|
18
|
+
// Not an error: a project can legitimately have no agent configured. The
|
|
19
|
+
// JSON form says so with an empty list rather than prose, so a caller does
|
|
20
|
+
// not have to tell "nothing to do" from "something went wrong" by reading
|
|
21
|
+
// English.
|
|
22
|
+
if (options.json) {
|
|
23
|
+
emitSuccess({ rules: [], message: 'No configured tools found.' }, { path: projectPath, source: 'explicit' });
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
15
26
|
console.log('No configured tools found. Run "tospec init" to set up tools.');
|
|
16
27
|
return;
|
|
17
28
|
}
|
|
18
29
|
const plan = await planWorkflowRules(projectPath, tools);
|
|
19
|
-
await writeWorkflowRules(plan);
|
|
30
|
+
await writeWorkflowRules(plan, { silent: options.json });
|
|
31
|
+
if (options.json) {
|
|
32
|
+
emitSuccess({
|
|
33
|
+
rules: plan.map((entry) => ({
|
|
34
|
+
tool: entry.toolId,
|
|
35
|
+
rule: entry.rule,
|
|
36
|
+
path: entry.destination,
|
|
37
|
+
action: entry.action,
|
|
38
|
+
...(entry.retire ? { retiredPath: entry.retire } : {}),
|
|
39
|
+
})),
|
|
40
|
+
}, { path: projectPath, source: 'explicit' });
|
|
41
|
+
}
|
|
20
42
|
}
|
|
21
43
|
}
|
|
22
44
|
//# sourceMappingURL=rules.js.map
|
package/dist/core/rules.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.js","sourceRoot":"","sources":["../../src/core/rules.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"rules.js","sourceRoot":"","sources":["../../src/core/rules.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AACrF,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAM3D,gFAAgF;AAChF,MAAM,CAAC,MAAM,qBAAqB,GAA4B,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AAE1F,oFAAoF;AACpF,MAAM,OAAO,YAAY;IACvB,KAAK,CAAC,OAAO,CAAC,UAAkB,EAAE,OAAO,GAAwB,EAAE;QACjE,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAC7C,IAAI,CAAC,MAAM,eAAe,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC;YACpF,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;QACzE,CAAC;QACD,MAAM,KAAK,GAAG,kBAAkB,CAAC,WAAW,CAAC,CAAC;QAC9C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,yEAAyE;YACzE,2EAA2E;YAC3E,0EAA0E;YAC1E,WAAW;YACX,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;gBACjB,WAAW,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,4BAA4B,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;gBAC7G,OAAO;YACT,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,+DAA+D,CAAC,CAAC;YAC7E,OAAO;QACT,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QACzD,MAAM,kBAAkB,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QAEzD,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,WAAW,CACT;gBACE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;oBAC1B,IAAI,EAAE,KAAK,CAAC,MAAM;oBAClB,IAAI,EAAE,KAAK,CAAC,IAAI;oBAChB,IAAI,EAAE,KAAK,CAAC,WAAW;oBACvB,MAAM,EAAE,KAAK,CAAC,MAAM;oBACpB,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBACvD,CAAC,CAAC;aACJ,EACD,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,CAC1C,CAAC;QACJ,CAAC;IACH,CAAC;CACF"}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
export declare const ScenarioSchema: z.ZodObject<{
|
|
3
|
+
name: z.ZodOptional<z.ZodString>;
|
|
3
4
|
rawText: z.ZodString;
|
|
4
5
|
}, z.core.$strip>;
|
|
5
6
|
export declare const RequirementSchema: z.ZodObject<{
|
|
7
|
+
name: z.ZodOptional<z.ZodString>;
|
|
6
8
|
text: z.ZodString;
|
|
7
9
|
scenarios: z.ZodArray<z.ZodObject<{
|
|
10
|
+
name: z.ZodOptional<z.ZodString>;
|
|
8
11
|
rawText: z.ZodString;
|
|
9
12
|
}, z.core.$strip>>;
|
|
10
13
|
}, z.core.$strip>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.schema.d.ts","sourceRoot":"","sources":["../../../src/core/schemas/base.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,cAAc
|
|
1
|
+
{"version":3,"file":"base.schema.d.ts","sourceRoot":"","sources":["../../../src/core/schemas/base.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,cAAc;;;iBASzB,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;;;;;iBA0B5B,CAAC;AAEH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AACtD,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC"}
|
|
@@ -1,9 +1,31 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { VALIDATION_MESSAGES } from '../validation/constants.js';
|
|
3
3
|
export const ScenarioSchema = z.object({
|
|
4
|
+
/**
|
|
5
|
+
* The `#### Scenario: <name>` heading text, without the `Scenario:` prefix.
|
|
6
|
+
*
|
|
7
|
+
* Optional only so a hand-built Scenario in a test or a future caller does
|
|
8
|
+
* not have to invent one; every parsed scenario carries it.
|
|
9
|
+
*/
|
|
10
|
+
name: z.string().optional(),
|
|
4
11
|
rawText: z.string().min(1, VALIDATION_MESSAGES.SCENARIO_EMPTY),
|
|
5
12
|
});
|
|
6
13
|
export const RequirementSchema = z.object({
|
|
14
|
+
/**
|
|
15
|
+
* The `### Requirement: <name>` heading text, without the `Requirement:`
|
|
16
|
+
* prefix.
|
|
17
|
+
*
|
|
18
|
+
* Carried rather than discarded because this string is load-bearing: a
|
|
19
|
+
* MODIFIED, REMOVED or RENAMED delta must reproduce the header exactly, and
|
|
20
|
+
* archive hard-fails on a mismatch. While `show --json` reported only `text`,
|
|
21
|
+
* the one command an agent would use to read the current spec withheld the
|
|
22
|
+
* single field needed to write a delta against it, forcing a fall back to
|
|
23
|
+
* parsing raw Markdown.
|
|
24
|
+
*
|
|
25
|
+
* Optional in the schema so a hand-built Requirement need not supply one;
|
|
26
|
+
* every parsed requirement carries it.
|
|
27
|
+
*/
|
|
28
|
+
name: z.string().optional(),
|
|
7
29
|
// SHALL/MUST body-keyword enforcement lives in the imperative validator
|
|
8
30
|
// (Validator.applySpecRules), not here: the parser collapses the requirement
|
|
9
31
|
// header into `text`, so a Zod refine on `text` cannot tell "keyword in header
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.schema.js","sourceRoot":"","sources":["../../../src/core/schemas/base.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEjE,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,mBAAmB,CAAC,cAAc,CAAC;CAC/D,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,wEAAwE;IACxE,6EAA6E;IAC7E,+EAA+E;IAC/E,yEAAyE;IACzE,yEAAyE;IACzE,4CAA4C;IAC5C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;SACb,GAAG,CAAC,CAAC,EAAE,mBAAmB,CAAC,iBAAiB,CAAC;IAChD,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC;SAC/B,GAAG,CAAC,CAAC,EAAE,mBAAmB,CAAC,wBAAwB,CAAC;CACxD,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"base.schema.js","sourceRoot":"","sources":["../../../src/core/schemas/base.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEjE,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC;;;;;OAKG;IACH,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,mBAAmB,CAAC,cAAc,CAAC;CAC/D,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC;;;;;;;;;;;;;OAaG;IACH,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,wEAAwE;IACxE,6EAA6E;IAC7E,+EAA+E;IAC/E,yEAAyE;IACzE,yEAAyE;IACzE,4CAA4C;IAC5C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;SACb,GAAG,CAAC,CAAC,EAAE,mBAAmB,CAAC,iBAAiB,CAAC;IAChD,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC;SAC/B,GAAG,CAAC,CAAC,EAAE,mBAAmB,CAAC,wBAAwB,CAAC;CACxD,CAAC,CAAC"}
|
|
@@ -15,14 +15,18 @@ export declare const DeltaSchema: z.ZodObject<{
|
|
|
15
15
|
}>;
|
|
16
16
|
description: z.ZodString;
|
|
17
17
|
requirement: z.ZodOptional<z.ZodObject<{
|
|
18
|
+
name: z.ZodOptional<z.ZodString>;
|
|
18
19
|
text: z.ZodString;
|
|
19
20
|
scenarios: z.ZodArray<z.ZodObject<{
|
|
21
|
+
name: z.ZodOptional<z.ZodString>;
|
|
20
22
|
rawText: z.ZodString;
|
|
21
23
|
}, z.core.$strip>>;
|
|
22
24
|
}, z.core.$strip>>;
|
|
23
25
|
requirements: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
26
|
+
name: z.ZodOptional<z.ZodString>;
|
|
24
27
|
text: z.ZodString;
|
|
25
28
|
scenarios: z.ZodArray<z.ZodObject<{
|
|
29
|
+
name: z.ZodOptional<z.ZodString>;
|
|
26
30
|
rawText: z.ZodString;
|
|
27
31
|
}, z.core.$strip>>;
|
|
28
32
|
}, z.core.$strip>>>;
|
|
@@ -45,14 +49,18 @@ export declare const ChangeSchema: z.ZodObject<{
|
|
|
45
49
|
}>;
|
|
46
50
|
description: z.ZodString;
|
|
47
51
|
requirement: z.ZodOptional<z.ZodObject<{
|
|
52
|
+
name: z.ZodOptional<z.ZodString>;
|
|
48
53
|
text: z.ZodString;
|
|
49
54
|
scenarios: z.ZodArray<z.ZodObject<{
|
|
55
|
+
name: z.ZodOptional<z.ZodString>;
|
|
50
56
|
rawText: z.ZodString;
|
|
51
57
|
}, z.core.$strip>>;
|
|
52
58
|
}, z.core.$strip>>;
|
|
53
59
|
requirements: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
60
|
+
name: z.ZodOptional<z.ZodString>;
|
|
54
61
|
text: z.ZodString;
|
|
55
62
|
scenarios: z.ZodArray<z.ZodObject<{
|
|
63
|
+
name: z.ZodOptional<z.ZodString>;
|
|
56
64
|
rawText: z.ZodString;
|
|
57
65
|
}, z.core.$strip>>;
|
|
58
66
|
}, z.core.$strip>>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"change.schema.d.ts","sourceRoot":"","sources":["../../../src/core/schemas/change.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AASxB,eAAO,MAAM,kBAAkB;;;;;EAAsD,CAAC;AAEtF,eAAO,MAAM,WAAW
|
|
1
|
+
{"version":3,"file":"change.schema.d.ts","sourceRoot":"","sources":["../../../src/core/schemas/change.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AASxB,eAAO,MAAM,kBAAkB;;;;;EAAsD,CAAC;AAEtF,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAUtB,CAAC;AAEH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAcvB,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAChE,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAChD,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC"}
|
|
@@ -3,8 +3,10 @@ export declare const SpecSchema: z.ZodObject<{
|
|
|
3
3
|
name: z.ZodString;
|
|
4
4
|
overview: z.ZodString;
|
|
5
5
|
requirements: z.ZodArray<z.ZodObject<{
|
|
6
|
+
name: z.ZodOptional<z.ZodString>;
|
|
6
7
|
text: z.ZodString;
|
|
7
8
|
scenarios: z.ZodArray<z.ZodObject<{
|
|
9
|
+
name: z.ZodOptional<z.ZodString>;
|
|
8
10
|
rawText: z.ZodString;
|
|
9
11
|
}, z.core.$strip>>;
|
|
10
12
|
}, z.core.$strip>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spec.schema.d.ts","sourceRoot":"","sources":["../../../src/core/schemas/spec.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,UAAU
|
|
1
|
+
{"version":3,"file":"spec.schema.d.ts","sourceRoot":"","sources":["../../../src/core/schemas/spec.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;iBAUrB,CAAC;AAEH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC"}
|
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export { SKILL_NAMES, LEGACY_SKILL_DIRS, type ToolSkillStatus, type ToolVersionStatus, removeLegacySkillDirs, removeLegacyToolSkillLayout, getToolsWithSkillsDir, getToolSkillStatus, getToolStates, extractGeneratedByVersion, getToolVersionStatus, getConfiguredTools, } from './tool-detection.js';
|
|
7
7
|
export { type SkillTemplateEntry, type CommandTemplateEntry, getSkillTemplates, getCommandTemplates, getCommandContents, generateSkillContent, writeSkillDir, writeToolCommands, } from './skill-generation.js';
|
|
8
|
-
export {
|
|
8
|
+
export { planWorkflowRules, writeWorkflowRules } from './rules-generation.js';
|
|
9
9
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/shared/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,qBAAqB,EACrB,2BAA2B,EAC3B,qBAAqB,EACrB,kBAAkB,EAClB,aAAa,EACb,yBAAyB,EACzB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,EACpB,aAAa,EACb,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/shared/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,qBAAqB,EACrB,2BAA2B,EAC3B,qBAAqB,EACrB,kBAAkB,EAClB,aAAa,EACb,yBAAyB,EACzB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,EACpB,aAAa,EACb,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export { SKILL_NAMES, LEGACY_SKILL_DIRS, removeLegacySkillDirs, removeLegacyToolSkillLayout, getToolsWithSkillsDir, getToolSkillStatus, getToolStates, extractGeneratedByVersion, getToolVersionStatus, getConfiguredTools, } from './tool-detection.js';
|
|
7
7
|
export { getSkillTemplates, getCommandTemplates, getCommandContents, generateSkillContent, writeSkillDir, writeToolCommands, } from './skill-generation.js';
|
|
8
|
-
export {
|
|
8
|
+
export { planWorkflowRules, writeWorkflowRules } from './rules-generation.js';
|
|
9
9
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/shared/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,WAAW,EACX,iBAAiB,EAGjB,qBAAqB,EACrB,2BAA2B,EAC3B,qBAAqB,EACrB,kBAAkB,EAClB,aAAa,EACb,yBAAyB,EACzB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAGL,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,EACpB,aAAa,EACb,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/shared/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,WAAW,EACX,iBAAiB,EAGjB,qBAAqB,EACrB,2BAA2B,EAC3B,qBAAqB,EACrB,kBAAkB,EAClB,aAAa,EACb,yBAAyB,EACzB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAGL,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,EACpB,aAAa,EACb,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -1,19 +1,40 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Rules Generation
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Every rule document tospec writes is managed the same way: a shipped Markdown
|
|
5
|
+
* template, wrapped in a hash-stamped marker, planned read-only before any
|
|
6
|
+
* project write, and refused rather than overwritten once somebody has edited it.
|
|
7
|
+
*
|
|
8
|
+
* `decision.md` used to be the exception — an init-only writer that overwrote it
|
|
9
|
+
* unconditionally, with no marker to tell a generated file from an edited one and
|
|
10
|
+
* no entry in what `rules`/`update` reported. Editing it therefore lost the edit
|
|
11
|
+
* on the next `tospec init`, silently, in the default path, while its sibling in
|
|
12
|
+
* the same directory refused even `--force`. Two standards in one directory teach
|
|
13
|
+
* the safer one and then break it, so there is now only one.
|
|
6
14
|
*/
|
|
7
|
-
/** Write tospec rule files into `<projectPath>/<agentBaseDir>/rules/` for one tool. */
|
|
8
|
-
export declare function writeToolRules(projectPath: string, agentBaseDir: string): Promise<void>;
|
|
9
15
|
export interface WorkflowRulePlan {
|
|
10
16
|
toolId: string;
|
|
17
|
+
/** Which managed rule this entry writes; distinguishes a tool's entries. */
|
|
18
|
+
rule: string;
|
|
11
19
|
destination: string;
|
|
12
20
|
content: string;
|
|
13
21
|
action: 'created' | 'updated' | 'unchanged';
|
|
22
|
+
/**
|
|
23
|
+
* A copy under the previous misspelled filename to delete after the write.
|
|
24
|
+
* Absent unless one is there and is verifiably tospec-generated.
|
|
25
|
+
*/
|
|
26
|
+
retire?: string;
|
|
14
27
|
}
|
|
15
28
|
/** Read every target before allowing any project mutation. */
|
|
16
29
|
export declare function planWorkflowRules(projectPath: string, toolIds: string[]): Promise<WorkflowRulePlan[]>;
|
|
17
|
-
/**
|
|
18
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Call only after the complete plan passed preflight.
|
|
32
|
+
*
|
|
33
|
+
* `silent` suppresses the progress prose for a `--json` caller, which reports
|
|
34
|
+
* the same facts from the plan itself — prose on stdout would break the
|
|
35
|
+
* one-document envelope.
|
|
36
|
+
*/
|
|
37
|
+
export declare function writeWorkflowRules(plan: WorkflowRulePlan[], options?: {
|
|
38
|
+
silent?: boolean;
|
|
39
|
+
}): Promise<void>;
|
|
19
40
|
//# sourceMappingURL=rules-generation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules-generation.d.ts","sourceRoot":"","sources":["../../../src/core/shared/rules-generation.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"rules-generation.d.ts","sourceRoot":"","sources":["../../../src/core/shared/rules-generation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAoEH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,CAAC;IAC5C;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAkCD,8DAA8D;AAC9D,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA8D3G;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,gBAAgB,EAAE,EACxB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACjC,OAAO,CAAC,IAAI,CAAC,CAuBf"}
|
|
@@ -1,95 +1,166 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Rules Generation
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Every rule document tospec writes is managed the same way: a shipped Markdown
|
|
5
|
+
* template, wrapped in a hash-stamped marker, planned read-only before any
|
|
6
|
+
* project write, and refused rather than overwritten once somebody has edited it.
|
|
7
|
+
*
|
|
8
|
+
* `decision.md` used to be the exception — an init-only writer that overwrote it
|
|
9
|
+
* unconditionally, with no marker to tell a generated file from an edited one and
|
|
10
|
+
* no entry in what `rules`/`update` reported. Editing it therefore lost the edit
|
|
11
|
+
* on the next `tospec init`, silently, in the default path, while its sibling in
|
|
12
|
+
* the same directory refused even `--force`. Two standards in one directory teach
|
|
13
|
+
* the safer one and then break it, so there is now only one.
|
|
6
14
|
*/
|
|
7
15
|
import path from 'node:path';
|
|
8
16
|
import { promises as fs } from 'node:fs';
|
|
9
17
|
import { createHash } from 'node:crypto';
|
|
10
|
-
import { AI_TOOLS, CODEX_TARGET_ID } from '../config.js';
|
|
18
|
+
import { AI_TOOLS, CODEX_TARGET_ID, DECISION_RULE_FILENAME, LEGACY_WORKFLOW_RULE_FILENAME, TOOL_RULES_SUBDIR, WORKFLOW_RULE_FILENAME, } from '../config.js';
|
|
11
19
|
import { FileSystemUtils } from '../../utils/file-system.js';
|
|
12
|
-
|
|
13
|
-
|
|
20
|
+
/**
|
|
21
|
+
* The exact text the init-only writer produced. Kept verbatim — not regenerated
|
|
22
|
+
* from the template — because its only job is to recognise files already on disk.
|
|
23
|
+
* If the shipped body ever changes, this string must not follow it.
|
|
24
|
+
*/
|
|
25
|
+
const UNMARKED_DECISION_RULE = `# Decision
|
|
14
26
|
|
|
15
27
|
Any material decision reached during discussion must be recorded with /tospec-decision, which creates a decision file and captures the relevant decision details.
|
|
16
28
|
`;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
29
|
+
const MANAGED_RULES = [
|
|
30
|
+
{
|
|
31
|
+
filename: WORKFLOW_RULE_FILENAME,
|
|
32
|
+
slug: 'single-source-of-truth',
|
|
33
|
+
templateUrl: new URL('../../../assets/rules/tospec/single-source-of-truth.md', import.meta.url),
|
|
34
|
+
// Carries the same `sourc` typo as the filename it was written beside.
|
|
35
|
+
legacySlugs: ['single-sourc-of-truth'],
|
|
36
|
+
legacyFilename: LEGACY_WORKFLOW_RULE_FILENAME,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
filename: DECISION_RULE_FILENAME,
|
|
40
|
+
slug: 'decision',
|
|
41
|
+
templateUrl: new URL('../../../assets/rules/tospec/decision.md', import.meta.url),
|
|
42
|
+
unmarkedLegacyBodies: [UNMARKED_DECISION_RULE],
|
|
43
|
+
},
|
|
20
44
|
];
|
|
21
|
-
/** Write tospec rule files into `<projectPath>/<agentBaseDir>/rules/` for one tool. */
|
|
22
|
-
export async function writeToolRules(projectPath, agentBaseDir) {
|
|
23
|
-
for (const rule of RULE_FILES) {
|
|
24
|
-
const dest = path.join(projectPath, agentBaseDir, 'rules', rule.relPath);
|
|
25
|
-
await FileSystemUtils.writeFile(dest, rule.content); // auto-creates parent dirs
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
const TEMPLATE_URL = new URL('../../../assets/rules/tospec/single-sourc-of-truth.md', import.meta.url);
|
|
29
|
-
const RULE_NAME = 'single-sourc-of-truth.md';
|
|
30
|
-
const END_MARKER = '<!-- /tospec:single-sourc-of-truth -->';
|
|
31
|
-
const MANAGED_DOCUMENT = /^<!-- tospec:single-sourc-of-truth:v1 sha256=([a-f0-9]{64}) -->\n([\s\S]*\n)<!-- \/tospec:single-sourc-of-truth -->\n$/;
|
|
32
45
|
function normalizeNewlines(content) {
|
|
33
46
|
return content.replace(/\r\n/g, '\n');
|
|
34
47
|
}
|
|
35
48
|
function bodyHash(body) {
|
|
36
49
|
return createHash('sha256').update(body, 'utf8').digest('hex');
|
|
37
50
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
51
|
+
const managedDocumentPattern = (slug) => new RegExp(`^<!-- tospec:${slug}:v1 sha256=([a-f0-9]{64}) -->\\n([\\s\\S]*\\n)<!-- \\/tospec:${slug} -->\\n$`);
|
|
52
|
+
/**
|
|
53
|
+
* Whether the file is an untouched tospec-generated rule document.
|
|
54
|
+
*
|
|
55
|
+
* Every slug this rule has ever used is accepted, and so is any unmarked body a
|
|
56
|
+
* previous tospec wrote: refusing either would turn a routine `tospec update`
|
|
57
|
+
* into a rule conflict for every project that predates the change.
|
|
58
|
+
*/
|
|
59
|
+
function isIntactDocument(rule, content) {
|
|
60
|
+
if (rule.unmarkedLegacyBodies?.some((body) => content === body))
|
|
61
|
+
return true;
|
|
62
|
+
return [rule.slug, ...(rule.legacySlugs ?? [])].some((slug) => {
|
|
63
|
+
const match = managedDocumentPattern(slug).exec(content);
|
|
64
|
+
// A dedicated file has exactly one frame; never silently drop text outside it.
|
|
65
|
+
return match !== null && match[0] === content
|
|
66
|
+
&& !match[2].includes(`<!-- tospec:${slug}:`)
|
|
67
|
+
&& !match[2].includes(`<!-- /tospec:${slug} -->`)
|
|
68
|
+
&& bodyHash(match[2]) === match[1];
|
|
69
|
+
});
|
|
45
70
|
}
|
|
46
71
|
/** Read every target before allowing any project mutation. */
|
|
47
72
|
export async function planWorkflowRules(projectPath, toolIds) {
|
|
48
73
|
if (toolIds.length === 0)
|
|
49
74
|
return [];
|
|
50
|
-
const
|
|
51
|
-
const
|
|
52
|
-
|
|
75
|
+
const contents = new Map();
|
|
76
|
+
for (const rule of MANAGED_RULES) {
|
|
77
|
+
const body = normalizeNewlines(await fs.readFile(rule.templateUrl, 'utf8')).replace(/\n*$/, '\n');
|
|
78
|
+
contents.set(rule.filename, `<!-- tospec:${rule.slug}:v1 sha256=${bodyHash(body)} -->\n${body}<!-- /tospec:${rule.slug} -->\n`);
|
|
79
|
+
}
|
|
53
80
|
const plan = [];
|
|
54
81
|
const conflicts = [];
|
|
55
|
-
|
|
56
|
-
const tool = AI_TOOLS.find((tool) => tool.value === toolId);
|
|
57
|
-
if (!tool?.skillsDir)
|
|
58
|
-
throw new Error(`Unknown rule target: ${toolId}`);
|
|
59
|
-
const destination = path.join(projectPath, tool.skillsDir, 'rules', 'tospec', RULE_NAME);
|
|
60
|
-
let previous;
|
|
82
|
+
const readIfPresent = async (file) => {
|
|
61
83
|
try {
|
|
62
|
-
|
|
84
|
+
return normalizeNewlines(await fs.readFile(file, 'utf8'));
|
|
63
85
|
}
|
|
64
86
|
catch (error) {
|
|
65
87
|
if (error.code !== 'ENOENT')
|
|
66
88
|
throw error;
|
|
89
|
+
return undefined;
|
|
67
90
|
}
|
|
68
|
-
|
|
69
|
-
|
|
91
|
+
};
|
|
92
|
+
for (const toolId of toolIds) {
|
|
93
|
+
const tool = AI_TOOLS.find((tool) => tool.value === toolId);
|
|
94
|
+
if (!tool?.skillsDir)
|
|
95
|
+
throw new Error(`Unknown rule target: ${toolId}`);
|
|
96
|
+
const rulesDir = path.join(projectPath, tool.skillsDir, ...TOOL_RULES_SUBDIR);
|
|
97
|
+
for (const rule of MANAGED_RULES) {
|
|
98
|
+
const content = contents.get(rule.filename);
|
|
99
|
+
const destination = path.join(rulesDir, rule.filename);
|
|
100
|
+
const previous = await readIfPresent(destination);
|
|
101
|
+
if (previous !== undefined && !isIntactDocument(rule, previous)) {
|
|
102
|
+
conflicts.push(destination);
|
|
103
|
+
}
|
|
104
|
+
let retire;
|
|
105
|
+
if (rule.legacyFilename) {
|
|
106
|
+
const legacy = path.join(rulesDir, rule.legacyFilename);
|
|
107
|
+
const legacyPrevious = await readIfPresent(legacy);
|
|
108
|
+
if (legacyPrevious !== undefined) {
|
|
109
|
+
// An edited copy under the old name is left exactly where it is and
|
|
110
|
+
// reported, not deleted: the rename is tospec's housekeeping, and it
|
|
111
|
+
// must not be the reason somebody's notes disappear. Removing it by
|
|
112
|
+
// hand is the same one-step fix the conflict message already asks for.
|
|
113
|
+
if (isIntactDocument(rule, legacyPrevious))
|
|
114
|
+
retire = legacy;
|
|
115
|
+
else
|
|
116
|
+
conflicts.push(legacy);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
plan.push({
|
|
120
|
+
toolId,
|
|
121
|
+
rule: rule.filename,
|
|
122
|
+
destination,
|
|
123
|
+
content,
|
|
124
|
+
action: previous === undefined ? 'created' : previous === content ? 'unchanged' : 'updated',
|
|
125
|
+
...(retire ? { retire } : {}),
|
|
126
|
+
});
|
|
70
127
|
}
|
|
71
|
-
plan.push({ toolId, destination, content,
|
|
72
|
-
action: previous === undefined ? 'created' : previous === content ? 'unchanged' : 'updated' });
|
|
73
128
|
}
|
|
74
129
|
if (conflicts.length > 0) {
|
|
75
130
|
throw new Error(`Workflow rule conflict:\n${conflicts.join('\n')}\nPreserve your edits, remove the conflicting generated files, then rerun. Force does not bypass rule conflicts.`);
|
|
76
131
|
}
|
|
77
132
|
return plan;
|
|
78
133
|
}
|
|
79
|
-
/**
|
|
80
|
-
|
|
134
|
+
/**
|
|
135
|
+
* Call only after the complete plan passed preflight.
|
|
136
|
+
*
|
|
137
|
+
* `silent` suppresses the progress prose for a `--json` caller, which reports
|
|
138
|
+
* the same facts from the plan itself — prose on stdout would break the
|
|
139
|
+
* one-document envelope.
|
|
140
|
+
*/
|
|
141
|
+
export async function writeWorkflowRules(plan, options = {}) {
|
|
142
|
+
const say = (line) => {
|
|
143
|
+
if (!options.silent)
|
|
144
|
+
console.log(line);
|
|
145
|
+
};
|
|
81
146
|
for (const entry of plan) {
|
|
82
147
|
if (entry.action !== 'unchanged') {
|
|
83
148
|
await FileSystemUtils.writeFile(entry.destination, entry.content);
|
|
84
149
|
}
|
|
85
|
-
|
|
150
|
+
say(`Rules ${entry.action}: ${entry.destination}`);
|
|
151
|
+
// After the write, never before: a failure between the two would otherwise
|
|
152
|
+
// leave the project with no rule document at all.
|
|
153
|
+
if (entry.retire) {
|
|
154
|
+
await fs.rm(entry.retire, { force: true });
|
|
155
|
+
say(`Rules removed (renamed): ${entry.retire}`);
|
|
156
|
+
}
|
|
86
157
|
}
|
|
87
158
|
// Kept, not dropped, when the rules moved to `.agents`: Codex reads command
|
|
88
159
|
// approval rules, AGENTS.md and skill files, never project Markdown under
|
|
89
160
|
// rules/. Relocating the file did not give it a loading path, so removing the
|
|
90
161
|
// notice would turn a known limitation into a silent failure.
|
|
91
162
|
if (plan.some((entry) => entry.toolId === CODEX_TARGET_ID)) {
|
|
92
|
-
|
|
163
|
+
say('Codex: rule documents are reference material; configure loading yourself. Markdown files in .agents/rules/ are not automatically loaded as instructions — Codex takes its text guidance from AGENTS.md and skill files.');
|
|
93
164
|
}
|
|
94
165
|
}
|
|
95
166
|
//# sourceMappingURL=rules-generation.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules-generation.js","sourceRoot":"","sources":["../../../src/core/shared/rules-generation.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"rules-generation.js","sourceRoot":"","sources":["../../../src/core/shared/rules-generation.ts"],"names":[],"mappings":"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"}
|
|
@@ -90,4 +90,23 @@ export declare function getToolVersionStatus(projectRoot: string, toolId: string
|
|
|
90
90
|
* Gets all configured tools in the project.
|
|
91
91
|
*/
|
|
92
92
|
export declare function getConfiguredTools(projectRoot: string): string[];
|
|
93
|
+
/**
|
|
94
|
+
* Whether tospec has been installed into this tool dir, independent of how many
|
|
95
|
+
* skills currently sit there.
|
|
96
|
+
*
|
|
97
|
+
* Distinct from `getToolSkillStatus().configured`, which answers "does this tool
|
|
98
|
+
* have skills right now" — the right question for the init menu's pre-selection,
|
|
99
|
+
* and the wrong one for `update`/`rules`. A profile that selects no workflows
|
|
100
|
+
* makes `update` remove every `tospec-<workflow>` dir, and while installation was
|
|
101
|
+
* inferred from that same directory count, the run that emptied the dir also
|
|
102
|
+
* erased the only evidence the tool was ever set up: the next `update` reported
|
|
103
|
+
* "No configured tools found" and only `init` could recover. See
|
|
104
|
+
* tospec/decisions/20260916_152000-tool-install-marker-not-skill-count.md
|
|
105
|
+
*
|
|
106
|
+
* The workflow rule document is the durable marker: written for every configured
|
|
107
|
+
* tool on every init/update/rules, and removed by none of them. The legacy
|
|
108
|
+
* `rules/tospec/decision.md` deliberately does not count — it is written by init
|
|
109
|
+
* only, so it proves tospec once touched the dir, not that it still manages it.
|
|
110
|
+
*/
|
|
111
|
+
export declare function isToolInstalled(projectRoot: string, toolId: string): boolean;
|
|
93
112
|
//# sourceMappingURL=tool-detection.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-detection.d.ts","sourceRoot":"","sources":["../../../src/core/shared/tool-detection.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"tool-detection.d.ts","sourceRoot":"","sources":["../../../src/core/shared/tool-detection.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,SAAS,MAAM,EAA4C,CAAC;AAEtF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iBAAiB,YAAI,eAAe,EAAE,kBAAkB,CAAU,CAAC;AAEhF;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,iDAAiD;IACjD,UAAU,EAAE,OAAO,CAAC;IACpB,wCAAwC;IACxC,eAAe,EAAE,OAAO,CAAC;IACzB,4CAA4C;IAC5C,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,kBAAkB;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,UAAU,EAAE,OAAO,CAAC;IACpB,6EAA6E;IAC7E,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,oEAAoE;IACpE,WAAW,EAAE,OAAO,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAc9E;AAED;;;;;;;;;GASG;AACH,wBAAsB,2BAA2B,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAiBtF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAEhD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,eAAe,CAqBvF;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAS/E;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA2B9E;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,GACrB,iBAAiB,CAkCnB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAIhE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAS5E"}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import path from 'path';
|
|
7
7
|
import * as fs from 'fs';
|
|
8
|
-
import { AI_TOOLS } from '../config.js';
|
|
8
|
+
import { AI_TOOLS, LEGACY_WORKFLOW_RULE_FILENAME, TOOL_RULES_SUBDIR, WORKFLOW_RULE_FILENAME, } from '../config.js';
|
|
9
9
|
import { ALL_WORKFLOWS, workflowSkillDirName } from './skill-generation.js';
|
|
10
10
|
/**
|
|
11
11
|
* Names of skill directories created by tospec init, derived from the one
|
|
@@ -183,7 +183,35 @@ export function getToolVersionStatus(projectRoot, toolId, currentVersion) {
|
|
|
183
183
|
*/
|
|
184
184
|
export function getConfiguredTools(projectRoot) {
|
|
185
185
|
return AI_TOOLS
|
|
186
|
-
.filter((t) => t.skillsDir &&
|
|
186
|
+
.filter((t) => t.skillsDir && isToolInstalled(projectRoot, t.value))
|
|
187
187
|
.map((t) => t.value);
|
|
188
188
|
}
|
|
189
|
+
/**
|
|
190
|
+
* Whether tospec has been installed into this tool dir, independent of how many
|
|
191
|
+
* skills currently sit there.
|
|
192
|
+
*
|
|
193
|
+
* Distinct from `getToolSkillStatus().configured`, which answers "does this tool
|
|
194
|
+
* have skills right now" — the right question for the init menu's pre-selection,
|
|
195
|
+
* and the wrong one for `update`/`rules`. A profile that selects no workflows
|
|
196
|
+
* makes `update` remove every `tospec-<workflow>` dir, and while installation was
|
|
197
|
+
* inferred from that same directory count, the run that emptied the dir also
|
|
198
|
+
* erased the only evidence the tool was ever set up: the next `update` reported
|
|
199
|
+
* "No configured tools found" and only `init` could recover. See
|
|
200
|
+
* tospec/decisions/20260916_152000-tool-install-marker-not-skill-count.md
|
|
201
|
+
*
|
|
202
|
+
* The workflow rule document is the durable marker: written for every configured
|
|
203
|
+
* tool on every init/update/rules, and removed by none of them. The legacy
|
|
204
|
+
* `rules/tospec/decision.md` deliberately does not count — it is written by init
|
|
205
|
+
* only, so it proves tospec once touched the dir, not that it still manages it.
|
|
206
|
+
*/
|
|
207
|
+
export function isToolInstalled(projectRoot, toolId) {
|
|
208
|
+
const tool = AI_TOOLS.find((t) => t.value === toolId);
|
|
209
|
+
if (!tool?.skillsDir)
|
|
210
|
+
return false;
|
|
211
|
+
if (getToolSkillStatus(projectRoot, toolId).configured)
|
|
212
|
+
return true;
|
|
213
|
+
// Either spelling: a project last touched before the filename typo was fixed
|
|
214
|
+
// still holds the legacy name, and it is just as much proof of an install.
|
|
215
|
+
return [WORKFLOW_RULE_FILENAME, LEGACY_WORKFLOW_RULE_FILENAME].some((name) => fs.existsSync(path.join(projectRoot, tool.skillsDir, ...TOOL_RULES_SUBDIR, name)));
|
|
216
|
+
}
|
|
189
217
|
//# sourceMappingURL=tool-detection.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-detection.js","sourceRoot":"","sources":["../../../src/core/shared/tool-detection.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,
|
|
1
|
+
{"version":3,"file":"tool-detection.js","sourceRoot":"","sources":["../../../src/core/shared/tool-detection.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spec-presenter.d.ts","sourceRoot":"","sources":["../../src/core/spec-presenter.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAOtD,UAAU,WAAW;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;
|
|
1
|
+
{"version":3,"file":"spec-presenter.d.ts","sourceRoot":"","sources":["../../src/core/spec-presenter.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAOtD,UAAU,WAAW;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB;AAqDD,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAC,CAAS;IAI1B,YAAY,QAAQ,CAAC,EAAE,MAAM,EAG5B;IAEK,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2CpE;CACF"}
|