@rpamis/comet 0.4.0-beta.7 → 0.4.0-beta.9
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/LICENSE +21 -21
- package/README.md +3 -3
- package/assets/manifest.json +1 -1
- package/assets/skills/comet/reference/comet-yaml-fields.md +2 -2
- package/assets/skills/comet/scripts/comet-entry-runtime.mjs +118 -6
- package/assets/skills/comet/scripts/comet-hook-router.mjs +244 -26
- package/assets/skills/comet/scripts/comet-runtime.mjs +221 -104
- package/assets/skills/comet-archive/SKILL.md +29 -20
- package/assets/skills/comet-native/SKILL.md +23 -15
- package/assets/skills/comet-native/reference/artifacts.md +19 -4
- package/assets/skills/comet-native/reference/commands.md +8 -2
- package/assets/skills/comet-native/reference/recovery.md +1 -1
- package/assets/skills/comet-native/scripts/comet-native-runtime.mjs +1136 -471
- package/assets/skills-zh/comet/reference/comet-yaml-fields.md +2 -2
- package/assets/skills-zh/comet-archive/SKILL.md +29 -20
- package/assets/skills-zh/comet-native/SKILL.md +23 -15
- package/assets/skills-zh/comet-native/reference/artifacts.md +20 -5
- package/assets/skills-zh/comet-native/reference/commands.md +8 -2
- package/assets/skills-zh/comet-native/reference/recovery.md +1 -1
- package/dist/app/commands/init.d.ts.map +1 -1
- package/dist/app/commands/init.js +3 -6
- package/dist/app/commands/init.js.map +1 -1
- package/dist/domains/bundle/bundle-platform.d.ts.map +1 -1
- package/dist/domains/bundle/bundle-platform.js +1 -1
- package/dist/domains/bundle/bundle-platform.js.map +1 -1
- package/dist/domains/comet-classic/classic-guard.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-guard.js +3 -2
- package/dist/domains/comet-classic/classic-guard.js.map +1 -1
- package/dist/domains/comet-entry/current-selection.d.ts.map +1 -1
- package/dist/domains/comet-entry/current-selection.js +6 -8
- package/dist/domains/comet-entry/current-selection.js.map +1 -1
- package/dist/domains/comet-entry/project-status.d.ts.map +1 -1
- package/dist/domains/comet-entry/project-status.js +5 -1
- package/dist/domains/comet-entry/project-status.js.map +1 -1
- package/dist/domains/comet-native/native-archive-transaction.d.ts.map +1 -1
- package/dist/domains/comet-native/native-archive-transaction.js +5 -6
- package/dist/domains/comet-native/native-archive-transaction.js.map +1 -1
- package/dist/domains/comet-native/native-atomic-file.d.ts.map +1 -1
- package/dist/domains/comet-native/native-atomic-file.js +11 -7
- package/dist/domains/comet-native/native-atomic-file.js.map +1 -1
- package/dist/domains/comet-native/native-bounded-file.d.ts.map +1 -1
- package/dist/domains/comet-native/native-bounded-file.js +11 -7
- package/dist/domains/comet-native/native-bounded-file.js.map +1 -1
- package/dist/domains/comet-native/native-build-evidence.js +2 -2
- package/dist/domains/comet-native/native-build-evidence.js.map +1 -1
- package/dist/domains/comet-native/native-change.d.ts +4 -2
- package/dist/domains/comet-native/native-change.d.ts.map +1 -1
- package/dist/domains/comet-native/native-change.js +18 -4
- package/dist/domains/comet-native/native-change.js.map +1 -1
- package/dist/domains/comet-native/native-check-receipt-storage.d.ts.map +1 -1
- package/dist/domains/comet-native/native-check-receipt-storage.js +11 -7
- package/dist/domains/comet-native/native-check-receipt-storage.js.map +1 -1
- package/dist/domains/comet-native/native-check-receipt.d.ts.map +1 -1
- package/dist/domains/comet-native/native-check-receipt.js +16 -11
- package/dist/domains/comet-native/native-check-receipt.js.map +1 -1
- package/dist/domains/comet-native/native-cli.d.ts.map +1 -1
- package/dist/domains/comet-native/native-cli.js +120 -16
- package/dist/domains/comet-native/native-cli.js.map +1 -1
- package/dist/domains/comet-native/native-config.d.ts +5 -1
- package/dist/domains/comet-native/native-config.d.ts.map +1 -1
- package/dist/domains/comet-native/native-config.js +78 -0
- package/dist/domains/comet-native/native-config.js.map +1 -1
- package/dist/domains/comet-native/native-continuation.d.ts +2 -1
- package/dist/domains/comet-native/native-continuation.d.ts.map +1 -1
- package/dist/domains/comet-native/native-continuation.js +13 -5
- package/dist/domains/comet-native/native-continuation.js.map +1 -1
- package/dist/domains/comet-native/native-diagnostics.d.ts +7 -3
- package/dist/domains/comet-native/native-diagnostics.d.ts.map +1 -1
- package/dist/domains/comet-native/native-diagnostics.js +19 -9
- package/dist/domains/comet-native/native-diagnostics.js.map +1 -1
- package/dist/domains/comet-native/native-evidence-retention.d.ts.map +1 -1
- package/dist/domains/comet-native/native-evidence-retention.js +5 -3
- package/dist/domains/comet-native/native-evidence-retention.js.map +1 -1
- package/dist/domains/comet-native/native-evidence-storage.d.ts.map +1 -1
- package/dist/domains/comet-native/native-evidence-storage.js +11 -7
- package/dist/domains/comet-native/native-evidence-storage.js.map +1 -1
- package/dist/domains/comet-native/native-file-identity.d.ts +3 -0
- package/dist/domains/comet-native/native-file-identity.d.ts.map +1 -0
- package/dist/domains/comet-native/native-file-identity.js +2 -0
- package/dist/domains/comet-native/native-file-identity.js.map +1 -0
- package/dist/domains/comet-native/native-findings.d.ts.map +1 -1
- package/dist/domains/comet-native/native-findings.js +19 -1
- package/dist/domains/comet-native/native-findings.js.map +1 -1
- package/dist/domains/comet-native/native-guards.d.ts +2 -1
- package/dist/domains/comet-native/native-guards.d.ts.map +1 -1
- package/dist/domains/comet-native/native-guards.js +14 -0
- package/dist/domains/comet-native/native-guards.js.map +1 -1
- package/dist/domains/comet-native/native-lock.d.ts.map +1 -1
- package/dist/domains/comet-native/native-lock.js +30 -35
- package/dist/domains/comet-native/native-lock.js.map +1 -1
- package/dist/domains/comet-native/native-protected-file.d.ts.map +1 -1
- package/dist/domains/comet-native/native-protected-file.js +9 -8
- package/dist/domains/comet-native/native-protected-file.js.map +1 -1
- package/dist/domains/comet-native/native-root-move.d.ts.map +1 -1
- package/dist/domains/comet-native/native-root-move.js +2 -0
- package/dist/domains/comet-native/native-root-move.js.map +1 -1
- package/dist/domains/comet-native/native-run-store.d.ts.map +1 -1
- package/dist/domains/comet-native/native-run-store.js +9 -8
- package/dist/domains/comet-native/native-run-store.js.map +1 -1
- package/dist/domains/comet-native/native-snapshot.d.ts +5 -1
- package/dist/domains/comet-native/native-snapshot.d.ts.map +1 -1
- package/dist/domains/comet-native/native-snapshot.js +225 -5
- package/dist/domains/comet-native/native-snapshot.js.map +1 -1
- package/dist/domains/comet-native/native-transitions.d.ts +2 -1
- package/dist/domains/comet-native/native-transitions.d.ts.map +1 -1
- package/dist/domains/comet-native/native-transitions.js +34 -11
- package/dist/domains/comet-native/native-transitions.js.map +1 -1
- package/dist/domains/comet-native/native-types.d.ts +16 -0
- package/dist/domains/comet-native/native-types.d.ts.map +1 -1
- package/dist/domains/comet-native/native-verification-runtime.d.ts.map +1 -1
- package/dist/domains/comet-native/native-verification-runtime.js +5 -3
- package/dist/domains/comet-native/native-verification-runtime.js.map +1 -1
- package/dist/domains/comet-native/native-verification-scope.d.ts +2 -1
- package/dist/domains/comet-native/native-verification-scope.d.ts.map +1 -1
- package/dist/domains/comet-native/native-verification-scope.js +6 -1
- package/dist/domains/comet-native/native-verification-scope.js.map +1 -1
- package/dist/domains/dashboard/native-collector.d.ts.map +1 -1
- package/dist/domains/dashboard/native-collector.js +4 -1
- package/dist/domains/dashboard/native-collector.js.map +1 -1
- package/dist/domains/dashboard/web/index.html +14 -14
- package/dist/domains/skill/platform-install.d.ts.map +1 -1
- package/dist/domains/skill/platform-install.js +9 -0
- package/dist/domains/skill/platform-install.js.map +1 -1
- package/dist/domains/skill/project-instructions.d.ts.map +1 -1
- package/dist/domains/skill/project-instructions.js +4 -2
- package/dist/domains/skill/project-instructions.js.map +1 -1
- package/dist/domains/workflow-contract/project-config.d.ts +1 -1
- package/dist/domains/workflow-contract/project-config.d.ts.map +1 -1
- package/dist/domains/workflow-contract/project-config.js +24 -2
- package/dist/domains/workflow-contract/project-config.js.map +1 -1
- package/dist/platform/fs/file-identity.d.ts +9 -0
- package/dist/platform/fs/file-identity.d.ts.map +1 -0
- package/dist/platform/fs/file-identity.js +21 -0
- package/dist/platform/fs/file-identity.js.map +1 -0
- package/dist/platform/fs/file-system.d.ts.map +1 -1
- package/dist/platform/fs/file-system.js +13 -9
- package/dist/platform/fs/file-system.js.map +1 -1
- package/dist/platform/fs/race-safe-read.d.ts +47 -0
- package/dist/platform/fs/race-safe-read.d.ts.map +1 -0
- package/dist/platform/fs/race-safe-read.js +132 -0
- package/dist/platform/fs/race-safe-read.js.map +1 -0
- package/eval/README.md +1 -1
- package/eval/local/tasks/comet-native-clarification-depth/environment/Dockerfile +27 -0
- package/eval/local/tasks/comet-native-clarification-depth/environment/test_wordcount.py +25 -0
- package/eval/local/tasks/comet-native-clarification-depth/environment/wordcount.py +36 -0
- package/eval/local/tasks/comet-native-clarification-depth/instruction.md +17 -0
- package/eval/local/tasks/comet-native-clarification-depth/task.toml +47 -0
- package/eval/local/tasks/comet-native-clarification-depth/validation/test_native_clarification_depth.py +618 -0
- package/eval/local/tasks/comet-native-clarification-modes/validation/test_native_clarification_modes.py +1 -1
- package/eval/local/tasks/index.yaml +6 -0
- package/eval/local/tests/conftest.py +146 -2
- package/eval/local/tests/scaffold/test_conftest_helpers.py +188 -1
- package/eval/local/tests/scaffold/test_tasks.py +440 -8
- package/eval/local/tests/scaffold/test_utils.py +114 -1
- package/eval/local/tests/tasks/test_tasks.py +2 -0
- package/eval/pyproject.toml +4 -4
- package/eval/scaffold/python/aligned_comparison.py +1 -0
- package/eval/scaffold/python/tasks.py +2 -0
- package/eval/scaffold/shell/docker.sh +1 -1
- package/eval/scaffold/shell/run-claude-loop.sh +25 -2
- package/package.json +8 -1
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 rpamis
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 rpamis
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -45,8 +45,8 @@ It provides two independent requirements workflows: Native for strong models, po
|
|
|
45
45
|
It allows you to use a toolchain to handle everything from requirements to archiving, combine any skill to make it like Comet, evolving your skills based on scientific **Rubric**, **Pass@k**, and **Pass^k** scoring.
|
|
46
46
|
|
|
47
47
|
> [!IMPORTANT]
|
|
48
|
-
> **0.4.0-beta.7** —
|
|
49
|
-
>
|
|
48
|
+
> **0.4.0-beta.7** — A new **high-performance, native and recoverable** Native workflow has been added. Native and Classic work independently through unified configuration, status, Guard, Dashboard, and Eval entry points. Eval alignment of experiments (16 tasks × 48 runs, selecting 41 pairs of samples that both passed) shows that **total Token has decreased by 76.8%**, **Agent rounds have dropped by 57.4%**, **time consumption has shrunk by 47.4%**, **pass^3 reaches 87.5% (+12.5pp) and pass@3 is 100%**. For more details, please refer to [Native vs. 0.4.0 Classic Real Evaluation](https://docs.comet.rpamis.com/zh/eval/comet-native-vs-040-experiment).
|
|
49
|
+
>
|
|
50
50
|
> **0.4.0-beta.1** — Upgrades Comet to a pure Node runtime without Bash/WSL and adds three core capabilities: compose **any** Skill through `/comet-any`, evaluate **any** Skill through `comet eval` with LangSmith integration, and visualize every change through `comet dashboard`.
|
|
51
51
|
>
|
|
52
52
|
> **0.3.9** — Review mode (`off|standard|thorough`) controls Build/Verify code review with project defaults; init/update now use optional dependency prompts, broader CLI i18n, stronger phase guards, and macOS executable bits.
|
|
@@ -837,7 +837,7 @@ Track our development progress and upcoming features on the [Comet Roadmap](http
|
|
|
837
837
|
|
|
838
838
|
## Star History
|
|
839
839
|
|
|
840
|
-
[](https://www.star-history.com/?repos=rpamis%2Fcomet&type=date&legend=top-left)
|
|
841
841
|
|
|
842
842
|
## Contributors
|
|
843
843
|
|
package/assets/manifest.json
CHANGED
|
@@ -55,10 +55,10 @@ archived: false
|
|
|
55
55
|
| `verify_result` | `pending`, `pass`, or `fail` |
|
|
56
56
|
| `verify_failures` | Machine-owned consecutive verification failure count. `verify-fail` increments it; `verify-pass` or `archive-reopen` resets it to `0`. At `3`, the next failure requires the retry-limit strategy decision |
|
|
57
57
|
| `verification_report` | Verification report file path; must point to an existing file before verify passes |
|
|
58
|
-
| `branch_status` | `pending` or `handled`; keep pending through verify
|
|
58
|
+
| `branch_status` | `pending` or `handled`; keep `pending` through verify. After the user confirms immediate remote delivery before archive, set `handled` when archive finishes and include it in the only archive commit. `handled` means only that the delivery method is confirmed, not that push or PR creation succeeded; clear current selection and report workflow completion only after remote operations succeed |
|
|
59
59
|
| `created_at` | Change creation date (auto-written at init), format `YYYY-MM-DD` |
|
|
60
60
|
| `verified_at` | Verification pass timestamp; may be empty |
|
|
61
|
-
| `archive_confirmation` | `null`, `pending`, or `confirmed`. `verify-pass` writes `pending` when entering the archive phase; after the user selects "
|
|
61
|
+
| `archive_confirmation` | `null`, `pending`, or `confirmed`. `verify-pass` writes `pending` when entering the archive phase; after the user selects either "confirm archive and deliver remotely now" choice in `/comet-archive`, the `archive-confirm` transition writes `confirmed`; `archive-reopen` clears the field so an earlier confirmation cannot be reused |
|
|
62
62
|
| `archived` | Whether the change has been archived |
|
|
63
63
|
|
|
64
64
|
## Optional Fields
|
|
@@ -7375,6 +7375,19 @@ import path3 from "path";
|
|
|
7375
7375
|
// domains/workflow-contract/project-config.ts
|
|
7376
7376
|
var import_yaml = __toESM(require_dist(), 1);
|
|
7377
7377
|
|
|
7378
|
+
// platform/fs/file-identity.ts
|
|
7379
|
+
function hasPlatformIdentity(value) {
|
|
7380
|
+
return value !== 0 && value !== 0n && value !== "0";
|
|
7381
|
+
}
|
|
7382
|
+
function sameFileObject(left, right) {
|
|
7383
|
+
const comparableDevice = hasPlatformIdentity(left.dev) && hasPlatformIdentity(right.dev);
|
|
7384
|
+
if (comparableDevice && left.dev !== right.dev) return false;
|
|
7385
|
+
const comparableInode = hasPlatformIdentity(left.ino) && hasPlatformIdentity(right.ino);
|
|
7386
|
+
if (comparableInode && left.ino !== right.ino) return false;
|
|
7387
|
+
if (comparableDevice && comparableInode) return true;
|
|
7388
|
+
return left.birthtime === right.birthtime;
|
|
7389
|
+
}
|
|
7390
|
+
|
|
7378
7391
|
// domains/comet-native/native-protected-file.ts
|
|
7379
7392
|
import { createHash } from "node:crypto";
|
|
7380
7393
|
import { constants as fsConstants, promises as fs } from "node:fs";
|
|
@@ -7391,10 +7404,13 @@ function positiveLimit(value) {
|
|
|
7391
7404
|
return value;
|
|
7392
7405
|
}
|
|
7393
7406
|
function sameDirectoryIdentity(expected, actual) {
|
|
7394
|
-
|
|
7395
|
-
|
|
7396
|
-
|
|
7397
|
-
|
|
7407
|
+
return sameFileObject(
|
|
7408
|
+
{ ...expected, birthtime: expected.birthtimeMs },
|
|
7409
|
+
{
|
|
7410
|
+
...actual,
|
|
7411
|
+
birthtime: actual.birthtimeMs
|
|
7412
|
+
}
|
|
7413
|
+
);
|
|
7398
7414
|
}
|
|
7399
7415
|
function asFileIdentity(stat) {
|
|
7400
7416
|
return {
|
|
@@ -7407,8 +7423,13 @@ function asFileIdentity(stat) {
|
|
|
7407
7423
|
};
|
|
7408
7424
|
}
|
|
7409
7425
|
function sameFileIdentity(expected, actual) {
|
|
7410
|
-
|
|
7411
|
-
|
|
7426
|
+
return sameFileObject(
|
|
7427
|
+
{ ...expected, birthtime: expected.birthtimeMs },
|
|
7428
|
+
{
|
|
7429
|
+
...actual,
|
|
7430
|
+
birthtime: actual.birthtimeMs
|
|
7431
|
+
}
|
|
7432
|
+
) && expected.birthtimeMs === actual.birthtimeMs && expected.ctimeMs === actual.ctimeMs && expected.mtimeMs === actual.mtimeMs && expected.size === actual.size;
|
|
7412
7433
|
}
|
|
7413
7434
|
async function captureDirectoryIdentity(directory, label) {
|
|
7414
7435
|
const stat = await fs.lstat(directory);
|
|
@@ -7604,11 +7625,100 @@ var NATIVE_KEYS = /* @__PURE__ */ new Set([
|
|
|
7604
7625
|
"artifact_root",
|
|
7605
7626
|
"language",
|
|
7606
7627
|
"clarification_mode",
|
|
7628
|
+
"snapshot",
|
|
7607
7629
|
"pending_root_move"
|
|
7608
7630
|
]);
|
|
7631
|
+
var SNAPSHOT_KEYS = /* @__PURE__ */ new Set([
|
|
7632
|
+
"include",
|
|
7633
|
+
"exclude",
|
|
7634
|
+
"max_files",
|
|
7635
|
+
"max_total_bytes",
|
|
7636
|
+
"max_duration_ms"
|
|
7637
|
+
]);
|
|
7609
7638
|
var PENDING_KEYS = /* @__PURE__ */ new Set(["id", "from_artifact_root", "to_artifact_root", "stage", "cleanup"]);
|
|
7610
7639
|
var NATIVE_PROJECT_CONFIG_MAX_BYTES = 64 * 1024;
|
|
7611
7640
|
var CLEANUP_KEYS = /* @__PURE__ */ new Set(["kind", "state", "manifest_hash"]);
|
|
7641
|
+
var MAX_NATIVE_SNAPSHOT_PATTERN_LENGTH = 1024;
|
|
7642
|
+
var MAX_NATIVE_SNAPSHOT_PATTERN_WILDCARDS = 64;
|
|
7643
|
+
var DEFAULT_NATIVE_SNAPSHOT_CONFIG = {
|
|
7644
|
+
include: ["**/*"],
|
|
7645
|
+
exclude: [],
|
|
7646
|
+
max_files: 1e4,
|
|
7647
|
+
max_total_bytes: 256 * 1024 * 1024,
|
|
7648
|
+
max_duration_ms: 6e4
|
|
7649
|
+
};
|
|
7650
|
+
function normalizeNativeSnapshotPattern(value, label) {
|
|
7651
|
+
if (typeof value !== "string" || value.length === 0 || value.includes("\\") || value.includes("\0") || value.startsWith("/") || value.split("/").includes("..")) {
|
|
7652
|
+
throw new Error(`${label} contains an unsafe pattern`);
|
|
7653
|
+
}
|
|
7654
|
+
if (value.length > MAX_NATIVE_SNAPSHOT_PATTERN_LENGTH) {
|
|
7655
|
+
throw new Error(`${label} exceeds ${MAX_NATIVE_SNAPSHOT_PATTERN_LENGTH} characters`);
|
|
7656
|
+
}
|
|
7657
|
+
let wildcardTokens = 0;
|
|
7658
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
7659
|
+
if (value[index] === "?") {
|
|
7660
|
+
wildcardTokens += 1;
|
|
7661
|
+
} else if (value[index] === "*") {
|
|
7662
|
+
wildcardTokens += 1;
|
|
7663
|
+
if (value[index + 1] === "*") index += 1;
|
|
7664
|
+
}
|
|
7665
|
+
}
|
|
7666
|
+
if (wildcardTokens > MAX_NATIVE_SNAPSHOT_PATTERN_WILDCARDS) {
|
|
7667
|
+
throw new Error(
|
|
7668
|
+
`${label} contains more than ${MAX_NATIVE_SNAPSHOT_PATTERN_WILDCARDS} wildcard tokens`
|
|
7669
|
+
);
|
|
7670
|
+
}
|
|
7671
|
+
return value;
|
|
7672
|
+
}
|
|
7673
|
+
function snapshotPatterns(value, label, fallback) {
|
|
7674
|
+
if (value === void 0) return [...fallback];
|
|
7675
|
+
if (!Array.isArray(value)) {
|
|
7676
|
+
throw new Error(`${label} contains an unsafe pattern`);
|
|
7677
|
+
}
|
|
7678
|
+
return [...new Set(value.map((pattern) => normalizeNativeSnapshotPattern(pattern, label)))].sort(
|
|
7679
|
+
(left, right) => left.localeCompare(right, "en")
|
|
7680
|
+
);
|
|
7681
|
+
}
|
|
7682
|
+
function positiveSnapshotInteger(value, fallback, label) {
|
|
7683
|
+
const resolved = value ?? fallback;
|
|
7684
|
+
if (!Number.isSafeInteger(resolved) || resolved < 1) {
|
|
7685
|
+
throw new Error(`${label} must be a positive integer`);
|
|
7686
|
+
}
|
|
7687
|
+
return resolved;
|
|
7688
|
+
}
|
|
7689
|
+
function parseSnapshot(value) {
|
|
7690
|
+
if (value === void 0)
|
|
7691
|
+
return { ...DEFAULT_NATIVE_SNAPSHOT_CONFIG, include: ["**/*"], exclude: [] };
|
|
7692
|
+
const snapshot = record(value, "native.snapshot");
|
|
7693
|
+
rejectUnknown(snapshot, SNAPSHOT_KEYS, "native.snapshot");
|
|
7694
|
+
return {
|
|
7695
|
+
include: snapshotPatterns(
|
|
7696
|
+
snapshot.include,
|
|
7697
|
+
"native.snapshot.include",
|
|
7698
|
+
DEFAULT_NATIVE_SNAPSHOT_CONFIG.include
|
|
7699
|
+
),
|
|
7700
|
+
exclude: snapshotPatterns(
|
|
7701
|
+
snapshot.exclude,
|
|
7702
|
+
"native.snapshot.exclude",
|
|
7703
|
+
DEFAULT_NATIVE_SNAPSHOT_CONFIG.exclude
|
|
7704
|
+
),
|
|
7705
|
+
max_files: positiveSnapshotInteger(
|
|
7706
|
+
snapshot.max_files,
|
|
7707
|
+
DEFAULT_NATIVE_SNAPSHOT_CONFIG.max_files,
|
|
7708
|
+
"native.snapshot.max_files"
|
|
7709
|
+
),
|
|
7710
|
+
max_total_bytes: positiveSnapshotInteger(
|
|
7711
|
+
snapshot.max_total_bytes,
|
|
7712
|
+
DEFAULT_NATIVE_SNAPSHOT_CONFIG.max_total_bytes,
|
|
7713
|
+
"native.snapshot.max_total_bytes"
|
|
7714
|
+
),
|
|
7715
|
+
max_duration_ms: positiveSnapshotInteger(
|
|
7716
|
+
snapshot.max_duration_ms,
|
|
7717
|
+
DEFAULT_NATIVE_SNAPSHOT_CONFIG.max_duration_ms,
|
|
7718
|
+
"native.snapshot.max_duration_ms"
|
|
7719
|
+
)
|
|
7720
|
+
};
|
|
7721
|
+
}
|
|
7612
7722
|
function record(value, label) {
|
|
7613
7723
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
7614
7724
|
throw new Error(`${label} must be a mapping`);
|
|
@@ -7694,6 +7804,7 @@ function parseConfig(value) {
|
|
|
7694
7804
|
throw new Error("native.clarification_mode must be sequential or batch");
|
|
7695
7805
|
}
|
|
7696
7806
|
const pending = parsePending(native.pending_root_move);
|
|
7807
|
+
const snapshot = parseSnapshot(native.snapshot);
|
|
7697
7808
|
return {
|
|
7698
7809
|
schema: "comet.project.v1",
|
|
7699
7810
|
default_workflow: root.default_workflow,
|
|
@@ -7703,6 +7814,7 @@ function parseConfig(value) {
|
|
|
7703
7814
|
artifact_root: normalizeArtifactRootRef(native.artifact_root),
|
|
7704
7815
|
language,
|
|
7705
7816
|
clarification_mode: clarificationMode,
|
|
7817
|
+
snapshot,
|
|
7706
7818
|
...pending ? { pending_root_move: pending } : {}
|
|
7707
7819
|
}
|
|
7708
7820
|
};
|
|
@@ -7964,8 +7964,127 @@ import { promises as fs6 } from "fs";
|
|
|
7964
7964
|
import path6 from "path";
|
|
7965
7965
|
|
|
7966
7966
|
// domains/comet-entry/current-selection.ts
|
|
7967
|
-
import { promises as fs3 } from "fs";
|
|
7968
7967
|
import path3 from "path";
|
|
7968
|
+
|
|
7969
|
+
// platform/fs/race-safe-read.ts
|
|
7970
|
+
import { constants as fsConstants, promises as fs3 } from "fs";
|
|
7971
|
+
|
|
7972
|
+
// platform/fs/file-identity.ts
|
|
7973
|
+
function hasPlatformIdentity(value) {
|
|
7974
|
+
return value !== 0 && value !== 0n && value !== "0";
|
|
7975
|
+
}
|
|
7976
|
+
function hasComparableFileObject(left, right) {
|
|
7977
|
+
return hasPlatformIdentity(left.dev) && hasPlatformIdentity(right.dev) && hasPlatformIdentity(left.ino) && hasPlatformIdentity(right.ino);
|
|
7978
|
+
}
|
|
7979
|
+
function sameFileObject(left, right) {
|
|
7980
|
+
const comparableDevice = hasPlatformIdentity(left.dev) && hasPlatformIdentity(right.dev);
|
|
7981
|
+
if (comparableDevice && left.dev !== right.dev) return false;
|
|
7982
|
+
const comparableInode = hasPlatformIdentity(left.ino) && hasPlatformIdentity(right.ino);
|
|
7983
|
+
if (comparableInode && left.ino !== right.ino) return false;
|
|
7984
|
+
if (comparableDevice && comparableInode) return true;
|
|
7985
|
+
return left.birthtime === right.birthtime;
|
|
7986
|
+
}
|
|
7987
|
+
|
|
7988
|
+
// platform/fs/race-safe-read.ts
|
|
7989
|
+
var RaceSafeReadError = class extends Error {
|
|
7990
|
+
reason;
|
|
7991
|
+
constructor(reason, message, options) {
|
|
7992
|
+
super(message, options);
|
|
7993
|
+
this.name = "RaceSafeReadError";
|
|
7994
|
+
this.reason = reason;
|
|
7995
|
+
}
|
|
7996
|
+
};
|
|
7997
|
+
function birthtimeOf(stat) {
|
|
7998
|
+
return "birthtimeNs" in stat && typeof stat.birthtimeNs === "bigint" ? stat.birthtimeNs : stat.birthtimeMs;
|
|
7999
|
+
}
|
|
8000
|
+
function ctimeOf(stat) {
|
|
8001
|
+
return "ctimeNs" in stat && typeof stat.ctimeNs === "bigint" ? stat.ctimeNs : stat.ctimeMs;
|
|
8002
|
+
}
|
|
8003
|
+
function identityOf(stat) {
|
|
8004
|
+
return { dev: stat.dev, ino: stat.ino, birthtime: birthtimeOf(stat) };
|
|
8005
|
+
}
|
|
8006
|
+
function sameStatIdentity(left, right) {
|
|
8007
|
+
const leftObject = identityOf(left);
|
|
8008
|
+
const rightObject = identityOf(right);
|
|
8009
|
+
if (hasComparableFileObject(leftObject, rightObject)) {
|
|
8010
|
+
return sameFileObject(leftObject, rightObject);
|
|
8011
|
+
}
|
|
8012
|
+
return sameFileObject(leftObject, rightObject) && birthtimeOf(left) === birthtimeOf(right) && ctimeOf(left) === ctimeOf(right) && left.size === right.size;
|
|
8013
|
+
}
|
|
8014
|
+
async function readFileRaceSafe(file, maxBytes, options = {}) {
|
|
8015
|
+
if (!Number.isSafeInteger(maxBytes) || maxBytes < 1) {
|
|
8016
|
+
throw new Error("race-safe read byte limit must be a positive integer");
|
|
8017
|
+
}
|
|
8018
|
+
const label = options.label ?? "file";
|
|
8019
|
+
const bigint = options.bigint === true;
|
|
8020
|
+
const before = await fs3.lstat(file, { bigint });
|
|
8021
|
+
if (!before.isFile() || before.isSymbolicLink()) {
|
|
8022
|
+
throw new RaceSafeReadError("not-regular-file", `${label} must be a regular file`);
|
|
8023
|
+
}
|
|
8024
|
+
if (BigInt(before.size) > BigInt(maxBytes)) {
|
|
8025
|
+
throw new RaceSafeReadError("too-large", `${label} exceeds ${maxBytes} bytes`);
|
|
8026
|
+
}
|
|
8027
|
+
const beforeRealPath = await fs3.realpath(file);
|
|
8028
|
+
await options.verify?.("pre-open", { realPath: beforeRealPath, identity: identityOf(before) });
|
|
8029
|
+
const flags = process.platform === "win32" ? fsConstants.O_RDONLY : fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW | fsConstants.O_NONBLOCK;
|
|
8030
|
+
let handle;
|
|
8031
|
+
try {
|
|
8032
|
+
handle = await fs3.open(file, flags);
|
|
8033
|
+
} catch (error) {
|
|
8034
|
+
if (error.code === "ELOOP") {
|
|
8035
|
+
throw new RaceSafeReadError("not-regular-file", `${label} must be a regular file`, {
|
|
8036
|
+
cause: error
|
|
8037
|
+
});
|
|
8038
|
+
}
|
|
8039
|
+
throw error;
|
|
8040
|
+
}
|
|
8041
|
+
try {
|
|
8042
|
+
const [opened, pathAfterOpen, realPathAfterOpen] = await Promise.all([
|
|
8043
|
+
handle.stat({ bigint }),
|
|
8044
|
+
fs3.lstat(file, { bigint }),
|
|
8045
|
+
fs3.realpath(file)
|
|
8046
|
+
]);
|
|
8047
|
+
if (!opened.isFile() || !pathAfterOpen.isFile() || pathAfterOpen.isSymbolicLink() || realPathAfterOpen !== beforeRealPath || !sameStatIdentity(before, opened) || !sameStatIdentity(before, pathAfterOpen)) {
|
|
8048
|
+
throw new RaceSafeReadError("changed", `${label} changed while opening`);
|
|
8049
|
+
}
|
|
8050
|
+
await options.verify?.("post-open", {
|
|
8051
|
+
realPath: realPathAfterOpen,
|
|
8052
|
+
identity: identityOf(opened)
|
|
8053
|
+
});
|
|
8054
|
+
await options.hooks?.afterOpen?.();
|
|
8055
|
+
const chunks = [];
|
|
8056
|
+
let total = 0;
|
|
8057
|
+
const buffer = Buffer.allocUnsafe(Math.min(64 * 1024, maxBytes + 1));
|
|
8058
|
+
for (; ; ) {
|
|
8059
|
+
const remaining = maxBytes + 1 - total;
|
|
8060
|
+
const { bytesRead } = await handle.read(buffer, 0, Math.min(buffer.length, remaining), null);
|
|
8061
|
+
if (bytesRead === 0) break;
|
|
8062
|
+
total += bytesRead;
|
|
8063
|
+
if (total > maxBytes) {
|
|
8064
|
+
throw new RaceSafeReadError("too-large", `${label} exceeds ${maxBytes} bytes`);
|
|
8065
|
+
}
|
|
8066
|
+
chunks.push(Buffer.from(buffer.subarray(0, bytesRead)));
|
|
8067
|
+
}
|
|
8068
|
+
await options.hooks?.beforeFinalCheck?.();
|
|
8069
|
+
const [afterHandle, afterPath, afterRealPath] = await Promise.all([
|
|
8070
|
+
handle.stat({ bigint }),
|
|
8071
|
+
fs3.lstat(file, { bigint }),
|
|
8072
|
+
fs3.realpath(file)
|
|
8073
|
+
]);
|
|
8074
|
+
if (!afterPath.isFile() || afterPath.isSymbolicLink() || afterRealPath !== beforeRealPath || !sameStatIdentity(before, afterHandle) || !sameStatIdentity(before, afterPath)) {
|
|
8075
|
+
throw new RaceSafeReadError("changed", `${label} changed while reading`);
|
|
8076
|
+
}
|
|
8077
|
+
await options.verify?.("post-read", {
|
|
8078
|
+
realPath: afterRealPath,
|
|
8079
|
+
identity: identityOf(afterHandle)
|
|
8080
|
+
});
|
|
8081
|
+
return { bytes: Buffer.concat(chunks, total), stat: afterHandle, realPath: afterRealPath };
|
|
8082
|
+
} finally {
|
|
8083
|
+
await handle.close();
|
|
8084
|
+
}
|
|
8085
|
+
}
|
|
8086
|
+
|
|
8087
|
+
// domains/comet-entry/current-selection.ts
|
|
7969
8088
|
var COMET_CURRENT_SELECTION_SCHEMA = "comet.selection.v2";
|
|
7970
8089
|
var COMET_CURRENT_SELECTION_MAX_BYTES = 16 * 1024;
|
|
7971
8090
|
function cometCurrentSelectionFile(projectRoot) {
|
|
@@ -8027,16 +8146,11 @@ function parseSelection(source) {
|
|
|
8027
8146
|
async function readCometCurrentSelection(projectRoot) {
|
|
8028
8147
|
let source;
|
|
8029
8148
|
try {
|
|
8030
|
-
const
|
|
8031
|
-
|
|
8032
|
-
|
|
8033
|
-
}
|
|
8034
|
-
|
|
8035
|
-
throw new Error(
|
|
8036
|
-
`current change selection exceeds ${COMET_CURRENT_SELECTION_MAX_BYTES} bytes`
|
|
8037
|
-
);
|
|
8038
|
-
}
|
|
8039
|
-
source = await fs3.readFile(cometCurrentSelectionFile(projectRoot), "utf8");
|
|
8149
|
+
const file = cometCurrentSelectionFile(projectRoot);
|
|
8150
|
+
const { bytes } = await readFileRaceSafe(file, COMET_CURRENT_SELECTION_MAX_BYTES, {
|
|
8151
|
+
label: "current change selection"
|
|
8152
|
+
});
|
|
8153
|
+
source = bytes.toString("utf8");
|
|
8040
8154
|
} catch (error) {
|
|
8041
8155
|
if (error.code === "ENOENT") return { status: "missing" };
|
|
8042
8156
|
throw new Error(
|
|
@@ -9084,16 +9198,21 @@ function positiveLimit(value) {
|
|
|
9084
9198
|
return value;
|
|
9085
9199
|
}
|
|
9086
9200
|
function sameDirectoryIdentity(identity, stat) {
|
|
9087
|
-
|
|
9088
|
-
|
|
9089
|
-
|
|
9090
|
-
|
|
9201
|
+
return sameFileObject(
|
|
9202
|
+
{ ...identity, birthtime: identity.birthtimeMs },
|
|
9203
|
+
{
|
|
9204
|
+
...stat,
|
|
9205
|
+
birthtime: stat.birthtimeMs
|
|
9206
|
+
}
|
|
9207
|
+
);
|
|
9091
9208
|
}
|
|
9092
9209
|
function sameFileIdentity(left, right) {
|
|
9093
|
-
|
|
9094
|
-
|
|
9210
|
+
const leftObject = { ...left, birthtime: left.birthtimeMs };
|
|
9211
|
+
const rightObject = { ...right, birthtime: right.birthtimeMs };
|
|
9212
|
+
if (hasComparableFileObject(leftObject, rightObject)) {
|
|
9213
|
+
return sameFileObject(leftObject, rightObject);
|
|
9095
9214
|
}
|
|
9096
|
-
return left.birthtimeMs === right.birthtimeMs && left.ctimeMs === right.ctimeMs && left.size === right.size;
|
|
9215
|
+
return sameFileObject(leftObject, rightObject) && left.birthtimeMs === right.birthtimeMs && left.ctimeMs === right.ctimeMs && left.size === right.size;
|
|
9097
9216
|
}
|
|
9098
9217
|
async function directoryIdentity(directory) {
|
|
9099
9218
|
const stat = await fs8.lstat(directory);
|
|
@@ -9210,7 +9329,7 @@ var import_yaml3 = __toESM(require_dist(), 1);
|
|
|
9210
9329
|
|
|
9211
9330
|
// domains/comet-native/native-protected-file.ts
|
|
9212
9331
|
import { createHash as createHash2 } from "node:crypto";
|
|
9213
|
-
import { constants as
|
|
9332
|
+
import { constants as fsConstants2, promises as fs9 } from "node:fs";
|
|
9214
9333
|
import path9 from "node:path";
|
|
9215
9334
|
import { TextDecoder as TextDecoder2 } from "node:util";
|
|
9216
9335
|
function isInside2(parent, target) {
|
|
@@ -9224,10 +9343,13 @@ function positiveLimit2(value) {
|
|
|
9224
9343
|
return value;
|
|
9225
9344
|
}
|
|
9226
9345
|
function sameDirectoryIdentity2(expected, actual) {
|
|
9227
|
-
|
|
9228
|
-
|
|
9229
|
-
|
|
9230
|
-
|
|
9346
|
+
return sameFileObject(
|
|
9347
|
+
{ ...expected, birthtime: expected.birthtimeMs },
|
|
9348
|
+
{
|
|
9349
|
+
...actual,
|
|
9350
|
+
birthtime: actual.birthtimeMs
|
|
9351
|
+
}
|
|
9352
|
+
);
|
|
9231
9353
|
}
|
|
9232
9354
|
function asFileIdentity(stat) {
|
|
9233
9355
|
return {
|
|
@@ -9240,8 +9362,13 @@ function asFileIdentity(stat) {
|
|
|
9240
9362
|
};
|
|
9241
9363
|
}
|
|
9242
9364
|
function sameFileIdentity2(expected, actual) {
|
|
9243
|
-
|
|
9244
|
-
|
|
9365
|
+
return sameFileObject(
|
|
9366
|
+
{ ...expected, birthtime: expected.birthtimeMs },
|
|
9367
|
+
{
|
|
9368
|
+
...actual,
|
|
9369
|
+
birthtime: actual.birthtimeMs
|
|
9370
|
+
}
|
|
9371
|
+
) && expected.birthtimeMs === actual.birthtimeMs && expected.ctimeMs === actual.ctimeMs && expected.mtimeMs === actual.mtimeMs && expected.size === actual.size;
|
|
9245
9372
|
}
|
|
9246
9373
|
async function captureDirectoryIdentity(directory, label) {
|
|
9247
9374
|
const stat = await fs9.lstat(directory);
|
|
@@ -9322,7 +9449,7 @@ async function readNativeProtectedFile(options) {
|
|
|
9322
9449
|
if (forbidden.some((identity) => isInside2(identity.realPath, beforeRealPath))) {
|
|
9323
9450
|
throw new Error(`${options.label} resolves inside an excluded root`);
|
|
9324
9451
|
}
|
|
9325
|
-
const flags = process.platform === "win32" ?
|
|
9452
|
+
const flags = process.platform === "win32" ? fsConstants2.O_RDONLY : fsConstants2.O_RDONLY | fsConstants2.O_NOFOLLOW | fsConstants2.O_NONBLOCK;
|
|
9326
9453
|
const handle = await fs9.open(file, flags);
|
|
9327
9454
|
try {
|
|
9328
9455
|
const opened = await handle.stat();
|
|
@@ -9374,11 +9501,100 @@ var NATIVE_KEYS = /* @__PURE__ */ new Set([
|
|
|
9374
9501
|
"artifact_root",
|
|
9375
9502
|
"language",
|
|
9376
9503
|
"clarification_mode",
|
|
9504
|
+
"snapshot",
|
|
9377
9505
|
"pending_root_move"
|
|
9378
9506
|
]);
|
|
9507
|
+
var SNAPSHOT_KEYS = /* @__PURE__ */ new Set([
|
|
9508
|
+
"include",
|
|
9509
|
+
"exclude",
|
|
9510
|
+
"max_files",
|
|
9511
|
+
"max_total_bytes",
|
|
9512
|
+
"max_duration_ms"
|
|
9513
|
+
]);
|
|
9379
9514
|
var PENDING_KEYS = /* @__PURE__ */ new Set(["id", "from_artifact_root", "to_artifact_root", "stage", "cleanup"]);
|
|
9380
9515
|
var NATIVE_PROJECT_CONFIG_MAX_BYTES = 64 * 1024;
|
|
9381
9516
|
var CLEANUP_KEYS = /* @__PURE__ */ new Set(["kind", "state", "manifest_hash"]);
|
|
9517
|
+
var MAX_NATIVE_SNAPSHOT_PATTERN_LENGTH = 1024;
|
|
9518
|
+
var MAX_NATIVE_SNAPSHOT_PATTERN_WILDCARDS = 64;
|
|
9519
|
+
var DEFAULT_NATIVE_SNAPSHOT_CONFIG = {
|
|
9520
|
+
include: ["**/*"],
|
|
9521
|
+
exclude: [],
|
|
9522
|
+
max_files: 1e4,
|
|
9523
|
+
max_total_bytes: 256 * 1024 * 1024,
|
|
9524
|
+
max_duration_ms: 6e4
|
|
9525
|
+
};
|
|
9526
|
+
function normalizeNativeSnapshotPattern(value, label) {
|
|
9527
|
+
if (typeof value !== "string" || value.length === 0 || value.includes("\\") || value.includes("\0") || value.startsWith("/") || value.split("/").includes("..")) {
|
|
9528
|
+
throw new Error(`${label} contains an unsafe pattern`);
|
|
9529
|
+
}
|
|
9530
|
+
if (value.length > MAX_NATIVE_SNAPSHOT_PATTERN_LENGTH) {
|
|
9531
|
+
throw new Error(`${label} exceeds ${MAX_NATIVE_SNAPSHOT_PATTERN_LENGTH} characters`);
|
|
9532
|
+
}
|
|
9533
|
+
let wildcardTokens = 0;
|
|
9534
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
9535
|
+
if (value[index] === "?") {
|
|
9536
|
+
wildcardTokens += 1;
|
|
9537
|
+
} else if (value[index] === "*") {
|
|
9538
|
+
wildcardTokens += 1;
|
|
9539
|
+
if (value[index + 1] === "*") index += 1;
|
|
9540
|
+
}
|
|
9541
|
+
}
|
|
9542
|
+
if (wildcardTokens > MAX_NATIVE_SNAPSHOT_PATTERN_WILDCARDS) {
|
|
9543
|
+
throw new Error(
|
|
9544
|
+
`${label} contains more than ${MAX_NATIVE_SNAPSHOT_PATTERN_WILDCARDS} wildcard tokens`
|
|
9545
|
+
);
|
|
9546
|
+
}
|
|
9547
|
+
return value;
|
|
9548
|
+
}
|
|
9549
|
+
function snapshotPatterns(value, label, fallback) {
|
|
9550
|
+
if (value === void 0) return [...fallback];
|
|
9551
|
+
if (!Array.isArray(value)) {
|
|
9552
|
+
throw new Error(`${label} contains an unsafe pattern`);
|
|
9553
|
+
}
|
|
9554
|
+
return [...new Set(value.map((pattern) => normalizeNativeSnapshotPattern(pattern, label)))].sort(
|
|
9555
|
+
(left, right) => left.localeCompare(right, "en")
|
|
9556
|
+
);
|
|
9557
|
+
}
|
|
9558
|
+
function positiveSnapshotInteger(value, fallback, label) {
|
|
9559
|
+
const resolved = value ?? fallback;
|
|
9560
|
+
if (!Number.isSafeInteger(resolved) || resolved < 1) {
|
|
9561
|
+
throw new Error(`${label} must be a positive integer`);
|
|
9562
|
+
}
|
|
9563
|
+
return resolved;
|
|
9564
|
+
}
|
|
9565
|
+
function parseSnapshot(value) {
|
|
9566
|
+
if (value === void 0)
|
|
9567
|
+
return { ...DEFAULT_NATIVE_SNAPSHOT_CONFIG, include: ["**/*"], exclude: [] };
|
|
9568
|
+
const snapshot = record(value, "native.snapshot");
|
|
9569
|
+
rejectUnknown(snapshot, SNAPSHOT_KEYS, "native.snapshot");
|
|
9570
|
+
return {
|
|
9571
|
+
include: snapshotPatterns(
|
|
9572
|
+
snapshot.include,
|
|
9573
|
+
"native.snapshot.include",
|
|
9574
|
+
DEFAULT_NATIVE_SNAPSHOT_CONFIG.include
|
|
9575
|
+
),
|
|
9576
|
+
exclude: snapshotPatterns(
|
|
9577
|
+
snapshot.exclude,
|
|
9578
|
+
"native.snapshot.exclude",
|
|
9579
|
+
DEFAULT_NATIVE_SNAPSHOT_CONFIG.exclude
|
|
9580
|
+
),
|
|
9581
|
+
max_files: positiveSnapshotInteger(
|
|
9582
|
+
snapshot.max_files,
|
|
9583
|
+
DEFAULT_NATIVE_SNAPSHOT_CONFIG.max_files,
|
|
9584
|
+
"native.snapshot.max_files"
|
|
9585
|
+
),
|
|
9586
|
+
max_total_bytes: positiveSnapshotInteger(
|
|
9587
|
+
snapshot.max_total_bytes,
|
|
9588
|
+
DEFAULT_NATIVE_SNAPSHOT_CONFIG.max_total_bytes,
|
|
9589
|
+
"native.snapshot.max_total_bytes"
|
|
9590
|
+
),
|
|
9591
|
+
max_duration_ms: positiveSnapshotInteger(
|
|
9592
|
+
snapshot.max_duration_ms,
|
|
9593
|
+
DEFAULT_NATIVE_SNAPSHOT_CONFIG.max_duration_ms,
|
|
9594
|
+
"native.snapshot.max_duration_ms"
|
|
9595
|
+
)
|
|
9596
|
+
};
|
|
9597
|
+
}
|
|
9382
9598
|
function record(value, label) {
|
|
9383
9599
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
9384
9600
|
throw new Error(`${label} must be a mapping`);
|
|
@@ -9464,6 +9680,7 @@ function parseConfig(value) {
|
|
|
9464
9680
|
throw new Error("native.clarification_mode must be sequential or batch");
|
|
9465
9681
|
}
|
|
9466
9682
|
const pending = parsePending(native.pending_root_move);
|
|
9683
|
+
const snapshot = parseSnapshot(native.snapshot);
|
|
9467
9684
|
return {
|
|
9468
9685
|
schema: "comet.project.v1",
|
|
9469
9686
|
default_workflow: root.default_workflow,
|
|
@@ -9473,6 +9690,7 @@ function parseConfig(value) {
|
|
|
9473
9690
|
artifact_root: normalizeArtifactRootRef(native.artifact_root),
|
|
9474
9691
|
language,
|
|
9475
9692
|
clarification_mode: clarificationMode,
|
|
9693
|
+
snapshot,
|
|
9476
9694
|
...pending ? { pending_root_move: pending } : {}
|
|
9477
9695
|
}
|
|
9478
9696
|
};
|