@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.
Files changed (161) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +3 -3
  3. package/assets/manifest.json +1 -1
  4. package/assets/skills/comet/reference/comet-yaml-fields.md +2 -2
  5. package/assets/skills/comet/scripts/comet-entry-runtime.mjs +118 -6
  6. package/assets/skills/comet/scripts/comet-hook-router.mjs +244 -26
  7. package/assets/skills/comet/scripts/comet-runtime.mjs +221 -104
  8. package/assets/skills/comet-archive/SKILL.md +29 -20
  9. package/assets/skills/comet-native/SKILL.md +23 -15
  10. package/assets/skills/comet-native/reference/artifacts.md +19 -4
  11. package/assets/skills/comet-native/reference/commands.md +8 -2
  12. package/assets/skills/comet-native/reference/recovery.md +1 -1
  13. package/assets/skills/comet-native/scripts/comet-native-runtime.mjs +1136 -471
  14. package/assets/skills-zh/comet/reference/comet-yaml-fields.md +2 -2
  15. package/assets/skills-zh/comet-archive/SKILL.md +29 -20
  16. package/assets/skills-zh/comet-native/SKILL.md +23 -15
  17. package/assets/skills-zh/comet-native/reference/artifacts.md +20 -5
  18. package/assets/skills-zh/comet-native/reference/commands.md +8 -2
  19. package/assets/skills-zh/comet-native/reference/recovery.md +1 -1
  20. package/dist/app/commands/init.d.ts.map +1 -1
  21. package/dist/app/commands/init.js +3 -6
  22. package/dist/app/commands/init.js.map +1 -1
  23. package/dist/domains/bundle/bundle-platform.d.ts.map +1 -1
  24. package/dist/domains/bundle/bundle-platform.js +1 -1
  25. package/dist/domains/bundle/bundle-platform.js.map +1 -1
  26. package/dist/domains/comet-classic/classic-guard.d.ts.map +1 -1
  27. package/dist/domains/comet-classic/classic-guard.js +3 -2
  28. package/dist/domains/comet-classic/classic-guard.js.map +1 -1
  29. package/dist/domains/comet-entry/current-selection.d.ts.map +1 -1
  30. package/dist/domains/comet-entry/current-selection.js +6 -8
  31. package/dist/domains/comet-entry/current-selection.js.map +1 -1
  32. package/dist/domains/comet-entry/project-status.d.ts.map +1 -1
  33. package/dist/domains/comet-entry/project-status.js +5 -1
  34. package/dist/domains/comet-entry/project-status.js.map +1 -1
  35. package/dist/domains/comet-native/native-archive-transaction.d.ts.map +1 -1
  36. package/dist/domains/comet-native/native-archive-transaction.js +5 -6
  37. package/dist/domains/comet-native/native-archive-transaction.js.map +1 -1
  38. package/dist/domains/comet-native/native-atomic-file.d.ts.map +1 -1
  39. package/dist/domains/comet-native/native-atomic-file.js +11 -7
  40. package/dist/domains/comet-native/native-atomic-file.js.map +1 -1
  41. package/dist/domains/comet-native/native-bounded-file.d.ts.map +1 -1
  42. package/dist/domains/comet-native/native-bounded-file.js +11 -7
  43. package/dist/domains/comet-native/native-bounded-file.js.map +1 -1
  44. package/dist/domains/comet-native/native-build-evidence.js +2 -2
  45. package/dist/domains/comet-native/native-build-evidence.js.map +1 -1
  46. package/dist/domains/comet-native/native-change.d.ts +4 -2
  47. package/dist/domains/comet-native/native-change.d.ts.map +1 -1
  48. package/dist/domains/comet-native/native-change.js +18 -4
  49. package/dist/domains/comet-native/native-change.js.map +1 -1
  50. package/dist/domains/comet-native/native-check-receipt-storage.d.ts.map +1 -1
  51. package/dist/domains/comet-native/native-check-receipt-storage.js +11 -7
  52. package/dist/domains/comet-native/native-check-receipt-storage.js.map +1 -1
  53. package/dist/domains/comet-native/native-check-receipt.d.ts.map +1 -1
  54. package/dist/domains/comet-native/native-check-receipt.js +16 -11
  55. package/dist/domains/comet-native/native-check-receipt.js.map +1 -1
  56. package/dist/domains/comet-native/native-cli.d.ts.map +1 -1
  57. package/dist/domains/comet-native/native-cli.js +120 -16
  58. package/dist/domains/comet-native/native-cli.js.map +1 -1
  59. package/dist/domains/comet-native/native-config.d.ts +5 -1
  60. package/dist/domains/comet-native/native-config.d.ts.map +1 -1
  61. package/dist/domains/comet-native/native-config.js +78 -0
  62. package/dist/domains/comet-native/native-config.js.map +1 -1
  63. package/dist/domains/comet-native/native-continuation.d.ts +2 -1
  64. package/dist/domains/comet-native/native-continuation.d.ts.map +1 -1
  65. package/dist/domains/comet-native/native-continuation.js +13 -5
  66. package/dist/domains/comet-native/native-continuation.js.map +1 -1
  67. package/dist/domains/comet-native/native-diagnostics.d.ts +7 -3
  68. package/dist/domains/comet-native/native-diagnostics.d.ts.map +1 -1
  69. package/dist/domains/comet-native/native-diagnostics.js +19 -9
  70. package/dist/domains/comet-native/native-diagnostics.js.map +1 -1
  71. package/dist/domains/comet-native/native-evidence-retention.d.ts.map +1 -1
  72. package/dist/domains/comet-native/native-evidence-retention.js +5 -3
  73. package/dist/domains/comet-native/native-evidence-retention.js.map +1 -1
  74. package/dist/domains/comet-native/native-evidence-storage.d.ts.map +1 -1
  75. package/dist/domains/comet-native/native-evidence-storage.js +11 -7
  76. package/dist/domains/comet-native/native-evidence-storage.js.map +1 -1
  77. package/dist/domains/comet-native/native-file-identity.d.ts +3 -0
  78. package/dist/domains/comet-native/native-file-identity.d.ts.map +1 -0
  79. package/dist/domains/comet-native/native-file-identity.js +2 -0
  80. package/dist/domains/comet-native/native-file-identity.js.map +1 -0
  81. package/dist/domains/comet-native/native-findings.d.ts.map +1 -1
  82. package/dist/domains/comet-native/native-findings.js +19 -1
  83. package/dist/domains/comet-native/native-findings.js.map +1 -1
  84. package/dist/domains/comet-native/native-guards.d.ts +2 -1
  85. package/dist/domains/comet-native/native-guards.d.ts.map +1 -1
  86. package/dist/domains/comet-native/native-guards.js +14 -0
  87. package/dist/domains/comet-native/native-guards.js.map +1 -1
  88. package/dist/domains/comet-native/native-lock.d.ts.map +1 -1
  89. package/dist/domains/comet-native/native-lock.js +30 -35
  90. package/dist/domains/comet-native/native-lock.js.map +1 -1
  91. package/dist/domains/comet-native/native-protected-file.d.ts.map +1 -1
  92. package/dist/domains/comet-native/native-protected-file.js +9 -8
  93. package/dist/domains/comet-native/native-protected-file.js.map +1 -1
  94. package/dist/domains/comet-native/native-root-move.d.ts.map +1 -1
  95. package/dist/domains/comet-native/native-root-move.js +2 -0
  96. package/dist/domains/comet-native/native-root-move.js.map +1 -1
  97. package/dist/domains/comet-native/native-run-store.d.ts.map +1 -1
  98. package/dist/domains/comet-native/native-run-store.js +9 -8
  99. package/dist/domains/comet-native/native-run-store.js.map +1 -1
  100. package/dist/domains/comet-native/native-snapshot.d.ts +5 -1
  101. package/dist/domains/comet-native/native-snapshot.d.ts.map +1 -1
  102. package/dist/domains/comet-native/native-snapshot.js +225 -5
  103. package/dist/domains/comet-native/native-snapshot.js.map +1 -1
  104. package/dist/domains/comet-native/native-transitions.d.ts +2 -1
  105. package/dist/domains/comet-native/native-transitions.d.ts.map +1 -1
  106. package/dist/domains/comet-native/native-transitions.js +34 -11
  107. package/dist/domains/comet-native/native-transitions.js.map +1 -1
  108. package/dist/domains/comet-native/native-types.d.ts +16 -0
  109. package/dist/domains/comet-native/native-types.d.ts.map +1 -1
  110. package/dist/domains/comet-native/native-verification-runtime.d.ts.map +1 -1
  111. package/dist/domains/comet-native/native-verification-runtime.js +5 -3
  112. package/dist/domains/comet-native/native-verification-runtime.js.map +1 -1
  113. package/dist/domains/comet-native/native-verification-scope.d.ts +2 -1
  114. package/dist/domains/comet-native/native-verification-scope.d.ts.map +1 -1
  115. package/dist/domains/comet-native/native-verification-scope.js +6 -1
  116. package/dist/domains/comet-native/native-verification-scope.js.map +1 -1
  117. package/dist/domains/dashboard/native-collector.d.ts.map +1 -1
  118. package/dist/domains/dashboard/native-collector.js +4 -1
  119. package/dist/domains/dashboard/native-collector.js.map +1 -1
  120. package/dist/domains/dashboard/web/index.html +14 -14
  121. package/dist/domains/skill/platform-install.d.ts.map +1 -1
  122. package/dist/domains/skill/platform-install.js +9 -0
  123. package/dist/domains/skill/platform-install.js.map +1 -1
  124. package/dist/domains/skill/project-instructions.d.ts.map +1 -1
  125. package/dist/domains/skill/project-instructions.js +4 -2
  126. package/dist/domains/skill/project-instructions.js.map +1 -1
  127. package/dist/domains/workflow-contract/project-config.d.ts +1 -1
  128. package/dist/domains/workflow-contract/project-config.d.ts.map +1 -1
  129. package/dist/domains/workflow-contract/project-config.js +24 -2
  130. package/dist/domains/workflow-contract/project-config.js.map +1 -1
  131. package/dist/platform/fs/file-identity.d.ts +9 -0
  132. package/dist/platform/fs/file-identity.d.ts.map +1 -0
  133. package/dist/platform/fs/file-identity.js +21 -0
  134. package/dist/platform/fs/file-identity.js.map +1 -0
  135. package/dist/platform/fs/file-system.d.ts.map +1 -1
  136. package/dist/platform/fs/file-system.js +13 -9
  137. package/dist/platform/fs/file-system.js.map +1 -1
  138. package/dist/platform/fs/race-safe-read.d.ts +47 -0
  139. package/dist/platform/fs/race-safe-read.d.ts.map +1 -0
  140. package/dist/platform/fs/race-safe-read.js +132 -0
  141. package/dist/platform/fs/race-safe-read.js.map +1 -0
  142. package/eval/README.md +1 -1
  143. package/eval/local/tasks/comet-native-clarification-depth/environment/Dockerfile +27 -0
  144. package/eval/local/tasks/comet-native-clarification-depth/environment/test_wordcount.py +25 -0
  145. package/eval/local/tasks/comet-native-clarification-depth/environment/wordcount.py +36 -0
  146. package/eval/local/tasks/comet-native-clarification-depth/instruction.md +17 -0
  147. package/eval/local/tasks/comet-native-clarification-depth/task.toml +47 -0
  148. package/eval/local/tasks/comet-native-clarification-depth/validation/test_native_clarification_depth.py +618 -0
  149. package/eval/local/tasks/comet-native-clarification-modes/validation/test_native_clarification_modes.py +1 -1
  150. package/eval/local/tasks/index.yaml +6 -0
  151. package/eval/local/tests/conftest.py +146 -2
  152. package/eval/local/tests/scaffold/test_conftest_helpers.py +188 -1
  153. package/eval/local/tests/scaffold/test_tasks.py +440 -8
  154. package/eval/local/tests/scaffold/test_utils.py +114 -1
  155. package/eval/local/tests/tasks/test_tasks.py +2 -0
  156. package/eval/pyproject.toml +4 -4
  157. package/eval/scaffold/python/aligned_comparison.py +1 -0
  158. package/eval/scaffold/python/tasks.py +2 -0
  159. package/eval/scaffold/shell/docker.sh +1 -1
  160. package/eval/scaffold/shell/run-claude-loop.sh +25 -2
  161. package/package.json +8 -1
