@jentrix/cli 0.5.21 → 0.5.23
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/main.js +146 -38
- package/package.json +1 -1
- package/surface.json +2 -2
package/dist/main.js
CHANGED
|
@@ -20966,7 +20966,7 @@ function refreshAccessToken(input) {
|
|
|
20966
20966
|
|
|
20967
20967
|
// src/client.ts
|
|
20968
20968
|
var CLI_NAME = "stacks-cli";
|
|
20969
|
-
var CLI_VERSION = "0.5.
|
|
20969
|
+
var CLI_VERSION = "0.5.23";
|
|
20970
20970
|
var DEAD_TOKEN_MESSAGE = "authentication failed (HTTP 401): the token is dead or expired \u2014 mint a new PAT at /account/tokens on your Jentrix server and update STACKS_TOKEN (or --token / the config file).";
|
|
20971
20971
|
var RELOGIN_MESSAGE = "OAuth session expired and could not be refreshed \u2014 run `jentrix login` to sign in again.";
|
|
20972
20972
|
function originOf2(url2) {
|
|
@@ -21386,7 +21386,10 @@ function buildAlignDisclosures(catalog) {
|
|
|
21386
21386
|
catalog.liveHostPid !== null ? `keep the live session host (pid ${catalog.liveHostPid}) running` : "start a detached session host (heartbeats + provider usage receipts)"
|
|
21387
21387
|
);
|
|
21388
21388
|
disclosures.push(
|
|
21389
|
-
catalog.captureMode === "on" ? "TRACE capture: ON \u2014 the full transcript will be recorded" : "TRACE capture: OFF
|
|
21389
|
+
catalog.captureMode === "on" ? "TRACE capture: ON \u2014 the full transcript will be recorded" : catalog.captureMode === "off" ? "TRACE capture: OFF \u2014 typed artifacts only, no transcript" : "TRACE capture: your account default (Account \u2192 Capture; the built-in is OFF \u2014 typed artifacts only). The confirmed value is printed after the align; --capture/--no-capture decides it here instead"
|
|
21390
|
+
);
|
|
21391
|
+
disclosures.push(
|
|
21392
|
+
catalog.skeletonMode === "on" ? "activity skeleton: ON \u2014 content-free counts/timing (turns, tool names, files-touched), independent of capture; --no-skeleton opts out" : catalog.skeletonMode === "off" ? "activity skeleton: OFF \u2014 no counts, no timing, no files-touched; the session's Session activity section will read as not observed" : "activity skeleton: your account default (Account \u2192 Capture; the built-in is ON \u2014 content-free counts/timing). The confirmed value is printed after the align; --skeleton/--no-skeleton decides it here instead"
|
|
21390
21393
|
);
|
|
21391
21394
|
disclosures.push("write the local alignment marker for this checkout");
|
|
21392
21395
|
const mcp = catalog.mcpConfig;
|
|
@@ -22004,6 +22007,10 @@ function upsertAlignmentMarker(file, providerSessionId, marker) {
|
|
|
22004
22007
|
sessions[providerSessionId] = marker;
|
|
22005
22008
|
return { version: 2, sessions, latest: providerSessionId };
|
|
22006
22009
|
}
|
|
22010
|
+
function findAlignmentMarkerForSession(file, sessionId) {
|
|
22011
|
+
if (!file) return null;
|
|
22012
|
+
return Object.values(file.sessions).find((m) => m.sessionId === sessionId) ?? null;
|
|
22013
|
+
}
|
|
22007
22014
|
function removeAlignmentMarkerEntry(file, sessionId) {
|
|
22008
22015
|
if (!file) return null;
|
|
22009
22016
|
const sessions = Object.fromEntries(
|
|
@@ -22450,20 +22457,39 @@ function readLiveHostMarker(deps2, sessionId) {
|
|
|
22450
22457
|
return null;
|
|
22451
22458
|
}
|
|
22452
22459
|
}
|
|
22453
|
-
async function
|
|
22460
|
+
async function waitForHostEnd(deps2, sessionId, pid, timeoutMs) {
|
|
22454
22461
|
const sleep = deps2.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
22455
|
-
const
|
|
22462
|
+
const dir = join2(deps2.spoolRoot, sessionId);
|
|
22463
|
+
const path = join2(dir, "host.json");
|
|
22456
22464
|
const deadline = Date.now() + timeoutMs;
|
|
22457
22465
|
while (Date.now() < deadline) {
|
|
22458
22466
|
await sleep(500);
|
|
22467
|
+
const refusal = readEndRefusal(deps2, sessionId);
|
|
22468
|
+
if (refusal) return { kind: "refused", message: refusal };
|
|
22459
22469
|
try {
|
|
22460
22470
|
const marker = JSON.parse(readFileSync2(path, "utf8"));
|
|
22461
|
-
if (marker.exitedAt) return
|
|
22471
|
+
if (marker.exitedAt) return { kind: "exited" };
|
|
22462
22472
|
} catch {
|
|
22463
22473
|
}
|
|
22464
|
-
if (!(deps2.isPidAlive ?? defaultIsPidAlive)(pid)) return
|
|
22474
|
+
if (!(deps2.isPidAlive ?? defaultIsPidAlive)(pid)) return { kind: "gone" };
|
|
22475
|
+
}
|
|
22476
|
+
return { kind: "gone" };
|
|
22477
|
+
}
|
|
22478
|
+
function readEndRefusal(deps2, sessionId) {
|
|
22479
|
+
try {
|
|
22480
|
+
const marker = JSON.parse(
|
|
22481
|
+
readFileSync2(join2(deps2.spoolRoot, sessionId, "end-refusal.json"), "utf8")
|
|
22482
|
+
);
|
|
22483
|
+
return typeof marker.message === "string" && marker.message.trim() ? marker.message : null;
|
|
22484
|
+
} catch {
|
|
22485
|
+
return null;
|
|
22486
|
+
}
|
|
22487
|
+
}
|
|
22488
|
+
function clearEndRefusal(deps2, sessionId) {
|
|
22489
|
+
try {
|
|
22490
|
+
unlinkSync(join2(deps2.spoolRoot, sessionId, "end-refusal.json"));
|
|
22491
|
+
} catch {
|
|
22465
22492
|
}
|
|
22466
|
-
return false;
|
|
22467
22493
|
}
|
|
22468
22494
|
function localCaptureLines(deps2, sessionId, serverStatus) {
|
|
22469
22495
|
const dir = join2(deps2.spoolRoot, sessionId);
|
|
@@ -23013,6 +23039,13 @@ async function runSessionStatus(sessionId, flags, deps2) {
|
|
|
23013
23039
|
const deadLocal = open && boundHere && !hasLocalCaptureFootprint(deps2, sessionId);
|
|
23014
23040
|
const captureOff = session.alignment?.capture === "off";
|
|
23015
23041
|
const capture = captureOff ? "off (MVP alignment \u2014 typed artifacts only)" : session.captureComplete ? "complete" : deadLocal ? "bound server-side; local capture NOT RUNNING" : open ? "recording (finalizes when the session ends)" : `INCOMPLETE${session.captureError ? ` \u2014 ${String(session.captureError)}` : ""}`;
|
|
23042
|
+
const inspection = await inspectRepository(deps2.cwd(), deps2.git);
|
|
23043
|
+
const alignMarker = inspection ? findAlignmentMarkerForSession(
|
|
23044
|
+
readAlignmentMarkerFile(deps2.configPath, inspection.root),
|
|
23045
|
+
sessionId
|
|
23046
|
+
) : null;
|
|
23047
|
+
const captureProvenance = alignMarker?.captureSource ? ` \xB7 resolved from ${alignMarker.captureSource}` : "";
|
|
23048
|
+
const skeletonProvenance = alignMarker?.skeletonSource ? ` \xB7 resolved from ${alignMarker.skeletonSource}` : "";
|
|
23016
23049
|
const local = deadLocal ? [
|
|
23017
23050
|
"Local capture: NOT RUNNING \u2014 this machine bound the session but no capture host ever started here (no host marker, no spool parts).",
|
|
23018
23051
|
` Fix: \`jentrix session end ${sessionId}\` closes it honestly (the capture gap is recorded), or reattach with a transcript path to start capture.`
|
|
@@ -23028,9 +23061,9 @@ async function runSessionStatus(sessionId, flags, deps2) {
|
|
|
23028
23061
|
`Session ${String(session.id)} \xB7 ${String(session.provider)} \xB7 ${String(session.status)}`,
|
|
23029
23062
|
`Project: ${String(session.projectName)} (${String(session.projectId)})`,
|
|
23030
23063
|
`Repository: ${String(session.repoOwnerName)}`,
|
|
23031
|
-
`Capture: ${capture}`,
|
|
23064
|
+
`Capture: ${capture}${captureProvenance}`,
|
|
23032
23065
|
// Evidence floor (D3): the skeleton mode the alignment declared.
|
|
23033
|
-
`Skeleton: ${session.alignment?.skeleton === "off" ? "off (
|
|
23066
|
+
`Skeleton: ${session.alignment?.skeleton === "off" ? "off (no activity counts, no timing, no files-touched)" : "on (content-free activity counts/timing)"}${skeletonProvenance}`,
|
|
23034
23067
|
...local,
|
|
23035
23068
|
telemetry.line,
|
|
23036
23069
|
`Summary artifact: ${session.summaryArtifactId ? String(session.summaryArtifactId) : "\u2014"}`
|
|
@@ -23163,14 +23196,12 @@ async function buildAttestedDiffBody(git, root, startHead, endHead, dirty) {
|
|
|
23163
23196
|
}
|
|
23164
23197
|
body = notice + kept;
|
|
23165
23198
|
}
|
|
23199
|
+
let uncommitted = null;
|
|
23166
23200
|
if (dirty) {
|
|
23167
23201
|
const delta = await git(["diff", "--stat", "HEAD"], root);
|
|
23168
|
-
|
|
23169
|
-
|
|
23170
|
-
Uncommitted delta at end (stat only \u2014 not part of the attested range):
|
|
23171
|
-
${delta.code === 0 && delta.stdout.trim() ? delta.stdout : "(unreadable or empty)"}`;
|
|
23202
|
+
uncommitted = delta.code === 0 && delta.stdout.trim() ? delta.stdout.trim() : null;
|
|
23172
23203
|
}
|
|
23173
|
-
return { body: header + body, commitCount };
|
|
23204
|
+
return { body: header + body, commitCount, uncommitted };
|
|
23174
23205
|
}
|
|
23175
23206
|
async function postAttestedArtifact(deps2, sessionId, input) {
|
|
23176
23207
|
const credentials = deps2.resolveTarget();
|
|
@@ -23298,6 +23329,12 @@ async function runSessionEnd(sessionIdFlag, flags, deps2) {
|
|
|
23298
23329
|
deps2.writeOut(
|
|
23299
23330
|
`Attested diff pushed \u2192 artifact ${pushed.artifactId ?? "(unknown)"} (${built.commitCount} commit(s), source: cli)`
|
|
23300
23331
|
);
|
|
23332
|
+
if (built.uncommitted) {
|
|
23333
|
+
deps2.writeOut(
|
|
23334
|
+
`note: uncommitted delta at end (stat only \u2014 not part of the attested range):
|
|
23335
|
+
${built.uncommitted}`
|
|
23336
|
+
);
|
|
23337
|
+
}
|
|
23301
23338
|
} else {
|
|
23302
23339
|
deps2.writeErr(
|
|
23303
23340
|
`note: attested diff push failed (${pushed.detail}) \u2014 the E1 delivery check will refuse the close; retry \`jentrix session end\`, or acknowledge with --acknowledge-evidence-gaps.`
|
|
@@ -23320,21 +23357,32 @@ async function runSessionEnd(sessionIdFlag, flags, deps2) {
|
|
|
23320
23357
|
};
|
|
23321
23358
|
const live = readLiveHostMarker(deps2, sessionId);
|
|
23322
23359
|
if (live) {
|
|
23360
|
+
clearEndRefusal(deps2, sessionId);
|
|
23323
23361
|
writeFileSync2(
|
|
23324
23362
|
join2(deps2.spoolRoot, sessionId, "end-request.json"),
|
|
23325
|
-
JSON.stringify({
|
|
23363
|
+
JSON.stringify({
|
|
23364
|
+
requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
23365
|
+
// JEN-167: the host closes the session, so the operator's
|
|
23366
|
+
// acknowledgement has to travel with the request — otherwise the
|
|
23367
|
+
// floor refuses a close they explicitly asked to force. The
|
|
23368
|
+
// CLI-counted commits ride along for the same reason: only the
|
|
23369
|
+
// CLI can count them, and the host's close is the one that lands.
|
|
23370
|
+
...flags.acknowledgeEvidenceGaps ? { acknowledgeEvidenceGaps: true } : {},
|
|
23371
|
+
...commitCount !== null ? { commitCount } : {}
|
|
23372
|
+
}),
|
|
23326
23373
|
{ mode: 384 }
|
|
23327
23374
|
);
|
|
23328
23375
|
deps2.writeOut(
|
|
23329
23376
|
`Local capture host (pid ${live.pid}) is finalizing capture\u2026`
|
|
23330
23377
|
);
|
|
23331
|
-
const
|
|
23332
|
-
|
|
23333
|
-
|
|
23334
|
-
|
|
23335
|
-
|
|
23336
|
-
|
|
23337
|
-
|
|
23378
|
+
const outcome = await waitForHostEnd(deps2, sessionId, live.pid, 9e4);
|
|
23379
|
+
if (outcome.kind === "refused") {
|
|
23380
|
+
deps2.writeErr(
|
|
23381
|
+
`local capture host (pid ${live.pid}) is still running \u2014 the skeleton, heartbeats and telemetry keep accumulating through the comply work; re-run \`jentrix session end ${sessionId}\` once the evidence is pushed`
|
|
23382
|
+
);
|
|
23383
|
+
throw new Error(outcome.message);
|
|
23384
|
+
}
|
|
23385
|
+
if (outcome.kind === "exited") {
|
|
23338
23386
|
const final = await call(caller, "get_agent_session", { sessionId });
|
|
23339
23387
|
const stillOpen = final.status === "STARTING" || final.status === "ACTIVE";
|
|
23340
23388
|
if (!stillOpen) {
|
|
@@ -24184,7 +24232,11 @@ async function buildCatalog(caller, flags, detection) {
|
|
|
24184
24232
|
// Host/capture disclosure inputs are filled by runAlign (they need the
|
|
24185
24233
|
// checkout root); defaults here are the no-live-host reading.
|
|
24186
24234
|
liveHostPid: null,
|
|
24187
|
-
captureMode:
|
|
24235
|
+
captureMode: captureSubmission(flags.capture, false, false) ?? "default",
|
|
24236
|
+
// JEN-169 + capture settings §5: the disclosure states the same tri-state
|
|
24237
|
+
// the submission carries, so "your account default" is never quietly
|
|
24238
|
+
// disclosed as a posture the wizard guessed.
|
|
24239
|
+
skeletonMode: skeletonSubmission(flags.skeleton) ?? "default",
|
|
24188
24240
|
producer: producerFromFlags(flags),
|
|
24189
24241
|
tokenBudget: budgetFromFlags(flags),
|
|
24190
24242
|
preconditionNotices: [],
|
|
@@ -24298,6 +24350,18 @@ function decideCaptureMode(requested, liveCapturing) {
|
|
|
24298
24350
|
if (requested === false) return "off";
|
|
24299
24351
|
return liveCapturing ? "on" : "off";
|
|
24300
24352
|
}
|
|
24353
|
+
function captureSubmission(requested, liveHost, liveCapturing) {
|
|
24354
|
+
if (requested === void 0 && !liveHost) return void 0;
|
|
24355
|
+
return decideCaptureMode(requested, liveCapturing);
|
|
24356
|
+
}
|
|
24357
|
+
function skeletonSubmission(requested) {
|
|
24358
|
+
if (requested === void 0) return void 0;
|
|
24359
|
+
return requested ? "on" : "off";
|
|
24360
|
+
}
|
|
24361
|
+
function captureSourceLabel(requested, liveHost, serverLabel) {
|
|
24362
|
+
if (requested === void 0 && liveHost) return "(live host)";
|
|
24363
|
+
return serverLabel;
|
|
24364
|
+
}
|
|
24301
24365
|
function keepCurrentAlignment(currentAlignment, projectId, workItem, ownerUserId) {
|
|
24302
24366
|
if (workItem !== null || !projectId) return null;
|
|
24303
24367
|
const current = currentAlignment;
|
|
@@ -24362,7 +24426,9 @@ ${JSON.stringify(session.alignment, null, 2)}`
|
|
|
24362
24426
|
sessionId,
|
|
24363
24427
|
alignment: session.alignment,
|
|
24364
24428
|
realigned: false,
|
|
24365
|
-
captureMode: (session.alignment.capture ?? "off") === "on" ? "on" : "off"
|
|
24429
|
+
captureMode: (session.alignment.capture ?? "off") === "on" ? "on" : "off",
|
|
24430
|
+
// No align ran, so nothing resolved anything — claim no provenance.
|
|
24431
|
+
captureSources: null
|
|
24366
24432
|
};
|
|
24367
24433
|
}
|
|
24368
24434
|
}
|
|
@@ -24413,7 +24479,12 @@ ${JSON.stringify(session.alignment, null, 2)}`
|
|
|
24413
24479
|
`cannot turn TRACE capture off: the live session host (pid ${liveHost.pid}) is actively capturing \u2014 end the session (\`jentrix session end\`) to stop it`
|
|
24414
24480
|
);
|
|
24415
24481
|
}
|
|
24416
|
-
const
|
|
24482
|
+
const captureSubmitted = captureSubmission(
|
|
24483
|
+
flags.capture,
|
|
24484
|
+
liveHost !== null,
|
|
24485
|
+
liveCapturing
|
|
24486
|
+
);
|
|
24487
|
+
const skeletonSubmitted = skeletonSubmission(flags.skeleton);
|
|
24417
24488
|
if (liveHost && session.taskId && session.taskId !== (taskId ?? null)) {
|
|
24418
24489
|
const acked = await requestUsageFlush(deps2, sessionId);
|
|
24419
24490
|
deps2.writeOut(
|
|
@@ -24431,14 +24502,22 @@ ${JSON.stringify(session.alignment, null, 2)}`
|
|
|
24431
24502
|
...producer.emoji ? { agentEmoji: producer.emoji } : {}
|
|
24432
24503
|
} : {},
|
|
24433
24504
|
...budget !== null ? { tokenBudget: budget } : {},
|
|
24434
|
-
capture:
|
|
24435
|
-
|
|
24436
|
-
// lets the server keep the stored mode (default "on").
|
|
24437
|
-
...flags.skeleton === false ? { skeleton: "off" } : {},
|
|
24505
|
+
...captureSubmitted !== void 0 ? { capture: captureSubmitted } : {},
|
|
24506
|
+
...skeletonSubmitted !== void 0 ? { skeleton: skeletonSubmitted } : {},
|
|
24438
24507
|
expectedUpdatedAt: session.updatedAt
|
|
24439
24508
|
});
|
|
24440
24509
|
const alignment = aligned.alignment;
|
|
24441
24510
|
const skeletonMode = alignment.skeleton === "off" ? "off" : "on";
|
|
24511
|
+
const captureMode = alignment.capture === "on" ? "on" : "off";
|
|
24512
|
+
const serverSources = aligned.captureSources ?? null;
|
|
24513
|
+
const captureSources = serverSources ? {
|
|
24514
|
+
capture: captureSourceLabel(
|
|
24515
|
+
flags.capture,
|
|
24516
|
+
liveHost !== null,
|
|
24517
|
+
serverSources.capture
|
|
24518
|
+
),
|
|
24519
|
+
skeleton: serverSources.skeleton
|
|
24520
|
+
} : null;
|
|
24442
24521
|
writeAlignmentMarker(
|
|
24443
24522
|
deps2.configPath,
|
|
24444
24523
|
inspection.root,
|
|
@@ -24448,6 +24527,12 @@ ${JSON.stringify(session.alignment, null, 2)}`
|
|
|
24448
24527
|
projectId: choices.projectId,
|
|
24449
24528
|
taskId,
|
|
24450
24529
|
capture: captureMode,
|
|
24530
|
+
// Capture settings D6/S4: `session status` reads the provenance back
|
|
24531
|
+
// from here — the snapshot deliberately stores values only, so the
|
|
24532
|
+
// align that resolved them is the only place the source exists.
|
|
24533
|
+
...captureSources?.capture ? { captureSource: captureSources.capture } : {},
|
|
24534
|
+
...captureSources?.skeleton ? { skeletonSource: captureSources.skeleton } : {},
|
|
24535
|
+
skeleton: skeletonMode,
|
|
24451
24536
|
alignedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
24452
24537
|
},
|
|
24453
24538
|
detected.providerSessionId
|
|
@@ -24474,7 +24559,8 @@ ${JSON.stringify(session.alignment, null, 2)}`
|
|
|
24474
24559
|
sessionId,
|
|
24475
24560
|
alignment,
|
|
24476
24561
|
realigned: Boolean(aligned.realigned),
|
|
24477
|
-
captureMode
|
|
24562
|
+
captureMode,
|
|
24563
|
+
captureSources
|
|
24478
24564
|
};
|
|
24479
24565
|
}
|
|
24480
24566
|
if (!liveHost && (detected.provider === "claude" && detected.transcriptPath || detected.provider === "codex" && detected.hookDir)) {
|
|
@@ -24518,7 +24604,8 @@ ${JSON.stringify(session.alignment, null, 2)}`
|
|
|
24518
24604
|
sessionId,
|
|
24519
24605
|
alignment,
|
|
24520
24606
|
realigned: Boolean(aligned.realigned),
|
|
24521
|
-
captureMode
|
|
24607
|
+
captureMode,
|
|
24608
|
+
captureSources
|
|
24522
24609
|
};
|
|
24523
24610
|
}
|
|
24524
24611
|
async function requestUsageFlush(deps2, sessionId, timeoutMs = 6e3) {
|
|
@@ -24569,10 +24656,11 @@ async function runAlign(flags, deps2) {
|
|
|
24569
24656
|
);
|
|
24570
24657
|
const markerHost = marker ? readLiveHostMarker(deps2, marker.sessionId) : null;
|
|
24571
24658
|
catalog.liveHostPid = markerHost?.pid ?? null;
|
|
24572
|
-
catalog.captureMode =
|
|
24659
|
+
catalog.captureMode = captureSubmission(
|
|
24573
24660
|
flags.capture,
|
|
24661
|
+
markerHost !== null,
|
|
24574
24662
|
marker !== null && markerHost !== null && isHostCapturing(deps2, marker.sessionId, markerHost)
|
|
24575
|
-
);
|
|
24663
|
+
) ?? "default";
|
|
24576
24664
|
const newest = newestAlignmentMarker(deps2.configPath, inspection.root);
|
|
24577
24665
|
catalog.lastAlignedWorkspaceId = newest?.workspaceId ?? null;
|
|
24578
24666
|
catalog.binding = {
|
|
@@ -24961,6 +25049,7 @@ async function runAlign(flags, deps2) {
|
|
|
24961
25049
|
deps2.writeOut(JSON.stringify(result));
|
|
24962
25050
|
} else {
|
|
24963
25051
|
const a = result.alignment;
|
|
25052
|
+
const sources = result.captureSources;
|
|
24964
25053
|
deps2.writeOut(
|
|
24965
25054
|
[
|
|
24966
25055
|
`${result.realigned ? "Re-aligned" : "Aligned"} session ${result.sessionId}:`,
|
|
@@ -24970,8 +25059,12 @@ async function runAlign(flags, deps2) {
|
|
|
24970
25059
|
` Owner: ${a.owner?.name ?? a.owner?.email ?? "\u2014"}`,
|
|
24971
25060
|
` Agent: ${a.agent?.provider ?? "\u2014"}`,
|
|
24972
25061
|
` Repo: ${a.repo?.ownerName ?? "\u2014"}@${a.repo?.branch ?? "detached"}`,
|
|
24973
|
-
|
|
24974
|
-
|
|
25062
|
+
// Capture settings D6: each resolved knob names WHERE it came
|
|
25063
|
+
// from, in the server's own words — "(flag)", "(this session)",
|
|
25064
|
+
// "(your default)", "(built-in)". A server older than this round
|
|
25065
|
+
// sends none, and then nothing is claimed.
|
|
25066
|
+
` Capture: ${a.capture ?? "off"}${sources?.capture ? ` ${sources.capture}` : ""}`,
|
|
25067
|
+
` Skeleton: ${a.skeleton ?? "on"}${sources?.skeleton ? ` ${sources.skeleton}` : ""} \u2014 content-free activity counts/timing; --skeleton/--no-skeleton decides one session, Account \u2192 Capture sets your default`,
|
|
24975
25068
|
`Alignment snapshot (server-confirmed): ${JSON.stringify(result.alignment)}`
|
|
24976
25069
|
].join("\n")
|
|
24977
25070
|
);
|
|
@@ -25032,13 +25125,16 @@ function registerAlignCommand(program3, deps2, onExit2) {
|
|
|
25032
25125
|
"token budget for this session \u2014 a breach is recorded and badged, never enforced"
|
|
25033
25126
|
).option(
|
|
25034
25127
|
"--capture",
|
|
25035
|
-
"turn TRACE capture ON for this session (
|
|
25128
|
+
"turn TRACE capture ON for this session (overrides your account default; applies from a fresh attach)"
|
|
25036
25129
|
).option(
|
|
25037
25130
|
"--no-capture",
|
|
25038
|
-
"keep TRACE capture OFF explicitly \u2014
|
|
25131
|
+
"keep TRACE capture OFF explicitly \u2014 overrides your account default, and corrects a wrongly-on record on re-align"
|
|
25132
|
+
).option(
|
|
25133
|
+
"--skeleton",
|
|
25134
|
+
"record the content-free activity skeleton for this session explicitly (overrides your account default)"
|
|
25039
25135
|
).option(
|
|
25040
25136
|
"--no-skeleton",
|
|
25041
|
-
"opt out of the content-free activity skeleton (event/tool counts, files-touched, timing buckets) for this session \u2014
|
|
25137
|
+
"opt out of the content-free activity skeleton (event/tool counts, files-touched, timing buckets) for this session \u2014 independent of capture"
|
|
25042
25138
|
).addOption(
|
|
25043
25139
|
new Option(
|
|
25044
25140
|
"--provider <provider>",
|
|
@@ -26574,6 +26670,10 @@ function parseArgsJson(raw, source) {
|
|
|
26574
26670
|
}
|
|
26575
26671
|
return { ok: true, value: parsed };
|
|
26576
26672
|
}
|
|
26673
|
+
function workspaceIdShapeError(value) {
|
|
26674
|
+
if (/^[a-z0-9]{20,}$/.test(value)) return null;
|
|
26675
|
+
return `workspaceId "${value}" is not a workspace id (ids look like "cmt2cuhyo000004l38ddsim1y"). Find yours with \`jentrix workspace list\`, set it once as \`defaults.workspace\` in the config file, or use \`jentrix align --workspace <id-or-slug>\` \u2014 align is the command that accepts a slug.`;
|
|
26676
|
+
}
|
|
26577
26677
|
async function runToolCommand(name, flags, deps2) {
|
|
26578
26678
|
const maxWaitSeconds = Number(flags.maxWait);
|
|
26579
26679
|
if (!Number.isFinite(maxWaitSeconds) || maxWaitSeconds < 0) {
|
|
@@ -26610,6 +26710,14 @@ async function runToolCommand(name, flags, deps2) {
|
|
|
26610
26710
|
deps2.writeErr(`error: ${parsed.error}`);
|
|
26611
26711
|
return EXIT_CODES.INVALID_INPUT;
|
|
26612
26712
|
}
|
|
26713
|
+
const workspaceId = parsed.value.workspaceId;
|
|
26714
|
+
if (typeof workspaceId === "string") {
|
|
26715
|
+
const shapeError = workspaceIdShapeError(workspaceId);
|
|
26716
|
+
if (shapeError) {
|
|
26717
|
+
deps2.writeErr(`error: ${shapeError}`);
|
|
26718
|
+
return EXIT_CODES.INVALID_INPUT;
|
|
26719
|
+
}
|
|
26720
|
+
}
|
|
26613
26721
|
let config2;
|
|
26614
26722
|
try {
|
|
26615
26723
|
config2 = resolveConfig({
|
package/package.json
CHANGED
package/surface.json
CHANGED
|
@@ -441,7 +441,7 @@
|
|
|
441
441
|
"description": "Optional producer label for this session (\"triage-bot\"). Null = the operator themself; absent leaves it unchanged."
|
|
442
442
|
},
|
|
443
443
|
"capture": {
|
|
444
|
-
"description": "TRACE capture mode the
|
|
444
|
+
"description": "TRACE capture mode for this session. OMIT to let the server resolve it: this session's previous value, then the operator's account default (Account → Capture), then the built-in off.",
|
|
445
445
|
"enum": [
|
|
446
446
|
"off",
|
|
447
447
|
"on"
|
|
@@ -464,7 +464,7 @@
|
|
|
464
464
|
"type": "string"
|
|
465
465
|
},
|
|
466
466
|
"skeleton": {
|
|
467
|
-
"description": "Activity-skeleton mode the
|
|
467
|
+
"description": "Activity-skeleton mode for this session, independent of capture. OMIT to let the server resolve it: this session's previous value, then the operator's account default, then the built-in on.",
|
|
468
468
|
"enum": [
|
|
469
469
|
"on",
|
|
470
470
|
"off"
|