snipara-companion 3.7.2 → 3.7.4
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 +1 -0
- package/dist/index.js +41 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,8 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
Release notes for `snipara-companion`, newest first.
|
|
4
4
|
|
|
5
|
+
## 3.7.4
|
|
6
|
+
|
|
7
|
+
- Fix hosted workflow session creation by separating logical workflow identity from the server-issued session ID. Reuse persisted IDs for claims and release, scope mappings by project, actor and worktree, and skip hosted claims when session creation fails.
|
|
8
|
+
- Cover session creation, repeated starts, distinct workflows/actors, refusal and lease release.
|
|
9
|
+
|
|
5
10
|
## Unreleased
|
|
6
11
|
|
|
12
|
+
## New In 3.7.3
|
|
13
|
+
|
|
14
|
+
- Restores source-bound Controller return projection for exact runtime context:
|
|
15
|
+
re-reads the bound context map, checks its hash and version, and reconstructs
|
|
16
|
+
the complete bridge identity. Verifies the Controller task context while
|
|
17
|
+
accepting Python's null representation of an omitted optional target attempt.
|
|
18
|
+
Regression qualification covers the corrected 3.7.2 candidate and the 3.7.3
|
|
19
|
+
release artifact; public round-trip tests assert the selected CLI version.
|
|
20
|
+
|
|
7
21
|
## New In 3.7.2
|
|
8
22
|
|
|
9
23
|
- Bundles the ESM-only runtime dependency graphs for the CommonJS Node 18
|
package/dist/index.d.ts
CHANGED
|
@@ -3985,6 +3985,7 @@ interface CollaborationReviewOnlyAcknowledgement {
|
|
|
3985
3985
|
expiresAt: string;
|
|
3986
3986
|
}
|
|
3987
3987
|
interface CollaborationLocalState {
|
|
3988
|
+
workflowSessions?: Record<string, string>;
|
|
3988
3989
|
schemaVersion: "snipara.collaboration.v1";
|
|
3989
3990
|
updatedAt: string;
|
|
3990
3991
|
workSessionId?: string;
|
package/dist/index.js
CHANGED
|
@@ -21495,6 +21495,9 @@ function loadCollaborationState(rootDir = process.cwd()) {
|
|
|
21495
21495
|
schemaVersion: "snipara.collaboration.v1",
|
|
21496
21496
|
updatedAt: typeof parsed.updatedAt === "string" ? parsed.updatedAt : (/* @__PURE__ */ new Date()).toISOString(),
|
|
21497
21497
|
workSessionId: normalizeOptionalString3(parsed.workSessionId),
|
|
21498
|
+
workflowSessions: Object.fromEntries(Object.entries(parsed.workflowSessions ?? {}).filter(
|
|
21499
|
+
([key, value]) => /^[a-f0-9]{64}$/.test(key) && typeof value === "string" && value.length > 0
|
|
21500
|
+
)),
|
|
21498
21501
|
sessionId: normalizeOptionalString3(parsed.sessionId),
|
|
21499
21502
|
actorId: normalizeOptionalString3(parsed.actorId),
|
|
21500
21503
|
actorType: normalizeActorType(parsed.actorType),
|
|
@@ -21723,26 +21726,32 @@ async function collaborationClaimCommand(options) {
|
|
|
21723
21726
|
}
|
|
21724
21727
|
async function workflowCollaborationStart(options) {
|
|
21725
21728
|
const rootDir = path25.resolve(options.rootDir ?? process.cwd());
|
|
21726
|
-
const
|
|
21729
|
+
const logicalSessionId = workflowWorkSessionId(options.workflowId);
|
|
21727
21730
|
const context = resolveCollaborationContext({
|
|
21728
21731
|
dir: rootDir,
|
|
21729
|
-
workSessionId,
|
|
21730
21732
|
client: "snipara-companion:workflow"
|
|
21731
21733
|
});
|
|
21732
21734
|
const state = loadCollaborationState(rootDir);
|
|
21735
|
+
const sessionKey = workflowSessionKey(context, options.workflowId);
|
|
21736
|
+
const persistedSessionId = state.workflowSessions?.[sessionKey];
|
|
21737
|
+
context.actor.sessionId = `${logicalSessionId}:${sessionKey}`;
|
|
21733
21738
|
const files = normalizeCollaborationFiles(options.files);
|
|
21734
21739
|
const resources = deriveLocalCollaborationResourcesFromFiles(files, rootDir);
|
|
21735
21740
|
const hostedSession = await maybeStartHostedSession(context, {
|
|
21736
|
-
workSessionId,
|
|
21741
|
+
workSessionId: persistedSessionId,
|
|
21737
21742
|
task: options.goal,
|
|
21738
21743
|
files,
|
|
21739
21744
|
resources
|
|
21740
21745
|
});
|
|
21741
21746
|
const session = hostedSession.status === "ok" ? hostedSession.data?.session : void 0;
|
|
21747
|
+
const workSessionId = session?.id ?? persistedSessionId ?? logicalSessionId;
|
|
21748
|
+
if (session) {
|
|
21749
|
+
state.workflowSessions = { ...state.workflowSessions, [sessionKey]: session.id };
|
|
21750
|
+
}
|
|
21742
21751
|
const effectiveResources = hostedSession.status === "ok" ? hostedSession.data?.resources ?? resources : resources;
|
|
21743
21752
|
let hostedClaim = { status: "skipped" };
|
|
21744
21753
|
const shouldClaim = options.mode === "full" || options.mode === "orchestrate";
|
|
21745
|
-
if (shouldClaim && (files.length > 0 || effectiveResources.length > 0)) {
|
|
21754
|
+
if (hostedSession.status === "ok" && shouldClaim && (files.length > 0 || effectiveResources.length > 0)) {
|
|
21746
21755
|
hostedClaim = await maybeCreateHostedLeases(context, {
|
|
21747
21756
|
workSessionId,
|
|
21748
21757
|
files,
|
|
@@ -21800,7 +21809,7 @@ async function workflowCollaborationRelease(options) {
|
|
|
21800
21809
|
client: "snipara-companion:workflow"
|
|
21801
21810
|
});
|
|
21802
21811
|
const state = loadCollaborationState(rootDir);
|
|
21803
|
-
const targetSessionId = options.workflowId ? workflowWorkSessionId(options.workflowId) : state.workSessionId;
|
|
21812
|
+
const targetSessionId = options.workflowId ? state.workflowSessions?.[workflowSessionKey(context, options.workflowId)] ?? workflowWorkSessionId(options.workflowId) : state.workSessionId;
|
|
21804
21813
|
const activeLeases = state.leases.filter(
|
|
21805
21814
|
(lease) => lease.status === "ACTIVE" && (lease.workSessionId === targetSessionId || !lease.workSessionId && Boolean(targetSessionId) && state.workSessionId === targetSessionId)
|
|
21806
21815
|
);
|
|
@@ -22767,6 +22776,9 @@ function expireLocalLeases(state, now = /* @__PURE__ */ new Date()) {
|
|
|
22767
22776
|
state.updatedAt = now.toISOString();
|
|
22768
22777
|
}
|
|
22769
22778
|
}
|
|
22779
|
+
function workflowSessionKey(context, workflowId) {
|
|
22780
|
+
return (0, import_node_crypto13.createHash)("sha256").update(JSON.stringify([context.config.apiUrl, context.config.projectId, context.actor.actorType, context.actor.actorId, context.worktree, workflowId])).digest("hex");
|
|
22781
|
+
}
|
|
22770
22782
|
function workflowWorkSessionId(workflowId) {
|
|
22771
22783
|
return `workflow:${workflowId}`;
|
|
22772
22784
|
}
|
|
@@ -44556,6 +44568,16 @@ function projectControllerBridge(options) {
|
|
|
44556
44568
|
throw new Error("Unsupported bridge artifact schema or authority");
|
|
44557
44569
|
if (artifact2.taskContextVersion != null && artifact2.taskContextVersion !== "source-context-v1")
|
|
44558
44570
|
throw new Error("Unsupported task context version");
|
|
44571
|
+
const hasRuntimeContext = "runtimeSourceContextVersion" in artifact2 || "sourceRuntimeContext" in artifact2;
|
|
44572
|
+
let runtimeRef;
|
|
44573
|
+
let runtimeSource;
|
|
44574
|
+
if (hasRuntimeContext) {
|
|
44575
|
+
if (artifact2.runtimeSourceContextVersion !== "runtime-source-context-v1")
|
|
44576
|
+
throw new Error("Unsupported runtime source context version");
|
|
44577
|
+
runtimeRef = object2(artifact2.sourceRuntimeContext);
|
|
44578
|
+
runtimeSource = source(cwd, runtimeRef.path);
|
|
44579
|
+
same(runtimeSource.hash, runtimeRef.sha256, "runtime context source hash");
|
|
44580
|
+
}
|
|
44559
44581
|
const leadRef = object2(artifact2.sourceLeadPlan);
|
|
44560
44582
|
const policyRef = object2(artifact2.sourcePolicy);
|
|
44561
44583
|
const workflowRef = object2(artifact2.workflowPlan);
|
|
@@ -44563,6 +44585,7 @@ function projectControllerBridge(options) {
|
|
|
44563
44585
|
{
|
|
44564
44586
|
leadPlanFile: String(leadRef.path),
|
|
44565
44587
|
policyFile: String(policyRef.path),
|
|
44588
|
+
...runtimeRef ? { taskContextFile: String(runtimeRef.path) } : {},
|
|
44566
44589
|
reviewerId: bridgeId(object2(artifact2.review).reviewedBy),
|
|
44567
44590
|
outDir: path42.relative(
|
|
44568
44591
|
cwd,
|
|
@@ -44582,6 +44605,10 @@ function projectControllerBridge(options) {
|
|
|
44582
44605
|
same(workflow2.hash, workflowRef.sha256, "workflow source hash");
|
|
44583
44606
|
const identity = {
|
|
44584
44607
|
...artifact2.taskContextVersion ? { taskContextVersion: artifact2.taskContextVersion } : {},
|
|
44608
|
+
...runtimeRef ? {
|
|
44609
|
+
runtimeSourceContextVersion: artifact2.runtimeSourceContextVersion,
|
|
44610
|
+
sourceRuntimeContext: runtimeRef
|
|
44611
|
+
} : {},
|
|
44585
44612
|
sourceLeadPlan: leadRef,
|
|
44586
44613
|
sourcePolicy: policyRef,
|
|
44587
44614
|
controllerId: artifact2.controllerId,
|
|
@@ -44645,6 +44672,8 @@ function projectControllerBridge(options) {
|
|
|
44645
44672
|
{ kind: "workflow_plan", id: String(workflowRef.path), sha256: workflow2.hash },
|
|
44646
44673
|
{ kind: "controller", id: controllerId, sha256: stateRead.hash }
|
|
44647
44674
|
];
|
|
44675
|
+
if (runtimeRef && runtimeSource)
|
|
44676
|
+
sourceHashes.push({ kind: "runtime_context", id: String(runtimeRef.path), sha256: runtimeSource.hash });
|
|
44648
44677
|
const acceptedProposals = /* @__PURE__ */ new Map();
|
|
44649
44678
|
const tasks = mappings.map((mapping) => {
|
|
44650
44679
|
const taskId = bridgeId(mapping.taskId);
|
|
@@ -44665,6 +44694,13 @@ function projectControllerBridge(options) {
|
|
|
44665
44694
|
"effectScope"
|
|
44666
44695
|
])
|
|
44667
44696
|
same(actual[key], expected[key], `task ${key}`);
|
|
44697
|
+
if (expected.sourceContext != null || actual.sourceContext != null) {
|
|
44698
|
+
const expectedContext = object2(expected.sourceContext);
|
|
44699
|
+
const actualContext = { ...object2(actual.sourceContext) };
|
|
44700
|
+
if (expectedContext.targetAttempt === void 0 && actualContext.targetAttempt === null)
|
|
44701
|
+
delete actualContext.targetAttempt;
|
|
44702
|
+
same(actualContext, expectedContext, "task sourceContext");
|
|
44703
|
+
}
|
|
44668
44704
|
same(expected.runtimeProfileId, mapping.runtimeProfileId, "runtime profile binding");
|
|
44669
44705
|
const reportedStatus = String(actual.status);
|
|
44670
44706
|
let proposalId = null;
|