@@ -57,7 +57,7 @@ export async function fileExists(filePath) {
57
57
  return true;
58
58
  }
59
59
  catch (error) {
60
- if (isNotFoundError(error))
60
+ if (isMissingPathError(error))
61
61
  return false;
62
62
  throw error;
63
63
  }
@@ -94,13 +94,17 @@ export async function readDir(dirPath) {
94
94
  }
95
95
  }
96
96
  /**
97
- * Returns true when an error means the path was simply not found. ENOENT is
98
- * the only non-fatal outcome for the removal helpers below; all other errors
99
- * (permissions, IO) are reported as failures instead of being masked as
100
- * "already gone".
97
+ * Returns true when an error means a path lookup found a file where it
98
+ * expected to be able to descend into a directory (ENOTDIR) e.g. a stray
99
+ * `.DS_Store` sitting where a plugin marketplace directory was expected
100
+ * treated the same as the path simply not being there (ENOENT). Only for
101
+ * read-only existence checks: a removal call hitting ENOTDIR means the
102
+ * on-disk shape is not what the caller expected, which is a real anomaly
103
+ * worth surfacing rather than masking as "already gone".
101
104
  */
102
- function isNotFoundError(error) {
103
- return error?.code === 'ENOENT';
105
+ function isMissingPathError(error) {
106
+ const code = error?.code;
107
+ return code === 'ENOENT' || code === 'ENOTDIR';
104
108
  }
105
109
  /**
106
110
  * Remove a file. Returns true if the file existed and was removed.
@@ -113,7 +117,7 @@ export async function removeFile(filePath) {
113
117
  return true;
114
118
  }
115
119
  catch (error) {
116
- if (isNotFoundError(error))
120
+ if (error?.code === 'ENOENT')
117
121
  return false;
118
122
  throw error;
119
123
  }
@@ -135,7 +139,7 @@ export async function removeDir(dirPath) {
135
139
  return true;
136
140
  }
137
141
  catch (error) {
138
- if (isNotFoundError(error))
142
+ if (error?.code === 'ENOENT')
139
143
  return false;
140
144
  throw error;
141
145
  }
@@ -1 +1 @@
1
- {"version":3,"file":"file-system.js","sourceRoot":"","sources":["../../../platform/fs/file-system.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"file-system.js","sourceRoot":"","sources":["../../../platform/fs/file-system.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import type { BigIntStats, Stats } from 'fs';
2
+ import { type FileObjectIdentity } from './file-identity.js';
3
+ export type RaceSafeReadCheckpoint = 'pre-open' | 'post-open' | 'post-read';
4
+ export interface RaceSafeReadContext {
5
+ realPath: string;
6
+ identity: FileObjectIdentity;
7
+ }
8
+ export type RaceSafeReadFailureReason = 'not-regular-file' | 'too-large' | 'changed';
9
+ export declare class RaceSafeReadError extends Error {
10
+ readonly reason: RaceSafeReadFailureReason;
11
+ constructor(reason: RaceSafeReadFailureReason, message: string, options?: {
12
+ cause?: unknown;
13
+ });
14
+ }
15
+ export interface RaceSafeReadOptions {
16
+ /** Use BigIntStats precision (dev/ino/size/mtimeNs/ctimeNs) end to end. */
17
+ bigint?: boolean;
18
+ /** Prefixed into built-in error messages, e.g. `${label} changed while reading`. */
19
+ label?: string;
20
+ /** Test-only synchronization points; behavior is passed through unchanged. */
21
+ hooks?: {
22
+ afterOpen?: () => void | Promise<void>;
23
+ beforeFinalCheck?: () => void | Promise<void>;
24
+ };
25
+ /**
26
+ * Called inside the same synchronization window as the built-in identity
27
+ * checks at each checkpoint. A thrown error aborts the read exactly like an
28
+ * identity mismatch. Use this to stack domain-specific checks (for example
29
+ * Native directory-chain verification) without opening a second race window.
30
+ */
31
+ verify?: (checkpoint: RaceSafeReadCheckpoint, context: RaceSafeReadContext) => void | Promise<void>;
32
+ }
33
+ export interface RaceSafeReadResult {
34
+ bytes: Buffer;
35
+ stat: Stats | BigIntStats;
36
+ realPath: string;
37
+ }
38
+ /**
39
+ * Read a regular file through one descriptor with identity re-verification
40
+ * before open, after open, and after the bounded read, so a path swapped for
41
+ * a symlink or replacement file between checks is always rejected.
42
+ *
43
+ * ENOENT (and every other system error except ELOOP) propagates unchanged so
44
+ * callers can keep their own missing-file semantics.
45
+ */
46
+ export declare function readFileRaceSafe(file: string, maxBytes: number, options?: RaceSafeReadOptions): Promise<RaceSafeReadResult>;
47
+ //# sourceMappingURL=race-safe-read.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"race-safe-read.d.ts","sourceRoot":"","sources":["../../../platform/fs/race-safe-read.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,IAAI,CAAC;AAE7C,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,MAAM,sBAAsB,GAAG,UAAU,GAAG,WAAW,GAAG,WAAW,CAAC;AAE5E,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,kBAAkB,CAAC;CAC9B;AAED,MAAM,MAAM,yBAAyB,GAAG,kBAAkB,GAAG,WAAW,GAAG,SAAS,CAAC;AAErF,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,MAAM,EAAE,yBAAyB,CAAC;gBAE/B,MAAM,EAAE,yBAAyB,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAK9F;AAED,MAAM,WAAW,mBAAmB;IAClC,2EAA2E;IAC3E,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,oFAAoF;IACpF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,KAAK,CAAC,EAAE;QACN,SAAS,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QACvC,gBAAgB,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KAC/C,CAAC;IACF;;;;;OAKG;IACH,MAAM,CAAC,EAAE,CACP,UAAU,EAAE,sBAAsB,EAClC,OAAO,EAAE,mBAAmB,KACzB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,KAAK,GAAG,WAAW,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAgCD;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,kBAAkB,CAAC,CAgG7B"}
@@ -0,0 +1,132 @@
1
+ import { constants as fsConstants, promises as fs } from 'fs';
2
+ import { hasComparableFileObject, sameFileObject, } from './file-identity.js';
3
+ export class RaceSafeReadError extends Error {
4
+ reason;
5
+ constructor(reason, message, options) {
6
+ super(message, options);
7
+ this.name = 'RaceSafeReadError';
8
+ this.reason = reason;
9
+ }
10
+ }
11
+ function birthtimeOf(stat) {
12
+ return 'birthtimeNs' in stat && typeof stat.birthtimeNs === 'bigint'
13
+ ? stat.birthtimeNs
14
+ : stat.birthtimeMs;
15
+ }
16
+ function ctimeOf(stat) {
17
+ return 'ctimeNs' in stat && typeof stat.ctimeNs === 'bigint' ? stat.ctimeNs : stat.ctimeMs;
18
+ }
19
+ function identityOf(stat) {
20
+ return { dev: stat.dev, ino: stat.ino, birthtime: birthtimeOf(stat) };
21
+ }
22
+ function sameStatIdentity(left, right) {
23
+ const leftObject = identityOf(left);
24
+ const rightObject = identityOf(right);
25
+ if (hasComparableFileObject(leftObject, rightObject)) {
26
+ return sameFileObject(leftObject, rightObject);
27
+ }
28
+ return (sameFileObject(leftObject, rightObject) &&
29
+ birthtimeOf(left) === birthtimeOf(right) &&
30
+ ctimeOf(left) === ctimeOf(right) &&
31
+ left.size === right.size);
32
+ }
33
+ /**
34
+ * Read a regular file through one descriptor with identity re-verification
35
+ * before open, after open, and after the bounded read, so a path swapped for
36
+ * a symlink or replacement file between checks is always rejected.
37
+ *
38
+ * ENOENT (and every other system error except ELOOP) propagates unchanged so
39
+ * callers can keep their own missing-file semantics.
40
+ */
41
+ export async function readFileRaceSafe(file, maxBytes, options = {}) {
42
+ if (!Number.isSafeInteger(maxBytes) || maxBytes < 1) {
43
+ throw new Error('race-safe read byte limit must be a positive integer');
44
+ }
45
+ const label = options.label ?? 'file';
46
+ const bigint = options.bigint === true;
47
+ const before = await fs.lstat(file, { bigint });
48
+ if (!before.isFile() || before.isSymbolicLink()) {
49
+ throw new RaceSafeReadError('not-regular-file', `${label} must be a regular file`);
50
+ }
51
+ if (BigInt(before.size) > BigInt(maxBytes)) {
52
+ throw new RaceSafeReadError('too-large', `${label} exceeds ${maxBytes} bytes`);
53
+ }
54
+ const beforeRealPath = await fs.realpath(file);
55
+ await options.verify?.('pre-open', { realPath: beforeRealPath, identity: identityOf(before) });
56
+ // POSIX: O_NOFOLLOW rejects a symlink swapped in since the lstat above and
57
+ // O_NONBLOCK prevents a FIFO from blocking the open. Windows: Node exposes
58
+ // neither flag, so this branch opens with plain O_RDONLY and the
59
+ // lstat/realpath identity checks below - which run identically on every
60
+ // platform - are the sole and sufficient guard against both swaps.
61
+ const flags = process.platform === 'win32'
62
+ ? fsConstants.O_RDONLY
63
+ : fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW | fsConstants.O_NONBLOCK;
64
+ let handle;
65
+ try {
66
+ handle = await fs.open(file, flags);
67
+ }
68
+ catch (error) {
69
+ if (error.code === 'ELOOP') {
70
+ throw new RaceSafeReadError('not-regular-file', `${label} must be a regular file`, {
71
+ cause: error,
72
+ });
73
+ }
74
+ throw error;
75
+ }
76
+ try {
77
+ const [opened, pathAfterOpen, realPathAfterOpen] = await Promise.all([
78
+ handle.stat({ bigint }),
79
+ fs.lstat(file, { bigint }),
80
+ fs.realpath(file),
81
+ ]);
82
+ if (!opened.isFile() ||
83
+ !pathAfterOpen.isFile() ||
84
+ pathAfterOpen.isSymbolicLink() ||
85
+ realPathAfterOpen !== beforeRealPath ||
86
+ !sameStatIdentity(before, opened) ||
87
+ !sameStatIdentity(before, pathAfterOpen)) {
88
+ throw new RaceSafeReadError('changed', `${label} changed while opening`);
89
+ }
90
+ await options.verify?.('post-open', {
91
+ realPath: realPathAfterOpen,
92
+ identity: identityOf(opened),
93
+ });
94
+ await options.hooks?.afterOpen?.();
95
+ const chunks = [];
96
+ let total = 0;
97
+ const buffer = Buffer.allocUnsafe(Math.min(64 * 1024, maxBytes + 1));
98
+ for (;;) {
99
+ const remaining = maxBytes + 1 - total;
100
+ const { bytesRead } = await handle.read(buffer, 0, Math.min(buffer.length, remaining), null);
101
+ if (bytesRead === 0)
102
+ break;
103
+ total += bytesRead;
104
+ if (total > maxBytes) {
105
+ throw new RaceSafeReadError('too-large', `${label} exceeds ${maxBytes} bytes`);
106
+ }
107
+ chunks.push(Buffer.from(buffer.subarray(0, bytesRead)));
108
+ }
109
+ await options.hooks?.beforeFinalCheck?.();
110
+ const [afterHandle, afterPath, afterRealPath] = await Promise.all([
111
+ handle.stat({ bigint }),
112
+ fs.lstat(file, { bigint }),
113
+ fs.realpath(file),
114
+ ]);
115
+ if (!afterPath.isFile() ||
116
+ afterPath.isSymbolicLink() ||
117
+ afterRealPath !== beforeRealPath ||
118
+ !sameStatIdentity(before, afterHandle) ||
119
+ !sameStatIdentity(before, afterPath)) {
120
+ throw new RaceSafeReadError('changed', `${label} changed while reading`);
121
+ }
122
+ await options.verify?.('post-read', {
123
+ realPath: afterRealPath,
124
+ identity: identityOf(afterHandle),
125
+ });
126
+ return { bytes: Buffer.concat(chunks, total), stat: afterHandle, realPath: afterRealPath };
127
+ }
128
+ finally {
129
+ await handle.close();
130
+ }
131
+ }
132
+ //# sourceMappingURL=race-safe-read.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"race-safe-read.js","sourceRoot":"","sources":["../../../platform/fs/race-safe-read.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,IAAI,WAAW,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AAG9D,OAAO,EACL,uBAAuB,EACvB,cAAc,GAEf,MAAM,oBAAoB,CAAC;AAW5B,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACjC,MAAM,CAA4B;IAE3C,YAAY,MAAiC,EAAE,OAAe,EAAE,OAA6B;QAC3F,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAgCD,SAAS,WAAW,CAAC,IAAc;IACjC,OAAO,aAAa,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ;QAClE,CAAC,CAAC,IAAI,CAAC,WAAW;QAClB,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;AACvB,CAAC;AAED,SAAS,OAAO,CAAC,IAAc;IAC7B,OAAO,SAAS,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;AAC7F,CAAC;AAED,SAAS,UAAU,CAAC,IAAc;IAChC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;AACxE,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAc,EAAE,KAAe;IACvD,MAAM,UAAU,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,WAAW,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IACtC,IAAI,uBAAuB,CAAC,UAAU,EAAE,WAAW,CAAC,EAAE,CAAC;QACrD,OAAO,cAAc,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,CACL,cAAc,CAAC,UAAU,EAAE,WAAW,CAAC;QACvC,WAAW,CAAC,IAAI,CAAC,KAAK,WAAW,CAAC,KAAK,CAAC;QACxC,OAAO,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,KAAK,CAAC;QAChC,IAAI,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,CACzB,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,IAAY,EACZ,QAAgB,EAChB,UAA+B,EAAE;IAEjC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAC1E,CAAC;IACD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAAC;IACtC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,KAAK,IAAI,CAAC;IAEvC,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAChD,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,MAAM,CAAC,cAAc,EAAE,EAAE,CAAC;QAChD,MAAM,IAAI,iBAAiB,CAAC,kBAAkB,EAAE,GAAG,KAAK,yBAAyB,CAAC,CAAC;IACrF,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,iBAAiB,CAAC,WAAW,EAAE,GAAG,KAAK,YAAY,QAAQ,QAAQ,CAAC,CAAC;IACjF,CAAC;IACD,MAAM,cAAc,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC/C,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,UAAU,EAAE,EAAE,QAAQ,EAAE,cAAc,EAAE,QAAQ,EAAE,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAE/F,2EAA2E;IAC3E,2EAA2E;IAC3E,iEAAiE;IACjE,wEAAwE;IACxE,mEAAmE;IACnE,MAAM,KAAK,GACT,OAAO,CAAC,QAAQ,KAAK,OAAO;QAC1B,CAAC,CAAC,WAAW,CAAC,QAAQ;QACtB,CAAC,CAAC,WAAW,CAAC,QAAQ,GAAG,WAAW,CAAC,UAAU,GAAG,WAAW,CAAC,UAAU,CAAC;IAC7E,IAAI,MAA2C,CAAC;IAChD,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACtC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YACtD,MAAM,IAAI,iBAAiB,CAAC,kBAAkB,EAAE,GAAG,KAAK,yBAAyB,EAAE;gBACjF,KAAK,EAAE,KAAK;aACb,CAAC,CAAC;QACL,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;IACD,IAAI,CAAC;QACH,MAAM,CAAC,MAAM,EAAE,aAAa,EAAE,iBAAiB,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YACnE,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;YACvB,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC;YAC1B,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC;SAClB,CAAC,CAAC;QACH,IACE,CAAC,MAAM,CAAC,MAAM,EAAE;YAChB,CAAC,aAAa,CAAC,MAAM,EAAE;YACvB,aAAa,CAAC,cAAc,EAAE;YAC9B,iBAAiB,KAAK,cAAc;YACpC,CAAC,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC;YACjC,CAAC,gBAAgB,CAAC,MAAM,EAAE,aAAa,CAAC,EACxC,CAAC;YACD,MAAM,IAAI,iBAAiB,CAAC,SAAS,EAAE,GAAG,KAAK,wBAAwB,CAAC,CAAC;QAC3E,CAAC;QACD,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE;YAClC,QAAQ,EAAE,iBAAiB;YAC3B,QAAQ,EAAE,UAAU,CAAC,MAAM,CAAC;SAC7B,CAAC,CAAC;QACH,MAAM,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC;QAEnC,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC;QACrE,SAAS,CAAC;YACR,MAAM,SAAS,GAAG,QAAQ,GAAG,CAAC,GAAG,KAAK,CAAC;YACvC,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,IAAI,CAAC,CAAC;YAC7F,IAAI,SAAS,KAAK,CAAC;gBAAE,MAAM;YAC3B,KAAK,IAAI,SAAS,CAAC;YACnB,IAAI,KAAK,GAAG,QAAQ,EAAE,CAAC;gBACrB,MAAM,IAAI,iBAAiB,CAAC,WAAW,EAAE,GAAG,KAAK,YAAY,QAAQ,QAAQ,CAAC,CAAC;YACjF,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;QAC1D,CAAC;QACD,MAAM,OAAO,CAAC,KAAK,EAAE,gBAAgB,EAAE,EAAE,CAAC;QAE1C,MAAM,CAAC,WAAW,EAAE,SAAS,EAAE,aAAa,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAChE,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;YACvB,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC;YAC1B,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC;SAClB,CAAC,CAAC;QACH,IACE,CAAC,SAAS,CAAC,MAAM,EAAE;YACnB,SAAS,CAAC,cAAc,EAAE;YAC1B,aAAa,KAAK,cAAc;YAChC,CAAC,gBAAgB,CAAC,MAAM,EAAE,WAAW,CAAC;YACtC,CAAC,gBAAgB,CAAC,MAAM,EAAE,SAAS,CAAC,EACpC,CAAC;YACD,MAAM,IAAI,iBAAiB,CAAC,SAAS,EAAE,GAAG,KAAK,wBAAwB,CAAC,CAAC;QAC3E,CAAC;QACD,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE;YAClC,QAAQ,EAAE,aAAa;YACvB,QAAQ,EAAE,UAAU,CAAC,WAAW,CAAC;SAClC,CAAC,CAAC;QACH,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC7F,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;AACH,CAAC"}
package/eval/README.md CHANGED
@@ -58,7 +58,7 @@ cp .env.example .env
58
58
  | ----------------------------------------------------------------- | ---- | --------------------------------------------------------------------------------------------------- |
