finitemonkey 0.1.0-next.8 → 0.1.0-next.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/dist/finitemonkey.mjs +89 -16
- package/package.json +1 -1
package/dist/finitemonkey.mjs
CHANGED
|
@@ -4441,11 +4441,11 @@ var requirement2 = (want, ctx) => {
|
|
|
4441
4441
|
};
|
|
4442
4442
|
var gitCheck = (check2, ctx) => {
|
|
4443
4443
|
const wants = check2.require ?? ["committed"];
|
|
4444
|
-
const
|
|
4444
|
+
const missing2 = wants.flatMap((want) => {
|
|
4445
4445
|
const problem4 = requirement2(want, ctx);
|
|
4446
4446
|
return problem4 === void 0 ? [] : [problem4];
|
|
4447
4447
|
});
|
|
4448
|
-
return
|
|
4448
|
+
return missing2.length > 0 ? failed(missing2) : passed([note("gate.git.ok", { require: wants.join(", ") })]);
|
|
4449
4449
|
};
|
|
4450
4450
|
|
|
4451
4451
|
// src/guards/release/grants.ts
|
|
@@ -6507,10 +6507,10 @@ var symbolFindings = (context, pair, path, text6) => {
|
|
|
6507
6507
|
var verifyFile = (context, pair) => {
|
|
6508
6508
|
const path = resultPathOf(context, pair);
|
|
6509
6509
|
if (pair.ours?.binary === true || pair.theirs?.binary === true) return binaryFindings(context, pair, path);
|
|
6510
|
-
const
|
|
6510
|
+
const missing2 = ["ours", "theirs"].flatMap(
|
|
6511
6511
|
(side) => created2(pair[side]) && path === void 0 ? [finding("missing-file", pair.key, side, pair.key)] : []
|
|
6512
6512
|
);
|
|
6513
|
-
if (
|
|
6513
|
+
if (missing2.length > 0) return missing2;
|
|
6514
6514
|
const copied = [pair.ours, pair.theirs].find((diff) => diff?.status === "copied");
|
|
6515
6515
|
const baseSource = copied?.oldPath ?? (created2(pair.ours) || created2(pair.theirs) ? void 0 : pair.key);
|
|
6516
6516
|
const baseText = baseSource === void 0 ? void 0 : blobText(context.runtime, context.repo, context.inputs.base, baseSource);
|
|
@@ -10817,34 +10817,49 @@ var mergeHooks = (hooks, isOwn, wanted) => {
|
|
|
10817
10817
|
var withHooks = (settings, hooks) => {
|
|
10818
10818
|
return setKey(settings, "hooks", Object.keys(hooks).length === 0 ? void 0 : hooks);
|
|
10819
10819
|
};
|
|
10820
|
-
var
|
|
10820
|
+
var BLOCK_READS = "blockReadsOutsideWorkingDirectories";
|
|
10821
|
+
var withPermissions = (settings, lists) => {
|
|
10821
10822
|
const permissions = asRecord(settings["permissions"]);
|
|
10822
|
-
const
|
|
10823
|
+
const withDeny = setKey(permissions, "deny", lists.deny.length === 0 ? void 0 : lists.deny);
|
|
10824
|
+
const withAsk = setKey(withDeny, "ask", lists.ask.length === 0 ? void 0 : lists.ask);
|
|
10825
|
+
const next2 = setKey(withAsk, BLOCK_READS, lists.blockReads);
|
|
10823
10826
|
return setKey(settings, "permissions", Object.keys(next2).length === 0 ? void 0 : next2);
|
|
10824
10827
|
};
|
|
10828
|
+
var missing = (wanted, existing) => wanted.filter((rule) => !existing.includes(rule));
|
|
10829
|
+
var withoutAdded = (existing, added) => existing.filter((rule) => typeof rule !== "string" || !added.includes(rule));
|
|
10825
10830
|
var ownHookMatcher = (recorded) => (handler) => isOwnHandler(handler) || recorded.some((own) => JSON.stringify(own) === JSON.stringify(handler));
|
|
10826
10831
|
var mergeSettings = (current, wanted, recorded) => {
|
|
10827
10832
|
const schema = Object.keys(current).length === 0;
|
|
10828
10833
|
const base = schema ? { $schema: SETTINGS_SCHEMA_URL } : current;
|
|
10829
10834
|
const hooks = mergeHooks(asRecord(base["hooks"]), ownHookMatcher(recorded), wanted.hooks);
|
|
10830
|
-
const
|
|
10831
|
-
const
|
|
10835
|
+
const permissions = asRecord(base["permissions"]);
|
|
10836
|
+
const existingDeny = asList(permissions["deny"]);
|
|
10837
|
+
const existingAsk = asList(permissions["ask"]);
|
|
10838
|
+
const deny2 = missing(wanted.deny, existingDeny);
|
|
10839
|
+
const ask = missing(wanted.ask, existingAsk);
|
|
10840
|
+
const blockReads = !(BLOCK_READS in permissions);
|
|
10832
10841
|
const attribution = wanted.attributionOff && !("attribution" in base);
|
|
10833
10842
|
const marketplace = wanted.marketplace && !hasEntry(base, "extraKnownMarketplaces", MARKETPLACE_KEY);
|
|
10834
10843
|
const plugin = wanted.marketplace && !hasEntry(base, "enabledPlugins", PLUGIN_ID);
|
|
10835
|
-
let settings = withPermissions(withHooks(base, hooks),
|
|
10844
|
+
let settings = withPermissions(withHooks(base, hooks), {
|
|
10845
|
+
deny: [...existingDeny, ...deny2],
|
|
10846
|
+
ask: [...existingAsk, ...ask],
|
|
10847
|
+
blockReads: blockReads ? true : permissions[BLOCK_READS]
|
|
10848
|
+
});
|
|
10836
10849
|
if (attribution) settings = { ...settings, attribution: ATTRIBUTION_OFF };
|
|
10837
10850
|
if (marketplace) settings = withEntry(settings, "extraKnownMarketplaces", MARKETPLACE_KEY, MARKETPLACE_ENTRY);
|
|
10838
10851
|
if (plugin) settings = withEntry(settings, "enabledPlugins", PLUGIN_ID, true);
|
|
10839
|
-
return { settings, added: { schema, deny: deny2, attribution, marketplace, plugin } };
|
|
10852
|
+
return { settings, added: { schema, deny: deny2, ask, blockReads, attribution, marketplace, plugin } };
|
|
10840
10853
|
};
|
|
10841
10854
|
var sameAttribution = (value) => JSON.stringify(value) === JSON.stringify(ATTRIBUTION_OFF);
|
|
10842
10855
|
var unmergeSettings = (current, added, recorded) => {
|
|
10843
10856
|
const hooks = mergeHooks(asRecord(current["hooks"]), ownHookMatcher(recorded), {});
|
|
10844
|
-
const
|
|
10845
|
-
|
|
10846
|
-
|
|
10847
|
-
|
|
10857
|
+
const permissions = asRecord(current["permissions"]);
|
|
10858
|
+
let settings = withPermissions(withHooks(current, hooks), {
|
|
10859
|
+
deny: withoutAdded(asList(permissions["deny"]), added.deny),
|
|
10860
|
+
ask: withoutAdded(asList(permissions["ask"]), added.ask),
|
|
10861
|
+
blockReads: added.blockReads && permissions[BLOCK_READS] === true ? void 0 : permissions[BLOCK_READS]
|
|
10862
|
+
});
|
|
10848
10863
|
if (added.attribution && sameAttribution(settings["attribution"])) {
|
|
10849
10864
|
settings = setKey(settings, "attribution", void 0);
|
|
10850
10865
|
}
|
|
@@ -11050,9 +11065,11 @@ var parseAdded = (value) => {
|
|
|
11050
11065
|
const deny2 = strings2(value["deny"]);
|
|
11051
11066
|
const { schema, attribution } = value;
|
|
11052
11067
|
if (deny2 === void 0 || typeof schema !== "boolean" || typeof attribution !== "boolean") return void 0;
|
|
11068
|
+
const ask = strings2(value["ask"]) ?? [];
|
|
11069
|
+
const blockReads = value["blockReads"] === true;
|
|
11053
11070
|
const marketplace = value["marketplace"] === true;
|
|
11054
11071
|
const plugin = value["plugin"] === true;
|
|
11055
|
-
return { schema, attribution, deny: deny2, marketplace, plugin };
|
|
11072
|
+
return { schema, attribution, deny: deny2, ask, blockReads, marketplace, plugin };
|
|
11056
11073
|
};
|
|
11057
11074
|
var parseEntry2 = (value) => {
|
|
11058
11075
|
if (!isRecord(value)) return void 0;
|
|
@@ -11099,6 +11116,42 @@ var parseLock = (text6) => {
|
|
|
11099
11116
|
var renderLock = (lock) => `${JSON.stringify(lock, null, 2)}
|
|
11100
11117
|
`;
|
|
11101
11118
|
|
|
11119
|
+
// src/install/ask-floor.ts
|
|
11120
|
+
var DEFAULT_BRANCHES = ["main", "master"];
|
|
11121
|
+
var pushTo = (branch) => [
|
|
11122
|
+
`Bash(git push * ${branch})`,
|
|
11123
|
+
`Bash(git push * ${branch} *)`,
|
|
11124
|
+
`Bash(git push *:${branch})`,
|
|
11125
|
+
`Bash(git push *:${branch} *)`
|
|
11126
|
+
];
|
|
11127
|
+
var ASK_FLOOR = {
|
|
11128
|
+
push: DEFAULT_BRANCHES.flatMap(pushTo),
|
|
11129
|
+
deploy: [
|
|
11130
|
+
"Bash(npm publish *)",
|
|
11131
|
+
"Bash(pnpm publish *)",
|
|
11132
|
+
"Bash(yarn publish *)",
|
|
11133
|
+
"Bash(yarn npm publish *)",
|
|
11134
|
+
"Bash(bun publish *)",
|
|
11135
|
+
"Bash(vercel * --prod*)",
|
|
11136
|
+
"Bash(vercel --prod*)",
|
|
11137
|
+
"Bash(netlify deploy * --prod*)",
|
|
11138
|
+
"Bash(fly deploy *)",
|
|
11139
|
+
"Bash(flyctl deploy *)",
|
|
11140
|
+
"Bash(firebase deploy *)",
|
|
11141
|
+
"Bash(wrangler deploy *)",
|
|
11142
|
+
"Bash(serverless deploy *)",
|
|
11143
|
+
"Bash(sls deploy *)",
|
|
11144
|
+
"Bash(cdk deploy *)",
|
|
11145
|
+
"Bash(terraform apply *)",
|
|
11146
|
+
"Bash(tofu apply *)",
|
|
11147
|
+
"Bash(pulumi up *)",
|
|
11148
|
+
"Bash(kubectl apply *)",
|
|
11149
|
+
"Bash(helm install *)",
|
|
11150
|
+
"Bash(helm upgrade *)"
|
|
11151
|
+
]
|
|
11152
|
+
};
|
|
11153
|
+
var ASK_RULES = [...ASK_FLOOR.push, ...ASK_FLOOR.deploy];
|
|
11154
|
+
|
|
11102
11155
|
// src/install/claude-version.ts
|
|
11103
11156
|
var ON_FAILURE_MIN = [2, 1, 295];
|
|
11104
11157
|
var PROBE_MS = 8e3;
|
|
@@ -11120,6 +11173,23 @@ var detectClaude = (probe) => {
|
|
|
11120
11173
|
return { version: parsed.join("."), failClosed: atLeast(parsed, ON_FAILURE_MIN) };
|
|
11121
11174
|
};
|
|
11122
11175
|
|
|
11176
|
+
// src/install/claudeignore.ts
|
|
11177
|
+
var CLAUDEIGNORE_FILES = [".claudeignore", ".claude/.claudeignore"];
|
|
11178
|
+
var ruleFor = (raw) => {
|
|
11179
|
+
const line2 = withoutCarriageReturn(raw).trim();
|
|
11180
|
+
if (line2 === "" || line2.startsWith("#") || line2.startsWith("!") || line2.includes(")")) return void 0;
|
|
11181
|
+
const anchored = line2.startsWith("/");
|
|
11182
|
+
const body = (anchored ? line2.slice(1) : line2).replace(/\/+$/, "");
|
|
11183
|
+
if (body === "" || body === "*" || body === "**") return void 0;
|
|
11184
|
+
const path = line2.endsWith("/") ? `${body}/**` : body;
|
|
11185
|
+
return `Read(${anchored || body.includes("/") ? "./" : ""}${path})`;
|
|
11186
|
+
};
|
|
11187
|
+
var claudeignoreRules = (texts) => [
|
|
11188
|
+
...new Set(
|
|
11189
|
+
texts.flatMap((text6) => (text6 ?? "").split("\n")).map(ruleFor).filter((rule) => rule !== void 0)
|
|
11190
|
+
)
|
|
11191
|
+
];
|
|
11192
|
+
|
|
11123
11193
|
// src/install/config-template.ts
|
|
11124
11194
|
var configTemplate = (t, preset, lang) => [
|
|
11125
11195
|
`# ${GENERATED_MARKER}`,
|
|
@@ -11346,6 +11416,8 @@ var joinAdded = (previous, next2) => previous === void 0 ? next2 : {
|
|
|
11346
11416
|
schema: previous.schema || next2.schema,
|
|
11347
11417
|
attribution: previous.attribution || next2.attribution,
|
|
11348
11418
|
deny: union(previous.deny, next2.deny),
|
|
11419
|
+
ask: union(previous.ask, next2.ask),
|
|
11420
|
+
blockReads: previous.blockReads || next2.blockReads,
|
|
11349
11421
|
marketplace: previous.marketplace || next2.marketplace,
|
|
11350
11422
|
plugin: previous.plugin || next2.plugin
|
|
11351
11423
|
};
|
|
@@ -11359,7 +11431,8 @@ var settingsItem = (project, detection, input, previous) => {
|
|
|
11359
11431
|
const hooks = wantedHooks(detection);
|
|
11360
11432
|
const wanted = {
|
|
11361
11433
|
hooks,
|
|
11362
|
-
deny: DENY_RULES,
|
|
11434
|
+
deny: [...DENY_RULES, ...claudeignoreRules(CLAUDEIGNORE_FILES.map((path) => project.read(path)))],
|
|
11435
|
+
ask: ASK_RULES,
|
|
11363
11436
|
attributionOff: input.preset === "gabriel",
|
|
11364
11437
|
marketplace: input.marketplace
|
|
11365
11438
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "finitemonkey",
|
|
3
|
-
"version": "0.1.0-next.
|
|
3
|
+
"version": "0.1.0-next.9",
|
|
4
4
|
"description": "Claude Code hooks that stop a coding agent from saying done before the tests pass: a machine-checked definition of done, plus guardrails for secrets, git safety and production. Pre-release.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|