@unbrained/pm-cli 2026.9.1 → 2026.9.3
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/.claude-plugin/marketplace.json +2 -2
- package/CHANGELOG.md +27 -0
- package/dist/cli/after-command-context-usage.js +16 -3
- package/dist/cli-bundle/bundle-manifest.json +153 -153
- package/dist/cli-bundle/chunks/{chunk-6XIIGE7U.js → chunk-34HASX3S.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-AY324UJ5.js +9 -0
- package/dist/cli-bundle/chunks/{chunk-TAG4VC22.js → chunk-DKGP3QLE.js} +27 -27
- package/dist/cli-bundle/chunks/chunk-E5RBBCXO.js +230 -0
- package/dist/cli-bundle/chunks/{chunk-DTGWEL23.js → chunk-EDPIS7EB.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-X4RCGLTX.js → chunk-IEHHE6GA.js} +5 -5
- package/dist/cli-bundle/chunks/{chunk-U45JXJCC.js → chunk-L7B7343B.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-2MC2LCXZ.js → chunk-LENC656S.js} +41 -41
- package/dist/cli-bundle/chunks/chunk-LISESA7W.js +35 -0
- package/dist/cli-bundle/chunks/{chunk-3WICXLVT.js → chunk-UPPM2FOZ.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-Y7VOMSZT.js → chunk-Y4PJ6HPK.js} +2 -2
- package/dist/cli-bundle/chunks/{register-list-query-XYNX4ASQ.js → register-list-query-W2ZTOMKP.js} +2 -2
- package/dist/cli-bundle/chunks/{register-mutation-2MVLRS3J.js → register-mutation-RVND5NCG.js} +2 -2
- package/dist/cli-bundle/chunks/{register-operations-WCIDXBU3.js → register-operations-TTROIVC4.js} +2 -2
- package/dist/cli-bundle/chunks/{register-setup-KVNC5KPL.js → register-setup-D3ZFHY3L.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-3ZBI35HU.js +176 -0
- package/dist/cli-bundle/focused-chunks/{chunk-SVXJYD6G.js → chunk-4HJFY4MB.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-4RRHC3S4.js +6 -0
- package/dist/cli-bundle/focused-chunks/chunk-4WR46RMG.js +9 -0
- package/dist/cli-bundle/focused-chunks/chunk-5RFXUPN5.js +3 -0
- package/dist/cli-bundle/focused-chunks/chunk-BWKHEIVF.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-4O4CJAR6.js → chunk-D7KXFBXV.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-MKHG3T76.js → chunk-GHCZ3YFR.js} +3 -3
- package/dist/cli-bundle/focused-chunks/{chunk-KB5OFSFD.js → chunk-GT7MXDLW.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-KBLZRU62.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-KZ2NB3ET.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-M5M6SVHS.js +3 -0
- package/dist/cli-bundle/focused-chunks/{chunk-BEVHCEWG.js → chunk-OL5EH6I3.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-MEASX544.js → chunk-Q45NHPF2.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-Y6JJIX6I.js → chunk-QKHCSUGJ.js} +48 -48
- package/dist/cli-bundle/focused-chunks/chunk-S27XMBIN.js +8 -0
- package/dist/cli-bundle/focused-chunks/chunk-TXE4TSHM.js +12 -0
- package/dist/cli-bundle/focused-chunks/chunk-UCLO3XDU.js +2 -0
- package/dist/cli-bundle/main.js +15 -15
- package/dist/cli-bundle/sdk-authoring.js +1 -1
- package/dist/cli-bundle/sdk-contracts.js +1 -1
- package/dist/cli-bundle/sdk-core.js +28 -28
- package/dist/cli-bundle/sdk-governance.js +1 -1
- package/dist/cli-bundle/sdk-graph.js +1 -1
- package/dist/cli-bundle/sdk-merge.js +35 -33
- package/dist/cli-bundle/sdk-query.js +1 -1
- package/dist/cli-bundle/sdk-runtime.js +1 -1
- package/dist/cli-bundle/sdk-testing.js +1 -1
- package/dist/cli-bundle/sdk.js +9 -9
- package/dist/core/diagnostics/remediation.js +9 -4
- package/dist/core/history/event-classification.d.ts +21 -0
- package/dist/core/history/event-classification.js +109 -0
- package/dist/core/history/event-index.d.ts +14 -3
- package/dist/core/history/event-index.js +543 -88
- package/dist/core/history/history.js +47 -18
- package/dist/core/history/workspace-history.js +7 -6
- package/dist/core/lock/lock.d.ts +22 -2
- package/dist/core/lock/lock.js +121 -19
- package/dist/core/output/output.js +31 -7
- package/dist/core/shared/time.d.ts +2 -0
- package/dist/core/shared/time.js +8 -2
- package/dist/core/store/item-metadata-query-index.js +5 -5
- package/dist/sdk/context/recency.d.ts +9 -0
- package/dist/sdk/context/recency.js +34 -0
- package/dist/sdk/context/usage-egress.d.ts +9 -0
- package/dist/sdk/context/usage-egress.js +30 -0
- package/dist/sdk/context-intent-contracts.js +7 -3
- package/dist/sdk/context-relevance.d.ts +23 -0
- package/dist/sdk/context-relevance.js +94 -23
- package/dist/sdk/context-signal-store.d.ts +7 -3
- package/dist/sdk/context-signal-store.js +155 -42
- package/dist/sdk/context-usage.d.ts +54 -0
- package/dist/sdk/context-usage.js +245 -16
- package/dist/sdk/generated/generated-error-code-catalog-part-1.js +26 -14
- package/dist/sdk/generated/generated-error-code-catalog-part-2.js +14 -2
- package/dist/sdk/governance/health.js +77 -11
- package/dist/sdk/governance/validate.js +4 -2
- package/dist/sdk/index.d.ts +2 -0
- package/dist/sdk/index.js +4 -2
- package/dist/sdk/init.d.ts +2 -0
- package/dist/sdk/init.js +18 -9
- package/dist/sdk/merge/index.d.ts +1 -1
- package/dist/sdk/merge/index.js +2 -2
- package/dist/sdk/merge/receipts.d.ts +24 -0
- package/dist/sdk/merge/receipts.js +122 -30
- package/dist/sdk/query/context.d.ts +3 -1
- package/dist/sdk/query/context.js +21 -9
- package/dist/sdk/query/next.js +18 -9
- package/dist/sdk/runtime-input.d.ts +2 -0
- package/dist/sdk/runtime-input.js +25 -2
- package/dist/sdk/runtime.d.ts +1 -0
- package/dist/sdk/runtime.js +17 -26
- package/dist/types.d.ts +2 -0
- package/dist/types.js +2 -2
- package/docs/CONTEXT_RECOVERY_PRIMITIVES.md +11 -2
- package/docs/CONTEXT_RELEVANCE.md +44 -1
- package/docs/MERGE_SAFETY.md +16 -2
- package/docs/PERFORMANCE.md +6 -3
- package/docs/READ_OUTPUT_CONTRACTS.md +9 -1
- package/docs/SDK.md +11 -8
- package/docs/SDK_CONTEXT.md +7 -0
- package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +5 -3
- package/marketplace.json +2 -2
- package/package.json +4 -4
- package/packages/pm-beads/package.json +1 -1
- package/packages/pm-calendar/package.json +1 -1
- package/packages/pm-command-kit/package.json +1 -1
- package/packages/pm-digital-twin/package.json +1 -1
- package/packages/pm-governance-audit/package.json +1 -1
- package/packages/pm-guide-shell/package.json +1 -1
- package/packages/pm-kanban/package.json +1 -1
- package/packages/pm-lifecycle-hooks/package.json +1 -1
- package/packages/pm-linked-test-adapters/package.json +1 -1
- package/packages/pm-search-advanced/package.json +1 -1
- package/packages/pm-templates/package.json +1 -1
- package/packages/pm-todos/package.json +1 -1
- package/packages/pm-vcs/package.json +1 -1
- package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
- package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
- package/sdk/public-surface.json +268 -28
- package/dist/cli-bundle/chunks/chunk-ALKKAUFN.js +0 -35
- package/dist/cli-bundle/chunks/chunk-GOACULJW.js +0 -13
- package/dist/cli-bundle/chunks/chunk-NOPL37X4.js +0 -205
- package/dist/cli-bundle/focused-chunks/chunk-2FEZ5SKM.js +0 -3
- package/dist/cli-bundle/focused-chunks/chunk-6GCRSLPG.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-7VATS5QY.js +0 -16
- package/dist/cli-bundle/focused-chunks/chunk-FWPLDEXF.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-JEFKLWMM.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-PF3E6Q36.js +0 -8
- package/dist/cli-bundle/focused-chunks/chunk-QDFJIRKN.js +0 -4
- package/dist/cli-bundle/focused-chunks/chunk-RMRCQPWU.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-S4U5CN5Q.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-T2LXXSOD.js +0 -158
- package/dist/cli-bundle/focused-chunks/chunk-Z2USIBR2.js +0 -5
|
@@ -4,18 +4,20 @@
|
|
|
4
4
|
* Implements append-only history and replay behavior for History.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
7
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="1f78448d-a042-588a-84ce-369bd9ce8726")}catch(e){}}();
|
|
8
8
|
import jsonPatch from "fast-json-patch";
|
|
9
|
-
import { ITEM_METADATA_KEY_ORDER } from "../shared/constants.js";
|
|
9
|
+
import { EXIT_CODE, ITEM_METADATA_KEY_ORDER } from "../shared/constants.js";
|
|
10
10
|
import { runActiveServiceOverride } from "../extensions/index.js";
|
|
11
11
|
import { appendLineAtomic } from "../fs/fs-utils.js";
|
|
12
12
|
import { canonicalDocument } from "../item/item-format.js";
|
|
13
13
|
import { toItemRecord } from "../item/item-record.js";
|
|
14
14
|
import { orderObject, sha256Hex, stableStringify, } from "../shared/serialization.js";
|
|
15
|
-
import { nowIso } from "../shared/time.js";
|
|
15
|
+
import { isMillisecondPrecisionRfc3339DateTime, nowIso, } from "../shared/time.js";
|
|
16
16
|
import { diagnoseAgentIdentity, resolveHistoryAgentIdentity, resolveHistoryAuthorSource, } from "../shared/author.js";
|
|
17
|
-
import {
|
|
17
|
+
import { appendHistoryEntryWithEventIndex, removeHistoryEventIndexForHistoryPath, } from "./event-index.js";
|
|
18
|
+
import { classifyHistoryEvent } from "./event-classification.js";
|
|
18
19
|
import { invalidateHistoryDriftCacheForPath } from "./drift-cache.js";
|
|
20
|
+
import { PmCliError } from "../shared/errors.js";
|
|
19
21
|
const EMPTY_LEGACY_HASH_DOCUMENT = {
|
|
20
22
|
front_matter: {},
|
|
21
23
|
body: "",
|
|
@@ -42,7 +44,8 @@ function compareLegacyLinkedTests(left, right) {
|
|
|
42
44
|
compareOptionalStrings(left.command, right.command),
|
|
43
45
|
compareOptionalNumbers(left.timeout_seconds, right.timeout_seconds),
|
|
44
46
|
compareOptionalStrings(left.pm_context_mode, right.pm_context_mode),
|
|
45
|
-
Number(Boolean(left.shared_host_safe)) -
|
|
47
|
+
Number(Boolean(left.shared_host_safe)) -
|
|
48
|
+
Number(Boolean(right.shared_host_safe)),
|
|
46
49
|
compareJsonValues(left.env_clear, right.env_clear, []),
|
|
47
50
|
compareJsonValues(left.env_set, right.env_set, {}),
|
|
48
51
|
compareJsonValues(left.assert_stdout_contains, right.assert_stdout_contains, []),
|
|
@@ -222,13 +225,14 @@ export function createHistoryEntry(params) {
|
|
|
222
225
|
const provenanceOutcomes = agentIdentity.harness
|
|
223
226
|
? Object.fromEntries(Object.entries(diagnoseAgentIdentity().provenance_outcomes).filter(([, outcome]) => outcome.resolver !== undefined && outcome.status !== "resolved"))
|
|
224
227
|
: undefined;
|
|
225
|
-
const context = provenanceOutcomes === undefined ||
|
|
228
|
+
const context = provenanceOutcomes === undefined ||
|
|
229
|
+
Object.keys(provenanceOutcomes).length === 0
|
|
226
230
|
? params.context
|
|
227
231
|
: {
|
|
228
232
|
...params.context,
|
|
229
233
|
agent_provenance_outcomes: provenanceOutcomes,
|
|
230
234
|
};
|
|
231
|
-
|
|
235
|
+
const entry = {
|
|
232
236
|
ts: params.nowIso,
|
|
233
237
|
author: params.author,
|
|
234
238
|
author_source: params.authorSource ?? resolveHistoryAuthorSource(params.author),
|
|
@@ -243,9 +247,7 @@ export function createHistoryEntry(params) {
|
|
|
243
247
|
...(agentIdentity.provenance
|
|
244
248
|
? { agent_provenance: agentIdentity.provenance }
|
|
245
249
|
: {}),
|
|
246
|
-
...(agentIdentity.episode
|
|
247
|
-
? { agent_episode: agentIdentity.episode }
|
|
248
|
-
: {}),
|
|
250
|
+
...(agentIdentity.episode ? { agent_episode: agentIdentity.episode } : {}),
|
|
249
251
|
op: params.op,
|
|
250
252
|
patch,
|
|
251
253
|
before_hash: sha256Hex(stableStringify(beforeHashCanonical)),
|
|
@@ -254,17 +256,34 @@ export function createHistoryEntry(params) {
|
|
|
254
256
|
message: params.message === undefined ? undefined : params.message,
|
|
255
257
|
...(context === undefined ? {} : { context }),
|
|
256
258
|
};
|
|
259
|
+
return { ...entry, event_class: classifyHistoryEvent(entry) };
|
|
257
260
|
}
|
|
258
261
|
function isRecord(value) {
|
|
259
262
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
260
263
|
}
|
|
264
|
+
function invalidHistoryTimestamp(message) {
|
|
265
|
+
return new PmCliError(message, EXIT_CODE.GENERIC_FAILURE, {
|
|
266
|
+
code: "history_timestamp_invalid",
|
|
267
|
+
});
|
|
268
|
+
}
|
|
261
269
|
function fallbackHistoryTimestamp(entry) {
|
|
262
270
|
const ts = entry.ts.trim();
|
|
263
|
-
|
|
271
|
+
if (ts.length === 0)
|
|
272
|
+
return nowIso();
|
|
273
|
+
if (!isMillisecondPrecisionRfc3339DateTime(ts)) {
|
|
274
|
+
throw invalidHistoryTimestamp("History timestamp must be a valid RFC 3339 date-time with millisecond precision");
|
|
275
|
+
}
|
|
276
|
+
if (ts !== entry.ts) {
|
|
277
|
+
throw invalidHistoryTimestamp("History timestamp must not contain surrounding whitespace");
|
|
278
|
+
}
|
|
279
|
+
return entry.ts;
|
|
264
280
|
}
|
|
265
281
|
function withHistoryTimestamp(value, fallbackTs) {
|
|
266
282
|
const ts = value.ts;
|
|
267
283
|
if (typeof ts === "string" && ts.trim().length > 0) {
|
|
284
|
+
if (!isMillisecondPrecisionRfc3339DateTime(ts)) {
|
|
285
|
+
throw invalidHistoryTimestamp("History timestamp must be a valid RFC 3339 date-time with millisecond precision");
|
|
286
|
+
}
|
|
268
287
|
return value;
|
|
269
288
|
}
|
|
270
289
|
return { ...value, ts: fallbackTs };
|
|
@@ -272,14 +291,16 @@ function withHistoryTimestamp(value, fallbackTs) {
|
|
|
272
291
|
function serializeHistoryLine(value, fallbackEntry) {
|
|
273
292
|
const fallbackTs = fallbackHistoryTimestamp(fallbackEntry);
|
|
274
293
|
if (typeof value === "string") {
|
|
294
|
+
let parsed;
|
|
275
295
|
try {
|
|
276
|
-
|
|
277
|
-
if (isRecord(parsed)) {
|
|
278
|
-
return JSON.stringify(withHistoryTimestamp(parsed, fallbackTs));
|
|
279
|
-
}
|
|
296
|
+
parsed = JSON.parse(value);
|
|
280
297
|
}
|
|
281
298
|
catch {
|
|
282
299
|
// Non-JSON extension lines are preserved for compatibility.
|
|
300
|
+
return value;
|
|
301
|
+
}
|
|
302
|
+
if (isRecord(parsed)) {
|
|
303
|
+
return JSON.stringify(withHistoryTimestamp(parsed, fallbackTs));
|
|
283
304
|
}
|
|
284
305
|
return value;
|
|
285
306
|
}
|
|
@@ -324,9 +345,17 @@ export async function appendHistoryEntry(historyPath, entry) {
|
|
|
324
345
|
return;
|
|
325
346
|
}
|
|
326
347
|
}
|
|
327
|
-
|
|
348
|
+
const timestampedEntry = entry.ts.trim().length > 0
|
|
349
|
+
? entry
|
|
350
|
+
: { ...entry, ts: fallbackHistoryTimestamp(entry) };
|
|
351
|
+
const normalizedEntry = {
|
|
352
|
+
...timestampedEntry,
|
|
353
|
+
event_class: classifyHistoryEvent(timestampedEntry),
|
|
354
|
+
};
|
|
355
|
+
await appendHistoryEntryWithEventIndex(historyPath, normalizedEntry, async () => {
|
|
356
|
+
await appendLineAtomic(historyPath, serializeHistoryLine(normalizedEntry, normalizedEntry));
|
|
357
|
+
});
|
|
328
358
|
await invalidateHistoryDriftCacheForPath(historyPath);
|
|
329
|
-
await updateHistoryEventIndexAfterAppend(historyPath, entry);
|
|
330
359
|
}
|
|
331
360
|
/** Public contract for test only, shared by SDK and presentation-layer consumers. */
|
|
332
361
|
export const _testOnly = {
|
|
@@ -334,4 +363,4 @@ export const _testOnly = {
|
|
|
334
363
|
isDefinedPointerPath,
|
|
335
364
|
};
|
|
336
365
|
//# sourceMappingURL=history.js.map
|
|
337
|
-
//# debugId=
|
|
366
|
+
//# debugId=1f78448d-a042-588a-84ce-369bd9ce8726
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* HistoryEntry format used by item mutations.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
8
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="4df21a17-43c0-5b63-adf3-657699e6a058")}catch(e){}}();
|
|
9
9
|
import fs from "node:fs/promises";
|
|
10
10
|
import path from "node:path";
|
|
11
11
|
import { readFileIfExists, writeFileAtomic } from "../fs/fs-utils.js";
|
|
@@ -13,6 +13,7 @@ import { acquireLock } from "../lock/lock.js";
|
|
|
13
13
|
import { EMPTY_CANONICAL_DOCUMENT, EXIT_CODE } from "../shared/constants.js";
|
|
14
14
|
import { PmCliError } from "../shared/errors.js";
|
|
15
15
|
import { stableStringify } from "../shared/serialization.js";
|
|
16
|
+
import { nowIso } from "../shared/time.js";
|
|
16
17
|
import { appendHistoryEntry, createHistoryEntry } from "./history.js";
|
|
17
18
|
import { readHistoryEntries } from "./read.js";
|
|
18
19
|
import { cloneEmptyReplayDocument, replayToItemDocument, tryApplyReplayPatch, verifyHistoryChain, } from "./replay.js";
|
|
@@ -153,7 +154,7 @@ async function appendWorkspaceHistoryChangeLocked(change) {
|
|
|
153
154
|
if (idempotentEntry) {
|
|
154
155
|
return { entry: idempotentEntry, historyPath };
|
|
155
156
|
}
|
|
156
|
-
const timestamp =
|
|
157
|
+
const timestamp = nowIso();
|
|
157
158
|
const beforeDocument = entries.length === 0
|
|
158
159
|
? EMPTY_CANONICAL_DOCUMENT
|
|
159
160
|
: replayWorkspaceEntries(entries);
|
|
@@ -222,7 +223,7 @@ export async function appendWorkspaceAuditEvent(options) {
|
|
|
222
223
|
? EMPTY_CANONICAL_DOCUMENT
|
|
223
224
|
: replayWorkspaceEntries(entries);
|
|
224
225
|
const entry = createHistoryEntry({
|
|
225
|
-
nowIso:
|
|
226
|
+
nowIso: nowIso(),
|
|
226
227
|
author: options.author,
|
|
227
228
|
op: options.op,
|
|
228
229
|
before: beforeDocument,
|
|
@@ -340,7 +341,7 @@ export async function reconcileWorkspaceJsonHistory(options) {
|
|
|
340
341
|
if (stableStringify(priorDocuments[documentPath]) === stableStringify(current)) {
|
|
341
342
|
return { changed: false, historyPath };
|
|
342
343
|
}
|
|
343
|
-
const timestamp =
|
|
344
|
+
const timestamp = nowIso();
|
|
344
345
|
const entry = createHistoryEntry({
|
|
345
346
|
nowIso: timestamp,
|
|
346
347
|
author: options.author,
|
|
@@ -393,7 +394,7 @@ export async function restoreWorkspaceJsonFromHistory(options) {
|
|
|
393
394
|
changed: false,
|
|
394
395
|
};
|
|
395
396
|
const beforeDocument = replayWorkspaceEntries(entries);
|
|
396
|
-
const timestamp =
|
|
397
|
+
const timestamp = nowIso();
|
|
397
398
|
const entry = createHistoryEntry({
|
|
398
399
|
nowIso: timestamp,
|
|
399
400
|
author: options.author,
|
|
@@ -430,4 +431,4 @@ export async function restoreWorkspaceJsonFromHistory(options) {
|
|
|
430
431
|
}
|
|
431
432
|
}
|
|
432
433
|
//# sourceMappingURL=workspace-history.js.map
|
|
433
|
-
//# debugId=
|
|
434
|
+
//# debugId=4df21a17-43c0-5b63-adf3-657699e6a058
|
package/dist/core/lock/lock.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ interface LockInfo {
|
|
|
2
2
|
id: string;
|
|
3
3
|
pid: number;
|
|
4
4
|
owner: string;
|
|
5
|
+
token?: string;
|
|
5
6
|
created_at: string;
|
|
6
7
|
ttl_seconds: number;
|
|
7
8
|
}
|
|
@@ -14,14 +15,31 @@ interface StaleLockRemovalResult {
|
|
|
14
15
|
shouldRetryCreate: boolean;
|
|
15
16
|
staleRemovalCounted: boolean;
|
|
16
17
|
}
|
|
18
|
+
/** Stable operating-system identity for a process when the host exposes one. */
|
|
19
|
+
export interface ProcessIdentity {
|
|
20
|
+
/** Operating-system process identifier captured with the owner record. */
|
|
21
|
+
pid: number;
|
|
22
|
+
/** Host process-start coordinate that distinguishes reuse of the same PID. */
|
|
23
|
+
process_start_identity?: string;
|
|
24
|
+
}
|
|
17
25
|
declare function parseLockInfo(raw: string): LockReadResult;
|
|
18
|
-
declare function readLockInfo(lockPath: string): Promise<LockReadResult>;
|
|
26
|
+
declare function readLockInfo(lockPath: string, emitReadHook?: boolean): Promise<LockReadResult>;
|
|
19
27
|
declare function isErrno(error: unknown, code: string): boolean;
|
|
20
|
-
declare function buildLockPayload(id: string, owner: string, ttlSeconds: number): LockInfo;
|
|
28
|
+
declare function buildLockPayload(id: string, owner: string, ttlSeconds: number, token?: string): LockInfo;
|
|
21
29
|
declare function isStaleLock(info: LockInfo | null, ttlSeconds: number): boolean;
|
|
22
30
|
declare function lockOwnerSuffix(info: LockInfo | null): string;
|
|
23
31
|
/** Resolves the effective bounded wait budget for a contended lock: the PM_LOCK_WAIT_MS environment override wins when it parses as a non-negative integer, then the caller-provided budget (settings `locks.wait_ms`), then 0 (fail-fast, the pre-wait behavior). */
|
|
24
32
|
declare function resolveLockWaitMs(waitMs: number | undefined): number;
|
|
33
|
+
declare function parseLinuxProcessStartIdentity(raw: string): string | null;
|
|
34
|
+
/** Read the host process-start coordinate used to distinguish PID reuse. */
|
|
35
|
+
export declare function readProcessStartIdentity(pid: number): Promise<string | null>;
|
|
36
|
+
/** Capture the current PID plus a host process-start coordinate when available. */
|
|
37
|
+
export declare function captureProcessIdentity(pid?: number): Promise<ProcessIdentity>;
|
|
38
|
+
/**
|
|
39
|
+
* Verify that a captured process owner still exists, with a bounded grace
|
|
40
|
+
* period when the host cannot expose a reusable-PID-safe start coordinate.
|
|
41
|
+
*/
|
|
42
|
+
export declare function isProcessIdentityAlive(identity: ProcessIdentity, unverifiedAgeMs: number, maxUnverifiedAgeMs: number): Promise<boolean>;
|
|
25
43
|
declare function acquireStaleCleanupGate(lockPath: string, _id: string): Promise<(() => Promise<void>) | null>;
|
|
26
44
|
declare function removeConfirmedStaleLock(params: {
|
|
27
45
|
lockPath: string;
|
|
@@ -43,6 +61,8 @@ export declare const _testOnly: {
|
|
|
43
61
|
isStaleLock: typeof isStaleLock;
|
|
44
62
|
lockOwnerSuffix: typeof lockOwnerSuffix;
|
|
45
63
|
resolveLockWaitMs: typeof resolveLockWaitMs;
|
|
64
|
+
parseLinuxProcessStartIdentity: typeof parseLinuxProcessStartIdentity;
|
|
65
|
+
readProcessStartIdentity: typeof readProcessStartIdentity;
|
|
46
66
|
acquireStaleCleanupGate: typeof acquireStaleCleanupGate;
|
|
47
67
|
removeConfirmedStaleLock: typeof removeConfirmedStaleLock;
|
|
48
68
|
};
|
package/dist/core/lock/lock.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Coordinates tracker lock ownership and cleanup for Lock.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
7
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="7352375d-55f2-5751-934e-ba0cd5c358d5")}catch(e){}}();
|
|
8
8
|
import { isFileMissingError } from "../fs/fs-utils.js";
|
|
9
9
|
import fs from "node:fs/promises";
|
|
10
10
|
import path from "node:path";
|
|
@@ -36,12 +36,15 @@ function parseLockInfo(raw) {
|
|
|
36
36
|
const id = candidate.id;
|
|
37
37
|
const pid = candidate.pid;
|
|
38
38
|
const owner = candidate.owner;
|
|
39
|
+
const token = candidate.token;
|
|
39
40
|
const createdAt = candidate.created_at;
|
|
40
41
|
const ttlSeconds = candidate.ttl_seconds;
|
|
41
42
|
if (typeof id !== "string" ||
|
|
42
43
|
typeof pid !== "number" ||
|
|
43
44
|
!Number.isFinite(pid) ||
|
|
44
45
|
typeof owner !== "string" ||
|
|
46
|
+
(token !== undefined &&
|
|
47
|
+
(typeof token !== "string" || token.trim().length === 0)) ||
|
|
45
48
|
typeof createdAt !== "string" ||
|
|
46
49
|
typeof ttlSeconds !== "number" ||
|
|
47
50
|
!Number.isFinite(ttlSeconds)) {
|
|
@@ -55,19 +58,22 @@ function parseLockInfo(raw) {
|
|
|
55
58
|
id,
|
|
56
59
|
pid,
|
|
57
60
|
owner,
|
|
61
|
+
...(typeof token === "string" ? { token } : {}),
|
|
58
62
|
created_at: createdAt,
|
|
59
63
|
ttl_seconds: ttlSeconds,
|
|
60
64
|
},
|
|
61
65
|
warnings: [],
|
|
62
66
|
};
|
|
63
67
|
}
|
|
64
|
-
async function readLockInfo(lockPath) {
|
|
68
|
+
async function readLockInfo(lockPath, emitReadHook = true) {
|
|
65
69
|
try {
|
|
66
70
|
const raw = await fs.readFile(lockPath, "utf8");
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
+
if (emitReadHook) {
|
|
72
|
+
await runActiveOnReadHooks({
|
|
73
|
+
path: lockPath,
|
|
74
|
+
scope: "project",
|
|
75
|
+
});
|
|
76
|
+
}
|
|
71
77
|
return parseLockInfo(raw);
|
|
72
78
|
}
|
|
73
79
|
catch (error) {
|
|
@@ -96,20 +102,21 @@ async function emitLockWriteHook(lockPath, op) {
|
|
|
96
102
|
op,
|
|
97
103
|
});
|
|
98
104
|
}
|
|
99
|
-
function buildLockPayload(id, owner, ttlSeconds) {
|
|
105
|
+
function buildLockPayload(id, owner, ttlSeconds, token = randomUUID()) {
|
|
100
106
|
return {
|
|
101
107
|
id,
|
|
102
108
|
pid: process.pid,
|
|
103
109
|
owner,
|
|
110
|
+
token,
|
|
104
111
|
created_at: nowIso(),
|
|
105
112
|
ttl_seconds: ttlSeconds,
|
|
106
113
|
};
|
|
107
114
|
}
|
|
108
|
-
async function createLockFile(lockPath, id, owner, ttlSeconds) {
|
|
115
|
+
async function createLockFile(lockPath, id, owner, ttlSeconds, token) {
|
|
109
116
|
await fs.mkdir(path.dirname(lockPath), { recursive: true });
|
|
110
117
|
const handle = await fs.open(lockPath, "wx");
|
|
111
118
|
try {
|
|
112
|
-
await handle.writeFile(`${JSON.stringify(buildLockPayload(id, owner, ttlSeconds), null, 2)}\n`, "utf8");
|
|
119
|
+
await handle.writeFile(`${JSON.stringify(buildLockPayload(id, owner, ttlSeconds, token), null, 2)}\n`, "utf8");
|
|
113
120
|
}
|
|
114
121
|
finally {
|
|
115
122
|
await handle.close();
|
|
@@ -127,6 +134,41 @@ async function unlinkLockWithHook(lockPath, op) {
|
|
|
127
134
|
return false;
|
|
128
135
|
}
|
|
129
136
|
}
|
|
137
|
+
async function releaseOwnedLock(lockPath, id, owner, token) {
|
|
138
|
+
const startedAtMs = Date.now();
|
|
139
|
+
let backoffMs = LOCK_WAIT_INITIAL_DELAY_MS;
|
|
140
|
+
for (;;) {
|
|
141
|
+
const releaseCleanupGate = await acquireStaleCleanupGate(lockPath, id);
|
|
142
|
+
if (releaseCleanupGate !== null) {
|
|
143
|
+
try {
|
|
144
|
+
const current = await readLockInfo(lockPath, false);
|
|
145
|
+
if (isOwnedLock(current.info, id, owner, token)) {
|
|
146
|
+
await unlinkLockWithHook(lockPath, "lock:release");
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
finally {
|
|
150
|
+
await releaseCleanupGate();
|
|
151
|
+
}
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const current = await readLockInfo(lockPath, false);
|
|
155
|
+
if (!isOwnedLock(current.info, id, owner, token)) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
const elapsedMs = Date.now() - startedAtMs;
|
|
159
|
+
if (elapsedMs >= LOCK_RELEASE_GATE_WAIT_MS) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
await sleepWithJitter(Math.min(backoffMs, LOCK_RELEASE_GATE_WAIT_MS - elapsedMs));
|
|
163
|
+
backoffMs = Math.min(backoffMs * 2, LOCK_WAIT_MAX_DELAY_MS);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function isOwnedLock(info, id, owner, token) {
|
|
167
|
+
return (info?.id === id &&
|
|
168
|
+
info.pid === process.pid &&
|
|
169
|
+
info.owner === owner &&
|
|
170
|
+
info.token === token);
|
|
171
|
+
}
|
|
130
172
|
function isStaleLock(info, ttlSeconds) {
|
|
131
173
|
const createdAtMs = info?.created_at
|
|
132
174
|
? Date.parse(info.created_at)
|
|
@@ -146,8 +188,8 @@ const MAX_STALE_LOCK_REMOVALS = 3;
|
|
|
146
188
|
const STALE_CLEANUP_GATE_SUFFIX = ".stale-cleanup";
|
|
147
189
|
const STALE_CLEANUP_GATE_OWNER_FILE = "owner.json";
|
|
148
190
|
const STALE_CLEANUP_GATE_STALE_MS = 10_000;
|
|
149
|
-
|
|
150
|
-
const
|
|
191
|
+
const LOCK_RELEASE_GATE_WAIT_MS = STALE_CLEANUP_GATE_STALE_MS + LOCK_WAIT_MAX_DELAY_MS;
|
|
192
|
+
const STALE_CLEANUP_GATE_MAX_UNVERIFIED_MS = 60 * 60_000;
|
|
151
193
|
function parseNonNegativeIntegerWaitMs(value) {
|
|
152
194
|
if (typeof value === "string") {
|
|
153
195
|
const trimmed = value.trim();
|
|
@@ -220,14 +262,24 @@ function parseStaleCleanupGateOwner(raw) {
|
|
|
220
262
|
const candidate = parsed;
|
|
221
263
|
const pid = candidate.pid;
|
|
222
264
|
const token = candidate.token;
|
|
265
|
+
const processStartIdentity = candidate.process_start_identity;
|
|
223
266
|
if (typeof pid !== "number" ||
|
|
224
267
|
!Number.isInteger(pid) ||
|
|
225
268
|
pid <= 0 ||
|
|
226
269
|
typeof token !== "string" ||
|
|
227
|
-
token.length === 0
|
|
270
|
+
token.length === 0 ||
|
|
271
|
+
(processStartIdentity !== undefined &&
|
|
272
|
+
(typeof processStartIdentity !== "string" ||
|
|
273
|
+
!/^\d+$/u.test(processStartIdentity)))) {
|
|
228
274
|
return null;
|
|
229
275
|
}
|
|
230
|
-
return {
|
|
276
|
+
return {
|
|
277
|
+
pid,
|
|
278
|
+
token,
|
|
279
|
+
...(typeof processStartIdentity === "string"
|
|
280
|
+
? { process_start_identity: processStartIdentity }
|
|
281
|
+
: {}),
|
|
282
|
+
};
|
|
231
283
|
}
|
|
232
284
|
async function readStaleCleanupGateOwner(gatePath) {
|
|
233
285
|
try {
|
|
@@ -238,6 +290,8 @@ async function readStaleCleanupGateOwner(gatePath) {
|
|
|
238
290
|
}
|
|
239
291
|
}
|
|
240
292
|
function isProcessAlive(pid) {
|
|
293
|
+
if (!Number.isSafeInteger(pid) || pid <= 0)
|
|
294
|
+
return false;
|
|
241
295
|
try {
|
|
242
296
|
process.kill(pid, 0);
|
|
243
297
|
return true;
|
|
@@ -249,6 +303,49 @@ function isProcessAlive(pid) {
|
|
|
249
303
|
return true;
|
|
250
304
|
}
|
|
251
305
|
}
|
|
306
|
+
function parseLinuxProcessStartIdentity(raw) {
|
|
307
|
+
const closeParenIndex = raw.lastIndexOf(")");
|
|
308
|
+
if (closeParenIndex < 0)
|
|
309
|
+
return null;
|
|
310
|
+
const startTime = raw
|
|
311
|
+
.slice(closeParenIndex + 2)
|
|
312
|
+
.trim()
|
|
313
|
+
.split(/\s+/u)[19];
|
|
314
|
+
return startTime !== undefined && /^\d+$/u.test(startTime) ? startTime : null;
|
|
315
|
+
}
|
|
316
|
+
/** Read the host process-start coordinate used to distinguish PID reuse. */
|
|
317
|
+
export async function readProcessStartIdentity(pid) {
|
|
318
|
+
try {
|
|
319
|
+
return parseLinuxProcessStartIdentity(await fs.readFile(`/proc/${pid}/stat`, "utf8"));
|
|
320
|
+
}
|
|
321
|
+
catch {
|
|
322
|
+
return null;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
/** Capture the current PID plus a host process-start coordinate when available. */
|
|
326
|
+
export async function captureProcessIdentity(pid = process.pid) {
|
|
327
|
+
const processStartIdentity = await readProcessStartIdentity(pid);
|
|
328
|
+
return {
|
|
329
|
+
pid,
|
|
330
|
+
...(processStartIdentity === null
|
|
331
|
+
? {}
|
|
332
|
+
: { process_start_identity: processStartIdentity }),
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Verify that a captured process owner still exists, with a bounded grace
|
|
337
|
+
* period when the host cannot expose a reusable-PID-safe start coordinate.
|
|
338
|
+
*/
|
|
339
|
+
export async function isProcessIdentityAlive(identity, unverifiedAgeMs, maxUnverifiedAgeMs) {
|
|
340
|
+
if (!isProcessAlive(identity.pid))
|
|
341
|
+
return false;
|
|
342
|
+
const currentStartIdentity = await readProcessStartIdentity(identity.pid);
|
|
343
|
+
if (identity.process_start_identity !== undefined &&
|
|
344
|
+
currentStartIdentity !== null) {
|
|
345
|
+
return currentStartIdentity === identity.process_start_identity;
|
|
346
|
+
}
|
|
347
|
+
return unverifiedAgeMs <= maxUnverifiedAgeMs;
|
|
348
|
+
}
|
|
252
349
|
async function removeStaleCleanupGateDirectory(gatePath) {
|
|
253
350
|
try {
|
|
254
351
|
await fs.rm(gatePath, { recursive: true, force: true });
|
|
@@ -275,7 +372,10 @@ async function tryCreateStaleCleanupGate(gatePath) {
|
|
|
275
372
|
}
|
|
276
373
|
return null;
|
|
277
374
|
}
|
|
278
|
-
const owner = {
|
|
375
|
+
const owner = {
|
|
376
|
+
...(await captureProcessIdentity()),
|
|
377
|
+
token: randomUUID(),
|
|
378
|
+
};
|
|
279
379
|
try {
|
|
280
380
|
await fs.writeFile(path.join(gatePath, STALE_CLEANUP_GATE_OWNER_FILE), `${JSON.stringify(owner)}\n`, "utf8");
|
|
281
381
|
}
|
|
@@ -299,8 +399,7 @@ async function removeExpiredStaleCleanupGate(gatePath) {
|
|
|
299
399
|
}
|
|
300
400
|
const owner = await readStaleCleanupGateOwner(gatePath);
|
|
301
401
|
if (owner !== null &&
|
|
302
|
-
|
|
303
|
-
gateAgeMs <= STALE_CLEANUP_GATE_MAX_ACTIVE_MS) {
|
|
402
|
+
(await isProcessIdentityAlive(owner, gateAgeMs, STALE_CLEANUP_GATE_MAX_UNVERIFIED_MS))) {
|
|
304
403
|
return false;
|
|
305
404
|
}
|
|
306
405
|
return removeStaleCleanupGateDirectory(gatePath);
|
|
@@ -369,6 +468,8 @@ export const _testOnly = {
|
|
|
369
468
|
isStaleLock,
|
|
370
469
|
lockOwnerSuffix,
|
|
371
470
|
resolveLockWaitMs,
|
|
471
|
+
parseLinuxProcessStartIdentity,
|
|
472
|
+
readProcessStartIdentity,
|
|
372
473
|
acquireStaleCleanupGate,
|
|
373
474
|
removeConfirmedStaleLock,
|
|
374
475
|
};
|
|
@@ -400,11 +501,12 @@ export async function acquireLock(pmRoot, id, ttlSeconds, owner, force = false,
|
|
|
400
501
|
const startedAtMs = Date.now();
|
|
401
502
|
let staleRemovals = 0;
|
|
402
503
|
let backoffMs = LOCK_WAIT_INITIAL_DELAY_MS;
|
|
504
|
+
const token = randomUUID();
|
|
403
505
|
for (;;) {
|
|
404
506
|
try {
|
|
405
|
-
await createLockFile(lockPath, id, owner, ttlSeconds);
|
|
507
|
+
await createLockFile(lockPath, id, owner, ttlSeconds, token);
|
|
406
508
|
return async () => {
|
|
407
|
-
await
|
|
509
|
+
await releaseOwnedLock(lockPath, id, owner, token);
|
|
408
510
|
await runActiveServiceOverride("lock_release", {
|
|
409
511
|
pm_root: pmRoot,
|
|
410
512
|
id,
|
|
@@ -447,4 +549,4 @@ export async function acquireLock(pmRoot, id, ttlSeconds, owner, force = false,
|
|
|
447
549
|
}
|
|
448
550
|
}
|
|
449
551
|
//# sourceMappingURL=lock.js.map
|
|
450
|
-
//# debugId=
|
|
552
|
+
//# debugId=7352375d-55f2-5751-934e-ba0cd5c358d5
|
|
@@ -4,13 +4,14 @@
|
|
|
4
4
|
* Formats compact human and machine output for Output.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
7
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="fa89762b-915f-5ef0-a091-f05338c11683")}catch(e){}}();
|
|
8
8
|
import { getActiveCommandContext, runActiveCommandOverride, runActiveRendererOverride, runActiveServiceOverrideSync, setActiveCommandResult, } from "../extensions/index.js";
|
|
9
9
|
import { EXIT_CODE } from "../shared/constants.js";
|
|
10
10
|
import { isHostOutputSuppressed } from "./output-control.js";
|
|
11
11
|
import { projectMutationResult } from "./mutation-projection.js";
|
|
12
12
|
import { attachReadOutputContracts } from "../../sdk/context-intent-contracts.js";
|
|
13
13
|
import { attachOutputTokenAccounting } from "../../sdk/output-token-accounting.js";
|
|
14
|
+
import { propagateContextUsageServingReceipt } from "../../sdk/context-usage.js";
|
|
14
15
|
import { isReadOutputBudgetExceeded, resolveReadOutputEncoding, } from "../../sdk/read-output-contracts.js";
|
|
15
16
|
import { encode as encodeToon } from "@toon-format/toon";
|
|
16
17
|
const DECLARED_PROCESS_EXIT_CODES = new Set(Object.values(EXIT_CODE));
|
|
@@ -19,6 +20,18 @@ let streamErrorHandlersInstalled = false;
|
|
|
19
20
|
function isPlainObject(value) {
|
|
20
21
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21
22
|
}
|
|
23
|
+
function setActiveCommandResultOmitted(source) {
|
|
24
|
+
const omitted = { read_output: { result_omitted: true } };
|
|
25
|
+
propagateContextUsageServingReceipt(source, omitted);
|
|
26
|
+
setActiveCommandResult(omitted);
|
|
27
|
+
}
|
|
28
|
+
function setActiveCommandDeliveryResult(result, receiptSource, structuredDeliveryPreserved) {
|
|
29
|
+
if (structuredDeliveryPreserved) {
|
|
30
|
+
setActiveCommandResult(result);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
setActiveCommandResultOmitted(receiptSource);
|
|
34
|
+
}
|
|
22
35
|
function shouldUseNativeOutput(result) {
|
|
23
36
|
return isPlainObject(result) && result[NATIVE_OUTPUT_MARKER] === true;
|
|
24
37
|
}
|
|
@@ -346,11 +359,13 @@ function resolveOutputService(effectiveResult, nativeOutput, options, format) {
|
|
|
346
359
|
rendered: serviceOverride.result.endsWith("\n")
|
|
347
360
|
? serviceOverride.result
|
|
348
361
|
: `${serviceOverride.result}\n`,
|
|
362
|
+
structuredDeliveryPreserved: false,
|
|
349
363
|
};
|
|
350
364
|
}
|
|
351
365
|
return {
|
|
352
366
|
result: serviceOverride.handled ? serviceOverride.result : effectiveResult,
|
|
353
367
|
rendered: null,
|
|
368
|
+
structuredDeliveryPreserved: !serviceOverride.handled || isPlainObject(serviceOverride.result),
|
|
354
369
|
};
|
|
355
370
|
}
|
|
356
371
|
/** Formats a command result after command-level output ownership is resolved. */
|
|
@@ -382,9 +397,12 @@ function formatEffectiveOutput(effectiveResult, nativeOutput, options) {
|
|
|
382
397
|
commandOptions: resolvedCommandOptions,
|
|
383
398
|
};
|
|
384
399
|
const service = resolveOutputService(effectiveResult, nativeOutput, effectiveOptions, format);
|
|
385
|
-
if (service.rendered !== null)
|
|
400
|
+
if (service.rendered !== null) {
|
|
401
|
+
setActiveCommandResultOmitted(effectiveResult);
|
|
386
402
|
return service.rendered;
|
|
403
|
+
}
|
|
387
404
|
const outputResult = service.result;
|
|
405
|
+
propagateContextUsageServingReceipt(effectiveResult, outputResult);
|
|
388
406
|
const projectedOutputResult = command === "test"
|
|
389
407
|
? projectLinkedTestEvidence(outputResult, options.lean === true)
|
|
390
408
|
: outputResult;
|
|
@@ -392,6 +410,7 @@ function formatEffectiveOutput(effectiveResult, nativeOutput, options) {
|
|
|
392
410
|
if (isReadOutputBudgetExceeded(intentOutputResult)) {
|
|
393
411
|
process.exitCode ||= EXIT_CODE.USAGE;
|
|
394
412
|
}
|
|
413
|
+
let { structuredDeliveryPreserved } = service;
|
|
395
414
|
const renderResolvedOutput = (value) => {
|
|
396
415
|
if (format === "toon") {
|
|
397
416
|
const markdownDefault = renderDefaultMarkdownResult(value);
|
|
@@ -402,6 +421,7 @@ function formatEffectiveOutput(effectiveResult, nativeOutput, options) {
|
|
|
402
421
|
? { rendered: null }
|
|
403
422
|
: runActiveRendererOverride(format, value);
|
|
404
423
|
if (rendererOverride.rendered !== null) {
|
|
424
|
+
structuredDeliveryPreserved = false;
|
|
405
425
|
return rendererOverride.rendered.endsWith("\n")
|
|
406
426
|
? rendererOverride.rendered
|
|
407
427
|
: `${rendererOverride.rendered}\n`;
|
|
@@ -414,7 +434,9 @@ function formatEffectiveOutput(effectiveResult, nativeOutput, options) {
|
|
|
414
434
|
const accountedOutputResult = options.tokenAccounting === true
|
|
415
435
|
? attachOutputTokenAccounting(intentOutputResult, renderResolvedOutput)
|
|
416
436
|
: intentOutputResult;
|
|
417
|
-
|
|
437
|
+
const rendered = renderResolvedOutput(accountedOutputResult);
|
|
438
|
+
setActiveCommandDeliveryResult(accountedOutputResult, effectiveResult, options.quiet !== true && structuredDeliveryPreserved);
|
|
439
|
+
return rendered;
|
|
418
440
|
}
|
|
419
441
|
/** Implements format output for the public runtime surface of this module. */
|
|
420
442
|
export function formatOutput(result, options) {
|
|
@@ -427,9 +449,11 @@ export function formatOutput(result, options) {
|
|
|
427
449
|
? suppressedOutput.result
|
|
428
450
|
: stripNativeOutputMarker(commandOverride.result);
|
|
429
451
|
setActiveCommandResult(effectiveResult);
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
452
|
+
if (suppressedOutput) {
|
|
453
|
+
setActiveCommandResultOmitted(effectiveResult);
|
|
454
|
+
return "";
|
|
455
|
+
}
|
|
456
|
+
return formatEffectiveOutput(effectiveResult, nativeOutput, options);
|
|
433
457
|
}
|
|
434
458
|
/** Implements print result for the public runtime surface of this module. */
|
|
435
459
|
export function printResult(result, options) {
|
|
@@ -468,4 +492,4 @@ export const outputTestOnly = {
|
|
|
468
492
|
renderToonValue,
|
|
469
493
|
};
|
|
470
494
|
//# sourceMappingURL=output.js.map
|
|
471
|
-
//# debugId=
|
|
495
|
+
//# debugId=fa89762b-915f-5ef0-a091-f05338c11683
|
|
@@ -4,6 +4,8 @@ export declare function nowIso(): string;
|
|
|
4
4
|
export declare function isTimestampLiteral(input: string): boolean;
|
|
5
5
|
/** Return whether a string is a calendar-valid RFC 3339 date-time. */
|
|
6
6
|
export declare function isRfc3339DateTime(input: string): boolean;
|
|
7
|
+
/** Return whether a value is a calendar-valid RFC 3339 date-time whose fractional seconds carry no sub-millisecond information. */
|
|
8
|
+
export declare function isMillisecondPrecisionRfc3339DateTime(input: string): boolean;
|
|
7
9
|
/** Implements compare timestamp strings for the public runtime surface of this module. */
|
|
8
10
|
export declare function compareTimestampStrings(left: string, right: string): number;
|
|
9
11
|
/** Timestamp-bearing record accepted by shared inclusive bound filtering. */
|
package/dist/core/shared/time.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Provides shared primitives and utilities for Time.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
7
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="fb1102d4-1beb-5de8-87e6-af2efebafe39")}catch(e){}}();
|
|
8
8
|
import { PmCliError } from "./errors.js";
|
|
9
9
|
import { evictOldestMemoEntries } from "./memo.js";
|
|
10
10
|
import { EXIT_CODE } from "./constants.js";
|
|
@@ -48,6 +48,12 @@ export function isRfc3339DateTime(input) {
|
|
|
48
48
|
(offsetHourRaw === undefined || Number(offsetHourRaw) <= 23) &&
|
|
49
49
|
(offsetMinuteRaw === undefined || Number(offsetMinuteRaw) <= 59));
|
|
50
50
|
}
|
|
51
|
+
/** Return whether a value is a calendar-valid RFC 3339 date-time whose fractional seconds carry no sub-millisecond information. */
|
|
52
|
+
export function isMillisecondPrecisionRfc3339DateTime(input) {
|
|
53
|
+
const fraction = /\.(\d+)(?:Z|[+-]\d{2}:\d{2})$/iu.exec(input)?.[1];
|
|
54
|
+
return (isRfc3339DateTime(input) &&
|
|
55
|
+
(fraction === undefined || /^\d{0,3}0*$/u.test(fraction)));
|
|
56
|
+
}
|
|
51
57
|
/**
|
|
52
58
|
* Memoized `Date.parse` for {@link compareTimestampStrings}. Sort comparators call it
|
|
53
59
|
* O(n log n) times over a corpus whose timestamp strings repeat heavily, and
|
|
@@ -298,4 +304,4 @@ export const _testOnly = {
|
|
|
298
304
|
isWhitespaceCharacter,
|
|
299
305
|
};
|
|
300
306
|
//# sourceMappingURL=time.js.map
|
|
301
|
-
//# debugId=
|
|
307
|
+
//# debugId=fb1102d4-1beb-5de8-87e6-af2efebafe39
|