snipara-companion 3.5.7 → 3.5.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/CHANGELOG.md +14 -0
- package/dist/index.d.ts +10 -1
- package/dist/index.js +194 -32
- package/docs/FULL_REFERENCE.md +11 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
Release notes for `snipara-companion`, newest first.
|
|
4
4
|
|
|
5
|
+
## New In 3.5.9
|
|
6
|
+
|
|
7
|
+
- Routes explicit `workflow phase-commit` and `final-commit` rationale through
|
|
8
|
+
the hosted atomic `why` block instead of issuing a second Why Capture request.
|
|
9
|
+
- Exposes decision, rationale, alternatives, constraints, and observed outcome
|
|
10
|
+
inputs on workflow commits while keeping candidates review-pending.
|
|
11
|
+
- Preserves handoff-only final commits when no structured rationale is supplied.
|
|
12
|
+
|
|
13
|
+
## New In 3.5.8
|
|
14
|
+
|
|
15
|
+
- Preserves the exact collaboration actor identity on hosted lease heartbeat
|
|
16
|
+
and release requests, preventing owner-authenticated cleanup from falling
|
|
17
|
+
back to the API-key actor and returning a false `403`.
|
|
18
|
+
|
|
5
19
|
## New In 3.5.7
|
|
6
20
|
|
|
7
21
|
- Bounds the best-effort hosted judgment lookup in `run` to 8 seconds instead
|
package/dist/index.d.ts
CHANGED
|
@@ -519,6 +519,13 @@ interface WhyCaptureResult {
|
|
|
519
519
|
failed?: Array<Record<string, unknown>>;
|
|
520
520
|
};
|
|
521
521
|
}
|
|
522
|
+
interface EndOfTaskCommitWhyInput {
|
|
523
|
+
decision?: string;
|
|
524
|
+
rationale?: string;
|
|
525
|
+
alternatives?: string[];
|
|
526
|
+
constraints?: string[];
|
|
527
|
+
observedOutcome?: string;
|
|
528
|
+
}
|
|
522
529
|
interface JournalAppendResult {
|
|
523
530
|
success?: boolean;
|
|
524
531
|
date?: string;
|
|
@@ -1471,7 +1478,7 @@ declare class RLMClient {
|
|
|
1471
1478
|
resources?: CollaborationResource[];
|
|
1472
1479
|
metadata?: Record<string, unknown>;
|
|
1473
1480
|
}): Promise<CollaborationLeaseResponse>;
|
|
1474
|
-
updateCollaborationLease(leaseId: string, args: {
|
|
1481
|
+
updateCollaborationLease(leaseId: string, args: CollaborationActorPayload & {
|
|
1475
1482
|
action?: "heartbeat" | "release" | "override";
|
|
1476
1483
|
reason?: string;
|
|
1477
1484
|
}): Promise<CollaborationLeaseUpdateResponse>;
|
|
@@ -1516,6 +1523,8 @@ declare class RLMClient {
|
|
|
1516
1523
|
getSessionMemories(maxCriticalTokens?: number, maxDailyTokens?: number, includeYesterday?: boolean): Promise<SessionMemoriesResult>;
|
|
1517
1524
|
endOfTaskCommit(args: {
|
|
1518
1525
|
summary: string;
|
|
1526
|
+
task?: string;
|
|
1527
|
+
why?: EndOfTaskCommitWhyInput;
|
|
1519
1528
|
category?: string;
|
|
1520
1529
|
outcome?: "completed" | "partial" | "blocked" | "abandoned";
|
|
1521
1530
|
filesTouched?: string[];
|
package/dist/index.js
CHANGED
|
@@ -1724,6 +1724,16 @@ var RLMClient = class {
|
|
|
1724
1724
|
async endOfTaskCommit(args) {
|
|
1725
1725
|
return this.mcpCall("snipara_end_of_task_commit", {
|
|
1726
1726
|
summary: args.summary,
|
|
1727
|
+
...args.task ? { task: args.task } : {},
|
|
1728
|
+
...args.why ? {
|
|
1729
|
+
why: {
|
|
1730
|
+
...args.why.decision ? { decision: args.why.decision } : {},
|
|
1731
|
+
...args.why.rationale ? { rationale: args.why.rationale } : {},
|
|
1732
|
+
...args.why.alternatives ? { alternatives: args.why.alternatives } : {},
|
|
1733
|
+
...args.why.constraints ? { constraints: args.why.constraints } : {},
|
|
1734
|
+
...args.why.observedOutcome ? { observed_outcome: args.why.observedOutcome } : {}
|
|
1735
|
+
}
|
|
1736
|
+
} : {},
|
|
1727
1737
|
category: args.category,
|
|
1728
1738
|
outcome: args.outcome || "completed",
|
|
1729
1739
|
files_touched: args.filesTouched || [],
|
|
@@ -12285,6 +12295,79 @@ function uniqueStrings12(values) {
|
|
|
12285
12295
|
return [...new Set(values.map((value) => value.trim()).filter(Boolean))];
|
|
12286
12296
|
}
|
|
12287
12297
|
|
|
12298
|
+
// ../project-intelligence-contracts/src/why-capture-confidence-v1.json
|
|
12299
|
+
var why_capture_confidence_v1_default = {
|
|
12300
|
+
version: "why-capture-confidence-v1",
|
|
12301
|
+
base: 0.72,
|
|
12302
|
+
decisionRationaleBonus: 0.1,
|
|
12303
|
+
nonManualSourceBonus: 0.04,
|
|
12304
|
+
maximum: 0.9,
|
|
12305
|
+
decimalPlaces: 2,
|
|
12306
|
+
validatedExecutionOutcomes: ["completed"],
|
|
12307
|
+
vectors: [
|
|
12308
|
+
{
|
|
12309
|
+
candidateType: "CONTEXT",
|
|
12310
|
+
hasDecision: false,
|
|
12311
|
+
hasRationale: false,
|
|
12312
|
+
sourceKind: "manual",
|
|
12313
|
+
executionOutcome: "completed",
|
|
12314
|
+
expected: 0.72
|
|
12315
|
+
},
|
|
12316
|
+
{
|
|
12317
|
+
candidateType: "DECISION",
|
|
12318
|
+
hasDecision: true,
|
|
12319
|
+
hasRationale: true,
|
|
12320
|
+
sourceKind: "manual",
|
|
12321
|
+
executionOutcome: "completed",
|
|
12322
|
+
expected: 0.82
|
|
12323
|
+
},
|
|
12324
|
+
{
|
|
12325
|
+
candidateType: "DECISION",
|
|
12326
|
+
hasDecision: true,
|
|
12327
|
+
hasRationale: true,
|
|
12328
|
+
sourceKind: "phase_commit",
|
|
12329
|
+
executionOutcome: "completed",
|
|
12330
|
+
expected: 0.86
|
|
12331
|
+
},
|
|
12332
|
+
{
|
|
12333
|
+
candidateType: "DECISION",
|
|
12334
|
+
hasDecision: true,
|
|
12335
|
+
hasRationale: true,
|
|
12336
|
+
sourceKind: "phase_commit",
|
|
12337
|
+
executionOutcome: "partial",
|
|
12338
|
+
expected: 0.76
|
|
12339
|
+
},
|
|
12340
|
+
{
|
|
12341
|
+
candidateType: "DECISION",
|
|
12342
|
+
hasDecision: true,
|
|
12343
|
+
hasRationale: true,
|
|
12344
|
+
sourceKind: "phase_commit",
|
|
12345
|
+
executionOutcome: "blocked",
|
|
12346
|
+
expected: 0.76
|
|
12347
|
+
},
|
|
12348
|
+
{
|
|
12349
|
+
candidateType: "DECISION",
|
|
12350
|
+
hasDecision: true,
|
|
12351
|
+
hasRationale: true,
|
|
12352
|
+
sourceKind: "phase_commit",
|
|
12353
|
+
executionOutcome: "abandoned",
|
|
12354
|
+
expected: 0.76
|
|
12355
|
+
},
|
|
12356
|
+
{
|
|
12357
|
+
candidateType: "DECISION",
|
|
12358
|
+
hasDecision: true,
|
|
12359
|
+
hasRationale: false,
|
|
12360
|
+
sourceKind: "final_commit",
|
|
12361
|
+
executionOutcome: "completed",
|
|
12362
|
+
expected: 0.76
|
|
12363
|
+
}
|
|
12364
|
+
]
|
|
12365
|
+
};
|
|
12366
|
+
|
|
12367
|
+
// ../project-intelligence-contracts/src/why-capture-confidence.ts
|
|
12368
|
+
var WHY_CAPTURE_CONFIDENCE_VERSION = why_capture_confidence_v1_default.version;
|
|
12369
|
+
var WHY_CAPTURE_CONFIDENCE_TEST_VECTORS = why_capture_confidence_v1_default.vectors;
|
|
12370
|
+
|
|
12288
12371
|
// src/commands/decision-requests.ts
|
|
12289
12372
|
var fs12 = __toESM(require("fs"));
|
|
12290
12373
|
var path11 = __toESM(require("path"));
|
|
@@ -16659,7 +16742,12 @@ async function heartbeatHostedLeases(context, leaseIds) {
|
|
|
16659
16742
|
}
|
|
16660
16743
|
try {
|
|
16661
16744
|
const data = await Promise.all(
|
|
16662
|
-
leaseIds.map(
|
|
16745
|
+
leaseIds.map(
|
|
16746
|
+
(leaseId) => client.updateCollaborationLease(leaseId, {
|
|
16747
|
+
...context.actor,
|
|
16748
|
+
action: "heartbeat"
|
|
16749
|
+
})
|
|
16750
|
+
)
|
|
16663
16751
|
);
|
|
16664
16752
|
return { status: "ok", data };
|
|
16665
16753
|
} catch (error) {
|
|
@@ -16675,6 +16763,7 @@ async function releaseHostedLeases(context, leaseIds, input) {
|
|
|
16675
16763
|
const data = await Promise.all(
|
|
16676
16764
|
leaseIds.map(
|
|
16677
16765
|
(leaseId) => client.updateCollaborationLease(leaseId, {
|
|
16766
|
+
...context.actor,
|
|
16678
16767
|
action: "release",
|
|
16679
16768
|
reason: input.reason
|
|
16680
16769
|
})
|
|
@@ -17822,16 +17911,16 @@ function previewCandidateReceipt(value) {
|
|
|
17822
17911
|
if (!isRecord9(value)) {
|
|
17823
17912
|
return void 0;
|
|
17824
17913
|
}
|
|
17825
|
-
const whyFields = isRecord9(value.whyFields) ? value.whyFields : void 0;
|
|
17914
|
+
const whyFields = isRecord9(value.whyFields) ? value.whyFields : isRecord9(value.why_fields) ? value.why_fields : void 0;
|
|
17826
17915
|
const decision = boundedText(whyFields?.decision);
|
|
17827
|
-
const rationale = boundedText(whyFields?.why);
|
|
17828
|
-
const text = boundedText(value.content) ?? decision;
|
|
17916
|
+
const rationale = boundedText(whyFields?.why ?? whyFields?.rationale);
|
|
17917
|
+
const text = boundedText(value.content ?? value.text) ?? decision;
|
|
17829
17918
|
if (!text) {
|
|
17830
17919
|
return void 0;
|
|
17831
17920
|
}
|
|
17832
17921
|
return {
|
|
17833
17922
|
text,
|
|
17834
|
-
...boundedText(value.type, 80) ? { type: boundedText(value.type, 80) } : {},
|
|
17923
|
+
...boundedText(value.type ?? value.memory_type, 80) ? { type: boundedText(value.type ?? value.memory_type, 80) } : {},
|
|
17835
17924
|
...boundedText(value.category, 120) ? { category: boundedText(value.category, 120) } : {},
|
|
17836
17925
|
...decision ? { decision } : {},
|
|
17837
17926
|
...rationale ? { rationale } : {}
|
|
@@ -17842,23 +17931,25 @@ function pendingMemoryReceipt(value) {
|
|
|
17842
17931
|
return void 0;
|
|
17843
17932
|
}
|
|
17844
17933
|
const memoryId = boundedText(value.memory_id ?? value.memoryId ?? value.id, 200);
|
|
17845
|
-
const text = boundedText(value.content) ?? (memoryId ? `Memory ${memoryId}` : void 0);
|
|
17934
|
+
const text = boundedText(value.content ?? value.text) ?? (memoryId ? `Memory ${memoryId}` : void 0);
|
|
17846
17935
|
if (!text) {
|
|
17847
17936
|
return void 0;
|
|
17848
17937
|
}
|
|
17849
17938
|
return {
|
|
17850
17939
|
...memoryId ? { memoryId } : {},
|
|
17851
17940
|
text,
|
|
17852
|
-
...boundedText(value.type, 80) ? { type: boundedText(value.type, 80) } : {},
|
|
17853
|
-
|
|
17854
|
-
reviewStatus: boundedText(value.review_status ?? value.reviewStatus, 80) ?? "
|
|
17941
|
+
...boundedText(value.type ?? value.memory_type, 80) ? { type: boundedText(value.type ?? value.memory_type, 80) } : {},
|
|
17942
|
+
category: boundedText(value.category, 120) ?? "why-capture",
|
|
17943
|
+
reviewStatus: boundedText(value.review_status ?? value.reviewStatus, 80) ?? "PENDING"
|
|
17855
17944
|
};
|
|
17856
17945
|
}
|
|
17857
17946
|
function issueReceipt(value, fallbackReason) {
|
|
17858
17947
|
if (!isRecord9(value)) {
|
|
17859
17948
|
return void 0;
|
|
17860
17949
|
}
|
|
17861
|
-
const text = boundedText(
|
|
17950
|
+
const text = boundedText(
|
|
17951
|
+
value.content ?? value.decision ?? value.title ?? value.error ?? value.reason ?? value.decision_id ?? value.id
|
|
17952
|
+
) ?? "Why Capture item";
|
|
17862
17953
|
const reason = boundedText(value.reason ?? value.error, 160) ?? fallbackReason;
|
|
17863
17954
|
return { text, ...reason ? { reason } : {} };
|
|
17864
17955
|
}
|
|
@@ -17896,6 +17987,47 @@ function readLatestWorkflowCommands(cwd) {
|
|
|
17896
17987
|
}
|
|
17897
17988
|
return [];
|
|
17898
17989
|
}
|
|
17990
|
+
function recordItems(value) {
|
|
17991
|
+
return Array.isArray(value) ? value.filter(isRecord9) : [];
|
|
17992
|
+
}
|
|
17993
|
+
function taskCommitWhyCaptureReceipt(result, sourceKind, cwd = process.cwd()) {
|
|
17994
|
+
const commitSha = readCommitSha(cwd);
|
|
17995
|
+
const candidates = recordItems(result.candidates).filter(
|
|
17996
|
+
(candidate) => isRecord9(candidate.why_fields) || isRecord9(candidate.whyFields)
|
|
17997
|
+
);
|
|
17998
|
+
const storedCandidates = recordItems(result.stored_candidates).filter(
|
|
17999
|
+
(candidate) => isRecord9(candidate.why_fields) || isRecord9(candidate.whyFields)
|
|
18000
|
+
);
|
|
18001
|
+
const decisionCapture = isRecord9(result.decision_capture) ? result.decision_capture : {};
|
|
18002
|
+
const duplicates = recordItems(decisionCapture.duplicates).map((item) => issueReceipt(item, "duplicate")).filter((item) => Boolean(item));
|
|
18003
|
+
const failed = recordItems(decisionCapture.failed).map((item) => issueReceipt(item, "capture_failed")).filter((item) => Boolean(item));
|
|
18004
|
+
const caveats = Array.isArray(result.caveats) ? result.caveats.filter((item) => typeof item === "string") : [];
|
|
18005
|
+
const hostedPhaseCommit = isRecord9(result.hosted_phase_commit) ? result.hosted_phase_commit : void 0;
|
|
18006
|
+
const hostedFinalCommit = isRecord9(result.hosted_final_commit) ? result.hosted_final_commit : void 0;
|
|
18007
|
+
const hostedError = boundedText(hostedPhaseCommit?.error ?? hostedFinalCommit?.error);
|
|
18008
|
+
const previewCandidates = candidates.map(previewCandidateReceipt).filter((item) => Boolean(item));
|
|
18009
|
+
const pendingMemories = storedCandidates.map(pendingMemoryReceipt).filter((item) => Boolean(item));
|
|
18010
|
+
const baseReceipt = {
|
|
18011
|
+
sourceKind,
|
|
18012
|
+
previewCandidateCount: previewCandidates.length,
|
|
18013
|
+
capturedCount: pendingMemories.length,
|
|
18014
|
+
previewCandidates,
|
|
18015
|
+
pendingMemories,
|
|
18016
|
+
duplicates,
|
|
18017
|
+
failed,
|
|
18018
|
+
...commitSha ? { commitSha } : {}
|
|
18019
|
+
};
|
|
18020
|
+
if (hostedError) {
|
|
18021
|
+
return { ...baseReceipt, status: "error", error: hostedError };
|
|
18022
|
+
}
|
|
18023
|
+
if (caveats.includes("why_requires_human_owner")) {
|
|
18024
|
+
return { ...baseReceipt, status: "skipped", error: "why_requires_human_owner" };
|
|
18025
|
+
}
|
|
18026
|
+
if (candidates.length === 0) {
|
|
18027
|
+
return { ...baseReceipt, status: "no_candidates" };
|
|
18028
|
+
}
|
|
18029
|
+
return { ...baseReceipt, status: "captured" };
|
|
18030
|
+
}
|
|
17899
18031
|
async function captureCompanionWhy(input) {
|
|
17900
18032
|
const cwd = input.cwd ?? process.cwd();
|
|
17901
18033
|
const commitSha = readCommitSha(cwd);
|
|
@@ -20660,7 +20792,7 @@ function recordList(value) {
|
|
|
20660
20792
|
return Array.isArray(value) ? value.filter(isRecord11) : [];
|
|
20661
20793
|
}
|
|
20662
20794
|
function buildWorkflowPhaseCommitReceipt(input) {
|
|
20663
|
-
const stored = recordList(input.result.stored_candidates).map((item) => normalizedMemoryItem(item, "phase_commit", input.phaseId)).filter((item) => Boolean(item));
|
|
20795
|
+
const stored = recordList(input.result.stored_candidates).filter((item) => !isRecord11(item.why_fields) && !isRecord11(item.whyFields)).map((item) => normalizedMemoryItem(item, "phase_commit", input.phaseId)).filter((item) => Boolean(item));
|
|
20664
20796
|
const skipped = recordList(input.result.skipped_candidates).map((item) => normalizedMemoryItem(item, "phase_commit", input.phaseId)).filter((item) => Boolean(item));
|
|
20665
20797
|
const hostedPhaseCommit = isRecord11(input.result.hosted_phase_commit) ? input.result.hosted_phase_commit : void 0;
|
|
20666
20798
|
return {
|
|
@@ -32147,6 +32279,8 @@ async function commitTaskMemory(options) {
|
|
|
32147
32279
|
const client = createClient(TASK_COMMIT_TIMEOUT_MS);
|
|
32148
32280
|
return client.endOfTaskCommit({
|
|
32149
32281
|
summary: options.summary,
|
|
32282
|
+
task: options.task,
|
|
32283
|
+
why: options.why,
|
|
32150
32284
|
category: options.category,
|
|
32151
32285
|
outcome: options.outcome,
|
|
32152
32286
|
filesTouched: options.files
|
|
@@ -32219,9 +32353,11 @@ async function commitFinalTaskMemory(options) {
|
|
|
32219
32353
|
});
|
|
32220
32354
|
const callHosted = async (summary, timeoutMs) => {
|
|
32221
32355
|
const client = createClient(timeoutMs);
|
|
32222
|
-
const handoffOnly = isFinalCommitCategory(category);
|
|
32356
|
+
const handoffOnly = isFinalCommitCategory(category) && !options.why;
|
|
32223
32357
|
return client.endOfTaskCommit({
|
|
32224
32358
|
summary,
|
|
32359
|
+
task: options.task,
|
|
32360
|
+
why: options.why,
|
|
32225
32361
|
category,
|
|
32226
32362
|
outcome: options.outcome,
|
|
32227
32363
|
filesTouched: options.files,
|
|
@@ -32275,6 +32411,28 @@ async function commitFinalTaskMemory(options) {
|
|
|
32275
32411
|
message: "Hosted final-commit failed; local fallback handoff created"
|
|
32276
32412
|
};
|
|
32277
32413
|
}
|
|
32414
|
+
function structuredTaskCommitWhy(options) {
|
|
32415
|
+
const rationale = compactWhitespace2(options.why ?? "");
|
|
32416
|
+
const explicitDecision = compactWhitespace2(options.decision ?? "");
|
|
32417
|
+
const alternatives = [
|
|
32418
|
+
...new Set((options.alternatives ?? []).map(compactWhitespace2).filter(Boolean))
|
|
32419
|
+
];
|
|
32420
|
+
const constraints = [
|
|
32421
|
+
...new Set((options.constraints ?? []).map(compactWhitespace2).filter(Boolean))
|
|
32422
|
+
];
|
|
32423
|
+
const observedOutcome = compactWhitespace2(options.observedOutcome ?? "");
|
|
32424
|
+
const decision = explicitDecision || (rationale ? compactWhitespace2(options.summary) : "");
|
|
32425
|
+
if (!decision && !rationale && alternatives.length === 0 && constraints.length === 0 && !observedOutcome) {
|
|
32426
|
+
return void 0;
|
|
32427
|
+
}
|
|
32428
|
+
return {
|
|
32429
|
+
...decision ? { decision } : {},
|
|
32430
|
+
...rationale ? { rationale } : {},
|
|
32431
|
+
...alternatives.length > 0 ? { alternatives } : {},
|
|
32432
|
+
...constraints.length > 0 ? { constraints } : {},
|
|
32433
|
+
...observedOutcome ? { observedOutcome } : {}
|
|
32434
|
+
};
|
|
32435
|
+
}
|
|
32278
32436
|
function printJournalWarning(result) {
|
|
32279
32437
|
if (result?.status === "error" && result.error) {
|
|
32280
32438
|
console.log(`Journal checkpoint: ${result.error}`);
|
|
@@ -32320,8 +32478,11 @@ async function workflowPhaseCommitCommand(options) {
|
|
|
32320
32478
|
phase,
|
|
32321
32479
|
summary: options.summary
|
|
32322
32480
|
});
|
|
32481
|
+
const structuredWhy = structuredTaskCommitWhy(options);
|
|
32323
32482
|
const result = await commitPhaseTaskMemory({
|
|
32324
32483
|
summary: durableSummary,
|
|
32484
|
+
task: `${state.goal} / ${phase.title}`,
|
|
32485
|
+
why: structuredWhy,
|
|
32325
32486
|
category,
|
|
32326
32487
|
outcome,
|
|
32327
32488
|
files
|
|
@@ -32396,14 +32557,7 @@ async function workflowPhaseCommitCommand(options) {
|
|
|
32396
32557
|
journalAttempted: true,
|
|
32397
32558
|
teamSyncCompletionAttempted: shouldCompleteTeamSyncWork
|
|
32398
32559
|
});
|
|
32399
|
-
const whyCapture =
|
|
32400
|
-
sourceKind: "phase_commit",
|
|
32401
|
-
sourceSessionId: state.workflowId,
|
|
32402
|
-
task: `${state.goal} / ${phase.title}`,
|
|
32403
|
-
summary: options.summary,
|
|
32404
|
-
files,
|
|
32405
|
-
commands: readLatestWorkflowCommands(process.cwd())
|
|
32406
|
-
});
|
|
32560
|
+
const whyCapture = taskCommitWhyCaptureReceipt(result, "phase_commit");
|
|
32407
32561
|
phaseCommitReceipt.whyCapture = whyCapture;
|
|
32408
32562
|
writeWorkflowState(state);
|
|
32409
32563
|
const coordinationRelease = await releaseWorkflowCoordination(
|
|
@@ -32501,8 +32655,11 @@ async function finalCommitCommand(options) {
|
|
|
32501
32655
|
});
|
|
32502
32656
|
const outcome = options.outcome ?? "completed";
|
|
32503
32657
|
const category = normalizeFinalCommitCategory(options.category);
|
|
32658
|
+
const structuredWhy = structuredTaskCommitWhy(options);
|
|
32504
32659
|
const result = await commitFinalTaskMemory({
|
|
32505
32660
|
workflowId: state?.workflowId,
|
|
32661
|
+
task: state?.goal,
|
|
32662
|
+
why: structuredWhy,
|
|
32506
32663
|
summary: options.summary,
|
|
32507
32664
|
category,
|
|
32508
32665
|
outcome,
|
|
@@ -32554,15 +32711,7 @@ async function finalCommitCommand(options) {
|
|
|
32554
32711
|
journalAttempted: true,
|
|
32555
32712
|
teamSyncCompletionAttempted: outcome === "completed"
|
|
32556
32713
|
});
|
|
32557
|
-
const whyCapture =
|
|
32558
|
-
sourceKind: "final_commit",
|
|
32559
|
-
sourceSessionId: state?.workflowId ?? loadConfig().sessionId,
|
|
32560
|
-
task: state?.goal,
|
|
32561
|
-
summary: options.summary,
|
|
32562
|
-
why: options.why,
|
|
32563
|
-
files: options.files,
|
|
32564
|
-
commands: readLatestWorkflowCommands(process.cwd())
|
|
32565
|
-
});
|
|
32714
|
+
const whyCapture = taskCommitWhyCaptureReceipt(result, "final_commit");
|
|
32566
32715
|
const coordinationRelease = state ? await releaseWorkflowCoordination(state, `Workflow ${state.workflowId} final-commit.`) : void 0;
|
|
32567
32716
|
const report = buildFinalCommitReport({
|
|
32568
32717
|
state,
|
|
@@ -39955,7 +40104,7 @@ workflow.command("runtime-checkpoint").description(
|
|
|
39955
40104
|
});
|
|
39956
40105
|
workflow.command("phase-commit").description(
|
|
39957
40106
|
"Persist a phase outcome through snipara_end_of_task_commit and advance the workflow"
|
|
39958
|
-
).argument("<phaseId>", "Workflow phase id").requiredOption("-s, --summary <summary>", "Phase outcome summary").option("-c, --category <category>", "Memory category", "workflow-phase").option("-o, --outcome <outcome>", "completed|partial|blocked|abandoned", "completed").option("-f, --files <files...>", "Files touched").option(
|
|
40107
|
+
).argument("<phaseId>", "Workflow phase id").requiredOption("-s, --summary <summary>", "Phase outcome summary").option("--decision <decision>", "Decision text; defaults to summary when --why is set").option("--why <why>", "Decision rationale; never inferred when absent").option("--alternative <alternative>", "Rejected alternative; repeatable", collectOption, []).option("--constraint <constraint>", "Decision constraint; repeatable", collectOption, []).option("--observed-outcome <outcome>", "Observed result, distinct from execution status").option("-c, --category <category>", "Memory category", "workflow-phase").option("-o, --outcome <outcome>", "completed|partial|blocked|abandoned", "completed").option("-f, --files <files...>", "Files touched").option(
|
|
39959
40108
|
"--evidence <evidence>",
|
|
39960
40109
|
"Phase evidence as passed|failed|not-run|unknown:text; repeatable",
|
|
39961
40110
|
collectOption,
|
|
@@ -39964,6 +40113,11 @@ workflow.command("phase-commit").description(
|
|
|
39964
40113
|
await workflowPhaseCommitCommand({
|
|
39965
40114
|
phaseId,
|
|
39966
40115
|
summary: options.summary,
|
|
40116
|
+
decision: options.decision,
|
|
40117
|
+
why: options.why,
|
|
40118
|
+
alternatives: options.alternative,
|
|
40119
|
+
constraints: options.constraint,
|
|
40120
|
+
observedOutcome: options.observedOutcome,
|
|
39967
40121
|
category: options.category,
|
|
39968
40122
|
outcome: options.outcome,
|
|
39969
40123
|
files: options.files,
|
|
@@ -39971,7 +40125,7 @@ workflow.command("phase-commit").description(
|
|
|
39971
40125
|
json: options.json
|
|
39972
40126
|
});
|
|
39973
40127
|
});
|
|
39974
|
-
workflow.command("final-commit").description("Persist the final workflow outcome and close the local workflow state").requiredOption("-s, --summary <summary>", "Final outcome summary").option("--why <why>", "Decision rationale; never inferred when absent").option("-c, --category <category>", "Memory category", "final-commit").option("-o, --outcome <outcome>", "completed|partial|blocked|abandoned", "completed").option("-f, --files <files...>", "Files touched").option(
|
|
40128
|
+
workflow.command("final-commit").description("Persist the final workflow outcome and close the local workflow state").requiredOption("-s, --summary <summary>", "Final outcome summary").option("--decision <decision>", "Decision text; defaults to summary when --why is set").option("--why <why>", "Decision rationale; never inferred when absent").option("--alternative <alternative>", "Rejected alternative; repeatable", collectOption, []).option("--constraint <constraint>", "Decision constraint; repeatable", collectOption, []).option("--observed-outcome <outcome>", "Observed result, distinct from execution status").option("-c, --category <category>", "Memory category", "final-commit").option("-o, --outcome <outcome>", "completed|partial|blocked|abandoned", "completed").option("-f, --files <files...>", "Files touched").option(
|
|
39975
40129
|
"--evidence <evidence>",
|
|
39976
40130
|
"Verification evidence as passed|failed|not-run|unknown:text; repeatable",
|
|
39977
40131
|
collectOption,
|
|
@@ -39979,7 +40133,11 @@ workflow.command("final-commit").description("Persist the final workflow outcome
|
|
|
39979
40133
|
).option("--risk <risk>", "Known residual risk; repeatable", collectOption, []).option("--next-step <nextStep>", "Recommended next action").option("--json", "Print raw JSON").action(async (options) => {
|
|
39980
40134
|
await finalCommitCommand({
|
|
39981
40135
|
summary: options.summary,
|
|
40136
|
+
decision: options.decision,
|
|
39982
40137
|
why: options.why,
|
|
40138
|
+
alternatives: options.alternative,
|
|
40139
|
+
constraints: options.constraint,
|
|
40140
|
+
observedOutcome: options.observedOutcome,
|
|
39983
40141
|
category: options.category,
|
|
39984
40142
|
outcome: options.outcome,
|
|
39985
40143
|
files: options.files,
|
|
@@ -41004,7 +41162,7 @@ program.command("task-commit").description("Persist durable outcomes after meani
|
|
|
41004
41162
|
json: options.json
|
|
41005
41163
|
});
|
|
41006
41164
|
});
|
|
41007
|
-
program.command("final-commit").description("Persist the final managed workflow outcome through snipara_end_of_task_commit").requiredOption("-s, --summary <summary>", "Final outcome summary").option("--why <why>", "Decision rationale; never inferred when absent").option("-c, --category <category>", "Category", "final-commit").option("-o, --outcome <outcome>", "Outcome", "completed").option("-f, --files <files...>", "Files touched").option(
|
|
41165
|
+
program.command("final-commit").description("Persist the final managed workflow outcome through snipara_end_of_task_commit").requiredOption("-s, --summary <summary>", "Final outcome summary").option("--decision <decision>", "Decision text; defaults to summary when --why is set").option("--why <why>", "Decision rationale; never inferred when absent").option("--alternative <alternative>", "Rejected alternative; repeatable", collectOption, []).option("--constraint <constraint>", "Decision constraint; repeatable", collectOption, []).option("--observed-outcome <outcome>", "Observed result, distinct from execution status").option("-c, --category <category>", "Category", "final-commit").option("-o, --outcome <outcome>", "Outcome", "completed").option("-f, --files <files...>", "Files touched").option(
|
|
41008
41166
|
"--evidence <evidence>",
|
|
41009
41167
|
"Verification evidence as passed|failed|not-run|unknown:text; repeatable",
|
|
41010
41168
|
collectOption,
|
|
@@ -41012,7 +41170,11 @@ program.command("final-commit").description("Persist the final managed workflow
|
|
|
41012
41170
|
).option("--risk <risk>", "Known residual risk; repeatable", collectOption, []).option("--next-step <nextStep>", "Recommended next action").option("--json", "Print raw JSON").action(async (options) => {
|
|
41013
41171
|
await finalCommitCommand({
|
|
41014
41172
|
summary: options.summary,
|
|
41173
|
+
decision: options.decision,
|
|
41015
41174
|
why: options.why,
|
|
41175
|
+
alternatives: options.alternative,
|
|
41176
|
+
constraints: options.constraint,
|
|
41177
|
+
observedOutcome: options.observedOutcome,
|
|
41016
41178
|
category: options.category,
|
|
41017
41179
|
outcome: options.outcome,
|
|
41018
41180
|
files: options.files,
|
package/docs/FULL_REFERENCE.md
CHANGED
|
@@ -1632,10 +1632,17 @@ Companion separates two concepts:
|
|
|
1632
1632
|
`workflow phase-commit` and `final-commit` keep local workflow state moving on transient
|
|
1633
1633
|
hosted commit timeouts and surface that local fallback explicitly in the result.
|
|
1634
1634
|
|
|
1635
|
-
`final-commit`
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1635
|
+
`final-commit` remains handoff-only when no structured rationale is supplied.
|
|
1636
|
+
When `--why` or another structured Why Capture field is present, Companion sends
|
|
1637
|
+
one atomic `why` block with the handoff commit; it does not issue a second capture
|
|
1638
|
+
request. `--decision` overrides the decision text, while `--why` uses the commit
|
|
1639
|
+
summary as the decision fallback. Repeat `--alternative` and `--constraint` as
|
|
1640
|
+
needed, and use `--observed-outcome` only for an observed result rather than the
|
|
1641
|
+
execution status. `workflow phase-commit` exposes the same fields. The resulting
|
|
1642
|
+
candidate remains pending review. The seven-section final report reads durable
|
|
1643
|
+
phase receipts already stored, marks Why Capture candidates as pending review,
|
|
1644
|
+
lists skipped/duplicate/failed items as not persisted, and never treats the final
|
|
1645
|
+
summary or handoff as newly approved durable memory.
|
|
1639
1646
|
|
|
1640
1647
|
Do not call `snipara_end_of_task_commit` mechanically for every Git commit. For risky commits,
|
|
1641
1648
|
package releases, or retries after failures, run Memory Guard first so the agent sees relevant
|