59
59
  | `ANTHROPIC_API_KEY` | ✅\* | Anthropic API 密钥;也可以由系统环境变量提供 |
60
60
  | `BENCH_CC_MODEL` | ❌ | Claude 模型覆盖(默认用 CLI 配置) |
61
- | `BENCH_SIMULATOR_PROMPT_FILE` | ❌ | 自定义用户模拟器提示词文件(默认 `eval/simulator-instruction.md`) |
61
+ | `BENCH_SIMULATOR_PROMPT_FILE` | ❌ | 显式覆盖任务级用户模拟器提示词;任务未配置时回退到 `eval/simulator-instruction.md` |
62
62
  | `ANTHROPIC_AUTH_TOKEN` / `ANTHROPIC_BASE_URL` / `ANTHROPIC_MODEL` | ❌ | 用 Anthropic 兼容代理时的认证与模型配置;设置 `ANTHROPIC_AUTH_TOKEN` 后可不设置 `ANTHROPIC_API_KEY` |
63
63
  | `BENCH_LLM_JUDGE` | ❌ | 设为 `1` 启用 LLM-as-judge 评分 |
64
64
  | `BENCH_JUDGE_MODEL` | ❌ | Judge 模型;启用 `BENCH_LLM_JUDGE=1` 时必须显式设置,不能复用主模型 |
