@stsepelin/checktrail 0.1.0-alpha.1 → 0.1.0-alpha.2
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/README.md +9 -5
- package/dist/src/cli.js +75 -3
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +1 -0
- package/dist/src/onboarding.d.ts +50 -0
- package/dist/src/onboarding.js +295 -0
- package/dist/src/types.d.ts +1 -1
- package/dist/src/types.js +1 -1
- package/docs/ACCEPTANCE.md +14 -13
- package/docs/ARCHITECTURE.md +3 -1
- package/docs/INSTALLATION.md +10 -5
- package/docs/LANGUAGES.md +4 -0
- package/docs/ONBOARDING.md +128 -0
- package/docs/RELEASE.md +19 -9
- package/docs/SKILLS.md +123 -0
- package/docs/STATUS.md +10 -3
- package/package.json +1 -1
- package/server.json +2 -2
package/README.md
CHANGED
|
@@ -4,18 +4,22 @@ Local code validation with a CLI, MCP tools, and evidence of what actually ran.
|
|
|
4
4
|
|
|
5
5
|
Formerly Repo Verifier. See the [rename guide](docs/RENAMING.md) for existing source checkouts.
|
|
6
6
|
|
|
7
|
-
**
|
|
7
|
+
**Published preview: 0.1.0-alpha.1; alpha.2 is in preparation.** Public source is available at
|
|
8
8
|
[stsepelin/checktrail](https://github.com/stsepelin/checktrail).
|
|
9
9
|
See [implementation status](docs/STATUS.md), the [plan](docs/PLAN.md) and the
|
|
10
10
|
[language matrix](docs/LANGUAGES.md) before relying on an adapter.
|
|
11
11
|
[Installation](docs/INSTALLATION.md) covers the CLI, Claude Code and Codex.
|
|
12
|
+
[Agent skills](docs/SKILLS.md) provides setup, validation and review workflows
|
|
13
|
+
installable with `npx skills add stsepelin/checktrail`.
|
|
14
|
+
[Project setup](docs/ONBOARDING.md) covers the alpha.2 candidate's `init`, `doctor`
|
|
15
|
+
and MCP configuration generator.
|
|
12
16
|
[Release preparation](docs/RELEASE.md) records publication and verification gates. The
|
|
13
17
|
[milestone audit](docs/ACCEPTANCE.md) separates implemented profiles from open
|
|
14
18
|
acceptance work; [client checks](docs/CLIENTS.md) record actual application coverage.
|
|
15
19
|
|
|
16
|
-
The [
|
|
17
|
-
passed at `
|
|
18
|
-
|
|
20
|
+
The [hosted matrix](https://github.com/stsepelin/checktrail/actions/runs/35585998184)
|
|
21
|
+
passed at `bfc8cc4` on Linux and macOS. That result predates the alpha.2 candidate;
|
|
22
|
+
new release changes require their own CI run and package verification.
|
|
19
23
|
|
|
20
24
|
Checktrail discovers projects, plans registered checks, invokes native tools
|
|
21
25
|
when explicitly trusted, and reports results without turning skipped or empty
|
|
@@ -41,7 +45,7 @@ node dist/src/cli.js run --root examples/javascript --trust-project --detailed
|
|
|
41
45
|
`--trust-project`: tests, compiler plugins and project configuration can execute
|
|
42
46
|
code with your user privileges. This is not a sandbox.
|
|
43
47
|
|
|
44
|
-
|
|
48
|
+
Successful commands return JSON except help/version; input errors use stderr. Exit codes:
|
|
45
49
|
|
|
46
50
|
| Code | Meaning |
|
|
47
51
|
| ---- | --------------------------------------------------------------------------------------- |
|
package/dist/src/cli.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { initialize, diagnose, mcpConfiguration, mcpClients, } from "./onboarding.js";
|
|
3
4
|
import { createReviewContext, projectReviewContext, receiveReview, projectReviewReceipt, } from "./review.js";
|
|
4
5
|
import { fetchPolicyPack } from "./fetch-pack.js";
|
|
5
6
|
import { externalReferencesSchema, loadExternalAdapters, } from "./external-adapter.js";
|
|
@@ -22,11 +23,15 @@ import { VERSION } from "./types.js";
|
|
|
22
23
|
import { validateContracts, projectContractReport } from "./contracts.js";
|
|
23
24
|
import { compareRuntimeInventories, projectRuntimeComparison, } from "./runtime-inventory.js";
|
|
24
25
|
async function main() {
|
|
25
|
-
const { values, positionals } = parseArgs({
|
|
26
|
+
const { values, positionals, tokens } = parseArgs({
|
|
27
|
+
tokens: true,
|
|
26
28
|
allowPositionals: true,
|
|
27
29
|
strict: true,
|
|
28
30
|
options: {
|
|
29
31
|
root: { type: "string", default: "." },
|
|
32
|
+
write: { type: "boolean", default: false },
|
|
33
|
+
check: { type: "string", multiple: true },
|
|
34
|
+
client: { type: "string" },
|
|
30
35
|
"trust-project": { type: "boolean", default: false },
|
|
31
36
|
"allow-execution": { type: "boolean", default: false },
|
|
32
37
|
detailed: { type: "boolean", default: false },
|
|
@@ -58,12 +63,29 @@ async function main() {
|
|
|
58
63
|
return;
|
|
59
64
|
}
|
|
60
65
|
if (values.help || positionals.length === 0) {
|
|
61
|
-
process.stdout.write("checktrail <inspect|plan|run|serve|adapters|import-junit|export-sarif|create-baseline|compare-findings|compare-runtime|check-contracts|check-architecture|guidance|review-context|review-receipt|mutate|fetch-pack> [--root PATH] [--detailed] [--base REVISION] [--policy-overlay PATH] [--adapter PATH#sha256=DIGEST ...]\nRun: --trust-project [--timeout-ms 30000] [--allow-env NAME ...]\nServe: --allow-execution (optional; disabled by default) [--allow-env NAME ...]\nFetch-pack: --url HTTPS_URL --sha256 DIGEST --output RELATIVE_JSON_PATH\nExit: 0 passed/read-only success/completed advisory experiment, 1 failed checks, 2 incomplete/error\n");
|
|
66
|
+
process.stdout.write("checktrail <init|doctor|mcp-config|inspect|plan|run|serve|adapters|import-junit|export-sarif|create-baseline|compare-findings|compare-runtime|check-contracts|check-architecture|guidance|review-context|review-receipt|mutate|fetch-pack> [--root PATH] [--detailed] [--base REVISION] [--policy-overlay PATH] [--adapter PATH#sha256=DIGEST ...]\nInit: [--write] [--check PATH#CHECK_ID ...] (preview by default; preserves existing config)\nDoctor: [--detailed] [--policy-overlay PATH] [--allow-env NAME ...] [--adapter PATH#sha256=DIGEST ...] (no execution)\nMcp-config: --client codex|claude-code|claude-desktop|cursor|vscode (prints configuration only)\nRun: --trust-project [--timeout-ms 30000] [--allow-env NAME ...]\nServe: --allow-execution (optional; disabled by default) [--allow-env NAME ...]\nFetch-pack: --url HTTPS_URL --sha256 DIGEST --output RELATIVE_JSON_PATH\nExit: 0 passed/read-only success/completed advisory experiment, 1 failed checks, 2 incomplete/error\n");
|
|
62
67
|
return;
|
|
63
68
|
}
|
|
64
69
|
if (positionals.length !== 1)
|
|
65
70
|
throw new Error("Expected exactly one command");
|
|
66
71
|
const command = positionals[0];
|
|
72
|
+
for (const token of tokens) {
|
|
73
|
+
if (token.kind !== "option")
|
|
74
|
+
continue;
|
|
75
|
+
if (["write", "check"].includes(token.name) && command !== "init")
|
|
76
|
+
throw new Error(`--${token.name} applies only to init`);
|
|
77
|
+
if (token.name === "client" && command !== "mcp-config")
|
|
78
|
+
throw new Error("--client applies only to mcp-config");
|
|
79
|
+
const allowed = command === "init"
|
|
80
|
+
? ["root", "write", "check"]
|
|
81
|
+
: command === "doctor"
|
|
82
|
+
? ["root", "detailed", "policy-overlay", "allow-env", "adapter"]
|
|
83
|
+
: command === "mcp-config"
|
|
84
|
+
? ["root", "client"]
|
|
85
|
+
: undefined;
|
|
86
|
+
if (allowed && !allowed.includes(token.name))
|
|
87
|
+
throw new Error(`--${token.name} does not apply to ${command}`);
|
|
88
|
+
}
|
|
67
89
|
if (values["allow-review-source"] &&
|
|
68
90
|
(!values.detailed ||
|
|
69
91
|
!["review-context", "review-receipt", "serve"].includes(command)))
|
|
@@ -85,7 +107,15 @@ async function main() {
|
|
|
85
107
|
};
|
|
86
108
|
}));
|
|
87
109
|
if (externalAdapters.length &&
|
|
88
|
-
![
|
|
110
|
+
![
|
|
111
|
+
"inspect",
|
|
112
|
+
"plan",
|
|
113
|
+
"run",
|
|
114
|
+
"serve",
|
|
115
|
+
"adapters",
|
|
116
|
+
"guidance",
|
|
117
|
+
"doctor",
|
|
118
|
+
].includes(command))
|
|
89
119
|
throw new Error("External adapters apply only to inspection, planning, validation, serving and derived guidance");
|
|
90
120
|
if (externalAdapters.length && command === "guidance" && values.input)
|
|
91
121
|
throw new Error("External adapters require derived guidance, not an imported context");
|
|
@@ -103,7 +133,49 @@ async function main() {
|
|
|
103
133
|
]);
|
|
104
134
|
return;
|
|
105
135
|
}
|
|
136
|
+
if (command === "doctor") {
|
|
137
|
+
const result = await diagnose(values.root, {
|
|
138
|
+
detailed: values.detailed,
|
|
139
|
+
externalAdapters,
|
|
140
|
+
environment: inheritEnvironment(values["allow-env"] ?? []),
|
|
141
|
+
...(values["policy-overlay"]
|
|
142
|
+
? { policyOverlay: values["policy-overlay"] }
|
|
143
|
+
: {}),
|
|
144
|
+
});
|
|
145
|
+
print(result);
|
|
146
|
+
process.exitCode = result.status === "no-static-blockers" ? 0 : 2;
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
106
149
|
const root = await realpath(values.root);
|
|
150
|
+
if (command === "init") {
|
|
151
|
+
const selections = new Map();
|
|
152
|
+
for (const value of values.check ?? []) {
|
|
153
|
+
const split = value.lastIndexOf("#");
|
|
154
|
+
if (split <= 0 || split === value.length - 1)
|
|
155
|
+
throw new Error("Check selection requires PATH#CHECK_ID");
|
|
156
|
+
const selectedPath = value.slice(0, split);
|
|
157
|
+
selections.set(selectedPath, [
|
|
158
|
+
...(selections.get(selectedPath) ?? []),
|
|
159
|
+
value.slice(split + 1),
|
|
160
|
+
]);
|
|
161
|
+
}
|
|
162
|
+
const result = await initialize(root, {
|
|
163
|
+
write: values.write,
|
|
164
|
+
selections: [...selections].map(([selectedPath, checks]) => ({
|
|
165
|
+
path: selectedPath,
|
|
166
|
+
checks,
|
|
167
|
+
})),
|
|
168
|
+
});
|
|
169
|
+
print(result);
|
|
170
|
+
process.exitCode = result.status === "needs-selection" ? 2 : 0;
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if (command === "mcp-config") {
|
|
174
|
+
if (!mcpClients.includes(values.client))
|
|
175
|
+
throw new Error(`mcp-config requires --client ${mcpClients.join("|")}`);
|
|
176
|
+
print(await mcpConfiguration(root, values.client));
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
107
179
|
if (command === "fetch-pack") {
|
|
108
180
|
if (!values.url || !values.sha256 || !values.output)
|
|
109
181
|
throw new Error("fetch-pack requires --url HTTPS_URL --sha256 DIGEST --output RELATIVE_JSON_PATH");
|
package/dist/src/index.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ export { validateContracts } from "./contracts.js";
|
|
|
3
3
|
export type { ContractBundle, ContractReport } from "./contract-schema.js";
|
|
4
4
|
export type { PlanOptions, ValidationOptions } from "./engine.js";
|
|
5
5
|
export { adapters } from "./adapters.js";
|
|
6
|
+
export { initialize, diagnose, mcpConfiguration, mcpClients, } from "./onboarding.js";
|
|
7
|
+
export type { InitOptions, InitResult, DoctorIssue, DoctorResult, McpClient, } from "./onboarding.js";
|
|
6
8
|
export type { PolicyPack, PackReference } from "./policy-pack.js";
|
|
7
9
|
export { fetchPolicyPack } from "./fetch-pack.js";
|
|
8
10
|
export type { FetchPackOptions, FetchedPack } from "./fetch-pack.js";
|
package/dist/src/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { createPlan, validate, aggregate } from "./engine.js";
|
|
2
2
|
export { validateContracts } from "./contracts.js";
|
|
3
3
|
export { adapters } from "./adapters.js";
|
|
4
|
+
export { initialize, diagnose, mcpConfiguration, mcpClients, } from "./onboarding.js";
|
|
4
5
|
export { fetchPolicyPack } from "./fetch-pack.js";
|
|
5
6
|
export { projectPlan, projectReport } from "./output.js";
|
|
6
7
|
export { importJUnit } from "./junit.js";
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type Config } from "./config.js";
|
|
2
|
+
import { type PlanOptions } from "./engine.js";
|
|
3
|
+
export interface InitOptions {
|
|
4
|
+
write?: boolean;
|
|
5
|
+
selections?: {
|
|
6
|
+
path: string;
|
|
7
|
+
checks: string[];
|
|
8
|
+
}[];
|
|
9
|
+
}
|
|
10
|
+
export interface InitResult {
|
|
11
|
+
schemaVersion: 1;
|
|
12
|
+
engineVersion: string;
|
|
13
|
+
status: "preview" | "created" | "preserved" | "needs-selection";
|
|
14
|
+
configuration: Config | null;
|
|
15
|
+
unresolved: {
|
|
16
|
+
path: string;
|
|
17
|
+
adapter: string;
|
|
18
|
+
choices: string[];
|
|
19
|
+
}[];
|
|
20
|
+
executionEnabled: false;
|
|
21
|
+
}
|
|
22
|
+
export declare function initialize(root: string, options?: InitOptions): Promise<InitResult>;
|
|
23
|
+
export interface DoctorIssue {
|
|
24
|
+
code: "configuration-error" | "empty-plan" | "unselected-project" | "unavailable-check" | "missing-executable" | "package-metadata" | "unsupported-platform";
|
|
25
|
+
check?: string;
|
|
26
|
+
adapter?: string;
|
|
27
|
+
project?: string;
|
|
28
|
+
detail?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface DoctorResult {
|
|
31
|
+
schemaVersion: 1;
|
|
32
|
+
engineVersion: string;
|
|
33
|
+
status: "no-static-blockers" | "attention-required";
|
|
34
|
+
validationPerformed: false;
|
|
35
|
+
projects: number;
|
|
36
|
+
checks: number;
|
|
37
|
+
issues: DoctorIssue[];
|
|
38
|
+
unverified: string[];
|
|
39
|
+
}
|
|
40
|
+
export declare function diagnose(root: string, options?: Omit<PlanOptions, "base"> & {
|
|
41
|
+
detailed?: boolean;
|
|
42
|
+
}): Promise<DoctorResult>;
|
|
43
|
+
export declare const mcpClients: readonly ["codex", "claude-code", "claude-desktop", "cursor", "vscode"];
|
|
44
|
+
export type McpClient = (typeof mcpClients)[number];
|
|
45
|
+
export declare function mcpConfiguration(root: string, client: McpClient): Promise<{
|
|
46
|
+
client: McpClient;
|
|
47
|
+
format: "json" | "toml";
|
|
48
|
+
configuration: string;
|
|
49
|
+
executionEnabled: false;
|
|
50
|
+
}>;
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import { constants } from "node:fs";
|
|
2
|
+
import { access, link, lstat, mkdtemp, realpath, rm, stat, writeFile, } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { adapters, checksFor } from "./adapters.js";
|
|
5
|
+
import { configSchema } from "./config.js";
|
|
6
|
+
import { createPlan } from "./engine.js";
|
|
7
|
+
import { inventory, readProjectFile } from "./inventory.js";
|
|
8
|
+
import { identifyTool } from "./tool-versions.js";
|
|
9
|
+
import { VERSION } from "./types.js";
|
|
10
|
+
async function configurationExists(root) {
|
|
11
|
+
try {
|
|
12
|
+
const entry = await lstat(path.join(root, "checktrail.json"));
|
|
13
|
+
if (!entry.isFile() || entry.isSymbolicLink())
|
|
14
|
+
throw new Error("checktrail.json must be a regular file, not a symlink or directory");
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
if (error.code === "ENOENT")
|
|
19
|
+
return false;
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export async function initialize(root, options = {}) {
|
|
24
|
+
root = await realpath(root);
|
|
25
|
+
const exists = await configurationExists(root);
|
|
26
|
+
const { source, plan } = await createPlan(root);
|
|
27
|
+
const result = {
|
|
28
|
+
schemaVersion: 1,
|
|
29
|
+
engineVersion: VERSION,
|
|
30
|
+
status: "preview",
|
|
31
|
+
configuration: null,
|
|
32
|
+
unresolved: [],
|
|
33
|
+
executionEnabled: false,
|
|
34
|
+
};
|
|
35
|
+
if (exists) {
|
|
36
|
+
if (options.selections?.length)
|
|
37
|
+
throw new Error("Existing configuration is preserved; edit its policy explicitly to change checks");
|
|
38
|
+
return { ...result, status: "preserved" };
|
|
39
|
+
}
|
|
40
|
+
const selected = new Map();
|
|
41
|
+
for (const selection of options.selections ?? []) {
|
|
42
|
+
if (selected.has(selection.path))
|
|
43
|
+
throw new Error("Duplicate selection path");
|
|
44
|
+
if (!selection.checks.length ||
|
|
45
|
+
new Set(selection.checks).size !== selection.checks.length)
|
|
46
|
+
throw new Error("Selections require nonempty, unique check IDs");
|
|
47
|
+
selected.set(selection.path, selection.checks);
|
|
48
|
+
}
|
|
49
|
+
for (const selectedPath of selected.keys())
|
|
50
|
+
if (!plan.projects.some((project) => project.path === selectedPath))
|
|
51
|
+
throw new Error("Selection does not match a discovered project path");
|
|
52
|
+
const grouped = new Map();
|
|
53
|
+
for (const project of plan.projects) {
|
|
54
|
+
const registered = adapters.find((adapter) => adapter.id === project.adapter).checks;
|
|
55
|
+
const requested = selected.get(project.path);
|
|
56
|
+
let ids = requested?.filter((id) => registered.includes(id));
|
|
57
|
+
if (!requested) {
|
|
58
|
+
ids = plan.checks
|
|
59
|
+
.filter((check) => check.project === project.path &&
|
|
60
|
+
check.adapter === project.adapter &&
|
|
61
|
+
registered.includes(check.id))
|
|
62
|
+
.map((check) => check.id);
|
|
63
|
+
if (project.adapter === "python")
|
|
64
|
+
ids = [];
|
|
65
|
+
if (project.adapter === "javascript") {
|
|
66
|
+
const manifest = JSON.parse(await readProjectFile(root, path.posix.join(project.path, "package.json")));
|
|
67
|
+
const runners = {
|
|
68
|
+
"node --test": "javascript.node-test",
|
|
69
|
+
"vitest run": "javascript.vitest",
|
|
70
|
+
jest: "javascript.jest",
|
|
71
|
+
"playwright test": "javascript.playwright",
|
|
72
|
+
};
|
|
73
|
+
const script = manifest?.scripts?.test;
|
|
74
|
+
ids =
|
|
75
|
+
typeof script === "string" && Object.hasOwn(runners, script)
|
|
76
|
+
? [runners[script]]
|
|
77
|
+
: [];
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (!ids?.length ||
|
|
81
|
+
plan.checks.some((check) => check.project === project.path &&
|
|
82
|
+
check.adapter === project.adapter &&
|
|
83
|
+
check.kind === "unsupported")) {
|
|
84
|
+
result.unresolved.push({
|
|
85
|
+
path: project.path,
|
|
86
|
+
adapter: project.adapter,
|
|
87
|
+
choices: [...registered],
|
|
88
|
+
});
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const candidates = await checksFor(source, project, ids);
|
|
92
|
+
if (ids.some((id) => !candidates.some((check) => check.id === id)))
|
|
93
|
+
throw new Error("Selected check is inapplicable to the discovered project");
|
|
94
|
+
const checks = grouped.get(project.path) ?? new Set();
|
|
95
|
+
for (const id of ids)
|
|
96
|
+
checks.add(id);
|
|
97
|
+
grouped.set(project.path, checks);
|
|
98
|
+
}
|
|
99
|
+
for (const [selectedPath, ids] of selected)
|
|
100
|
+
if (ids.some((id) => !grouped.get(selectedPath)?.has(id)))
|
|
101
|
+
throw new Error("Selected check is unknown or inapplicable");
|
|
102
|
+
if (!plan.projects.length || result.unresolved.length)
|
|
103
|
+
return { ...result, status: "needs-selection" };
|
|
104
|
+
result.configuration = configSchema.parse({
|
|
105
|
+
schemaVersion: 1,
|
|
106
|
+
projects: [...grouped].map(([projectPath, checks]) => ({
|
|
107
|
+
path: projectPath,
|
|
108
|
+
checks: [...checks].sort(),
|
|
109
|
+
})),
|
|
110
|
+
});
|
|
111
|
+
if (!options.write)
|
|
112
|
+
return result;
|
|
113
|
+
if ((await inventory(root)).fingerprint !== source.fingerprint)
|
|
114
|
+
throw new Error("Project changed during setup; review a fresh preview");
|
|
115
|
+
const temporary = await mkdtemp(path.join(root, ".checktrail-init-"));
|
|
116
|
+
try {
|
|
117
|
+
const staged = path.join(temporary, "checktrail.json");
|
|
118
|
+
await writeFile(staged, `${JSON.stringify(result.configuration, null, 2)}\n`, { flag: "wx", mode: 0o600 });
|
|
119
|
+
// An exclusive link publishes complete bytes without replacing a concurrent writer.
|
|
120
|
+
await link(staged, path.join(root, "checktrail.json"));
|
|
121
|
+
}
|
|
122
|
+
finally {
|
|
123
|
+
await rm(temporary, { recursive: true, force: true });
|
|
124
|
+
}
|
|
125
|
+
return { ...result, status: "created" };
|
|
126
|
+
}
|
|
127
|
+
async function executableAvailable(executable, cwd, searchPath) {
|
|
128
|
+
const candidates = executable.includes("/") || path.isAbsolute(executable)
|
|
129
|
+
? [path.resolve(cwd, executable)]
|
|
130
|
+
: searchPath
|
|
131
|
+
.split(path.delimiter)
|
|
132
|
+
.map((directory) => path.resolve(cwd, directory, executable));
|
|
133
|
+
for (const candidate of candidates) {
|
|
134
|
+
try {
|
|
135
|
+
if (!(await stat(candidate)).isFile())
|
|
136
|
+
continue;
|
|
137
|
+
await access(candidate, constants.X_OK);
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
/* Other PATH entries may provide the executable. */
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
export async function diagnose(root, options = {}) {
|
|
147
|
+
const issues = [];
|
|
148
|
+
const result = {
|
|
149
|
+
schemaVersion: 1,
|
|
150
|
+
engineVersion: VERSION,
|
|
151
|
+
status: "attention-required",
|
|
152
|
+
validationPerformed: false,
|
|
153
|
+
projects: 0,
|
|
154
|
+
checks: 0,
|
|
155
|
+
issues,
|
|
156
|
+
unverified: [
|
|
157
|
+
"Tool versions and runtime compatibility",
|
|
158
|
+
"Importable modules and runtime services",
|
|
159
|
+
"Validation results; run with explicit project trust",
|
|
160
|
+
],
|
|
161
|
+
};
|
|
162
|
+
const add = (issue) => {
|
|
163
|
+
const summary = { ...issue };
|
|
164
|
+
delete summary.project;
|
|
165
|
+
delete summary.detail;
|
|
166
|
+
issues.push(options.detailed ? issue : summary);
|
|
167
|
+
};
|
|
168
|
+
if (process.platform === "win32")
|
|
169
|
+
add({ code: "unsupported-platform" });
|
|
170
|
+
try {
|
|
171
|
+
root = await realpath(root);
|
|
172
|
+
await configurationExists(root);
|
|
173
|
+
const { plan } = await createPlan(root, {
|
|
174
|
+
...(options.externalAdapters
|
|
175
|
+
? { externalAdapters: options.externalAdapters }
|
|
176
|
+
: {}),
|
|
177
|
+
...(options.policyOverlay
|
|
178
|
+
? { policyOverlay: options.policyOverlay }
|
|
179
|
+
: {}),
|
|
180
|
+
...(options.environment ? { environment: options.environment } : {}),
|
|
181
|
+
});
|
|
182
|
+
result.projects = plan.projects.length;
|
|
183
|
+
result.checks = plan.checks.length;
|
|
184
|
+
if (!plan.checks.length)
|
|
185
|
+
add({ code: "empty-plan" });
|
|
186
|
+
for (const project of plan.projects)
|
|
187
|
+
if (!plan.checks.some((check) => check.project === project.path && check.adapter === project.adapter))
|
|
188
|
+
add({
|
|
189
|
+
code: "unselected-project",
|
|
190
|
+
project: project.path,
|
|
191
|
+
adapter: project.adapter,
|
|
192
|
+
});
|
|
193
|
+
for (const check of plan.checks) {
|
|
194
|
+
const context = {
|
|
195
|
+
check: check.id,
|
|
196
|
+
adapter: check.adapter,
|
|
197
|
+
project: check.project,
|
|
198
|
+
};
|
|
199
|
+
if (check.unavailableReason)
|
|
200
|
+
add({
|
|
201
|
+
...context,
|
|
202
|
+
code: "unavailable-check",
|
|
203
|
+
detail: check.unavailableReason,
|
|
204
|
+
});
|
|
205
|
+
const commands = [...check.commands];
|
|
206
|
+
for (const tool of check.tools ?? []) {
|
|
207
|
+
if (tool.source === "version-command")
|
|
208
|
+
commands.push(tool.command);
|
|
209
|
+
else if (tool.source === "package-metadata") {
|
|
210
|
+
const identity = await identifyTool(root, tool, async () => {
|
|
211
|
+
throw new Error("Doctor must not execute version probes");
|
|
212
|
+
});
|
|
213
|
+
if (identity.status !== "identified")
|
|
214
|
+
add({
|
|
215
|
+
...context,
|
|
216
|
+
code: "package-metadata",
|
|
217
|
+
detail: `Missing or invalid package metadata: ${tool.name}`,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
const wrapped = check.adapter === "jvm"
|
|
222
|
+
? ["java"]
|
|
223
|
+
: check.adapter === "dotnet"
|
|
224
|
+
? ["dotnet"]
|
|
225
|
+
: check.id === "infrastructure.actionlint"
|
|
226
|
+
? ["actionlint"]
|
|
227
|
+
: [];
|
|
228
|
+
for (const executable of wrapped)
|
|
229
|
+
commands.push({ executable, args: [], cwd: check.project });
|
|
230
|
+
const checked = new Set();
|
|
231
|
+
for (const command of commands) {
|
|
232
|
+
const searchPath = command.env?.PATH ??
|
|
233
|
+
(check.environment?.includes("PATH")
|
|
234
|
+
? options.environment?.PATH
|
|
235
|
+
: undefined) ??
|
|
236
|
+
process.env.PATH ??
|
|
237
|
+
"/usr/bin:/bin";
|
|
238
|
+
const cwd = path.resolve(root, command.cwd);
|
|
239
|
+
const key = JSON.stringify([command.executable, cwd, searchPath]);
|
|
240
|
+
if (checked.has(key))
|
|
241
|
+
continue;
|
|
242
|
+
checked.add(key);
|
|
243
|
+
if (!(await executableAvailable(command.executable, cwd, searchPath)))
|
|
244
|
+
add({
|
|
245
|
+
...context,
|
|
246
|
+
code: "missing-executable",
|
|
247
|
+
detail: `Executable unavailable or not executable: ${command.executable}`,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
catch (error) {
|
|
253
|
+
add({
|
|
254
|
+
code: "configuration-error",
|
|
255
|
+
detail: error instanceof Error ? error.message : "Cannot inspect project",
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
result.status = issues.length ? "attention-required" : "no-static-blockers";
|
|
259
|
+
return result;
|
|
260
|
+
}
|
|
261
|
+
export const mcpClients = [
|
|
262
|
+
"codex",
|
|
263
|
+
"claude-code",
|
|
264
|
+
"claude-desktop",
|
|
265
|
+
"cursor",
|
|
266
|
+
"vscode",
|
|
267
|
+
];
|
|
268
|
+
export async function mcpConfiguration(root, client) {
|
|
269
|
+
if (!mcpClients.includes(client))
|
|
270
|
+
throw new Error("Unknown MCP client");
|
|
271
|
+
root = await realpath(root);
|
|
272
|
+
if (!(await stat(root)).isDirectory())
|
|
273
|
+
throw new Error("MCP root must be a directory");
|
|
274
|
+
if (root.includes("${"))
|
|
275
|
+
throw new Error("MCP root contains client variable syntax; choose a path without ${");
|
|
276
|
+
const server = {
|
|
277
|
+
command: "npx",
|
|
278
|
+
args: [
|
|
279
|
+
"--yes",
|
|
280
|
+
"--ignore-scripts",
|
|
281
|
+
`@stsepelin/checktrail@${VERSION}`,
|
|
282
|
+
"serve",
|
|
283
|
+
"--root",
|
|
284
|
+
root,
|
|
285
|
+
],
|
|
286
|
+
};
|
|
287
|
+
return {
|
|
288
|
+
client,
|
|
289
|
+
executionEnabled: false,
|
|
290
|
+
format: client === "codex" ? "toml" : "json",
|
|
291
|
+
configuration: client === "codex"
|
|
292
|
+
? `[mcp_servers.checktrail]\ncommand = "npx"\nargs = ${JSON.stringify(server.args)}\n`
|
|
293
|
+
: `${JSON.stringify(client === "vscode" ? { servers: { checktrail: { type: "stdio", ...server } } } : { mcpServers: { checktrail: server } }, null, 2)}\n`,
|
|
294
|
+
};
|
|
295
|
+
}
|
package/dist/src/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ExternalIdentity } from "./external-adapter.js";
|
|
2
2
|
import type { RuntimeInventory } from "./runtime-inventory.js";
|
|
3
|
-
export declare const VERSION = "0.1.0-alpha.
|
|
3
|
+
export declare const VERSION = "0.1.0-alpha.2";
|
|
4
4
|
export declare const PARSERS: readonly ["vue-router-json", "nuxt-json", "exit", "empty", "node-events", "unittest", "go-scope-test", "go-scope-analysis", "golangci-json", "staticcheck-json", "go-json", "typescript-build-json", "tsc-files", "eslint-json", "vitest-json", "playwright-json", "jest-json", "pytest-json", "fastapi-json", "django-json", "laravel-json", "rust-json", "clang-json", "java-json", "dotnet-json", "actionlint-json", "external-json", "ruby-syntax", "silent-syntax", "ruff-json", "mypy-json", "phpstan-json", "phpunit-junit", "pint-json"];
|
|
5
5
|
export type Status = "passed" | "failed" | "unavailable" | "skipped" | "error" | "inconclusive";
|
|
6
6
|
export type Outcome = "passed" | "failed" | "incomplete";
|
package/dist/src/types.js
CHANGED
package/docs/ACCEPTANCE.md
CHANGED
|
@@ -5,14 +5,14 @@ verification. It does not replace the plan or promote an unverified capability.
|
|
|
5
5
|
Local implementation, local native evidence, hosted CI and publication are
|
|
6
6
|
separate states. Follow the linked evidence for tested versions and limits.
|
|
7
7
|
|
|
8
|
-
| Milestone | Implemented scope and evidence | Open acceptance work
|
|
9
|
-
| --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
10
|
-
| M0: public contracts | Original public fixtures, MIT license, security/contribution guidance, schemas, explicit package allowlist, dependency notices and CI definitions. `STATUS.md`, `SECURITY.md`, `RELEASE.md`. | Public source
|
|
11
|
-
| M1: executable foundation | Shared CLI/library/MCP engine, bounded inventory/runner, startup trust, native Node/Python/Go/PHP profiles, protocol and lifecycle regressions. `ARCHITECTURE.md`, `STATUS.md`, `MCP-COMPATIBILITY.md`. Fresh installed application-client profiles now have evidence in `CLIENTS.md`. | Application-client coverage beyond the named profiles. PHP remains unavailable when the consumer has no prepared runtime.
|
|
12
|
-
| M2: practical language validation | Explicit JS/TS, Python, Go and PHP native tool profiles, structured diagnostics/test evidence, versions, environments, workspace selection, scope accounting, SARIF/JUnit and finding ratchets. `LANGUAGES.md`, adapter documents, `WORKSPACES.md`, `FINDING-POLICY.md`, `NATIVE-CI.md`. | Hosted toolchain profiles passed at `52ba415`. Wider tool versions/framework configurations must be promoted separately; detection is not execution support.
|
|
13
|
-
| M3: framework/contracts | Native Laravel, Vue Router/Nuxt, Django/FastAPI assembly projections; imported runtime comparison, explicit architecture boundaries, producer/consumer schemas and a built package consumer. `RUNTIME-INVENTORY.md`, framework documents, `CONTRACTS.md`, `ARCHITECTURE-POLICY.md`, `examples/package-contract/README.md`. | Broader native semantics/import collection and live service integration are not implemented. Synthetic evidence does not establish equivalent results in a private application; private integration feedback must remain private.
|
|
14
|
-
| M4: ecosystem/distribution | Bounded Rust, Java, C#, Ruby, Swift, Clang and actionlint profiles; trusted external adapters, pinned data-only pack distribution, fresh offline package checks, production notice audit, measured performance and unpublished registry metadata. `LANGUAGES.md`, `EXTERNAL-ADAPTERS.md`, `PACK-DISTRIBUTION.md`, `PERFORMANCE.md`, `RELEASE.md`. |
|
|
15
|
-
| M5: measured assistance | Advisory guidance, bounded Node mutation experiments, explicit-graph impact measurements, optional local/model review exchange, durable library task storage/worker, development evaluation and externally authored ESLint and Ruff integration cohorts. `GUIDANCE.md`, `MUTATIONS.md`, `IMPACT-MEASUREMENT.md`, `REVIEW-EXCHANGE.md`, `VALIDATION-TASKS.md`, `EVALUATION.md`, `EXTERNAL-EVALUATION.md`, `EXTERNAL-RUFF-EVALUATION.md`. | Standard MCP Tasks wire integration; wider held-out rule-family/review evidence, prior-workflow comparison and representative cost/latency measurement. No general equal-or-better review-quality claim is supported.
|
|
8
|
+
| Milestone | Implemented scope and evidence | Open acceptance work |
|
|
9
|
+
| --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
10
|
+
| M0: public contracts | Original public fixtures, MIT license, security/contribution guidance, schemas, explicit package allowlist, dependency notices and CI definitions. `STATUS.md`, `SECURITY.md`, `RELEASE.md`. | Public source and npm alpha.1 are published. Hosted CI passed at `bfc8cc4`; alpha.2 requires its own release commit, CI and publication verification. |
|
|
11
|
+
| M1: executable foundation | Shared CLI/library/MCP engine, bounded inventory/runner, startup trust, native Node/Python/Go/PHP profiles, protocol and lifecycle regressions. `ARCHITECTURE.md`, `STATUS.md`, `MCP-COMPATIBILITY.md`. Fresh installed application-client profiles now have evidence in `CLIENTS.md`. | Application-client coverage beyond the named profiles. PHP remains unavailable when the consumer has no prepared runtime. |
|
|
12
|
+
| M2: practical language validation | Explicit JS/TS, Python, Go and PHP native tool profiles, structured diagnostics/test evidence, versions, environments, workspace selection, scope accounting, SARIF/JUnit and finding ratchets. `LANGUAGES.md`, adapter documents, `WORKSPACES.md`, `FINDING-POLICY.md`, `NATIVE-CI.md`. | Hosted toolchain profiles passed at `52ba415`. Wider tool versions/framework configurations must be promoted separately; detection is not execution support. |
|
|
13
|
+
| M3: framework/contracts | Native Laravel, Vue Router/Nuxt, Django/FastAPI assembly projections; imported runtime comparison, explicit architecture boundaries, producer/consumer schemas and a built package consumer. `RUNTIME-INVENTORY.md`, framework documents, `CONTRACTS.md`, `ARCHITECTURE-POLICY.md`, `examples/package-contract/README.md`. | Broader native semantics/import collection and live service integration are not implemented. Synthetic evidence does not establish equivalent results in a private application; private integration feedback must remain private. |
|
|
14
|
+
| M4: ecosystem/distribution | Bounded Rust, Java, C#, Ruby, Swift, Clang and actionlint profiles; trusted external adapters, pinned data-only pack distribution, fresh offline package checks, production notice audit, measured performance and unpublished registry metadata. `LANGUAGES.md`, `EXTERNAL-ADAPTERS.md`, `PACK-DISTRIBUTION.md`, `PERFORMANCE.md`, `RELEASE.md`. | Alpha.2 release verification and MCP Registry registration. Windows execution and the unimplemented subsequent integrations in `LANGUAGES.md` remain unsupported. Runtime/container/development dependency provenance is broader than the production npm notice audit. |
|
|
15
|
+
| M5: measured assistance | Advisory guidance, bounded Node mutation experiments, explicit-graph impact measurements, optional local/model review exchange, durable library task storage/worker, development evaluation and externally authored ESLint and Ruff integration cohorts. `GUIDANCE.md`, `MUTATIONS.md`, `IMPACT-MEASUREMENT.md`, `REVIEW-EXCHANGE.md`, `VALIDATION-TASKS.md`, `EVALUATION.md`, `EXTERNAL-EVALUATION.md`, `EXTERNAL-RUFF-EVALUATION.md`. | Standard MCP Tasks wire integration; wider held-out rule-family/review evidence, prior-workflow comparison and representative cost/latency measurement. No general equal-or-better review-quality claim is supported. |
|
|
16
16
|
|
|
17
17
|
## Remaining work that can proceed locally
|
|
18
18
|
|
|
@@ -43,11 +43,12 @@ run. The local worker/store are available independently; standard Tasks must sta
|
|
|
43
43
|
unadvertised until routing and the integrated wire/lifecycle suite pass. See
|
|
44
44
|
`MCP-COMPATIBILITY.md` for the reproduction and upstream issue.
|
|
45
45
|
|
|
46
|
-
The public repository and
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
requirements still apply.
|
|
46
|
+
The public repository and npm preview `0.1.0-alpha.1` are published. The
|
|
47
|
+
[hosted run at bfc8cc4](https://github.com/stsepelin/checktrail/actions/runs/35585998184)
|
|
48
|
+
passed all jobs. Alpha.2 adds [setup commands](ONBOARDING.md); it requires its own
|
|
49
|
+
release CI and publication. GitHub releases and MCP Registry registration remain
|
|
50
|
+
pending. The repository's explicit-action requirements still apply.
|
|
51
|
+
`RELEASE.md` defines the concrete
|
|
51
52
|
candidate checks and the authorization sequence; a local green run does not
|
|
52
53
|
replace external acceptance.
|
|
53
54
|
|
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -58,7 +58,9 @@ pass by a parser. Source changes during execution invalidate a green result.
|
|
|
58
58
|
|
|
59
59
|
Use bounded process output and timeouts, terminate the process group on supported
|
|
60
60
|
POSIX hosts, and propagate cancellation. No automatic dependency installation,
|
|
61
|
-
source rewriting, infrastructure startup
|
|
61
|
+
source rewriting, infrastructure startup or deployment. The explicit `init --write`
|
|
62
|
+
setup command can create a new `checktrail.json`; it preserves existing
|
|
63
|
+
configuration and grants no execution. See [ONBOARDING.md](ONBOARDING.md).
|
|
62
64
|
Executed project code still has the process user's privileges; this is not a
|
|
63
65
|
sandbox. Tests may modify files or access networks and must be trusted accordingly.
|
|
64
66
|
|
package/docs/INSTALLATION.md
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
# Install the preview
|
|
2
2
|
|
|
3
|
-
The
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
The published preview is `0.1.0-alpha.1` on
|
|
4
|
+
[npm](https://www.npmjs.com/package/@stsepelin/checktrail).
|
|
5
|
+
Use the exact version below. The registry currently assigns both `next` and
|
|
6
|
+
`latest` to that preview; `latest` is not a stable-release guarantee.
|
|
7
|
+
The alpha.2 candidate adds [project setup and diagnosis](ONBOARDING.md) and is
|
|
8
|
+
available from source or a reviewed candidate tarball until published.
|
|
7
9
|
|
|
8
10
|
Use Node.js 22 or newer on macOS or Linux. Windows execution is not supported.
|
|
9
11
|
Install each project's compilers, linters and test runners separately; Checktrail
|
|
10
12
|
does not download them. Missing tools produce incomplete results.
|
|
11
13
|
|
|
14
|
+
For agent workflows, see [installing skills with `npx skills`](SKILLS.md).
|
|
15
|
+
Skills install separately from the engine and MCP configuration.
|
|
16
|
+
|
|
12
17
|
## CLI
|
|
13
18
|
|
|
14
19
|
Install the exact version once:
|
|
@@ -84,7 +89,7 @@ Validation uses asynchronous calls and supports cancellation. Standard MCP Tasks
|
|
|
84
89
|
is not advertised; the durable worker is a separate library API. See
|
|
85
90
|
[client coverage](CLIENTS.md) and [MCP compatibility](MCP-COMPATIBILITY.md).
|
|
86
91
|
|
|
87
|
-
##
|
|
92
|
+
## Source checkout or unpublished candidate
|
|
88
93
|
|
|
89
94
|
Build the public source checkout:
|
|
90
95
|
|
package/docs/LANGUAGES.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Language and ecosystem roadmap
|
|
2
2
|
|
|
3
|
+
The alpha.2 candidate's [setup guide](ONBOARDING.md) describes conservative
|
|
4
|
+
per-language configuration proposals and static tool diagnosis. Setup does not
|
|
5
|
+
extend the execution capabilities or native evidence listed below.
|
|
6
|
+
|
|
3
7
|
Capability levels are discovery, planning, execution, structured evidence,
|
|
4
8
|
semantic rules, and integration validation. None implies the next. This file's
|
|
5
9
|
initial scope column describes the experimental implementation. Node, Python,
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Project setup
|
|
2
|
+
|
|
3
|
+
These commands are new in the unpublished `0.1.0-alpha.2` candidate. Use the
|
|
4
|
+
source checkout or a reviewed candidate tarball, with Node.js 22+ on macOS/Linux.
|
|
5
|
+
|
|
6
|
+
## Preview and create a policy
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
checktrail init --root "$PWD"
|
|
10
|
+
checktrail init --root "$PWD" --write
|
|
11
|
+
checktrail doctor --root "$PWD" --detailed
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
`init` returns JSON with a proposed `configuration`. The preview changes nothing.
|
|
15
|
+
`--write` creates `checktrail.json` only when every discovered ecosystem has a
|
|
16
|
+
selected supported check, publishing complete contents without replacing an
|
|
17
|
+
existing file. A valid existing policy returns `preserved`, retaining its bytes,
|
|
18
|
+
packs, environment requirements and workspace graph. Invalid policies, directories
|
|
19
|
+
and symlinks are errors and remain untouched. There is no overwrite option.
|
|
20
|
+
|
|
21
|
+
The preview includes relative project paths, groups ecosystems sharing a directory
|
|
22
|
+
and preserves nested project boundaries. It does not infer workspace dependencies,
|
|
23
|
+
grant execution, install tools, run scripts or import project code. Use `doctor`
|
|
24
|
+
and the detailed plan to inspect prerequisites before running validation.
|
|
25
|
+
|
|
26
|
+
| Ecosystem | Initial selection |
|
|
27
|
+
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
28
|
+
| JavaScript / TypeScript | Exact test scripts `node --test`, `vitest run`, `jest`, or `playwright test`; other commands need selection. Linters and type checks require explicit selection. |
|
|
29
|
+
| Python | Explicit runner/check selection required; a manifest cannot identify a test framework. |
|
|
30
|
+
| Go | Existing format, vet and test defaults. |
|
|
31
|
+
| PHP | Syntax only; tests and analysis require explicit selection. |
|
|
32
|
+
| Rust, Java, C#, Ruby, Swift, C/C++ | Existing bounded adapter defaults; profiles, tools and dependencies still need preparation. |
|
|
33
|
+
| Infrastructure | GitHub Actions checking where applicable; other infrastructure remains an unresolved gap. |
|
|
34
|
+
|
|
35
|
+
`needs-selection` exits `2`, returns no partial configuration and writes nothing.
|
|
36
|
+
Its `unresolved` entries list paths, ecosystems and registered choices; those
|
|
37
|
+
choices do not promise tools are installed or applicable to every source file.
|
|
38
|
+
Repeated `--check PATH#CHECK_ID` arguments select the complete check set for a path:
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
checktrail init --root "$PWD" --check '.#python.pytest' --check '.#python.ruff'
|
|
42
|
+
checktrail init --root "$PWD" --check '.#python.pytest' --check '.#python.ruff' --write
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Paths must exactly match discovered roots. For a polyglot directory, include
|
|
46
|
+
checks for every discovered ecosystem there. Unmentioned paths keep defaults.
|
|
47
|
+
Unknown and duplicate IDs are errors. Setup never silently drops unsupported
|
|
48
|
+
ecosystems. External adapters and private overlays are supported by planning and
|
|
49
|
+
diagnosis but are not generated by `init`.
|
|
50
|
+
|
|
51
|
+
## Diagnose setup without execution
|
|
52
|
+
|
|
53
|
+
`doctor` reuses the planner. It reports invalid configuration, unavailable checks,
|
|
54
|
+
missing/non-executable programs, invalid JS tool metadata, missing required
|
|
55
|
+
environment, empty plans, unsupported platforms and ecosystems omitted by policy.
|
|
56
|
+
An intentionally narrowed policy can therefore produce `unselected-project`.
|
|
57
|
+
|
|
58
|
+
Executable checks use the effective PATH and file permissions. Diagnosis never
|
|
59
|
+
runs version commands, imports modules, boots frameworks or runs tests. Prepare
|
|
60
|
+
native tools and activate Python environments on the PATH used for validation.
|
|
61
|
+
|
|
62
|
+
Output always includes `validationPerformed: false` and unverified runtime
|
|
63
|
+
properties. `no-static-blockers` exits `0`; `attention-required` exits `2`.
|
|
64
|
+
Neither means validation passed. Tool compatibility, importable modules, services
|
|
65
|
+
and execution results still need a trusted `run`.
|
|
66
|
+
|
|
67
|
+
Summary output omits paths and raw errors. `--detailed` adds paths and diagnostic
|
|
68
|
+
details that can contain absolute paths. Supported options include
|
|
69
|
+
`--policy-overlay`, pinned `--adapter` references and `--allow-env NAME`.
|
|
70
|
+
Environment values are not printed. Git selection and execution flags are rejected.
|
|
71
|
+
|
|
72
|
+
## Generate MCP configuration
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
checktrail mcp-config --root "$PWD" --client codex
|
|
76
|
+
checktrail mcp-config --root "$PWD" --client claude-code
|
|
77
|
+
checktrail mcp-config --root "$PWD" --client claude-desktop
|
|
78
|
+
checktrail mcp-config --root "$PWD" --client cursor
|
|
79
|
+
checktrail mcp-config --root "$PWD" --client vscode
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Output is JSON containing `format` and a `configuration` string. Merge the decoded
|
|
83
|
+
string's server entry into the appropriate client configuration. The generator
|
|
84
|
+
never opens or overwrites client files. Do not redirect the JSON envelope over
|
|
85
|
+
an existing configuration.
|
|
86
|
+
|
|
87
|
+
| Client | Generated format / location |
|
|
88
|
+
| -------------- | ------------------------------------------------------------- |
|
|
89
|
+
| Codex | TOML `mcp_servers.checktrail`; Codex `config.toml`. |
|
|
90
|
+
| Claude Code | JSON `mcpServers.checktrail`; project `.mcp.json`. |
|
|
91
|
+
| Claude Desktop | JSON `mcpServers.checktrail`; developer MCP configuration. |
|
|
92
|
+
| Cursor | JSON `mcpServers.checktrail`; `.cursor/mcp.json`. |
|
|
93
|
+
| VS Code | JSON `servers.checktrail`, `type: stdio`; `.vscode/mcp.json`. |
|
|
94
|
+
|
|
95
|
+
Snippets capture the canonical absolute root and pin the generating engine version
|
|
96
|
+
in `npx --yes --ignore-scripts @stsepelin/checktrail@VERSION serve`. Execution
|
|
97
|
+
and detailed output remain disabled; client trust settings still apply. Roots
|
|
98
|
+
containing `${` are rejected because client interpolation could change the root.
|
|
99
|
+
|
|
100
|
+
Generation needs no network; starting npx may download the pinned package. The
|
|
101
|
+
version must be published first. For an unpublished candidate, use its installed
|
|
102
|
+
absolute `checktrail` executable with `serve --root /absolute/project` instead.
|
|
103
|
+
After reviewing an update, regenerate/merge the entry and restart the client.
|
|
104
|
+
Updating a global CLI does not change an npx version pin.
|
|
105
|
+
|
|
106
|
+
Formats follow official [Codex](https://developers.openai.com/codex/mcp/),
|
|
107
|
+
[Claude Code](https://code.claude.com/docs/en/mcp),
|
|
108
|
+
[Cursor](https://cursor.com/docs/mcp), and
|
|
109
|
+
[VS Code](https://code.visualstudio.com/docs/agent-customization/mcp-servers)
|
|
110
|
+
documentation. Generation is not proof of a client connection; [CLIENTS.md](CLIENTS.md)
|
|
111
|
+
records tested application profiles and limits.
|
|
112
|
+
|
|
113
|
+
## Upgrade and rollback verification
|
|
114
|
+
|
|
115
|
+
Build and prepare the npm cache for both reviewed artifacts, then run:
|
|
116
|
+
|
|
117
|
+
```sh
|
|
118
|
+
node scripts/verify-package-upgrade.mjs /absolute/baseline.tgz /absolute/candidate.tgz
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The verifier installs baseline → candidate → baseline into one isolated consumer
|
|
122
|
+
offline with lifecycle scripts disabled. Each stage checks the CLI version,
|
|
123
|
+
planning, a native Node test, MCP planning and denied untrusted execution. Project
|
|
124
|
+
source, policy and existing client configuration must remain byte-identical.
|
|
125
|
+
The candidate must preserve the policy through `init --write`, diagnose it, and
|
|
126
|
+
import the baseline report through SARIF export. Output records artifact hashes
|
|
127
|
+
and measured stages. This exercises a synthetic Node workflow, not migration of
|
|
128
|
+
every language/tool profile.
|
package/docs/RELEASE.md
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
# Release preparation
|
|
2
2
|
|
|
3
3
|
The source is public at [stsepelin/checktrail](https://github.com/stsepelin/checktrail);
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
`@stsepelin/checktrail@0.1.0-alpha.1` is published on npm. Its downloaded artifact
|
|
5
|
+
matched the reviewed tarball with SHA-256
|
|
6
|
+
`84003e184805b6c5362c0801c702a72e415040ae5142fcd70f01eb9758637d04`.
|
|
7
|
+
Fresh registry installation, CLI and MCP startup were verified. The alpha.2
|
|
8
|
+
candidate adds [setup and diagnosis](ONBOARDING.md); it is not yet published.
|
|
9
|
+
`server.json` describes the intended `io.github.stsepelin/checktrail` MCP Registry
|
|
10
|
+
identity with the candidate's matching npm version. Registry registration remains
|
|
11
|
+
pending. No credentials or automatic publishing workflow are stored here.
|
|
12
|
+
|
|
13
|
+
Publication is configured for npm's `next` tag. After alpha.1 publication, the
|
|
14
|
+
registry assigned both `next` and `latest` to that preview; attempts to remove
|
|
15
|
+
`latest` returned HTTP 400. The cause is unresolved. Use exact versions and
|
|
16
|
+
resolve the tag policy before publishing another candidate; do not treat `latest`
|
|
17
|
+
as evidence of a stable release or republish an existing version.
|
|
10
18
|
|
|
11
19
|
## Prepared artifacts
|
|
12
20
|
|
|
@@ -24,8 +32,8 @@ publishing workflow are stored in this repository.
|
|
|
24
32
|
loads the installed metadata and verifies its actual startup command.
|
|
25
33
|
- CI definitions cover the host suite and prepared native profiles. Local
|
|
26
34
|
containers and package checks are evidence only for the environments actually
|
|
27
|
-
exercised.
|
|
28
|
-
release commit requires its own run. The local Claude Code health/discovery and
|
|
35
|
+
exercised. The [hosted run at bfc8cc4](https://github.com/stsepelin/checktrail/actions/runs/35585998184)
|
|
36
|
+
passed all jobs; the alpha.2 release commit requires its own run. The local Claude Code health/discovery and
|
|
29
37
|
Codex direct app-server profiles have fresh-install evidence in `CLIENTS.md`.
|
|
30
38
|
|
|
31
39
|
The metadata follows the official registry
|
|
@@ -61,7 +69,7 @@ After explicit approval and npm authentication for the `@stsepelin` scope, publi
|
|
|
61
69
|
the approved file, not a newly packed working tree:
|
|
62
70
|
|
|
63
71
|
```sh
|
|
64
|
-
npm publish /absolute/path/stsepelin-checktrail-0.1.0-alpha.
|
|
72
|
+
npm publish /absolute/path/stsepelin-checktrail-0.1.0-alpha.2.tgz \
|
|
65
73
|
--tag next --access public --ignore-scripts --registry=https://registry.npmjs.org
|
|
66
74
|
```
|
|
67
75
|
|
|
@@ -93,6 +101,8 @@ GitHub private vulnerability reporting is enabled. Use the channel linked in
|
|
|
93
101
|
Run the corresponding native verification helpers for every advertised profile.
|
|
94
102
|
Record actual tool/platform results and explicit skips. Repeat registry schema
|
|
95
103
|
validation against its pinned bytes.
|
|
104
|
+
Run `scripts/verify-package-upgrade.mjs` with the reviewed previous and candidate
|
|
105
|
+
tarballs to verify offline upgrade, policy/report compatibility and rollback.
|
|
96
106
|
3. Inspect the exact tarball and its SHA-256, its source revision, dependency/notice
|
|
97
107
|
report, package allowlist, public examples and documentation. The smoke helper
|
|
98
108
|
compares repeated packing of the same checkout and tests a fresh offline install;
|
package/docs/SKILLS.md
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Install agent skills with npx skills
|
|
2
|
+
|
|
3
|
+
Checktrail provides portable workflows for setup, validation and review:
|
|
4
|
+
|
|
5
|
+
| Skill | Use it for |
|
|
6
|
+
| --------------------- | ------------------------------------------------------------------------------ |
|
|
7
|
+
| `checktrail-setup` | Configure project roots, select supported language checks and connect MCP |
|
|
8
|
+
| `checktrail-validate` | Run authorized checks and distinguish passed, failed and incomplete evidence |
|
|
9
|
+
| `checktrail-review` | Review code and test adequacy using validation evidence and advisory questions |
|
|
10
|
+
|
|
11
|
+
Each skill is self-contained in `skills/<name>/SKILL.md` and follows the
|
|
12
|
+
[Agent Skills format](https://agentskills.io/specification). The
|
|
13
|
+
[Vercel skills CLI](https://github.com/vercel-labs/skills) installs these folders
|
|
14
|
+
from GitHub. No Checktrail plugin or separate skills registry registration is
|
|
15
|
+
required for installation by repository URL.
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
These GitHub commands require the `skills/` directory to be present on the public
|
|
20
|
+
repository's default branch. For an unpublished checkout, use the local command
|
|
21
|
+
below. Listing the remote source first verifies what is available:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
npx skills add stsepelin/checktrail --list
|
|
25
|
+
npx skills add stsepelin/checktrail
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The interactive installer lets you choose skills and target agents. For an
|
|
29
|
+
explicit project installation, run from the repository where you want to use
|
|
30
|
+
Checktrail:
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
npx skills add stsepelin/checktrail \
|
|
34
|
+
--skill checktrail-setup checktrail-validate checktrail-review \
|
|
35
|
+
--agent codex claude-code cursor
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Choose only the agents you use. Add `--global` for a personal installation shared
|
|
39
|
+
across projects, or `--yes` when deliberately skipping installer prompts. The
|
|
40
|
+
default installation uses project directories; it does not configure an MCP server.
|
|
41
|
+
Use `--copy` if independent copies are preferable to the installer's default links.
|
|
42
|
+
|
|
43
|
+
To install from a local checkout before pushing, substitute its absolute path:
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
npx skills add /absolute/path/to/checktrail --skill checktrail-validate --agent codex
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The CLI's agent target names are installer options, not evidence that Checktrail
|
|
50
|
+
has been tested end-to-end in every editor. See [client coverage](CLIENTS.md).
|
|
51
|
+
Reload skills or start a new session as required by the selected agent. Example
|
|
52
|
+
requests are "Set up Checktrail for this repository", "Validate these changes
|
|
53
|
+
with Checktrail", and "Review this diff using Checktrail evidence".
|
|
54
|
+
|
|
55
|
+
## Install the engine separately
|
|
56
|
+
|
|
57
|
+
`npx skills` installs instructions. It does not install the npm engine, native
|
|
58
|
+
language tools, an MCP server, or execution permissions. The skills support an
|
|
59
|
+
existing MCP connection or the CLI, including the published preview:
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
npx --yes --ignore-scripts @stsepelin/checktrail@0.1.0-alpha.1 plan --root /absolute/project
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Use Node.js 22+ on macOS or Linux. See [installation](INSTALLATION.md) for persistent
|
|
66
|
+
CLI installation, MCP registration and operator-controlled execution. Skills do
|
|
67
|
+
not expand native language coverage, grant trust, or replace required CI checks.
|
|
68
|
+
|
|
69
|
+
## Update and remove
|
|
70
|
+
|
|
71
|
+
For GitHub-installed project skills, update just Checktrail's workflows:
|
|
72
|
+
|
|
73
|
+
```sh
|
|
74
|
+
npx skills update checktrail-setup checktrail-validate checktrail-review --project
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Use `--global` instead of `--project` for a global installation. Updates replace
|
|
78
|
+
installed instructions; keep project-specific policy in your project's own files.
|
|
79
|
+
Retain and review the project installation's `skills-lock.json` and file changes.
|
|
80
|
+
For local-path installations, re-run `skills add` against the updated checkout.
|
|
81
|
+
|
|
82
|
+
The installer version used for local verification is `skills@1.7.0`. It aliases
|
|
83
|
+
`skills check` to `skills update`; do not use `check` as a read-only update probe.
|
|
84
|
+
Use `npx skills list` to inspect installed skills. Pin the installer itself with
|
|
85
|
+
`npx skills@1.7.0` when reproducing the installation checks.
|
|
86
|
+
|
|
87
|
+
Skill updates and engine updates are separate. The skills declare the Checktrail
|
|
88
|
+
version they target. To update the engine, deliberately select a compatible npm
|
|
89
|
+
version and restart the MCP process. Updating skills never changes its root,
|
|
90
|
+
execution grant or output disclosure settings. For a reproducible skill revision,
|
|
91
|
+
install from a reviewed GitHub tree URL containing a commit SHA and the selected
|
|
92
|
+
skill path; re-add that same revision to roll back. Do not treat following a branch
|
|
93
|
+
as an immutable pin.
|
|
94
|
+
|
|
95
|
+
Remove the project skills with:
|
|
96
|
+
|
|
97
|
+
```sh
|
|
98
|
+
npx skills remove checktrail-setup checktrail-validate checktrail-review
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Add `--global` for a global removal. This removes skills, not the separately
|
|
102
|
+
installed engine or MCP configuration.
|
|
103
|
+
|
|
104
|
+
## Verification boundaries
|
|
105
|
+
|
|
106
|
+
Local checks exercise discovery, selective installation, copy/link destinations,
|
|
107
|
+
file integrity, reinstallation from an updated local source and removal in
|
|
108
|
+
temporary projects. They do not modify personal agent installations. Skill format
|
|
109
|
+
validation does not prove model behavior or improved review quality. Installation
|
|
110
|
+
from the public GitHub source and remote update verification require the changes
|
|
111
|
+
to be pushed; a local installation is not evidence of either.
|
|
112
|
+
|
|
113
|
+
Reproduce the installation checks from the Checktrail checkout:
|
|
114
|
+
|
|
115
|
+
```sh
|
|
116
|
+
npm install --prefix .checktrail/skills-tools --ignore-scripts --no-audit --no-fund \
|
|
117
|
+
--package-lock=false --save-exact skills@1.7.0
|
|
118
|
+
node scripts/verify-skills-install.mjs .checktrail/skills-tools/node_modules/skills/bin/cli.mjs
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The helper uses temporary project and installer-state directories, exercises the
|
|
122
|
+
real installer, and removes its fixtures afterward. It does not run a model,
|
|
123
|
+
register MCP, install global skills, or invoke remote skill updates.
|
package/docs/STATUS.md
CHANGED
|
@@ -3,12 +3,19 @@
|
|
|
3
3
|
This is an experimental foundation with public source at
|
|
4
4
|
[stsepelin/checktrail](https://github.com/stsepelin/checktrail).
|
|
5
5
|
Check the [installation guide](INSTALLATION.md) for package availability and setup.
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
The `0.1.0-alpha.1` preview is published on npm. The newer
|
|
7
|
+
[hosted run at bfc8cc4](https://github.com/stsepelin/checktrail/actions/runs/35585998184)
|
|
8
|
+
passed all jobs; earlier toolchain evidence remains in `NATIVE-CI.md`.
|
|
9
|
+
The alpha.2 candidate adds setup commands and requires its own release CI and
|
|
10
|
+
publication. MCP Registry registration remains pending.
|
|
9
11
|
|
|
10
12
|
## Implemented
|
|
11
13
|
|
|
14
|
+
- Alpha.2 candidate: conservative multi-language `init`, execution-free `doctor`,
|
|
15
|
+
and version-pinned MCP configuration output for Codex, Claude Code/Desktop,
|
|
16
|
+
Cursor and VS Code. Existing files are preserved. See [ONBOARDING.md](ONBOARDING.md)
|
|
17
|
+
for scope, ambiguity handling and package upgrade/rollback verification.
|
|
18
|
+
|
|
12
19
|
- Exact required-test accounting across prepared CI language profiles and native
|
|
13
20
|
container helpers, including dedicated Ruby/Swift jobs. Skipped, missing,
|
|
14
21
|
duplicate, TODO or failing cases cannot satisfy these profiles. Hosted profiles
|
package/package.json
CHANGED
package/server.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "io.github.stsepelin/checktrail",
|
|
4
4
|
"title": "Checktrail",
|
|
5
5
|
"description": "Local code validation with explicit execution trust and evidence of what actually ran.",
|
|
6
|
-
"version": "0.1.0-alpha.
|
|
6
|
+
"version": "0.1.0-alpha.2",
|
|
7
7
|
"repository": {
|
|
8
8
|
"url": "https://github.com/stsepelin/checktrail",
|
|
9
9
|
"source": "github"
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"registryType": "npm",
|
|
14
14
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
15
15
|
"identifier": "@stsepelin/checktrail",
|
|
16
|
-
"version": "0.1.0-alpha.
|
|
16
|
+
"version": "0.1.0-alpha.2",
|
|
17
17
|
"runtimeHint": "npx",
|
|
18
18
|
"transport": {
|
|
19
19
|
"type": "stdio"
|