@sleepy_panda_srl/portulan 0.2.0 → 0.4.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/README.md +15 -4
- package/cli/README.md +61 -6
- package/cli/advisory.mjs +167 -53
- package/cli/cache-risk.mjs +69 -0
- package/cli/comments.mjs +8 -5
- package/cli/compile.mjs +781 -130
- package/cli/context.mjs +204 -43
- package/cli/doctor.mjs +248 -31
- package/cli/drills.mjs +56 -9
- package/cli/finish.md +34 -0
- package/cli/finish.mjs +8 -67
- package/cli/form.mjs +34 -18
- package/cli/frontmatter.mjs +39 -0
- package/cli/gate.mjs +14 -12
- package/cli/guidance-files.mjs +335 -0
- package/cli/handoff-policy.mjs +76 -0
- package/cli/html-entities.mjs +2130 -0
- package/cli/import-files.mjs +15 -0
- package/cli/index.mjs +77 -24
- package/cli/init-preview.mjs +553 -0
- package/cli/init.mjs +261 -46
- package/cli/instructions-journal.mjs +1185 -0
- package/cli/instructions.mjs +332 -57
- package/cli/ledger.mjs +230 -40
- package/cli/librarian.mjs +103 -19
- package/cli/persona-routing.mjs +209 -0
- package/cli/plugin-lint.mjs +77 -56
- package/cli/portulan.mjs +1 -1
- package/cli/recipe-output.mjs +91 -0
- package/cli/recipe-runner.md +68 -0
- package/cli/recipe-runner.mjs +131 -0
- package/cli/recipe-set.mjs +12 -3
- package/cli/review-meter.mjs +14 -9
- package/cli/ritual-contexts.mjs +103 -0
- package/cli/sessions.mjs +2 -1
- package/cli/spend-analysis.mjs +111 -0
- package/cli/spend-offer.md +53 -0
- package/cli/spend-offer.mjs +93 -0
- package/cli/stop-diagnostics.mjs +114 -0
- package/cli/stop-gate.mjs +133 -90
- package/cli/stop-policy.mjs +14 -0
- package/cli/symbols.mjs +55 -8
- package/cli/telemetry.mjs +66 -17
- package/cli/upgrade.mjs +62 -44
- package/cli/vendor.mjs +207 -125
- package/core/operating/context.md +401 -18
- package/core/operating/evolution.md +3 -2
- package/core/operating/loop.md +9 -4
- package/core/operating/sessions.md +6 -15
- package/core/personas/README.md +75 -0
- package/core/personas/implementer.md +3 -0
- package/core/personas/librarian.md +3 -0
- package/core/personas/reviewer.md +3 -0
- package/core/skills/clarify/SKILL.md +1 -1
- package/core/skills/consolidate/SKILL.md +1 -1
- package/core/templates/handoff.md +6 -2
- package/evals/README.md +23 -7
- package/evals/ab/personas/README.md +111 -0
- package/evals/ab/personas/acquisition.json +330 -0
- package/evals/ab/personas/bindings/implementer.txt +43 -0
- package/evals/ab/personas/bindings/librarian.txt +40 -0
- package/evals/ab/personas/bindings/reviewer.txt +41 -0
- package/evals/ab/personas/corpus.json +69 -0
- package/evals/ab/personas/grader.mjs +171 -0
- package/evals/ab/personas/implementer.json +774 -0
- package/evals/ab/personas/implementer.md +22 -0
- package/evals/ab/personas/librarian.json +758 -0
- package/evals/ab/personas/librarian.md +22 -0
- package/evals/ab/personas/protocol/continuation.mjs.txt +284 -0
- package/evals/ab/personas/protocol/first-outcome.mjs.txt +227 -0
- package/evals/ab/personas/protocol/first-probe.mjs.txt +172 -0
- package/evals/ab/personas/protocol/publisher.mjs.txt +126 -0
- package/evals/ab/personas/protocol/second-probe.mjs.txt +193 -0
- package/evals/ab/personas/repairs/first-control-answer.txt +23 -0
- package/evals/ab/personas/repairs/grader-before-decode-repair.mjs.txt +143 -0
- package/evals/ab/personas/reviewer.json +758 -0
- package/evals/ab/personas/reviewer.md +22 -0
- package/evals/releases/0.3.0.json +150 -0
- package/evals/releases/0.3.0.md +68 -0
- package/evals/releases/0.4.0.json +154 -0
- package/evals/releases/0.4.0.md +69 -0
- package/package.json +7 -2
- package/packs/.claude-plugin/plugin.json +2 -1
- package/packs/README.md +7 -4
- package/packs/rituals/checkpoints/README.md +35 -0
- package/packs/rituals/checkpoints/pack.json +3 -2
- package/packs/tools/README.md +8 -8
- package/packs/tools/local-llm/README.md +176 -0
- package/packs/tools/local-llm/pack.json +32 -0
- package/packs/tools/local-llm/personas/local-worker.md +44 -0
- package/packs/tools/local-llm/runner/local-llm.mjs +1779 -0
- package/packs/tools/local-llm/skills/delegate-local/SKILL.md +88 -0
- package/packs/tools/local-llm/verify/README.md +18 -0
- package/spec/README.md +37 -3
- package/spec/migrations/0009-instruction-sections-on-read.mjs +60 -11
- package/spec/migrations/0011-persona-bindings-compiled.mjs +23 -0
- package/spec/migrations/README.md +6 -0
- package/spec/pack.schema.json +12 -3
- package/spec/slots.md +272 -123
- package/spec/workspace.schema.json +67 -11
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Potential cache risks from project files; host activation is not inferred.
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { readOwnedText } from "./compile.mjs";
|
|
5
|
+
|
|
6
|
+
const object = v => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
7
|
+
const strings = v => Array.isArray(v) && v.every(s => typeof s === "string");
|
|
8
|
+
const scope = "Project files only; full MCP schema, trust, live activation, user/managed/CLI overrides, broader model/MCP policies and untested selectors (including experimental-beta disabling) are unassessed.";
|
|
9
|
+
|
|
10
|
+
export function cacheRiskLines(root) {
|
|
11
|
+
const lines = [`Assessed selectors: project model/ANTHROPIC_MODEL (opusplan and conditional Haiku), ENABLE_TOOL_SEARCH=false and ToolSearch denial; ${scope}`];
|
|
12
|
+
const read = label => {
|
|
13
|
+
const file = path.join(root, label);
|
|
14
|
+
try { fs.lstatSync(file); }
|
|
15
|
+
catch (error) {
|
|
16
|
+
if (error.code === "ENOENT") return {};
|
|
17
|
+
lines.push(`${label}: unassessed — project source is unreadable.`); return {};
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
const value = JSON.parse(readOwnedText(file, root));
|
|
21
|
+
if (!object(value)) throw Error();
|
|
22
|
+
return value;
|
|
23
|
+
} catch { lines.push(`${label}: unassessed — project source is unreadable, malformed, nonregular or outside its tree.`); return {}; }
|
|
24
|
+
};
|
|
25
|
+
const settings = label => {
|
|
26
|
+
const value = read(label);
|
|
27
|
+
if ((value.model !== undefined && typeof value.model !== "string") ||
|
|
28
|
+
(value.env !== undefined && (!object(value.env) || ["ANTHROPIC_MODEL", "ENABLE_TOOL_SEARCH"].some(k => value.env[k] !== undefined && typeof value.env[k] !== "string"))) ||
|
|
29
|
+
(value.permissions !== undefined && (!object(value.permissions) || (value.permissions.deny !== undefined && !strings(value.permissions.deny)))) ||
|
|
30
|
+
["enabledMcpjsonServers", "disabledMcpjsonServers"].some(k => value[k] !== undefined && !strings(value[k])) ||
|
|
31
|
+
(value.enableAllProjectMcpServers !== undefined && typeof value.enableAllProjectMcpServers !== "boolean")) {
|
|
32
|
+
lines.push(`${label}: unassessed — relevant project settings have invalid shapes.`); return {};
|
|
33
|
+
}
|
|
34
|
+
return value;
|
|
35
|
+
};
|
|
36
|
+
const shared = settings(".claude/settings.json"), local = settings(".claude/settings.local.json");
|
|
37
|
+
const env = { ...shared.env, ...local.env };
|
|
38
|
+
const model = env.ANTHROPIC_MODEL || (local.model ?? shared.model);
|
|
39
|
+
const source = env.ANTHROPIC_MODEL ? "project ANTHROPIC_MODEL" : "project model";
|
|
40
|
+
if (typeof model === "string" && /^opusplan(?:\[1m\])?$/i.test(model)) {
|
|
41
|
+
lines.push(`plan-mode model switching configured via ${source}: Opus planning and Sonnet execution can rebuild the model-specific cache at the boundary.`);
|
|
42
|
+
} else if (typeof model === "string" && /^(?:haiku(?:\[1m\])?|claude-haiku-[a-z0-9.-]+)$/i.test(model)) {
|
|
43
|
+
lines.push(`plan-mode model upgrade possible via ${source} for a Haiku selection: a permitted Sonnet upgrade can rebuild the model-specific cache. Provider and allowlist behavior is unresolved.`);
|
|
44
|
+
} else if (model === "") lines.push("project model selection is empty: resolved default and plan-mode behavior are unassessed.");
|
|
45
|
+
const mcp = read(".mcp.json");
|
|
46
|
+
const candidates = [];
|
|
47
|
+
if (mcp.mcpServers !== undefined && !object(mcp.mcpServers)) lines.push(".mcp.json: unassessed — project MCP definitions have an invalid shape.");
|
|
48
|
+
else for (const [name, server] of Object.entries(mcp.mcpServers ?? {})) {
|
|
49
|
+
const stdio = object(server) && (server.type === undefined || server.type === "stdio") && typeof server.command === "string" && server.command.trim() !== "";
|
|
50
|
+
let remote = false;
|
|
51
|
+
if (object(server) && ["http", "sse", "ws"].includes(server.type) && typeof server.url === "string") {
|
|
52
|
+
try { remote = (server.type === "ws" ? ["ws:", "wss:"] : ["http:", "https:"]).includes(new URL(server.url).protocol); } catch { /* Invalid endpoint is never printed. */ }
|
|
53
|
+
}
|
|
54
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(name) || (!stdio && !remote) || server.disabled !== undefined ||
|
|
55
|
+
(server.args !== undefined && !strings(server.args)) || (server.env !== undefined && (!object(server.env) || !Object.values(server.env).every(v => typeof v === "string")))) {
|
|
56
|
+
lines.push(".mcp.json: unassessed — a project MCP definition is unsupported or invalid.");
|
|
57
|
+
} else candidates.push(name);
|
|
58
|
+
}
|
|
59
|
+
const rejected = new Set([...(shared.disabledMcpjsonServers ?? []), ...(local.disabledMcpjsonServers ?? [])]);
|
|
60
|
+
const approved = new Set([...(shared.enabledMcpjsonServers ?? []), ...(local.enabledMcpjsonServers ?? [])]);
|
|
61
|
+
const all = local.enableAllProjectMcpServers ?? shared.enableAllProjectMcpServers ?? false;
|
|
62
|
+
const eligible = candidates.filter(name => !rejected.has(name));
|
|
63
|
+
const denial = [...(shared.permissions?.deny ?? []), ...(local.permissions?.deny ?? [])].includes("ToolSearch");
|
|
64
|
+
if (eligible.length && (env.ENABLE_TOOL_SEARCH === "false" || denial)) {
|
|
65
|
+
const known = eligible.filter(name => all || approved.has(name)).length;
|
|
66
|
+
lines.push(`tool search disabled by ${denial ? "project ToolSearch denial" : "project ENABLE_TOOL_SEARCH=false"}: ${eligible.length} eligible project MCP candidate(s), ${known} with project-file approval; upfront tool definitions can enlarge or change the cache prefix.`);
|
|
67
|
+
}
|
|
68
|
+
return lines;
|
|
69
|
+
}
|
package/cli/comments.mjs
CHANGED
|
@@ -764,12 +764,15 @@ export function historyOf(comments) {
|
|
|
764
764
|
return comments.filter((comment) => kinds.has(comment)).map((comment) => ({ ...comment, kinds: [...kinds.get(comment)] }));
|
|
765
765
|
}
|
|
766
766
|
|
|
767
|
-
function trackedFiles(root) {
|
|
767
|
+
function trackedFiles(root, timeout, env, noFsmonitor) {
|
|
768
768
|
try {
|
|
769
|
-
const out = execFileSync("git", ["ls-files", "--cached", "--others", "--exclude-standard", "-z"], {
|
|
769
|
+
const out = execFileSync("git", [...(noFsmonitor ? ["-c", "core.fsmonitor=false"] : []), "ls-files", "--cached", "--others", "--exclude-standard", "-z"], {
|
|
770
770
|
cwd: root,
|
|
771
771
|
encoding: "utf8",
|
|
772
772
|
maxBuffer: 256 * 1024 * 1024,
|
|
773
|
+
timeout,
|
|
774
|
+
env,
|
|
775
|
+
killSignal: "SIGKILL",
|
|
773
776
|
stdio: ["ignore", "pipe", "pipe"],
|
|
774
777
|
});
|
|
775
778
|
return [...new Set(out.split("\0").filter(Boolean))].sort();
|
|
@@ -799,8 +802,8 @@ function readSource(root, file, linked) {
|
|
|
799
802
|
}
|
|
800
803
|
|
|
801
804
|
/** Every file the tree holds in a language this reads, with its comments and the ones recording history. */
|
|
802
|
-
export function scan(root, { exclude = [] } = {}) {
|
|
803
|
-
const files = trackedFiles(root);
|
|
805
|
+
export function scan(root, { exclude = [], timeout, env, noFsmonitor = false } = {}) {
|
|
806
|
+
const files = trackedFiles(root, timeout, env, noFsmonitor);
|
|
804
807
|
const unused = exclude.filter((prefix) => !files.some((file) => file.startsWith(prefix)));
|
|
805
808
|
if (unused.length) throw new CommentsError(`--exclude ${unused.join(", ")} names no file in the tree: remove it`);
|
|
806
809
|
const read = [];
|
|
@@ -822,7 +825,7 @@ export function scan(root, { exclude = [] } = {}) {
|
|
|
822
825
|
const sum = (items, pick) => items.reduce((total, item) => total + pick(item), 0);
|
|
823
826
|
const figure = (n) => n.toLocaleString("en-US");
|
|
824
827
|
|
|
825
|
-
export const historyCount = (root) => sum(scan(root), (entry) => entry.history.length);
|
|
828
|
+
export const historyCount = (root, options) => sum(scan(root, options), (entry) => entry.history.length);
|
|
826
829
|
|
|
827
830
|
function directoryTable(read) {
|
|
828
831
|
const directories = new Map();
|