candor-ts 0.26.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +49 -2
- package/README.md +2 -2
- package/contract.mjs +16 -2
- package/lsp.mjs +51 -3
- package/mcp.mjs +181 -21
- package/package.json +2 -2
- package/policy.mjs +134 -6
- package/query-core.mjs +335 -12
- package/query.mjs +879 -57
- package/scan-core.mjs +39 -0
- package/scan.mjs +1330 -39
- package/surface.mjs +15 -2
package/scan-core.mjs
CHANGED
|
@@ -215,6 +215,45 @@ export const MODEL_SDK_RE =
|
|
|
215
215
|
export function isModelSdkPackage(moduleName) {
|
|
216
216
|
return MODEL_SDK_RE.test(moduleName);
|
|
217
217
|
}
|
|
218
|
+
/// SPEC §2 `fs` — for a call ALREADY classified `Fs`, the read/write direction its verb implies.
|
|
219
|
+
/// Returns ["read"], ["write"], ["read","write"], or [] when the verb does not say.
|
|
220
|
+
///
|
|
221
|
+
/// THE EMPTY CASE IS THE POINT. §2: "when `Fs` is reached but its kind is unknown … the field MUST be
|
|
222
|
+
/// omitted rather than guessed. An empty or partial `fs` would be read as a positive claim ('reads but
|
|
223
|
+
/// never writes'), which is the §4 trust contract's forbidden direction." So an unrecognised verb
|
|
224
|
+
/// contributes nothing and the field stays absent — absence means "kind undetermined", never "read-only".
|
|
225
|
+
///
|
|
226
|
+
/// A syntactic refinement of an effect candor already proved, NOT a soundness claim: a wrong direction
|
|
227
|
+
/// misreports a detail, a wrong EFFECT is the cardinal sin, and those are different failures. Deliberately
|
|
228
|
+
/// the same vocabulary and shape as candor-java's `fsKind` and candor-swift's — the surface is spec'd
|
|
229
|
+
/// four-way, and three engines inventing three verb tables for one field is how a shared field stops
|
|
230
|
+
/// meaning one thing. Node's sync/promise variants are handled by stripping the `Sync` suffix rather than
|
|
231
|
+
/// by listing every pair.
|
|
232
|
+
export function fsKind(moduleName, member) {
|
|
233
|
+
if (!member) return [];
|
|
234
|
+
const m = member.endsWith("Sync") ? member.slice(0, -4) : member;
|
|
235
|
+
// Reads the source AND writes the destination, in one call.
|
|
236
|
+
if (m === "copyFile" || m === "cp") return ["read", "write"];
|
|
237
|
+
const WRITE = new Set([
|
|
238
|
+
"writeFile", "appendFile", "write", "writev", "mkdir", "mkdtemp", "rmdir", "rm", "unlink",
|
|
239
|
+
"rename", "truncate", "ftruncate", "chmod", "fchmod", "lchmod", "chown", "fchown", "lchown",
|
|
240
|
+
"utimes", "futimes", "lutimes", "symlink", "link", "createWriteStream", "outputFile", "ensureDir",
|
|
241
|
+
"ensureFile", "emptyDir", "remove", "move", "outputJson", "writeJson", "writeJSON",
|
|
242
|
+
]);
|
|
243
|
+
const READ = new Set([
|
|
244
|
+
"readFile", "readdir", "read", "readv", "stat", "lstat", "fstat", "statfs", "access", "exists",
|
|
245
|
+
"realpath", "readlink", "createReadStream", "opendir", "watch", "watchFile", "readJson",
|
|
246
|
+
"readJSON", "pathExists", "lstatSync",
|
|
247
|
+
]);
|
|
248
|
+
if (WRITE.has(m)) return ["write"];
|
|
249
|
+
if (READ.has(m)) return ["read"];
|
|
250
|
+
// `open`/`openSync` take a MODE — "r", "w", "a" — so the verb alone does not say. Deliberately no claim
|
|
251
|
+
// rather than a guess at the common case.
|
|
252
|
+
if (m.startsWith("write") || m.startsWith("append")) return ["write"];
|
|
253
|
+
if (m.startsWith("read")) return ["read"];
|
|
254
|
+
return [];
|
|
255
|
+
}
|
|
256
|
+
|
|
218
257
|
export function kappa(moduleName, member) {
|
|
219
258
|
for (const [mre, vre, eff] of KAPPA_RULES) {
|
|
220
259
|
if (mre.test(moduleName) && (!vre || vre.test(member))) return eff;
|