@fro.bot/systematic 3.16.2 → 3.16.3
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/dist/cli.js
CHANGED
|
@@ -2085,6 +2085,23 @@ function isLegacyReviewArtifact(value) {
|
|
|
2085
2085
|
function hasParentDirectoryTraversal(input) {
|
|
2086
2086
|
return input.split(/[\\/]+/).some((segment) => segment === "..");
|
|
2087
2087
|
}
|
|
2088
|
+
var ALLOW_OUTSIDE_ARTIFACT_ROOT_FLAG = "--allow-outside-artifact-root";
|
|
2089
|
+
var VALIDATE_REVIEW_ARTIFACT_USAGE = "Usage: systematic validate-review-artifact <path> [--allow-outside-artifact-root]";
|
|
2090
|
+
function parseValidateReviewArtifactArguments(argv) {
|
|
2091
|
+
const allowOutsideArtifactRoot = argv.includes(ALLOW_OUTSIDE_ARTIFACT_ROOT_FLAG);
|
|
2092
|
+
const positional = argv.filter((arg) => arg !== ALLOW_OUTSIDE_ARTIFACT_ROOT_FLAG);
|
|
2093
|
+
if (positional.length !== 1)
|
|
2094
|
+
return;
|
|
2095
|
+
const path = positional[0];
|
|
2096
|
+
if (path === undefined)
|
|
2097
|
+
return;
|
|
2098
|
+
return { allowOutsideArtifactRoot, path };
|
|
2099
|
+
}
|
|
2100
|
+
var REVIEW_ARTIFACT_VALID_MESSAGE = "Review artifact is valid";
|
|
2101
|
+
var REVIEW_ARTIFACT_VALID_EXTERNAL_MESSAGE = "Review artifact is valid (validated outside the run directory; not evidence for this run)";
|
|
2102
|
+
function formatReviewArtifactSuccessMessage(allowOutsideArtifactRoot) {
|
|
2103
|
+
return allowOutsideArtifactRoot ? REVIEW_ARTIFACT_VALID_EXTERNAL_MESSAGE : REVIEW_ARTIFACT_VALID_MESSAGE;
|
|
2104
|
+
}
|
|
2088
2105
|
function pathContainsSymlink(candidate) {
|
|
2089
2106
|
let current = path3.parse(candidate).root;
|
|
2090
2107
|
const relative = path3.relative(current, candidate);
|
|
@@ -2105,30 +2122,33 @@ function isWithinDirectory(candidate, directory) {
|
|
|
2105
2122
|
const relative = path3.relative(directory, candidate);
|
|
2106
2123
|
return relative !== "" && relative !== ".." && !relative.startsWith(`..${path3.sep}`) && !path3.isAbsolute(relative);
|
|
2107
2124
|
}
|
|
2108
|
-
function resolveReviewArtifactPath(input, cwd) {
|
|
2125
|
+
function resolveReviewArtifactPath(input, cwd, options = {}) {
|
|
2126
|
+
const allowOutsideArtifactRoot = options.allowOutsideArtifactRoot ?? false;
|
|
2109
2127
|
if (hasParentDirectoryTraversal(input)) {
|
|
2110
2128
|
return {
|
|
2111
2129
|
message: "Review artifact path must not contain parent-directory traversal",
|
|
2112
2130
|
ok: false
|
|
2113
2131
|
};
|
|
2114
2132
|
}
|
|
2115
|
-
const artifactRoot = path3.resolve(cwd, ".context", "systematic", "ce-review");
|
|
2116
2133
|
let canonicalRoot;
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2134
|
+
if (!allowOutsideArtifactRoot) {
|
|
2135
|
+
const artifactRoot = path3.resolve(cwd, ".context", "systematic", "ce-review");
|
|
2136
|
+
try {
|
|
2137
|
+
canonicalRoot = fs4.realpathSync(artifactRoot);
|
|
2138
|
+
if (!fs4.statSync(canonicalRoot).isDirectory()) {
|
|
2139
|
+
return {
|
|
2140
|
+
message: "Review artifact directory is not a directory",
|
|
2141
|
+
ok: false
|
|
2142
|
+
};
|
|
2143
|
+
}
|
|
2144
|
+
} catch {
|
|
2145
|
+
return { message: "Review artifact directory is unavailable", ok: false };
|
|
2124
2146
|
}
|
|
2125
|
-
} catch {
|
|
2126
|
-
return { message: "Review artifact directory is unavailable", ok: false };
|
|
2127
2147
|
}
|
|
2128
2148
|
const candidate = path3.resolve(cwd, input);
|
|
2129
2149
|
if (pathContainsSymlink(candidate)) {
|
|
2130
2150
|
return {
|
|
2131
|
-
message: "Review artifact path must not contain symlinks",
|
|
2151
|
+
message: "Review artifact path must not contain symlinks; pass a fully resolved path",
|
|
2132
2152
|
ok: false
|
|
2133
2153
|
};
|
|
2134
2154
|
}
|
|
@@ -2138,7 +2158,7 @@ function resolveReviewArtifactPath(input, cwd) {
|
|
|
2138
2158
|
} catch {
|
|
2139
2159
|
return { message: "Review artifact file was not found", ok: false };
|
|
2140
2160
|
}
|
|
2141
|
-
if (!isWithinDirectory(canonicalTarget, canonicalRoot)) {
|
|
2161
|
+
if (canonicalRoot !== undefined && !isWithinDirectory(canonicalTarget, canonicalRoot)) {
|
|
2142
2162
|
return {
|
|
2143
2163
|
message: "Review artifact path must remain inside .context/systematic/ce-review",
|
|
2144
2164
|
ok: false
|
|
@@ -2721,9 +2741,12 @@ Usage:
|
|
|
2721
2741
|
Commands:
|
|
2722
2742
|
list [type] List available skills, agents, or commands
|
|
2723
2743
|
capabilities Read-only standalone-CLI observation; not a host-runtime or canonical-registry view
|
|
2724
|
-
validate-review-artifact <path>
|
|
2744
|
+
validate-review-artifact <path> [--allow-outside-artifact-root]
|
|
2725
2745
|
Validate a ce:review run artifact
|
|
2726
2746
|
The <path> argument is required by design; no artifact discovery is performed.
|
|
2747
|
+
--allow-outside-artifact-root skips the requirement that <path> resolve
|
|
2748
|
+
inside .context/systematic/ce-review, for validating artifacts copied from
|
|
2749
|
+
CI, issues, or fixtures. Not for the ce:review parent's own run artifact.
|
|
2727
2750
|
Exit statuses: 0 valid artifact, 1 validation failure,
|
|
2728
2751
|
2 operational failure, 3 legacy artifact with no schema_version
|
|
2729
2752
|
config [subcommand] Configuration management
|
|
@@ -2744,6 +2767,7 @@ Examples:
|
|
|
2744
2767
|
systematic list skills
|
|
2745
2768
|
systematic capabilities
|
|
2746
2769
|
systematic validate-review-artifact .context/systematic/ce-review/review-summary.json
|
|
2770
|
+
systematic validate-review-artifact --allow-outside-artifact-root /path/to/external-artifact.json
|
|
2747
2771
|
systematic list agents
|
|
2748
2772
|
systematic config show
|
|
2749
2773
|
systematic config show --json
|
|
@@ -2774,7 +2798,6 @@ Scope:
|
|
|
2774
2798
|
project <cwd>/.pi/agents (default)
|
|
2775
2799
|
global $PI_CODING_AGENT_DIR/agents or ~/.pi/agent/agents
|
|
2776
2800
|
`;
|
|
2777
|
-
var VALIDATE_REVIEW_ARTIFACT_USAGE = "Usage: systematic validate-review-artifact <path>";
|
|
2778
2801
|
var REVIEW_ARTIFACT_SCHEMA_RELATIVE_PATH = "skills/ce-review/references/review-summary-schema.json";
|
|
2779
2802
|
function defaultCapabilityRoots() {
|
|
2780
2803
|
const configDir = process.env.XDG_CONFIG_HOME ? path5.join(process.env.XDG_CONFIG_HOME, "opencode") : path5.join(os2.homedir(), ".config/opencode");
|
|
@@ -2935,19 +2958,17 @@ function validateReviewArtifactArgument(argv) {
|
|
|
2935
2958
|
const commandIndex = argv[0] === "systematic" ? 1 : 0;
|
|
2936
2959
|
if (argv[commandIndex] !== "validate-review-artifact")
|
|
2937
2960
|
return;
|
|
2938
|
-
|
|
2939
|
-
return;
|
|
2940
|
-
return argv[commandIndex + 1];
|
|
2961
|
+
return parseValidateReviewArtifactArguments(argv.slice(commandIndex + 1));
|
|
2941
2962
|
}
|
|
2942
2963
|
function runValidateReviewArtifact(options) {
|
|
2943
2964
|
const outputSink = options.outputSink ?? ((message) => console.log(message));
|
|
2944
2965
|
const errorSink = options.errorSink ?? ((message) => console.error(message));
|
|
2945
|
-
const
|
|
2946
|
-
if (
|
|
2966
|
+
const parsedArgs = validateReviewArtifactArgument(options.argv);
|
|
2967
|
+
if (parsedArgs === undefined) {
|
|
2947
2968
|
errorSink(VALIDATE_REVIEW_ARTIFACT_USAGE);
|
|
2948
2969
|
return 2;
|
|
2949
2970
|
}
|
|
2950
|
-
const resolved = resolveReviewArtifactPath(
|
|
2971
|
+
const resolved = resolveReviewArtifactPath(parsedArgs.path, options.cwd ?? process.cwd(), { allowOutsideArtifactRoot: parsedArgs.allowOutsideArtifactRoot });
|
|
2951
2972
|
if (!resolved.ok) {
|
|
2952
2973
|
errorSink(resolved.message);
|
|
2953
2974
|
return 2;
|
|
@@ -2972,7 +2993,7 @@ function runValidateReviewArtifact(options) {
|
|
|
2972
2993
|
errorSink(`Review artifact validation failed: ${result.error.issues.length} issue(s)`);
|
|
2973
2994
|
return 1;
|
|
2974
2995
|
}
|
|
2975
|
-
outputSink(
|
|
2996
|
+
outputSink(formatReviewArtifactSuccessMessage(parsedArgs.allowOutsideArtifactRoot));
|
|
2976
2997
|
return 0;
|
|
2977
2998
|
}
|
|
2978
2999
|
function runValidateReviewArtifactCli(options) {
|
|
@@ -16,5 +16,16 @@ export declare function formatReviewArtifactIssuePath(issuePath: readonly Proper
|
|
|
16
16
|
export declare function readReviewArtifact(filePath: string): ReadArtifactResult;
|
|
17
17
|
export declare function isLegacyReviewArtifact(value: unknown): boolean;
|
|
18
18
|
export declare function hasParentDirectoryTraversal(input: string): boolean;
|
|
19
|
+
export declare const ALLOW_OUTSIDE_ARTIFACT_ROOT_FLAG = "--allow-outside-artifact-root";
|
|
20
|
+
export declare const VALIDATE_REVIEW_ARTIFACT_USAGE = "Usage: systematic validate-review-artifact <path> [--allow-outside-artifact-root]";
|
|
21
|
+
export interface ValidateReviewArtifactArguments {
|
|
22
|
+
readonly path: string;
|
|
23
|
+
readonly allowOutsideArtifactRoot: boolean;
|
|
24
|
+
}
|
|
25
|
+
export declare function parseValidateReviewArtifactArguments(argv: readonly string[]): ValidateReviewArtifactArguments | undefined;
|
|
26
|
+
export declare function formatReviewArtifactSuccessMessage(allowOutsideArtifactRoot: boolean): string;
|
|
19
27
|
export declare function pathContainsSymlink(candidate: string): boolean;
|
|
20
|
-
export
|
|
28
|
+
export interface ResolveReviewArtifactPathOptions {
|
|
29
|
+
readonly allowOutsideArtifactRoot?: boolean;
|
|
30
|
+
}
|
|
31
|
+
export declare function resolveReviewArtifactPath(input: string, cwd: string, options?: ResolveReviewArtifactPathOptions): ArtifactPathResult;
|
package/package.json
CHANGED
|
@@ -247,6 +247,18 @@ validation, and it does not delete the artifact to escape the check. A failing
|
|
|
247
247
|
artifact is evidence and stays on disk; an absent artifact is never evidence
|
|
248
248
|
of a clean run.
|
|
249
249
|
|
|
250
|
+
Both commands also accept `--allow-outside-artifact-root`, which skips the
|
|
251
|
+
containment check so a copy fetched from CI, an issue attachment, or a fixture
|
|
252
|
+
can be validated from outside `.context/systematic/ce-review`. It also drops
|
|
253
|
+
the requirement that `.context/systematic/ce-review` exist at all. That is not
|
|
254
|
+
a workaround for the "directory is unavailable" degradation described above:
|
|
255
|
+
that degradation is deliberate visible failure for the parent's own run
|
|
256
|
+
artifact, and the flag does not change how the parent's own validation run is
|
|
257
|
+
judged. This is an external-validation mode for artifacts the parent did not
|
|
258
|
+
just produce. The parent must never pass this flag when validating its own
|
|
259
|
+
run's `review-summary.json`; doing so would silently accept a mismatched or
|
|
260
|
+
misplaced artifact as this run's evidence.
|
|
261
|
+
|
|
250
262
|
This is enforcement by visible failure, not by containment. An agent that
|
|
251
263
|
never runs the command can still finalize an artifact, but produces no evidence
|
|
252
264
|
in either direction. That is why the command exists as an independently
|