product-spec 0.2.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/CHANGELOG.md +49 -0
- package/LICENSE +21 -0
- package/README.md +152 -0
- package/assets/claude/commands/product-spec-align.md +37 -0
- package/assets/claude/commands/product-spec-domain.md +32 -0
- package/assets/claude/commands/product-spec-faq.md +34 -0
- package/assets/claude/commands/product-spec-press.md +31 -0
- package/assets/codex/commands/product-spec-align.md +25 -0
- package/assets/codex/commands/product-spec-domain.md +19 -0
- package/assets/codex/commands/product-spec-faq.md +22 -0
- package/assets/codex/commands/product-spec-press.md +19 -0
- package/assets/product/templates/domain-template.md +52 -0
- package/assets/product/templates/faq-template.md +38 -0
- package/assets/product/templates/press-template.md +26 -0
- package/assets/product/templates/requirements-template.md +34 -0
- package/dist/adapters/claude.d.ts +2 -0
- package/dist/adapters/claude.js +26 -0
- package/dist/adapters/claude.js.map +1 -0
- package/dist/adapters/codex.d.ts +2 -0
- package/dist/adapters/codex.js +26 -0
- package/dist/adapters/codex.js.map +1 -0
- package/dist/adapters/types.d.ts +12 -0
- package/dist/adapters/types.js +2 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/cli/commands/add.d.ts +6 -0
- package/dist/cli/commands/add.js +19 -0
- package/dist/cli/commands/add.js.map +1 -0
- package/dist/cli/commands/check.d.ts +4 -0
- package/dist/cli/commands/check.js +17 -0
- package/dist/cli/commands/check.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +4 -0
- package/dist/cli/commands/doctor.js +17 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/help.d.ts +2 -0
- package/dist/cli/commands/help.js +17 -0
- package/dist/cli/commands/help.js.map +1 -0
- package/dist/cli/commands/remove.d.ts +4 -0
- package/dist/cli/commands/remove.js +17 -0
- package/dist/cli/commands/remove.js.map +1 -0
- package/dist/cli/commands/targets.d.ts +2 -0
- package/dist/cli/commands/targets.js +9 -0
- package/dist/cli/commands/targets.js.map +1 -0
- package/dist/cli/commands/version.d.ts +2 -0
- package/dist/cli/commands/version.js +9 -0
- package/dist/cli/commands/version.js.map +1 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.js +33 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/output/reporter.d.ts +6 -0
- package/dist/cli/output/reporter.js +38 -0
- package/dist/cli/output/reporter.js.map +1 -0
- package/dist/core/assets/registry.d.ts +11 -0
- package/dist/core/assets/registry.js +34 -0
- package/dist/core/assets/registry.js.map +1 -0
- package/dist/core/fs/project.d.ts +13 -0
- package/dist/core/fs/project.js +67 -0
- package/dist/core/fs/project.js.map +1 -0
- package/dist/core/orchestration/add.d.ts +8 -0
- package/dist/core/orchestration/add.js +63 -0
- package/dist/core/orchestration/add.js.map +1 -0
- package/dist/core/orchestration/check.d.ts +9 -0
- package/dist/core/orchestration/check.js +80 -0
- package/dist/core/orchestration/check.js.map +1 -0
- package/dist/core/orchestration/doctor.d.ts +9 -0
- package/dist/core/orchestration/doctor.js +18 -0
- package/dist/core/orchestration/doctor.js.map +1 -0
- package/dist/core/orchestration/remove.d.ts +6 -0
- package/dist/core/orchestration/remove.js +60 -0
- package/dist/core/orchestration/remove.js.map +1 -0
- package/dist/core/orchestration/shared-assets.d.ts +8 -0
- package/dist/core/orchestration/shared-assets.js +38 -0
- package/dist/core/orchestration/shared-assets.js.map +1 -0
- package/dist/core/orchestration/targets.d.ts +5 -0
- package/dist/core/orchestration/targets.js +19 -0
- package/dist/core/orchestration/targets.js.map +1 -0
- package/dist/core/state/manifest.d.ts +13 -0
- package/dist/core/state/manifest.js +91 -0
- package/dist/core/state/manifest.js.map +1 -0
- package/dist/types/index.d.ts +53 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +45 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AssistantTarget, AssetRecord, HealthIssue } from "../types/index.js";
|
|
2
|
+
export interface AdapterHealthContext {
|
|
3
|
+
rootDir: string;
|
|
4
|
+
targetAssets: AssetRecord[];
|
|
5
|
+
}
|
|
6
|
+
export interface AssistantAdapter {
|
|
7
|
+
key: AssistantTarget;
|
|
8
|
+
displayName: string;
|
|
9
|
+
commandDir: string;
|
|
10
|
+
resolveCommandTarget(fileName: string): string;
|
|
11
|
+
describeHealthIssues(context: AdapterHealthContext): Promise<HealthIssue[]>;
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/adapters/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { runAdd } from "../../core/orchestration/add.js";
|
|
2
|
+
import { formatOperationSummary } from "../output/reporter.js";
|
|
3
|
+
import { parseRequestedTarget } from "./targets.js";
|
|
4
|
+
export function registerAddCommand(program, context) {
|
|
5
|
+
program
|
|
6
|
+
.command("add")
|
|
7
|
+
.argument("<target>", "claude, codex, or both")
|
|
8
|
+
.description("Add product-spec-managed integration files to the current project")
|
|
9
|
+
.action(async (target) => {
|
|
10
|
+
const summary = await runAdd({
|
|
11
|
+
rootDir: context.rootDir,
|
|
12
|
+
packageRoot: context.packageRoot,
|
|
13
|
+
requestedTarget: parseRequestedTarget(target),
|
|
14
|
+
productSpecVersion: context.version
|
|
15
|
+
});
|
|
16
|
+
process.stdout.write(formatOperationSummary("add", summary));
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=add.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add.js","sourceRoot":"","sources":["../../../src/cli/commands/add.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,iCAAiC,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEpD,MAAM,UAAU,kBAAkB,CAAC,OAAgB,EAAE,OAAkE;IACrH,OAAO;SACJ,OAAO,CAAC,KAAK,CAAC;SACd,QAAQ,CAAC,UAAU,EAAE,wBAAwB,CAAC;SAC9C,WAAW,CAAC,mEAAmE,CAAC;SAChF,MAAM,CAAC,KAAK,EAAE,MAAc,EAAE,EAAE;QAC/B,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC;YAC3B,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,eAAe,EAAE,oBAAoB,CAAC,MAAM,CAAC;YAC7C,kBAAkB,EAAE,OAAO,CAAC,OAAO;SACpC,CAAC,CAAC;QACH,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sBAAsB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { runCheck } from "../../core/orchestration/check.js";
|
|
2
|
+
import { formatCheckResult } from "../output/reporter.js";
|
|
3
|
+
import { parseRequestedTarget } from "./targets.js";
|
|
4
|
+
export function registerCheckCommand(program, context) {
|
|
5
|
+
program
|
|
6
|
+
.command("check")
|
|
7
|
+
.argument("[target]", "claude, codex, or both", "both")
|
|
8
|
+
.description("Validate integration health for one or all supported assistants")
|
|
9
|
+
.action(async (target) => {
|
|
10
|
+
const result = await runCheck({
|
|
11
|
+
rootDir: context.rootDir,
|
|
12
|
+
requestedTarget: parseRequestedTarget(target, "both")
|
|
13
|
+
});
|
|
14
|
+
process.stdout.write(formatCheckResult(result));
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../../../src/cli/commands/check.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEpD,MAAM,UAAU,oBAAoB,CAAC,OAAgB,EAAE,OAA4B;IACjF,OAAO;SACJ,OAAO,CAAC,OAAO,CAAC;SAChB,QAAQ,CAAC,UAAU,EAAE,wBAAwB,EAAE,MAAM,CAAC;SACtD,WAAW,CAAC,iEAAiE,CAAC;SAC9E,MAAM,CAAC,KAAK,EAAE,MAA0B,EAAE,EAAE;QAC3C,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC;YAC5B,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,eAAe,EAAE,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC;SACtD,CAAC,CAAC;QACH,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { runDoctor } from "../../core/orchestration/doctor.js";
|
|
2
|
+
import { formatDoctorResult } from "../output/reporter.js";
|
|
3
|
+
import { parseRequestedTarget } from "./targets.js";
|
|
4
|
+
export function registerDoctorCommand(program, context) {
|
|
5
|
+
program
|
|
6
|
+
.command("doctor")
|
|
7
|
+
.argument("[target]", "claude, codex, or both", "both")
|
|
8
|
+
.description("Show detailed diagnostics and repair guidance")
|
|
9
|
+
.action(async (target) => {
|
|
10
|
+
const result = await runDoctor({
|
|
11
|
+
rootDir: context.rootDir,
|
|
12
|
+
requestedTarget: parseRequestedTarget(target, "both")
|
|
13
|
+
});
|
|
14
|
+
process.stdout.write(formatDoctorResult(result));
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEpD,MAAM,UAAU,qBAAqB,CAAC,OAAgB,EAAE,OAA4B;IAClF,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,QAAQ,CAAC,UAAU,EAAE,wBAAwB,EAAE,MAAM,CAAC;SACtD,WAAW,CAAC,+CAA+C,CAAC;SAC5D,MAAM,CAAC,KAAK,EAAE,MAA0B,EAAE,EAAE;QAC3C,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC;YAC7B,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,eAAe,EAAE,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC;SACtD,CAAC,CAAC;QACH,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function configureHelp(program) {
|
|
2
|
+
program.addHelpText("after", `
|
|
3
|
+
Examples:
|
|
4
|
+
product-spec add claude
|
|
5
|
+
product-spec add both
|
|
6
|
+
product-spec remove codex
|
|
7
|
+
product-spec check both
|
|
8
|
+
product-spec doctor claude
|
|
9
|
+
`);
|
|
10
|
+
program
|
|
11
|
+
.command("help")
|
|
12
|
+
.description("Show help for product-spec")
|
|
13
|
+
.action(() => {
|
|
14
|
+
program.outputHelp();
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=help.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help.js","sourceRoot":"","sources":["../../../src/cli/commands/help.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,aAAa,CAAC,OAAgB;IAC5C,OAAO,CAAC,WAAW,CACjB,OAAO,EACP;;;;;;;CAOH,CACE,CAAC;IAEF,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,4BAA4B,CAAC;SACzC,MAAM,CAAC,GAAG,EAAE;QACX,OAAO,CAAC,UAAU,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { runRemove } from "../../core/orchestration/remove.js";
|
|
2
|
+
import { formatOperationSummary } from "../output/reporter.js";
|
|
3
|
+
import { parseRequestedTarget } from "./targets.js";
|
|
4
|
+
export function registerRemoveCommand(program, context) {
|
|
5
|
+
program
|
|
6
|
+
.command("remove")
|
|
7
|
+
.argument("<target>", "claude, codex, or both")
|
|
8
|
+
.description("Remove product-spec-managed integration files from the current project")
|
|
9
|
+
.action(async (target) => {
|
|
10
|
+
const summary = await runRemove({
|
|
11
|
+
rootDir: context.rootDir,
|
|
12
|
+
requestedTarget: parseRequestedTarget(target)
|
|
13
|
+
});
|
|
14
|
+
process.stdout.write(formatOperationSummary("remove", summary));
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=remove.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove.js","sourceRoot":"","sources":["../../../src/cli/commands/remove.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEpD,MAAM,UAAU,qBAAqB,CAAC,OAAgB,EAAE,OAA4B;IAClF,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,QAAQ,CAAC,UAAU,EAAE,wBAAwB,CAAC;SAC9C,WAAW,CAAC,wEAAwE,CAAC;SACrF,MAAM,CAAC,KAAK,EAAE,MAAc,EAAE,EAAE;QAC/B,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC;YAC9B,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,eAAe,EAAE,oBAAoB,CAAC,MAAM,CAAC;SAC9C,CAAC,CAAC;QACH,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sBAAsB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { InvalidArgumentError } from "commander";
|
|
2
|
+
export function parseRequestedTarget(value, fallback = "both") {
|
|
3
|
+
const resolved = value ?? fallback;
|
|
4
|
+
if (resolved === "claude" || resolved === "codex" || resolved === "both") {
|
|
5
|
+
return resolved;
|
|
6
|
+
}
|
|
7
|
+
throw new InvalidArgumentError(`Unknown target "${resolved}". Use claude, codex, or both.`);
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=targets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"targets.js","sourceRoot":"","sources":["../../../src/cli/commands/targets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAGjD,MAAM,UAAU,oBAAoB,CAAC,KAAyB,EAAE,WAA4B,MAAM;IAChG,MAAM,QAAQ,GAAG,KAAK,IAAI,QAAQ,CAAC;IAEnC,IAAI,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,OAAO,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;QACzE,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,IAAI,oBAAoB,CAAC,mBAAmB,QAAQ,gCAAgC,CAAC,CAAC;AAC9F,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/cli/commands/version.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,sBAAsB,CAAC,OAAgB,EAAE,OAAe;IACtE,OAAO;SACJ,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,8CAA8C,CAAC;SAC3D,MAAM,CAAC,GAAG,EAAE;QACX,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACP,CAAC"}
|
package/dist/cli/main.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import packageJson from "../../package.json" with { type: "json" };
|
|
4
|
+
import { resolveProjectRoot, getPackageRoot } from "../core/fs/project.js";
|
|
5
|
+
import { registerAddCommand } from "./commands/add.js";
|
|
6
|
+
import { registerRemoveCommand } from "./commands/remove.js";
|
|
7
|
+
import { registerCheckCommand } from "./commands/check.js";
|
|
8
|
+
import { registerDoctorCommand } from "./commands/doctor.js";
|
|
9
|
+
import { registerVersionCommand } from "./commands/version.js";
|
|
10
|
+
import { configureHelp } from "./commands/help.js";
|
|
11
|
+
async function main() {
|
|
12
|
+
const rootDir = resolveProjectRoot(process.cwd());
|
|
13
|
+
const packageRoot = getPackageRoot();
|
|
14
|
+
const program = new Command();
|
|
15
|
+
program
|
|
16
|
+
.name("product-spec")
|
|
17
|
+
.description("Manage product-spec project integrations for Claude Code and Codex")
|
|
18
|
+
.version(packageJson.version, "-V, --version", "Print the product-spec CLI version")
|
|
19
|
+
.showHelpAfterError();
|
|
20
|
+
registerAddCommand(program, { rootDir, packageRoot, version: packageJson.version });
|
|
21
|
+
registerRemoveCommand(program, { rootDir });
|
|
22
|
+
registerCheckCommand(program, { rootDir });
|
|
23
|
+
registerDoctorCommand(program, { rootDir });
|
|
24
|
+
registerVersionCommand(program, packageJson.version);
|
|
25
|
+
configureHelp(program);
|
|
26
|
+
await program.parseAsync(process.argv);
|
|
27
|
+
}
|
|
28
|
+
main().catch((error) => {
|
|
29
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
30
|
+
process.stderr.write(`${message}\n`);
|
|
31
|
+
process.exitCode = 1;
|
|
32
|
+
});
|
|
33
|
+
//# sourceMappingURL=main.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAwB,MAAM,WAAW,CAAC;AAC1D,OAAO,WAAW,MAAM,oBAAoB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAEnE,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,KAAK,UAAU,IAAI;IACjB,MAAM,OAAO,GAAG,kBAAkB,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAClD,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IAErC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAC9B,OAAO;SACJ,IAAI,CAAC,cAAc,CAAC;SACpB,WAAW,CAAC,oEAAoE,CAAC;SACjF,OAAO,CAAC,WAAW,CAAC,OAAO,EAAE,eAAe,EAAE,oCAAoC,CAAC;SACnF,kBAAkB,EAAE,CAAC;IAExB,kBAAkB,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC;IACpF,qBAAqB,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IAC5C,oBAAoB,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IAC3C,qBAAqB,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IAC5C,sBAAsB,CAAC,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IACrD,aAAa,CAAC,OAAO,CAAC,CAAC;IAEvB,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAC9B,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC;IACrC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CheckResult } from "../../core/orchestration/check.js";
|
|
2
|
+
import type { DoctorResult } from "../../core/orchestration/doctor.js";
|
|
3
|
+
import type { OperationSummary } from "../../types/index.js";
|
|
4
|
+
export declare function formatOperationSummary(action: "add" | "remove", summary: OperationSummary): string;
|
|
5
|
+
export declare function formatCheckResult(result: CheckResult): string;
|
|
6
|
+
export declare function formatDoctorResult(result: DoctorResult): string;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export function formatOperationSummary(action, summary) {
|
|
2
|
+
const lines = [
|
|
3
|
+
`product-spec ${action} ${summary.requestedTarget}`,
|
|
4
|
+
`Changed targets: ${summary.changedTargets.length > 0 ? summary.changedTargets.join(", ") : "none"}`,
|
|
5
|
+
`Skipped targets: ${summary.skippedTargets.length > 0 ? summary.skippedTargets.join(", ") : "none"}`
|
|
6
|
+
];
|
|
7
|
+
if (summary.files.length > 0) {
|
|
8
|
+
lines.push("Files:");
|
|
9
|
+
for (const file of summary.files) {
|
|
10
|
+
lines.push(`- ${file.action}: ${file.path}`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
if (summary.notes.length > 0) {
|
|
14
|
+
lines.push("Notes:");
|
|
15
|
+
for (const note of summary.notes) {
|
|
16
|
+
lines.push(`- ${note}`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return `${lines.join("\n")}\n`;
|
|
20
|
+
}
|
|
21
|
+
export function formatCheckResult(result) {
|
|
22
|
+
const lines = [];
|
|
23
|
+
for (const report of result.reports) {
|
|
24
|
+
lines.push(`${report.target}: ${report.status}`);
|
|
25
|
+
lines.push(`- manifest aligned: ${report.manifestAligned ? "yes" : "no"}`);
|
|
26
|
+
if (report.issues.length > 0) {
|
|
27
|
+
for (const issue of report.issues) {
|
|
28
|
+
lines.push(`- ${issue.severity}: ${issue.message}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
lines.push(`- next step: ${report.recommendedAction}`);
|
|
32
|
+
}
|
|
33
|
+
return `${lines.join("\n")}\n`;
|
|
34
|
+
}
|
|
35
|
+
export function formatDoctorResult(result) {
|
|
36
|
+
return `${result.details.join("\n\n")}\n`;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=reporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporter.js","sourceRoot":"","sources":["../../../src/cli/output/reporter.ts"],"names":[],"mappings":"AAIA,MAAM,UAAU,sBAAsB,CAAC,MAAwB,EAAE,OAAyB;IACxF,MAAM,KAAK,GAAG;QACZ,gBAAgB,MAAM,IAAI,OAAO,CAAC,eAAe,EAAE;QACnD,oBAAoB,OAAO,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE;QACpG,oBAAoB,OAAO,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE;KACrG,CAAC;IAEF,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACrB,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YACjC,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACrB,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YACjC,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAmB;IACnD,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACpC,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACjD,KAAK,CAAC,IAAI,CAAC,uBAAuB,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAC3E,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;gBAClC,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,QAAQ,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YACtD,CAAC;QACH,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,gBAAgB,MAAM,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAoB;IACrD,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AssetCategory, AssistantTarget } from "../../types/index.js";
|
|
2
|
+
export interface AssetDefinition {
|
|
3
|
+
id: string;
|
|
4
|
+
category: AssetCategory;
|
|
5
|
+
target: AssistantTarget | "shared";
|
|
6
|
+
sourcePath: string;
|
|
7
|
+
targetPath: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const assistantAssetRegistry: Record<AssistantTarget, AssetDefinition[]>;
|
|
10
|
+
export declare const sharedAssetRegistry: AssetDefinition[];
|
|
11
|
+
export declare function getTargetAssetDefinitions(target: AssistantTarget): AssetDefinition[];
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const assistantCommands = ["product-spec-domain.md", "product-spec-press.md", "product-spec-faq.md", "product-spec-align.md"];
|
|
2
|
+
const sharedTemplates = [
|
|
3
|
+
"domain-template.md",
|
|
4
|
+
"press-template.md",
|
|
5
|
+
"faq-template.md",
|
|
6
|
+
"requirements-template.md"
|
|
7
|
+
];
|
|
8
|
+
function buildAssistantAssets(target, commandDir) {
|
|
9
|
+
return assistantCommands.map((fileName) => ({
|
|
10
|
+
id: `${target}/${fileName.replace(/\.md$/, "")}`,
|
|
11
|
+
category: "assistant-command",
|
|
12
|
+
target,
|
|
13
|
+
sourcePath: `assets/${target}/commands/${fileName}`,
|
|
14
|
+
targetPath: `${commandDir}/${fileName}`
|
|
15
|
+
}));
|
|
16
|
+
}
|
|
17
|
+
function buildSharedAssets() {
|
|
18
|
+
return sharedTemplates.map((fileName) => ({
|
|
19
|
+
id: `shared/${fileName.replace(/\.md$/, "")}`,
|
|
20
|
+
category: "product-template",
|
|
21
|
+
target: "shared",
|
|
22
|
+
sourcePath: `assets/product/templates/${fileName}`,
|
|
23
|
+
targetPath: `.product/templates/${fileName}`
|
|
24
|
+
}));
|
|
25
|
+
}
|
|
26
|
+
export const assistantAssetRegistry = {
|
|
27
|
+
claude: buildAssistantAssets("claude", ".claude/commands"),
|
|
28
|
+
codex: buildAssistantAssets("codex", ".Codex/commands")
|
|
29
|
+
};
|
|
30
|
+
export const sharedAssetRegistry = buildSharedAssets();
|
|
31
|
+
export function getTargetAssetDefinitions(target) {
|
|
32
|
+
return assistantAssetRegistry[target];
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/core/assets/registry.ts"],"names":[],"mappings":"AAUA,MAAM,iBAAiB,GAAG,CAAC,wBAAwB,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,uBAAuB,CAAC,CAAC;AAC9H,MAAM,eAAe,GAAG;IACtB,oBAAoB;IACpB,mBAAmB;IACnB,iBAAiB;IACjB,0BAA0B;CAC3B,CAAC;AAEF,SAAS,oBAAoB,CAAC,MAAuB,EAAE,UAAkB;IACvE,OAAO,iBAAiB,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC1C,EAAE,EAAE,GAAG,MAAM,IAAI,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE;QAChD,QAAQ,EAAE,mBAAmB;QAC7B,MAAM;QACN,UAAU,EAAE,UAAU,MAAM,aAAa,QAAQ,EAAE;QACnD,UAAU,EAAE,GAAG,UAAU,IAAI,QAAQ,EAAE;KACxC,CAAC,CAAC,CAAC;AACN,CAAC;AAED,SAAS,iBAAiB;IACxB,OAAO,eAAe,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACxC,EAAE,EAAE,UAAU,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE;QAC7C,QAAQ,EAAE,kBAAkB;QAC5B,MAAM,EAAE,QAAQ;QAChB,UAAU,EAAE,4BAA4B,QAAQ,EAAE;QAClD,UAAU,EAAE,sBAAsB,QAAQ,EAAE;KAC7C,CAAC,CAAC,CAAC;AACN,CAAC;AAED,MAAM,CAAC,MAAM,sBAAsB,GAA+C;IAChF,MAAM,EAAE,oBAAoB,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IAC1D,KAAK,EAAE,oBAAoB,CAAC,OAAO,EAAE,iBAAiB,CAAC;CACxD,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAG,iBAAiB,EAAE,CAAC;AAEvD,MAAM,UAAU,yBAAyB,CAAC,MAAuB;IAC/D,OAAO,sBAAsB,CAAC,MAAM,CAAC,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare function getPackageRoot(): string;
|
|
2
|
+
export declare function resolveProjectRoot(cwd: string): string;
|
|
3
|
+
export declare function pathExists(targetPath: string): Promise<boolean>;
|
|
4
|
+
export declare function ensureDirectory(targetPath: string): Promise<void>;
|
|
5
|
+
export declare function readText(targetPath: string): Promise<string>;
|
|
6
|
+
export declare function writeText(targetPath: string, contents: string): Promise<void>;
|
|
7
|
+
export declare function writeJsonAtomic(targetPath: string, value: unknown): Promise<void>;
|
|
8
|
+
export declare function removeIfExists(targetPath: string): Promise<boolean>;
|
|
9
|
+
export declare function hashFile(targetPath: string): Promise<string>;
|
|
10
|
+
export declare function relativeFromRoot(rootDir: string, targetPath: string): string;
|
|
11
|
+
export declare function joinProjectPath(rootDir: string, relativePath: string): string;
|
|
12
|
+
export declare function assertInsideRoot(rootDir: string, candidatePath: string): void;
|
|
13
|
+
export declare function removeEmptyDirectoryIfExists(targetPath: string): Promise<void>;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
export function getPackageRoot() {
|
|
6
|
+
return path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../..");
|
|
7
|
+
}
|
|
8
|
+
export function resolveProjectRoot(cwd) {
|
|
9
|
+
return path.resolve(cwd);
|
|
10
|
+
}
|
|
11
|
+
export async function pathExists(targetPath) {
|
|
12
|
+
try {
|
|
13
|
+
await stat(targetPath);
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export async function ensureDirectory(targetPath) {
|
|
21
|
+
await mkdir(targetPath, { recursive: true });
|
|
22
|
+
}
|
|
23
|
+
export async function readText(targetPath) {
|
|
24
|
+
return readFile(targetPath, "utf8");
|
|
25
|
+
}
|
|
26
|
+
export async function writeText(targetPath, contents) {
|
|
27
|
+
await ensureDirectory(path.dirname(targetPath));
|
|
28
|
+
await writeFile(targetPath, contents, "utf8");
|
|
29
|
+
}
|
|
30
|
+
export async function writeJsonAtomic(targetPath, value) {
|
|
31
|
+
const tempPath = `${targetPath}.tmp`;
|
|
32
|
+
await ensureDirectory(path.dirname(targetPath));
|
|
33
|
+
await writeFile(tempPath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
|
|
34
|
+
await rename(tempPath, targetPath);
|
|
35
|
+
}
|
|
36
|
+
export async function removeIfExists(targetPath) {
|
|
37
|
+
if (!(await pathExists(targetPath))) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
await rm(targetPath, { force: true, recursive: false });
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
export async function hashFile(targetPath) {
|
|
44
|
+
const contents = await readFile(targetPath);
|
|
45
|
+
return createHash("sha256").update(contents).digest("hex");
|
|
46
|
+
}
|
|
47
|
+
export function relativeFromRoot(rootDir, targetPath) {
|
|
48
|
+
return path.relative(rootDir, targetPath).split(path.sep).join("/");
|
|
49
|
+
}
|
|
50
|
+
export function joinProjectPath(rootDir, relativePath) {
|
|
51
|
+
return path.join(rootDir, ...relativePath.split("/"));
|
|
52
|
+
}
|
|
53
|
+
export function assertInsideRoot(rootDir, candidatePath) {
|
|
54
|
+
const relative = path.relative(rootDir, candidatePath);
|
|
55
|
+
if (relative.startsWith("..") || path.isAbsolute(relative)) {
|
|
56
|
+
throw new Error(`Refusing to operate outside project root: ${candidatePath}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export async function removeEmptyDirectoryIfExists(targetPath) {
|
|
60
|
+
try {
|
|
61
|
+
await rm(targetPath, { recursive: false });
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// Ignore non-empty or missing directories.
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.js","sourceRoot":"","sources":["../../../src/core/fs/project.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { OperationSummary, RequestedTarget } from "../../types/index.js";
|
|
2
|
+
export interface AddOptions {
|
|
3
|
+
rootDir: string;
|
|
4
|
+
packageRoot: string;
|
|
5
|
+
requestedTarget: RequestedTarget;
|
|
6
|
+
productSpecVersion: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function runAdd(options: AddOptions): Promise<OperationSummary>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { getTargetAssetDefinitions } from "../assets/registry.js";
|
|
3
|
+
import { assertInsideRoot, ensureDirectory, hashFile, joinProjectPath, pathExists, readText, writeText } from "../fs/project.js";
|
|
4
|
+
import { createEmptyManifest, loadManifest, saveManifest, setSharedAssets, upsertTargetState } from "../state/manifest.js";
|
|
5
|
+
import { resolveTargets } from "./targets.js";
|
|
6
|
+
import { installSharedAssets } from "./shared-assets.js";
|
|
7
|
+
function buildTargetState(target, assets) {
|
|
8
|
+
return {
|
|
9
|
+
target,
|
|
10
|
+
installed: true,
|
|
11
|
+
assets,
|
|
12
|
+
lastOperation: "add"
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export async function runAdd(options) {
|
|
16
|
+
const selectedTargets = resolveTargets(options.requestedTarget);
|
|
17
|
+
let manifest = (await loadManifest(options.rootDir)) ?? createEmptyManifest(options.rootDir, options.productSpecVersion);
|
|
18
|
+
manifest.productSpecVersion = options.productSpecVersion;
|
|
19
|
+
const files = [];
|
|
20
|
+
const changedTargets = [];
|
|
21
|
+
const skippedTargets = [];
|
|
22
|
+
for (const target of selectedTargets) {
|
|
23
|
+
const assetDefinitions = getTargetAssetDefinitions(target);
|
|
24
|
+
const managedAssets = [];
|
|
25
|
+
for (const asset of assetDefinitions) {
|
|
26
|
+
const sourcePath = joinProjectPath(options.packageRoot, asset.sourcePath);
|
|
27
|
+
const targetPath = joinProjectPath(options.rootDir, asset.targetPath);
|
|
28
|
+
assertInsideRoot(options.rootDir, targetPath);
|
|
29
|
+
await ensureDirectory(path.dirname(targetPath));
|
|
30
|
+
const existed = await pathExists(targetPath);
|
|
31
|
+
await writeText(targetPath, await readText(sourcePath));
|
|
32
|
+
managedAssets.push({
|
|
33
|
+
...asset,
|
|
34
|
+
checksum: await hashFile(targetPath),
|
|
35
|
+
managed: true
|
|
36
|
+
});
|
|
37
|
+
files.push({
|
|
38
|
+
path: asset.targetPath,
|
|
39
|
+
action: existed ? "updated" : "created"
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
const alreadyManaged = manifest.targets.some((entry) => entry.target === target && entry.installed);
|
|
43
|
+
manifest = upsertTargetState(manifest, buildTargetState(target, managedAssets));
|
|
44
|
+
if (alreadyManaged) {
|
|
45
|
+
skippedTargets.push(target);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
changedTargets.push(target);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const sharedInstall = await installSharedAssets(options.rootDir, options.packageRoot);
|
|
52
|
+
manifest = setSharedAssets(manifest, sharedInstall.sharedAssets);
|
|
53
|
+
files.push(...sharedInstall.files);
|
|
54
|
+
await saveManifest(options.rootDir, manifest);
|
|
55
|
+
return {
|
|
56
|
+
requestedTarget: options.requestedTarget,
|
|
57
|
+
changedTargets,
|
|
58
|
+
skippedTargets,
|
|
59
|
+
files,
|
|
60
|
+
notes: ["Run `product-spec check` to validate the installed integrations."]
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=add.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add.js","sourceRoot":"","sources":["../../../src/core/orchestration/add.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAU7B,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,QAAQ,EACR,eAAe,EACf,UAAU,EACV,QAAQ,EACR,SAAS,EACV,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,iBAAiB,EAClB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AASzD,SAAS,gBAAgB,CAAC,MAAuB,EAAE,MAAqB;IACtE,OAAO;QACL,MAAM;QACN,SAAS,EAAE,IAAI;QACf,MAAM;QACN,aAAa,EAAE,KAAK;KACrB,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,OAAmB;IAC9C,MAAM,eAAe,GAAG,cAAc,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAChE,IAAI,QAAQ,GAAG,CAAC,MAAM,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,mBAAmB,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACzH,QAAQ,CAAC,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAEzD,MAAM,KAAK,GAA0B,EAAE,CAAC;IACxC,MAAM,cAAc,GAAsB,EAAE,CAAC;IAC7C,MAAM,cAAc,GAAsB,EAAE,CAAC;IAE7C,KAAK,MAAM,MAAM,IAAI,eAAe,EAAE,CAAC;QACrC,MAAM,gBAAgB,GAAG,yBAAyB,CAAC,MAAM,CAAC,CAAC;QAC3D,MAAM,aAAa,GAAkB,EAAE,CAAC;QAExC,KAAK,MAAM,KAAK,IAAI,gBAAgB,EAAE,CAAC;YACrC,MAAM,UAAU,GAAG,eAAe,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;YAC1E,MAAM,UAAU,GAAG,eAAe,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;YACtE,gBAAgB,CAAC,OAAO,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;YAE9C,MAAM,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;YAChD,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,UAAU,CAAC,CAAC;YAC7C,MAAM,SAAS,CAAC,UAAU,EAAE,MAAM,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;YAExD,aAAa,CAAC,IAAI,CAAC;gBACjB,GAAG,KAAK;gBACR,QAAQ,EAAE,MAAM,QAAQ,CAAC,UAAU,CAAC;gBACpC,OAAO,EAAE,IAAI;aACd,CAAC,CAAC;YACH,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,KAAK,CAAC,UAAU;gBACtB,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;aACxC,CAAC,CAAC;QACL,CAAC;QAED,MAAM,cAAc,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,MAAM,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC;QACpG,QAAQ,GAAG,iBAAiB,CAAC,QAAQ,EAAE,gBAAgB,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;QAChF,IAAI,cAAc,EAAE,CAAC;YACnB,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC9B,CAAC;aAAM,CAAC;YACN,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,MAAM,aAAa,GAAG,MAAM,mBAAmB,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IACtF,QAAQ,GAAG,eAAe,CAAC,QAAQ,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IACjE,KAAK,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAEnC,MAAM,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAE9C,OAAO;QACL,eAAe,EAAE,OAAO,CAAC,eAAe;QACxC,cAAc;QACd,cAAc;QACd,KAAK;QACL,KAAK,EAAE,CAAC,kEAAkE,CAAC;KAC5E,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { HealthReport, RequestedTarget } from "../../types/index.js";
|
|
2
|
+
export interface CheckOptions {
|
|
3
|
+
rootDir: string;
|
|
4
|
+
requestedTarget: RequestedTarget;
|
|
5
|
+
}
|
|
6
|
+
export interface CheckResult {
|
|
7
|
+
reports: HealthReport[];
|
|
8
|
+
}
|
|
9
|
+
export declare function runCheck(options: CheckOptions): Promise<CheckResult>;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { getTargetAssetDefinitions, sharedAssetRegistry } from "../assets/registry.js";
|
|
2
|
+
import { joinProjectPath, pathExists } from "../fs/project.js";
|
|
3
|
+
import { loadManifest } from "../state/manifest.js";
|
|
4
|
+
import { getAdapter, resolveTargets } from "./targets.js";
|
|
5
|
+
function classifyStatus(commandFilesPresent, expectedCommandFiles, manifestInstalled, issues) {
|
|
6
|
+
if (commandFilesPresent === 0 && !manifestInstalled) {
|
|
7
|
+
return "missing";
|
|
8
|
+
}
|
|
9
|
+
if (issues.length > 0) {
|
|
10
|
+
if (commandFilesPresent > 0 && commandFilesPresent < expectedCommandFiles) {
|
|
11
|
+
return "partial";
|
|
12
|
+
}
|
|
13
|
+
return "unhealthy";
|
|
14
|
+
}
|
|
15
|
+
return "healthy";
|
|
16
|
+
}
|
|
17
|
+
export async function runCheck(options) {
|
|
18
|
+
const manifest = await loadManifest(options.rootDir);
|
|
19
|
+
const selectedTargets = resolveTargets(options.requestedTarget);
|
|
20
|
+
const reports = [];
|
|
21
|
+
for (const target of selectedTargets) {
|
|
22
|
+
const adapter = getAdapter(target);
|
|
23
|
+
const targetAssets = getTargetAssetDefinitions(target);
|
|
24
|
+
const targetState = manifest?.targets.find((entry) => entry.target === target);
|
|
25
|
+
const issues = [];
|
|
26
|
+
let presentCount = 0;
|
|
27
|
+
for (const asset of targetAssets) {
|
|
28
|
+
const absolutePath = joinProjectPath(options.rootDir, asset.targetPath);
|
|
29
|
+
if (await pathExists(absolutePath)) {
|
|
30
|
+
presentCount += 1;
|
|
31
|
+
}
|
|
32
|
+
else if (targetState?.installed) {
|
|
33
|
+
issues.push({
|
|
34
|
+
code: "TARGET_ASSET_MISSING",
|
|
35
|
+
severity: "error",
|
|
36
|
+
message: `Expected managed asset is missing: ${asset.targetPath}`,
|
|
37
|
+
path: asset.targetPath
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
for (const asset of sharedAssetRegistry) {
|
|
42
|
+
const absolutePath = joinProjectPath(options.rootDir, asset.targetPath);
|
|
43
|
+
if (!(await pathExists(absolutePath))) {
|
|
44
|
+
issues.push({
|
|
45
|
+
code: "SHARED_ASSET_MISSING",
|
|
46
|
+
severity: "warning",
|
|
47
|
+
message: `Shared template is missing: ${asset.targetPath}`,
|
|
48
|
+
path: asset.targetPath
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (!manifest && presentCount > 0) {
|
|
53
|
+
issues.push({
|
|
54
|
+
code: "MANIFEST_MISSING",
|
|
55
|
+
severity: "warning",
|
|
56
|
+
message: "Managed files exist but .product-spec/manifest.json is missing."
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
issues.push(...(await adapter.describeHealthIssues({
|
|
60
|
+
rootDir: options.rootDir,
|
|
61
|
+
targetAssets: (targetState?.assets ?? []).filter((asset) => asset.target === target)
|
|
62
|
+
})));
|
|
63
|
+
const manifestAligned = Boolean(targetState?.installed) || presentCount === 0;
|
|
64
|
+
const status = classifyStatus(presentCount, targetAssets.length, Boolean(targetState?.installed), issues);
|
|
65
|
+
const recommendedAction = status === "healthy"
|
|
66
|
+
? "No action needed."
|
|
67
|
+
: status === "missing"
|
|
68
|
+
? `Run \`product-spec add ${target}\` to install this integration.`
|
|
69
|
+
: `Run \`product-spec add ${target}\` to refresh managed files, then \`product-spec check ${target}\` again.`;
|
|
70
|
+
reports.push({
|
|
71
|
+
target,
|
|
72
|
+
status,
|
|
73
|
+
issues,
|
|
74
|
+
recommendedAction,
|
|
75
|
+
manifestAligned
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
return { reports };
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../../../src/core/orchestration/check.ts"],"names":[],"mappings":"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"}
|