snipara-companion 3.2.16 → 3.2.17
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 +6 -0
- package/dist/index.js +160 -0
- package/docs/FULL_REFERENCE.md +6 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -77,6 +77,7 @@ These commands are useful without hosted Snipara:
|
|
|
77
77
|
| `workflow start` / `phase-start` / `phase-commit` / `resume` | Agent continuity that survives compaction |
|
|
78
78
|
| `workflow timeline` / `workflow session` | Append-only local activity log and Session Snapshot V0 |
|
|
79
79
|
| `workflow decisions` / `workflow decide` | Local human decision requests and response receipts |
|
|
80
|
+
| `workflow policy-ledger` | Project Policy decisions for agent review and audit |
|
|
80
81
|
| `run --emit-policy-decisions` | Project Policy review requests in the agent workflow |
|
|
81
82
|
| `workflow producer-triage` | Ask for human review of unreviewed Producer Loop samples |
|
|
82
83
|
| `workflow producer-report` | Local Producer Loop adoption and calibration report |
|
|
@@ -144,6 +145,7 @@ npx -y snipara-companion lead-plan --from-plan ./project-health-lead-plan.json -
|
|
|
144
145
|
npx -y snipara-companion workflow phase-commit audit --summary "mapped auth impact"
|
|
145
146
|
npx -y snipara-companion workflow producer-triage
|
|
146
147
|
npx -y snipara-companion workflow decisions
|
|
148
|
+
npx -y snipara-companion workflow policy-ledger
|
|
147
149
|
npx -y snipara-companion workflow decide decision-abc123 --choose accept_all --reviewer alice
|
|
148
150
|
npx -y snipara-companion workflow timeline
|
|
149
151
|
npx -y snipara-companion workflow timeline --export md
|
|
@@ -193,6 +195,10 @@ opaque refs. Decision requests never resolve by timeout or default, and only
|
|
|
193
195
|
When repeated resolved receipts share the same human choice and rationale,
|
|
194
196
|
`workflow decide` may emit a new review-only policy suggestion decision request;
|
|
195
197
|
it still uses manual apply instructions and never writes policy automatically.
|
|
198
|
+
`workflow policy-ledger` gives the LLM agent a consolidated view of pending,
|
|
199
|
+
approved, refused, modified, and deferred Project Policy decision artifacts,
|
|
200
|
+
plus the exact pending requests it should ask the human about. It is read-only
|
|
201
|
+
and does not apply policy edits.
|
|
196
202
|
Other producers such as `outcome-capture preview --emit-decisions`,
|
|
197
203
|
`memory reviews --emit-decisions`, `workflow decision-producer memory`, and
|
|
198
204
|
`workflow decision-producer context-risk` emit requests with their existing apply
|
package/dist/index.js
CHANGED
|
@@ -18917,6 +18917,163 @@ function compactDecisionRequest(request, status) {
|
|
|
18917
18917
|
expiresAt: request.expiresAt
|
|
18918
18918
|
};
|
|
18919
18919
|
}
|
|
18920
|
+
function isPolicyDecisionRequest(request) {
|
|
18921
|
+
return request.producer.kind === "project_policy_review" || request.producer.kind === "policy_suggestion" || request.evidence.reasonCodes.some((code2) => /policy/i.test(code2)) || /project policy|policy suggestion|policy/i.test(
|
|
18922
|
+
[
|
|
18923
|
+
request.decision,
|
|
18924
|
+
request.question,
|
|
18925
|
+
request.evidence.summary,
|
|
18926
|
+
request.evidence.applyPath ?? ""
|
|
18927
|
+
].join(" ")
|
|
18928
|
+
);
|
|
18929
|
+
}
|
|
18930
|
+
function classifyResolvedPolicyDecisionChoice(choice) {
|
|
18931
|
+
switch (choice) {
|
|
18932
|
+
case "approve_once":
|
|
18933
|
+
case "accept":
|
|
18934
|
+
case "accept_all":
|
|
18935
|
+
case "create_policy_suggestion":
|
|
18936
|
+
case "keep_advisory":
|
|
18937
|
+
return "approved";
|
|
18938
|
+
case "reject":
|
|
18939
|
+
case "reject_all":
|
|
18940
|
+
case "reject_policy_suggestion":
|
|
18941
|
+
case "require_changes":
|
|
18942
|
+
case "respect_block":
|
|
18943
|
+
return "refused";
|
|
18944
|
+
case "mark_policy_stale":
|
|
18945
|
+
case "request_exception":
|
|
18946
|
+
return "modified";
|
|
18947
|
+
case "ignore_once":
|
|
18948
|
+
case "inspect":
|
|
18949
|
+
case "defer":
|
|
18950
|
+
default:
|
|
18951
|
+
return "deferred";
|
|
18952
|
+
}
|
|
18953
|
+
}
|
|
18954
|
+
function buildPolicyLedgerEntries() {
|
|
18955
|
+
const pending = listPendingDecisionRequests().filter((entry) => isPolicyDecisionRequest(entry.request)).map((entry) => {
|
|
18956
|
+
const request = entry.request;
|
|
18957
|
+
return {
|
|
18958
|
+
requestId: request.requestId,
|
|
18959
|
+
fingerprint: request.fingerprint,
|
|
18960
|
+
status: entry.status,
|
|
18961
|
+
producerKind: request.producer.kind,
|
|
18962
|
+
decision: request.decision,
|
|
18963
|
+
question: request.question,
|
|
18964
|
+
recommendation: request.recommendation,
|
|
18965
|
+
evidenceSummary: request.evidence.summary,
|
|
18966
|
+
reasonCodes: request.evidence.reasonCodes,
|
|
18967
|
+
files: request.evidence.files ?? [],
|
|
18968
|
+
applyPath: request.evidence.applyPath,
|
|
18969
|
+
applyCommand: request.evidence.applyCommand,
|
|
18970
|
+
createdAt: request.createdAt
|
|
18971
|
+
};
|
|
18972
|
+
});
|
|
18973
|
+
const resolved = listResolvedDecisionRecords().filter((record) => isPolicyDecisionRequest(record.request)).map((record) => {
|
|
18974
|
+
const request = record.request;
|
|
18975
|
+
return {
|
|
18976
|
+
requestId: request.requestId,
|
|
18977
|
+
fingerprint: request.fingerprint,
|
|
18978
|
+
status: classifyResolvedPolicyDecisionChoice(record.response.choice),
|
|
18979
|
+
producerKind: request.producer.kind,
|
|
18980
|
+
decision: request.decision,
|
|
18981
|
+
question: request.question,
|
|
18982
|
+
recommendation: request.recommendation,
|
|
18983
|
+
humanChoice: record.response.choice,
|
|
18984
|
+
reviewer: record.response.reviewer,
|
|
18985
|
+
note: record.response.note,
|
|
18986
|
+
evidenceSummary: request.evidence.summary,
|
|
18987
|
+
reasonCodes: request.evidence.reasonCodes,
|
|
18988
|
+
files: request.evidence.files ?? [],
|
|
18989
|
+
applyPath: request.evidence.applyPath,
|
|
18990
|
+
applyCommand: request.evidence.applyCommand,
|
|
18991
|
+
createdAt: request.createdAt,
|
|
18992
|
+
resolvedAt: record.response.resolvedAt
|
|
18993
|
+
};
|
|
18994
|
+
});
|
|
18995
|
+
return [...pending, ...resolved].sort((left, right) => {
|
|
18996
|
+
const leftTime = left.resolvedAt ?? left.createdAt;
|
|
18997
|
+
const rightTime = right.resolvedAt ?? right.createdAt;
|
|
18998
|
+
return rightTime.localeCompare(leftTime) || left.requestId.localeCompare(right.requestId);
|
|
18999
|
+
});
|
|
19000
|
+
}
|
|
19001
|
+
function summarizePolicyLedger(entries) {
|
|
19002
|
+
const counts = {
|
|
19003
|
+
pending: 0,
|
|
19004
|
+
expired_pending: 0,
|
|
19005
|
+
approved: 0,
|
|
19006
|
+
refused: 0,
|
|
19007
|
+
modified: 0,
|
|
19008
|
+
deferred: 0
|
|
19009
|
+
};
|
|
19010
|
+
for (const entry of entries) {
|
|
19011
|
+
counts[entry.status] += 1;
|
|
19012
|
+
}
|
|
19013
|
+
return {
|
|
19014
|
+
total: entries.length,
|
|
19015
|
+
pending: counts.pending,
|
|
19016
|
+
expiredPending: counts.expired_pending,
|
|
19017
|
+
approved: counts.approved,
|
|
19018
|
+
refused: counts.refused,
|
|
19019
|
+
modified: counts.modified,
|
|
19020
|
+
deferred: counts.deferred
|
|
19021
|
+
};
|
|
19022
|
+
}
|
|
19023
|
+
function buildPolicyLedgerAgentPrompt(entries) {
|
|
19024
|
+
const active = entries.filter(
|
|
19025
|
+
(entry) => entry.status === "pending" || entry.status === "expired_pending"
|
|
19026
|
+
);
|
|
19027
|
+
if (active.length === 0) {
|
|
19028
|
+
return ["No pending Project Policy decision needs a human response right now."];
|
|
19029
|
+
}
|
|
19030
|
+
return active.slice(0, 5).map((entry) => {
|
|
19031
|
+
const options = entry.recommendation ? ` Recommended: ${entry.recommendation}.` : "";
|
|
19032
|
+
return `Ask the user: ${entry.question} Options are recorded in the pending Decision Request.${options} Resolve with snipara-companion workflow decide ${entry.requestId} --choose <human-choice> --reviewer <name>.`;
|
|
19033
|
+
});
|
|
19034
|
+
}
|
|
19035
|
+
async function workflowPolicyLedgerCommand(options) {
|
|
19036
|
+
const entries = buildPolicyLedgerEntries();
|
|
19037
|
+
const summary = summarizePolicyLedger(entries);
|
|
19038
|
+
const payload = {
|
|
19039
|
+
version: "snipara.workflow_policy_ledger.v0",
|
|
19040
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
19041
|
+
summary,
|
|
19042
|
+
entries,
|
|
19043
|
+
agentPrompt: buildPolicyLedgerAgentPrompt(entries),
|
|
19044
|
+
caveats: [
|
|
19045
|
+
"Policy ledger is observational; it never applies or edits Project Policy automatically.",
|
|
19046
|
+
"The LLM agent must ask the user for pending policy decisions and resolve them with workflow decide.",
|
|
19047
|
+
"The dashboard is for auditability and administration, not a replacement for explicit human approval."
|
|
19048
|
+
]
|
|
19049
|
+
};
|
|
19050
|
+
if (options.json) {
|
|
19051
|
+
printJson2(payload);
|
|
19052
|
+
return;
|
|
19053
|
+
}
|
|
19054
|
+
console.log(import_chalk6.default.bold("Project Policy Ledger"));
|
|
19055
|
+
printKeyValue2("Pending:", String(summary.pending));
|
|
19056
|
+
printKeyValue2("Approved:", String(summary.approved));
|
|
19057
|
+
printKeyValue2("Refused:", String(summary.refused));
|
|
19058
|
+
printKeyValue2("Modified:", String(summary.modified));
|
|
19059
|
+
if (entries.length === 0) {
|
|
19060
|
+
console.log("No Project Policy decision artifacts found.");
|
|
19061
|
+
return;
|
|
19062
|
+
}
|
|
19063
|
+
for (const entry of entries.slice(0, 20)) {
|
|
19064
|
+
const actor = entry.reviewer ? ` by ${entry.reviewer}` : "";
|
|
19065
|
+
console.log(`- ${entry.requestId} [${entry.status}${actor}] ${entry.question}`);
|
|
19066
|
+
if (entry.humanChoice) {
|
|
19067
|
+
console.log(` choice: ${entry.humanChoice}`);
|
|
19068
|
+
}
|
|
19069
|
+
console.log(` evidence: ${entry.evidenceSummary}`);
|
|
19070
|
+
if (entry.status === "pending" || entry.status === "expired_pending") {
|
|
19071
|
+
console.log(
|
|
19072
|
+
` ask: snipara-companion workflow decide ${entry.requestId} --choose <human-choice> --reviewer <name>`
|
|
19073
|
+
);
|
|
19074
|
+
}
|
|
19075
|
+
}
|
|
19076
|
+
}
|
|
18920
19077
|
function printDecisionRequests(entries) {
|
|
18921
19078
|
console.log(import_chalk6.default.bold("Pending Decision Requests"));
|
|
18922
19079
|
if (entries.length === 0) {
|
|
@@ -34149,6 +34306,9 @@ workflow.command("scaffold").description("Generate a reusable managed workflow p
|
|
|
34149
34306
|
workflow.command("decisions").description("List pending local decision requests for the LLM to ask the human").option("--json", "Print raw JSON").action(async (options) => {
|
|
34150
34307
|
await workflowDecisionsCommand({ json: options.json });
|
|
34151
34308
|
});
|
|
34309
|
+
workflow.command("policy-ledger").description("Summarize Project Policy decisions for agent-mediated review and audit").option("--json", "Print raw JSON").action(async (options) => {
|
|
34310
|
+
await workflowPolicyLedgerCommand({ json: options.json });
|
|
34311
|
+
});
|
|
34152
34312
|
workflow.command("decide").description("Resolve a pending local decision request with an explicit human choice").argument("<request-id>", "Decision request id or fingerprint").requiredOption("--choose <option>", "Chosen option from the decision request").requiredOption("--reviewer <name>", "Human reviewer name or handle").option("--note <note>", "Review note").option("--json", "Print raw JSON").action(async (requestId, options) => {
|
|
34153
34313
|
await workflowDecideCommand({
|
|
34154
34314
|
requestId,
|
package/docs/FULL_REFERENCE.md
CHANGED
|
@@ -225,6 +225,7 @@ snipara-companion workflow phase-commit build --summary "tests green"
|
|
|
225
225
|
snipara-companion workflow impact-gate
|
|
226
226
|
snipara-companion workflow producer-triage
|
|
227
227
|
snipara-companion workflow decisions
|
|
228
|
+
snipara-companion workflow policy-ledger
|
|
228
229
|
snipara-companion workflow decide decision-abc123 --choose accept_all --reviewer alice
|
|
229
230
|
snipara-companion workflow producer-report
|
|
230
231
|
snipara-companion workflow producer-review --latest --outcome useful --reviewer alice
|
|
@@ -280,6 +281,10 @@ snipara-companion workflow resume --include-session-context
|
|
|
280
281
|
client can render as a human question, including evidence, options,
|
|
281
282
|
recommendation, declared apply path, and readable evidence items for batched
|
|
282
283
|
decisions.
|
|
284
|
+
- `workflow policy-ledger` summarizes local Project Policy decision artifacts
|
|
285
|
+
for agent-mediated governance. It reports pending, approved, refused,
|
|
286
|
+
modified, deferred, and expired policy decisions, includes agent prompts for
|
|
287
|
+
pending human choices, and never applies or edits policy automatically.
|
|
283
288
|
- `workflow decide <request-id> --choose <option> --reviewer <name>` writes a
|
|
284
289
|
Decision Response receipt under `.snipara/decisions/resolved/`. For
|
|
285
290
|
Producer Loop triage accept/reject choices, it applies the existing
|
|
@@ -1277,6 +1282,7 @@ Semantics:
|
|
|
1277
1282
|
- `snipara-companion workflow phase-commit` = calls hosted `snipara_end_of_task_commit` for that phase, updates local state, and advances the next phase; if the hosted commit times out or hits a transient network failure, local workflow state still advances with an explicit local fallback record
|
|
1278
1283
|
- `snipara-companion workflow phase-commit` and `workflow final-commit` also emit local Producer Loop artifacts under `.snipara/producer-loop/`, backed by the redacted Coding Intelligence Ledger. PR Answer Pack decision capture uses the same schema with producer kind `pr_answer_pack_decision_capture` when the artifact is exported or embedded by the hosted PR pack producer. These artifacts are review evidence only: they do not launch workers, approve durable memory, claim calibrated confidence, or provide server-side attestation.
|
|
1279
1284
|
- `snipara-companion workflow decisions` = lists local pending Decision Request artifacts for LLM clients to ask the human, with evidence, options, recommendation, and apply-path metadata
|
|
1285
|
+
- `snipara-companion workflow policy-ledger` = read-only local Project Policy ledger for pending, approved, refused, modified, deferred, and expired policy decisions, including agent prompts for unresolved human choices
|
|
1280
1286
|
- `snipara-companion workflow decide` = records a Decision Response receipt and moves the request to `.snipara/decisions/resolved/`; it never resolves by timeout/default, only applies existing reviewed paths such as `workflow producer-review`, and may emit review-only policy suggestion requests when repeated receipts show the same human rule
|
|
1281
1287
|
- `snipara-companion workflow producer-triage` = emits a batched decision request for unreviewed Producer Loop samples; it does not mark samples reviewed until `workflow decide` records the human answer
|
|
1282
1288
|
- `snipara-companion workflow producer-report` = scans local Producer Loop artifacts and reports adoption, producer kinds, workflow ids, latest artifact, reason-code counts, invalid artifacts, sample size, reviewed/rejected/unreviewed counts, and calibration caveats with `hardGateReady=false`
|