@@ -0,0 +1,27 @@
1
+ FROM python:3.12-slim
2
+
3
+ WORKDIR /workspace
4
+
5
+ RUN apt-get update && apt-get install -y --no-install-recommends \
6
+ git nodejs npm ca-certificates && \
7
+ rm -rf /var/lib/apt/lists/*
8
+
9
+ RUN npm config set registry https://registry.npmmirror.com && \
10
+ npm install -g @anthropic-ai/claude-code@latest && \
11
+ npm config delete registry
12
+
13
+ RUN pip install --no-cache-dir pyyaml pytest
14
+
15
+ COPY wordcount.py /workspace/wordcount.py
16
+ COPY test_wordcount.py /workspace/test_wordcount.py
17
+
18
+ RUN useradd --create-home --shell /bin/bash agent && \
19
+ chown -R agent:agent /workspace
20
+ USER agent
21
+ ENV HOME=/home/agent
22
+ ENV PYTHONPATH=/workspace
23
+ RUN git config --global user.email "agent@eval.local" && \
24
+ git config --global user.name "Comet Native Clarification Depth Eval Agent" && \
25
+ git config --global init.defaultBranch master
26
+
27
+ CMD ["bash"]
@@ -0,0 +1,25 @@
1
+ """Baseline tests for the word-count CLI."""
2
+
3
+ import subprocess
4
+ import sys
5
+
6
+
7
+ def run_cli(*args: str, input_text: str) -> str:
8
+ result = subprocess.run(
9
+ [sys.executable, "wordcount.py", *args],
10
+ input=input_text,
11
+ capture_output=True,
12
+ text=True,
13
+ check=True,
14
+ )
15
+ return result.stdout
16
+
17
+
18
+ def test_count_words():
19
+ assert "Words: 3" in run_cli(input_text="hello world foo")
20
+
21
+
22
+ def test_count_lines():
23
+ output = run_cli("--lines", input_text="hello\nworld\nfoo")
24
+ assert "Words: 3" in output
25
+ assert "Lines: 3" in output
@@ -0,0 +1,36 @@
1
+ """Simple word count CLI tool."""
2
+
3
+ import argparse
4
+ import sys
5
+
6
+
7
+ def count_words(text: str) -> int:
8
+ """Count words in text."""
9
+ return len(text.split())
10
+
11
+
12
+ def count_lines(text: str) -> int:
13
+ """Count lines in text."""
14
+ return len(text.splitlines())
15
+
16
+
17
+ def main():
18
+ parser = argparse.ArgumentParser(description="Count words and lines in text")
19
+ parser.add_argument("file", nargs="?", help="Input file (reads stdin if omitted)")
20
+ parser.add_argument("--lines", action="store_true", help="Also count lines")
21
+ parser.add_argument("--words", action="store_true", default=True, help="Count words (default)")
22
+ args = parser.parse_args()
23
+
24
+ if args.file:
25
+ with open(args.file) as source:
26
+ text = source.read()
27
+ else:
28
+ text = sys.stdin.read()
29
+
30
+ print(f"Words: {count_words(text)}")
31
+ if args.lines:
32
+ print(f"Lines: {count_lines(text)}")
33
+
34
+
35
+ if __name__ == "__main__":
36
+ main()
@@ -0,0 +1,17 @@
1
+ You are working on a Python project named `wordcount-cli`.
2
+
3
+ Begin by invoking the `/comet-native` Skill. Initialize Native under `docs/comet/`, create one change named `add-sentence-counting`, and add an opt-in `--sentences` CLI flag that prints `Sentences: N` after any requested `Lines: N` output while preserving the existing word and line counters.
4
+
5
+ The fixed interface contract is:
6
+
7
+ - only the ASCII terminal characters `.`, `!`, and `?` can create sentence boundaries;
8
+ - non-empty input with no terminal character counts as one sentence;
9
+ - when `--sentences` is present, it prints independently of `--lines`; the flag behavior and output order described above are not open product decisions.
10
+
11
+ The input domain is ordinary ASCII prose. Numbers, URLs, file paths, code, markup, quoted data, and Unicode-specific segmentation are out of scope.
12
+
13
+ The contract deliberately leaves three areas unresolved: empty or whitespace-only input, consecutive terminal characters, and terminal-looking characters embedded inside ordinary prose tokens. Resolve them in that listed order through the configured clarification protocol. An answer about whether an embedded character creates a boundary may introduce later decisions about how the recognized token collection is maintained and its exact contents; handle each dependent decision immediately after its parent.
14
+
15
+ The requested interface is intentionally underspecified. Follow the already configured Native Sequential clarification protocol and resolve every undefined user-visible behavior before implementation. Investigate repository-owned facts yourself, and do not change the configured clarification mode.
16
+
17
+ Complete Shape, Build, Verify, and Archive using only the Comet Native Skill and its bundled runtime.
@@ -0,0 +1,47 @@
1
+ [metadata]
2
+ name = "comet-native-clarification-depth"
3
+ description = "Measure whether Native Sequential discovers hidden user-owned decisions before implementation"
4
+ difficulty = "hard"
5
+ category = "comet-native"
6
+ tags = ["comet-native", "clarification", "sequential", "multi-turn", "decision-depth"]
7
+ default_treatments = ["COMET_NATIVE_SEQUENTIAL"]
8
+
9
+ [template]
10
+ required = []
11
+
12
+ [environment]
13
+ description = "Python word-count workspace with only the self-contained Comet Native Skill available."
14
+ dockerfile = "environment/Dockerfile"
15
+ timeout_sec = 2400
16
+
17
+ [validation]
18
+ test_scripts = "test_native_clarification_depth.py"
19
+ target_artifacts = [".comet/config.yaml", "docs/comet/archive", "docs/comet/specs"]
20
+ timeout = 120
21
+
22
+ [evaluation]
23
+ profile = "generic"
24
+ required_skills = ["comet-native"]
25
+ expected_artifacts = [".comet/config.yaml", "docs/comet/archive", "docs/comet/specs"]
26
+ require_skill_invocation = true
27
+ rubric_criteria = [
28
+ "Investigates repository-owned facts without asking the user",
29
+ "Discovers all hidden user-owned behavior decisions one at a time",
30
+ "Provides a recommendation and practical impact for each decision",
31
+ "Obtains explicit shared-understanding confirmation before Build",
32
+ "Completes Build, Verify, and Archive using only the Comet Native Skill and bundled runtime",
33
+ ]
34
+
35
+ [interaction]
36
+ mode = "auto_user"
37
+ max_turns = 8
38
+ decision_replies = [
39
+ "It prints Sentences: 0.",
40
+ "They count as one sentence boundary.",
41
+ "Recognized abbreviations such as e.g. and Dr. always suppress their periods, including at end-of-input; every other occurrence of ., !, or ? remains a sentence boundary, and the non-empty fallback still makes an abbreviation-only input one sentence.",
42
+ "Use a small explicit list. Ask me for the exact entries separately.",
43
+ "Use exactly Dr., Mr., Mrs., Ms., Prof., Sr., Jr., e.g., i.e., etc., vs., Inc., Ltd., Corp., St., and Ave., matched case-sensitively exactly as written.",
44
+ "confirmed",
45
+ ]
46
+ decision_patterns = ["Question:", "Recommendation:", "Impact:", "shared understanding", "Please confirm"]
47
+ continue_prompt = "Please read the persisted Native state and continue the same confirmed change through verification and archive."