deepline 0.3.65 → 0.3.67
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/bundling-sources/sdk/src/client.ts +2 -0
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/sdk/src/types.ts +2 -0
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +89 -2
- package/dist/bundling-sources/shared_libs/play-runtime/log-provenance.ts +80 -3
- package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +3 -0
- package/dist/cli/index.js +278 -155
- package/dist/cli/index.mjs +190 -67
- package/dist/index.d.mts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -1199,7 +1199,7 @@ var SDK_RELEASE = {
|
|
|
1199
1199
|
// available at toolResponse.rawV2 while toolResponse.raw and all declared
|
|
1200
1200
|
// getters keep their established compatibility behavior.
|
|
1201
1201
|
// 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
|
|
1202
|
-
version: "0.3.
|
|
1202
|
+
version: "0.3.67",
|
|
1203
1203
|
updateSummary: "Automatic CLI updates are now enabled by default. To opt out, run `deepline settings autoupdate off`; use `deepline settings autoupdate on` to re-enable updates or `deepline settings autoupdate pin <version>` to hold an exact release. This release also adds raw-v2 tool responses at toolResponse.rawV2 while preserving existing toolResponse.raw and declared getters.",
|
|
1204
1204
|
packageCapabilities: {
|
|
1205
1205
|
updatePreferences: 1
|
|
@@ -16820,9 +16820,7 @@ function readProvenanceTag(line) {
|
|
|
16820
16820
|
return { provenance: null, line };
|
|
16821
16821
|
}
|
|
16822
16822
|
const candidate = line.slice(PROVENANCE_PREFIX.length, end);
|
|
16823
|
-
const provenance = LOG_PROVENANCE_CLASSES.includes(
|
|
16824
|
-
candidate
|
|
16825
|
-
) ? candidate : null;
|
|
16823
|
+
const provenance = LOG_PROVENANCE_CLASSES.includes(candidate) ? candidate : null;
|
|
16826
16824
|
return { provenance, line: line.slice(end + 1) };
|
|
16827
16825
|
}
|
|
16828
16826
|
function classifyLegacyLogLine(line) {
|
|
@@ -17156,12 +17154,16 @@ var PLAY_RUN_RESERVED_BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
|
17156
17154
|
"--watch",
|
|
17157
17155
|
"--no-wait",
|
|
17158
17156
|
"--logs",
|
|
17157
|
+
"--debug",
|
|
17159
17158
|
"--full",
|
|
17160
17159
|
"--force",
|
|
17161
17160
|
"--force-tool-refresh",
|
|
17162
17161
|
"--open",
|
|
17163
17162
|
"--debug-map-latency"
|
|
17164
17163
|
]);
|
|
17164
|
+
function isBarePlayRunDebugFlag(args, index) {
|
|
17165
|
+
return args[index] === "--debug" && (args[index + 1] === void 0 || args[index + 1].startsWith("--"));
|
|
17166
|
+
}
|
|
17165
17167
|
async function pathExistsIncludingSymlink(path) {
|
|
17166
17168
|
try {
|
|
17167
17169
|
await lstat(path);
|
|
@@ -18214,12 +18216,20 @@ async function publishImportedPlayDependencies(client2, graph) {
|
|
|
18214
18216
|
};
|
|
18215
18217
|
await publishNode(graph.root.filePath, true);
|
|
18216
18218
|
}
|
|
18219
|
+
function timestampDate(value) {
|
|
18220
|
+
if (value === null || value === void 0 || value === "") return null;
|
|
18221
|
+
const normalized = typeof value === "string" && /^\d+$/.test(value.trim()) ? Number(value) : value;
|
|
18222
|
+
const date = new Date(normalized);
|
|
18223
|
+
return Number.isNaN(date.getTime()) ? null : date;
|
|
18224
|
+
}
|
|
18217
18225
|
function formatTimestamp(value) {
|
|
18218
|
-
|
|
18219
|
-
|
|
18220
|
-
if (Number.isNaN(date.getTime())) return "\u2014";
|
|
18226
|
+
const date = timestampDate(value);
|
|
18227
|
+
if (!date) return "\u2014";
|
|
18221
18228
|
return date.toISOString();
|
|
18222
18229
|
}
|
|
18230
|
+
function isoTimestamp(value) {
|
|
18231
|
+
return timestampDate(value)?.toISOString() ?? null;
|
|
18232
|
+
}
|
|
18223
18233
|
function formatRunLine(run) {
|
|
18224
18234
|
const credits = typeof run.billingTotalCredits === "number" && Number.isFinite(run.billingTotalCredits) ? `${formatCreditAmount(run.billingTotalCredits)} credits` : "\u2014";
|
|
18225
18235
|
return `${run.workflowId} ${run.status} ${formatTimestamp(run.startTime)} ${credits}`;
|
|
@@ -21119,12 +21129,13 @@ function parsePlayRunOptions(args) {
|
|
|
21119
21129
|
const watch = !args.includes("--no-wait");
|
|
21120
21130
|
let jsonOutput = watch ? args.includes("--json") : argsWantJson(args);
|
|
21121
21131
|
const fullJson = args.includes("--full");
|
|
21122
|
-
const
|
|
21132
|
+
const explicitDebugLogs = args.includes("--logs") || args.some((_, index) => isBarePlayRunDebugFlag(args, index));
|
|
21133
|
+
const emitLogs = !jsonOutput || explicitDebugLogs;
|
|
21123
21134
|
const force = args.includes("--force");
|
|
21124
21135
|
const forceToolRefresh = args.includes("--force-tool-refresh");
|
|
21125
21136
|
const open2 = args.includes("--open");
|
|
21126
21137
|
const debugMapLatency = args.includes("--debug-map-latency");
|
|
21127
|
-
const verboseLogs =
|
|
21138
|
+
const verboseLogs = explicitDebugLogs || debugMapLatency;
|
|
21128
21139
|
let waitTimeoutMs = null;
|
|
21129
21140
|
let maxConcurrentExternalCalls = null;
|
|
21130
21141
|
let maxConcurrentRows = null;
|
|
@@ -21255,6 +21266,20 @@ function parsePlayRunOptions(args) {
|
|
|
21255
21266
|
waitTimeoutMs = parsePositiveInteger3(args[++index], arg);
|
|
21256
21267
|
continue;
|
|
21257
21268
|
}
|
|
21269
|
+
if (arg === "--debug" && args[index + 1] && !args[index + 1].startsWith("--")) {
|
|
21270
|
+
input2 ??= {};
|
|
21271
|
+
setDottedInputValue(input2, "debug", parseInputFlagValue(args[++index]));
|
|
21272
|
+
continue;
|
|
21273
|
+
}
|
|
21274
|
+
if (arg.startsWith("--debug=")) {
|
|
21275
|
+
input2 ??= {};
|
|
21276
|
+
setDottedInputValue(
|
|
21277
|
+
input2,
|
|
21278
|
+
"debug",
|
|
21279
|
+
parseInputFlagValue(arg.slice("--debug=".length))
|
|
21280
|
+
);
|
|
21281
|
+
continue;
|
|
21282
|
+
}
|
|
21258
21283
|
if (PLAY_RUN_RESERVED_BOOLEAN_FLAGS.has(arg)) {
|
|
21259
21284
|
if (arg === "--watch") {
|
|
21260
21285
|
continue;
|
|
@@ -22513,7 +22538,7 @@ async function handlePlayRun(args, hooks) {
|
|
|
22513
22538
|
function parseRunIdPositional(args, usage) {
|
|
22514
22539
|
for (let index = 0; index < args.length; index += 1) {
|
|
22515
22540
|
const arg = args[index];
|
|
22516
|
-
if (arg === "--json" || arg === "--full" || arg === "--input" || arg === "--logs" || arg === "--compact" || arg === "--log-failed" || arg === "--failed" || arg === "--limit") {
|
|
22541
|
+
if (arg === "--json" || arg === "--full" || arg === "--input" || arg === "--logs" || arg === "--debug" || arg === "--compact" || arg === "--log-failed" || arg === "--failed" || arg === "--limit") {
|
|
22517
22542
|
if (arg === "--limit" && args[index + 1]) {
|
|
22518
22543
|
index += 1;
|
|
22519
22544
|
}
|
|
@@ -22630,13 +22655,22 @@ async function handleRunsList(args) {
|
|
|
22630
22655
|
...offset !== void 0 ? { offset } : {}
|
|
22631
22656
|
})).map((run) => ({
|
|
22632
22657
|
runId: run.workflowId,
|
|
22658
|
+
// `workflowId` is the legacy SDK name for the same public Deepline run
|
|
22659
|
+
// identity. Keep it during the compatibility window, but never label the
|
|
22660
|
+
// duplicate as a Temporal/runtime id.
|
|
22633
22661
|
workflowId: run.workflowId,
|
|
22634
|
-
|
|
22662
|
+
// Retain the runtime identifier for existing JSON consumers. It is not a
|
|
22663
|
+
// stable Deepline run id; `runId` above is the canonical public id.
|
|
22664
|
+
temporalRunId: run.runId ?? null,
|
|
22635
22665
|
parentRunId: run.parentRunId ?? null,
|
|
22636
22666
|
rootRunId: run.rootRunId ?? null,
|
|
22637
22667
|
status: String(run.status ?? "").toLowerCase(),
|
|
22668
|
+
createdAt: run.createdAt ?? null,
|
|
22669
|
+
createdAtIso: isoTimestamp(run.createdAt),
|
|
22638
22670
|
startedAt: run.startTime ?? run.startedAt ?? null,
|
|
22671
|
+
startedAtIso: isoTimestamp(run.startTime ?? run.startedAt ?? null),
|
|
22639
22672
|
finishedAt: run.closeTime ?? run.finishedAt ?? null,
|
|
22673
|
+
finishedAtIso: isoTimestamp(run.closeTime ?? run.finishedAt ?? null),
|
|
22640
22674
|
executionTime: run.executionTime,
|
|
22641
22675
|
billingTotalCredits: run.billingTotalCredits,
|
|
22642
22676
|
billingMaxCreditsPerRun: run.billingMaxCreditsPerRun,
|
|
@@ -22644,9 +22678,19 @@ async function handleRunsList(args) {
|
|
|
22644
22678
|
}));
|
|
22645
22679
|
const lines = runs.length === 0 ? [
|
|
22646
22680
|
playName ? `No runs found for ${playName}.` : `No runs found for status ${statusFilter}.`
|
|
22647
|
-
] : runs.map(
|
|
22648
|
-
|
|
22649
|
-
|
|
22681
|
+
] : runs.map((run) => {
|
|
22682
|
+
const lines2 = [
|
|
22683
|
+
`${run.runId} ${run.status}`,
|
|
22684
|
+
` created: ${formatTimestamp(run.createdAt)}`,
|
|
22685
|
+
` started: ${formatTimestamp(run.startedAt)}`,
|
|
22686
|
+
` finished: ${formatTimestamp(run.finishedAt)}`,
|
|
22687
|
+
` credits: ${typeof run.billingTotalCredits === "number" && Number.isFinite(run.billingTotalCredits) ? formatCreditAmount(run.billingTotalCredits) : "\u2014"}`,
|
|
22688
|
+
` inspect: deepline runs get ${run.runId} --json`
|
|
22689
|
+
];
|
|
22690
|
+
if (run.parentRunId) lines2.push(` parent: ${run.parentRunId}`);
|
|
22691
|
+
if (run.rootRunId) lines2.push(` root: ${run.rootRunId}`);
|
|
22692
|
+
return lines2.join("\n");
|
|
22693
|
+
});
|
|
22650
22694
|
printCommandEnvelope(
|
|
22651
22695
|
{
|
|
22652
22696
|
runs,
|
|
@@ -22661,7 +22705,7 @@ async function handleRunsList(args) {
|
|
|
22661
22705
|
return 0;
|
|
22662
22706
|
}
|
|
22663
22707
|
async function handleRunTail(args) {
|
|
22664
|
-
const usage = "Usage: deepline runs tail <run-id> [--json | --jsonl] [--compact]";
|
|
22708
|
+
const usage = "Usage: deepline runs tail <run-id> [--json | --jsonl] [--compact] [--debug]";
|
|
22665
22709
|
let runId;
|
|
22666
22710
|
try {
|
|
22667
22711
|
runId = parseRunIdPositional(args, usage);
|
|
@@ -22677,7 +22721,7 @@ async function handleRunTail(args) {
|
|
|
22677
22721
|
);
|
|
22678
22722
|
return 1;
|
|
22679
22723
|
}
|
|
22680
|
-
if (arg.startsWith("--") && arg !== "--json" && arg !== "--jsonl" && arg !== "--compact") {
|
|
22724
|
+
if (arg.startsWith("--") && arg !== "--json" && arg !== "--jsonl" && arg !== "--compact" && arg !== "--logs" && arg !== "--debug") {
|
|
22681
22725
|
console.error(`${arg} is not supported by deepline runs tail.`);
|
|
22682
22726
|
return 1;
|
|
22683
22727
|
}
|
|
@@ -22686,6 +22730,13 @@ async function handleRunTail(args) {
|
|
|
22686
22730
|
console.error("--json and --jsonl cannot be used together.");
|
|
22687
22731
|
return 1;
|
|
22688
22732
|
}
|
|
22733
|
+
const debug = args.includes("--logs") || args.includes("--debug");
|
|
22734
|
+
if (args.includes("--jsonl") && debug) {
|
|
22735
|
+
console.error(
|
|
22736
|
+
"--debug is redundant with --jsonl: JSON Lines already includes every canonical live event."
|
|
22737
|
+
);
|
|
22738
|
+
return 1;
|
|
22739
|
+
}
|
|
22689
22740
|
const client2 = new DeeplineClient();
|
|
22690
22741
|
const jsonLines = args.includes("--jsonl");
|
|
22691
22742
|
const jsonOutput = !jsonLines && argsWantJson(args);
|
|
@@ -22695,7 +22746,8 @@ async function handleRunTail(args) {
|
|
|
22695
22746
|
emittedRunnerStarted: false,
|
|
22696
22747
|
lastProgressSignature: null,
|
|
22697
22748
|
lastProgressHeartbeatAt: 0,
|
|
22698
|
-
lastStatusHeartbeatAt: 0
|
|
22749
|
+
lastStatusHeartbeatAt: 0,
|
|
22750
|
+
verbose: debug
|
|
22699
22751
|
};
|
|
22700
22752
|
const status = await client2.runs.tail(runId, {
|
|
22701
22753
|
onEvent: jsonLines ? (event) => {
|
|
@@ -22707,7 +22759,20 @@ async function handleRunTail(args) {
|
|
|
22707
22759
|
})}
|
|
22708
22760
|
`
|
|
22709
22761
|
);
|
|
22710
|
-
} : compact
|
|
22762
|
+
} : compact || debug ? (event) => {
|
|
22763
|
+
if (debug) {
|
|
22764
|
+
for (const line of getLogLinesFromLiveEvent(event)) {
|
|
22765
|
+
const formatted = formatPlayLogLine(
|
|
22766
|
+
line,
|
|
22767
|
+
void 0,
|
|
22768
|
+
compactState
|
|
22769
|
+
);
|
|
22770
|
+
if (formatted) process.stderr.write(`${formatted}
|
|
22771
|
+
`);
|
|
22772
|
+
compactState.lastLogIndex += 1;
|
|
22773
|
+
}
|
|
22774
|
+
}
|
|
22775
|
+
if (!compact || jsonOutput) return;
|
|
22711
22776
|
const transition = getStepTransitionLineFromLiveEvent(
|
|
22712
22777
|
event,
|
|
22713
22778
|
compactState
|
|
@@ -22730,7 +22795,7 @@ async function handleRunTail(args) {
|
|
|
22730
22795
|
}
|
|
22731
22796
|
} : void 0,
|
|
22732
22797
|
// Human mode only: in --json mode emit nothing non-protocol.
|
|
22733
|
-
onReconnect: jsonOutput ? void 0 : ({ reason }) => {
|
|
22798
|
+
onReconnect: jsonOutput && !debug ? void 0 : ({ reason }) => {
|
|
22734
22799
|
process.stderr.write(
|
|
22735
22800
|
`[runs tail] stream ended without a terminal status; reconnecting to run ${runId} (${reason})
|
|
22736
22801
|
`
|
|
@@ -22746,7 +22811,7 @@ async function handleRunTail(args) {
|
|
|
22746
22811
|
return status.status === "failed" ? 1 : 0;
|
|
22747
22812
|
}
|
|
22748
22813
|
async function handleRunLogs(args) {
|
|
22749
|
-
const usage = "Usage: deepline runs logs <run-id> [--limit 200] [--failed] [--out run.log] [--json]";
|
|
22814
|
+
const usage = "Usage: deepline runs logs <run-id> [--limit 200] [--failed] [--out run.log] [--json] [--debug]";
|
|
22750
22815
|
let runId;
|
|
22751
22816
|
try {
|
|
22752
22817
|
runId = parseRunIdPositional(args, usage);
|
|
@@ -22759,12 +22824,20 @@ async function handleRunLogs(args) {
|
|
|
22759
22824
|
const failed = args.includes("--failed");
|
|
22760
22825
|
for (let index = 0; index < args.length; index += 1) {
|
|
22761
22826
|
const arg = args[index];
|
|
22827
|
+
if (arg === "--debug" || arg === "--logs" || arg === "--json" || arg === "--failed") {
|
|
22828
|
+
continue;
|
|
22829
|
+
}
|
|
22762
22830
|
if (arg === "--limit" && args[index + 1]) {
|
|
22763
22831
|
limit = parsePositiveInteger3(args[++index], "--limit");
|
|
22764
22832
|
continue;
|
|
22765
22833
|
}
|
|
22766
22834
|
if (arg === "--out" && args[index + 1]) {
|
|
22767
22835
|
outPath = resolve11(args[++index]);
|
|
22836
|
+
continue;
|
|
22837
|
+
}
|
|
22838
|
+
if (arg.startsWith("--")) {
|
|
22839
|
+
console.error(`${arg} is not supported by deepline runs logs.`);
|
|
22840
|
+
return 1;
|
|
22768
22841
|
}
|
|
22769
22842
|
}
|
|
22770
22843
|
if (failed && outPath) {
|
|
@@ -24237,9 +24310,9 @@ Examples:
|
|
|
24237
24310
|
).option("--watch", "Compatibility alias; run waits by default").option("--wait", "Compatibility alias; run waits by default").option("--no-wait", "Start the run and return immediately").option(
|
|
24238
24311
|
"--run-id-file <path>",
|
|
24239
24312
|
"Atomically write the accepted run id to a new JSON file"
|
|
24240
|
-
).option(
|
|
24241
|
-
"--
|
|
24242
|
-
"
|
|
24313
|
+
).option("--logs", "Compatibility alias for --debug").option(
|
|
24314
|
+
"--debug [value]",
|
|
24315
|
+
"Stream complete customer-safe runtime logs when passed without a value; otherwise pass input.debug"
|
|
24243
24316
|
).option("--tail-timeout-ms <ms>", "Timeout while watching the run stream").option("--force", "Start a fresh run graph").option(
|
|
24244
24317
|
"--force-tool-refresh",
|
|
24245
24318
|
"Refresh completed tool receipts; may repeat billed provider calls"
|
|
@@ -24288,6 +24361,7 @@ Pass-through input flags:
|
|
|
24288
24361
|
...options.runIdFile ? ["--run-id-file", options.runIdFile] : [],
|
|
24289
24362
|
...options.watch || options.wait ? ["--watch"] : [],
|
|
24290
24363
|
...options.logs ? ["--logs"] : [],
|
|
24364
|
+
...options.debug === true ? ["--debug"] : typeof options.debug === "string" ? ["--debug", options.debug] : [],
|
|
24291
24365
|
...options.tailTimeoutMs ? ["--tail-timeout-ms", options.tailTimeoutMs] : [],
|
|
24292
24366
|
...options.force ? ["--force"] : [],
|
|
24293
24367
|
...options.forceToolRefresh ? ["--force-tool-refresh"] : [],
|
|
@@ -24705,11 +24779,13 @@ Notes:
|
|
|
24705
24779
|
logs for persisted log history. In human output, --compact prints deduplicated
|
|
24706
24780
|
step transitions and progress instead of the full event stream. --json emits
|
|
24707
24781
|
one terminal package. --jsonl emits canonical live events as JSON Lines and
|
|
24708
|
-
ends with the same compact package shape as runs get --json.
|
|
24782
|
+
ends with the same compact package shape as runs get --json. Use --debug
|
|
24783
|
+
(or legacy --logs) to also print customer-safe runtime log lines to stderr.
|
|
24709
24784
|
|
|
24710
24785
|
Examples:
|
|
24711
24786
|
deepline runs tail play/my-play/run/20260501t000000-000
|
|
24712
24787
|
deepline runs tail play/my-play/run/20260501t000000-000 --compact
|
|
24788
|
+
deepline runs tail play/my-play/run/20260501t000000-000 --debug
|
|
24713
24789
|
deepline runs tail play/my-play/run/20260501t000000-000 --jsonl
|
|
24714
24790
|
`
|
|
24715
24791
|
).option("--json", "Emit one terminal JSON package after the run completes").option(
|
|
@@ -24718,12 +24794,17 @@ Examples:
|
|
|
24718
24794
|
).option(
|
|
24719
24795
|
"--compact",
|
|
24720
24796
|
"Show deduplicated human step transitions and progress"
|
|
24797
|
+
).option("--logs", "Compatibility alias for --debug").option(
|
|
24798
|
+
"--debug",
|
|
24799
|
+
"Print customer-safe runtime log lines to stderr while tailing"
|
|
24721
24800
|
).action(async (runId, options) => {
|
|
24722
24801
|
process.exitCode = await handleRunTail([
|
|
24723
24802
|
runId,
|
|
24724
24803
|
...options.json ? ["--json"] : [],
|
|
24725
24804
|
...options.jsonl ? ["--jsonl"] : [],
|
|
24726
|
-
...options.compact ? ["--compact"] : []
|
|
24805
|
+
...options.compact ? ["--compact"] : [],
|
|
24806
|
+
...options.logs ? ["--logs"] : [],
|
|
24807
|
+
...options.debug ? ["--debug"] : []
|
|
24727
24808
|
]);
|
|
24728
24809
|
});
|
|
24729
24810
|
runs.command("logs <runId>").description("Fetch persisted logs for a play run.").addHelpText(
|
|
@@ -24731,24 +24812,31 @@ Examples:
|
|
|
24731
24812
|
`
|
|
24732
24813
|
Notes:
|
|
24733
24814
|
Prints a bounded recent log preview by default. Use --out to write the full
|
|
24734
|
-
persisted log stream to a local file.
|
|
24815
|
+
persisted log stream to a local file. --debug (or legacy --logs) is accepted
|
|
24816
|
+
for script parity; this command already returns the unfiltered durable stream.
|
|
24735
24817
|
|
|
24736
24818
|
Examples:
|
|
24737
24819
|
deepline runs logs play/my-play/run/20260501t000000-000
|
|
24738
24820
|
deepline runs logs play/my-play/run/20260501t000000-000 --limit 500
|
|
24739
24821
|
deepline runs logs play/my-play/run/20260501t000000-000 --failed --json
|
|
24822
|
+
deepline runs logs play/my-play/run/20260501t000000-000 --debug
|
|
24740
24823
|
deepline runs logs play/my-play/run/20260501t000000-000 --out run.log --json
|
|
24741
24824
|
`
|
|
24742
24825
|
).option(
|
|
24743
24826
|
"--limit <count>",
|
|
24744
24827
|
"Maximum recent log lines to print without --out",
|
|
24745
24828
|
"200"
|
|
24746
|
-
).option("--out <path>", "Write the full persisted log stream to a file").option("--failed", "Show the bounded terminal-failure log window").option("--
|
|
24829
|
+
).option("--out <path>", "Write the full persisted log stream to a file").option("--failed", "Show the bounded terminal-failure log window").option("--logs", "Compatibility alias for --debug").option(
|
|
24830
|
+
"--debug",
|
|
24831
|
+
"Explicitly request the same persisted log view (no provenance filtering)"
|
|
24832
|
+
).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (runId, options) => {
|
|
24747
24833
|
process.exitCode = await handleRunLogs([
|
|
24748
24834
|
runId,
|
|
24749
24835
|
...options.limit ? ["--limit", options.limit] : [],
|
|
24750
24836
|
...options.out ? ["--out", options.out] : [],
|
|
24751
24837
|
...options.failed ? ["--failed"] : [],
|
|
24838
|
+
...options.logs ? ["--logs"] : [],
|
|
24839
|
+
...options.debug ? ["--debug"] : [],
|
|
24752
24840
|
...options.json ? ["--json"] : []
|
|
24753
24841
|
]);
|
|
24754
24842
|
});
|
|
@@ -30408,10 +30496,12 @@ function registerEnrichCommand(program) {
|
|
|
30408
30496
|
}
|
|
30409
30497
|
|
|
30410
30498
|
// src/cli/commands/feedback.ts
|
|
30499
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
30411
30500
|
async function handleFeedback(text, options) {
|
|
30501
|
+
const message = resolveFeedbackText(text, options.file);
|
|
30412
30502
|
const { http } = getAuthedHttpClient();
|
|
30413
30503
|
const response = await http.post("/api/v2/cli/feedback", {
|
|
30414
|
-
text,
|
|
30504
|
+
text: message,
|
|
30415
30505
|
requested: options.requested === true,
|
|
30416
30506
|
environment: collectLocalEnvInfo(),
|
|
30417
30507
|
...options.command ? { command: options.command } : {},
|
|
@@ -30429,6 +30519,35 @@ async function handleFeedback(text, options) {
|
|
|
30429
30519
|
{ json: options.json }
|
|
30430
30520
|
);
|
|
30431
30521
|
}
|
|
30522
|
+
function resolveFeedbackText(text, file, readFile6 = (path) => readFileSync9(path, "utf8")) {
|
|
30523
|
+
if (text !== void 0 && file !== void 0) {
|
|
30524
|
+
throw new Error(
|
|
30525
|
+
"Pass feedback text positionally or with --file, not both."
|
|
30526
|
+
);
|
|
30527
|
+
}
|
|
30528
|
+
let value;
|
|
30529
|
+
if (file !== void 0) {
|
|
30530
|
+
try {
|
|
30531
|
+
value = readFile6(file === "-" ? 0 : file);
|
|
30532
|
+
} catch (error) {
|
|
30533
|
+
throw new Error(
|
|
30534
|
+
`Could not read feedback ${file === "-" ? "from stdin" : `file ${file}`}: ${error instanceof Error ? error.message : String(error)}`
|
|
30535
|
+
);
|
|
30536
|
+
}
|
|
30537
|
+
} else if (text !== void 0) {
|
|
30538
|
+
value = text;
|
|
30539
|
+
} else if (!process.stdin.isTTY) {
|
|
30540
|
+
value = readFile6(0);
|
|
30541
|
+
} else {
|
|
30542
|
+
throw new Error(
|
|
30543
|
+
"Feedback text is required. Pass it positionally, use --file <path>, or pipe stdin."
|
|
30544
|
+
);
|
|
30545
|
+
}
|
|
30546
|
+
if (!value.trim()) {
|
|
30547
|
+
throw new Error("Feedback text must not be empty.");
|
|
30548
|
+
}
|
|
30549
|
+
return value;
|
|
30550
|
+
}
|
|
30432
30551
|
function registerFeedbackCommands(program) {
|
|
30433
30552
|
const feedback = program.command("feedback").description("Submit CLI feedback to Deepline.").addHelpText(
|
|
30434
30553
|
"after",
|
|
@@ -30448,10 +30567,12 @@ Examples:
|
|
|
30448
30567
|
`
|
|
30449
30568
|
Examples:
|
|
30450
30569
|
deepline feedback send "tools search returned stale results" --json
|
|
30570
|
+
deepline feedback send --file incident.md --requested --json
|
|
30571
|
+
cat incident.md | deepline feedback send --requested --json
|
|
30451
30572
|
deepline feedback send "tools search returned stale results" --requested --json
|
|
30452
30573
|
deepline feedback send "plays run failed after upload" --command "deepline plays run my.play.ts --watch"
|
|
30453
30574
|
`
|
|
30454
|
-
).argument("
|
|
30575
|
+
).argument("[text]", "Feedback text").option("--file <path>", "Read feedback text from a file, or - for stdin").option("--command <command>", "Command that reproduced the issue").option("--payload <payload>", "JSON or plain-text payload for the repro").option(
|
|
30455
30576
|
"--requested",
|
|
30456
30577
|
"Mark the report as explicitly requested by the user"
|
|
30457
30578
|
).option("--json", "Emit JSON output").action(handleFeedback);
|
|
@@ -30462,7 +30583,7 @@ import {
|
|
|
30462
30583
|
existsSync as existsSync10,
|
|
30463
30584
|
mkdirSync as mkdirSync8,
|
|
30464
30585
|
readdirSync as readdirSync3,
|
|
30465
|
-
readFileSync as
|
|
30586
|
+
readFileSync as readFileSync10,
|
|
30466
30587
|
statSync as statSync4,
|
|
30467
30588
|
writeFileSync as writeFileSync11
|
|
30468
30589
|
} from "fs";
|
|
@@ -30600,7 +30721,7 @@ function sessionIdFromCodexFilePath(filePath) {
|
|
|
30600
30721
|
}
|
|
30601
30722
|
function readCodexSessionId(filePath) {
|
|
30602
30723
|
try {
|
|
30603
|
-
for (const line of normalizedJsonLines(
|
|
30724
|
+
for (const line of normalizedJsonLines(readFileSync10(filePath)).slice(
|
|
30604
30725
|
0,
|
|
30605
30726
|
20
|
|
30606
30727
|
)) {
|
|
@@ -30919,7 +31040,7 @@ async function handleSessionsSend(options) {
|
|
|
30919
31040
|
throw new Error(`File not found: ${options.file}`);
|
|
30920
31041
|
}
|
|
30921
31042
|
const response2 = await uploadPayload("/api/v2/cli/send-session", {
|
|
30922
|
-
file:
|
|
31043
|
+
file: readFileSync10(filePath).toString("base64"),
|
|
30923
31044
|
filename: basename5(filePath)
|
|
30924
31045
|
});
|
|
30925
31046
|
printCommandEnvelope(
|
|
@@ -30949,7 +31070,7 @@ async function handleSessionsSend(options) {
|
|
|
30949
31070
|
agent: options.agent
|
|
30950
31071
|
});
|
|
30951
31072
|
const built = targets.map((target) => {
|
|
30952
|
-
const upload = buildSessionUploadContent(
|
|
31073
|
+
const upload = buildSessionUploadContent(readFileSync10(target.filePath));
|
|
30953
31074
|
return { ...target, ...upload };
|
|
30954
31075
|
});
|
|
30955
31076
|
if (built.some((session) => session.needsChunking)) {
|
|
@@ -31033,8 +31154,8 @@ function loadViewerAssets() {
|
|
|
31033
31154
|
const jsPath = join12(root, "viewer.js");
|
|
31034
31155
|
if (!existsSync10(cssPath) || !existsSync10(jsPath)) continue;
|
|
31035
31156
|
return {
|
|
31036
|
-
css:
|
|
31037
|
-
js:
|
|
31157
|
+
css: readFileSync10(cssPath, "utf8"),
|
|
31158
|
+
js: readFileSync10(jsPath, "utf8")
|
|
31038
31159
|
};
|
|
31039
31160
|
} catch {
|
|
31040
31161
|
continue;
|
|
@@ -31072,7 +31193,7 @@ async function handleSessionsRender(options) {
|
|
|
31072
31193
|
const sessions = targets.map((target) => ({
|
|
31073
31194
|
label: target.label,
|
|
31074
31195
|
events: parsePreparedEvents(
|
|
31075
|
-
prepareSessionBuffer(
|
|
31196
|
+
prepareSessionBuffer(readFileSync10(target.filePath))
|
|
31076
31197
|
)
|
|
31077
31198
|
}));
|
|
31078
31199
|
const { css, js } = loadViewerAssets();
|
|
@@ -31306,7 +31427,7 @@ Examples:
|
|
|
31306
31427
|
|
|
31307
31428
|
// src/cli/commands/monitors.ts
|
|
31308
31429
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
31309
|
-
import { readFileSync as
|
|
31430
|
+
import { readFileSync as readFileSync11, writeFileSync as writeFileSync12 } from "fs";
|
|
31310
31431
|
import { resolve as resolve14 } from "path";
|
|
31311
31432
|
import { createInterface } from "readline/promises";
|
|
31312
31433
|
|
|
@@ -31746,8 +31867,8 @@ function parseJsonObjectArg(raw, argLabel) {
|
|
|
31746
31867
|
return parsed;
|
|
31747
31868
|
}
|
|
31748
31869
|
function resolveMonitorJsonBody(input2) {
|
|
31749
|
-
const readFile6 = input2.readFile ?? ((path) =>
|
|
31750
|
-
const readStdin = input2.readStdin ?? (() =>
|
|
31870
|
+
const readFile6 = input2.readFile ?? ((path) => readFileSync11(path, "utf-8"));
|
|
31871
|
+
const readStdin = input2.readStdin ?? (() => readFileSync11(0, "utf-8"));
|
|
31751
31872
|
if (input2.positional !== void 0 && input2.file !== void 0) {
|
|
31752
31873
|
throw new MonitorsUsageError(
|
|
31753
31874
|
`Pass exactly one source for ${input2.argLabel}: the positional JSON or --file, not both.`
|
|
@@ -32144,6 +32265,7 @@ function renderDeployedListText(payload, requestedStatus) {
|
|
|
32144
32265
|
if (!entry || !key) continue;
|
|
32145
32266
|
const status = asString(entry.status);
|
|
32146
32267
|
const tool = asString(entry.tool);
|
|
32268
|
+
const monitorType = asString(entry.type);
|
|
32147
32269
|
const name = asString(entry.name);
|
|
32148
32270
|
const outputTable = asString(entry.output_table);
|
|
32149
32271
|
const webhookState = asString(entry.webhook_state);
|
|
@@ -32154,10 +32276,11 @@ function renderDeployedListText(payload, requestedStatus) {
|
|
|
32154
32276
|
lines.push(
|
|
32155
32277
|
` ${key}${status ? ` ${status}` : ""}${tool ? ` ${tool}` : ""}${name ? ` (${name})` : ""}`
|
|
32156
32278
|
);
|
|
32157
|
-
if (outputTable || webhookState || executionType || boundPlays !== void 0) {
|
|
32279
|
+
if (outputTable || monitorType || webhookState || executionType || boundPlays !== void 0) {
|
|
32158
32280
|
lines.push(
|
|
32159
32281
|
` ${[
|
|
32160
32282
|
outputTable ? `table: ${outputTable}` : null,
|
|
32283
|
+
monitorType ? `type: ${monitorType}` : null,
|
|
32161
32284
|
webhookState ? `webhook: ${webhookState}` : null,
|
|
32162
32285
|
executionType ? `execution: ${executionType}` : null,
|
|
32163
32286
|
boundPlays !== void 0 ? `bound Plays: ${boundPlays}` : null
|
|
@@ -32982,6 +33105,7 @@ function renderMonitorGet(payload) {
|
|
|
32982
33105
|
const tool = asString(payload.tool);
|
|
32983
33106
|
if (!key || !tool) return void 0;
|
|
32984
33107
|
const status = asString(payload.status);
|
|
33108
|
+
const monitorType = asString(payload.type);
|
|
32985
33109
|
const hasLastReceivedEvent = "last_received_event" in payload;
|
|
32986
33110
|
const lastReceivedEvent = asString(payload.last_received_event);
|
|
32987
33111
|
const definition = asRecord2(payload.definition);
|
|
@@ -32999,8 +33123,9 @@ function renderMonitorGet(payload) {
|
|
|
32999
33123
|
const lines = [
|
|
33000
33124
|
`Monitor: ${key}`,
|
|
33001
33125
|
`Tool: ${tool}`,
|
|
33126
|
+
...monitorType ? [`Type: ${monitorType}`] : [],
|
|
33002
33127
|
...status ? [`Status: ${status}`] : [],
|
|
33003
|
-
...hasLastReceivedEvent ? [`
|
|
33128
|
+
...hasLastReceivedEvent ? [`Latest inbound event: ${lastReceivedEvent ?? "never"}`] : [],
|
|
33004
33129
|
...pricingLine ? [`Pricing: ${pricingLine}`] : [],
|
|
33005
33130
|
...nextRenewalAt ? [`Next renewal: ${nextRenewalAt}`] : []
|
|
33006
33131
|
];
|
|
@@ -33066,17 +33191,15 @@ function renderMonitorGet(payload) {
|
|
|
33066
33191
|
const name = asString(play.name) ?? "unnamed Play";
|
|
33067
33192
|
const listener = asString(play.listener_key);
|
|
33068
33193
|
const health = asRecord2(play.consumer_health);
|
|
33069
|
-
const
|
|
33194
|
+
const runStatus = asString(health?.last_run_status);
|
|
33070
33195
|
const lastDelivery = asFiniteNumber(health?.last_delivery_at);
|
|
33196
|
+
const runId = asString(health?.last_run_id);
|
|
33071
33197
|
const error = asString(health?.last_error);
|
|
33198
|
+
lines.push(` ${name}${listener ? ` (listener: ${listener})` : ""}:`);
|
|
33072
33199
|
lines.push(
|
|
33073
|
-
`
|
|
33200
|
+
` Latest delivered event: ${lastDelivery !== void 0 ? new Date(lastDelivery).toISOString() : "never"}`,
|
|
33201
|
+
` Latest consumer run: ${runId ?? "never"}${runStatus ? ` (${runStatus})` : ""}`
|
|
33074
33202
|
);
|
|
33075
|
-
if (lastDelivery !== void 0) {
|
|
33076
|
-
lines.push(
|
|
33077
|
-
` last delivery: ${new Date(lastDelivery).toISOString()}`
|
|
33078
|
-
);
|
|
33079
|
-
}
|
|
33080
33203
|
if (error) lines.push(` error: ${error}`);
|
|
33081
33204
|
}
|
|
33082
33205
|
}
|
|
@@ -34734,7 +34857,7 @@ import {
|
|
|
34734
34857
|
existsSync as existsSync14,
|
|
34735
34858
|
lstatSync as lstatSync2,
|
|
34736
34859
|
mkdirSync as mkdirSync11,
|
|
34737
|
-
readFileSync as
|
|
34860
|
+
readFileSync as readFileSync15,
|
|
34738
34861
|
realpathSync as realpathSync4,
|
|
34739
34862
|
writeFileSync as writeFileSync15
|
|
34740
34863
|
} from "fs";
|
|
@@ -34745,7 +34868,7 @@ import { dirname as dirname16, join as join16, resolve as resolve16 } from "path
|
|
|
34745
34868
|
import {
|
|
34746
34869
|
existsSync as existsSync11,
|
|
34747
34870
|
lstatSync,
|
|
34748
|
-
readFileSync as
|
|
34871
|
+
readFileSync as readFileSync12,
|
|
34749
34872
|
realpathSync as realpathSync3,
|
|
34750
34873
|
rmSync as rmSync4
|
|
34751
34874
|
} from "fs";
|
|
@@ -34761,7 +34884,7 @@ var nodeFileSystem = {
|
|
|
34761
34884
|
},
|
|
34762
34885
|
read(path) {
|
|
34763
34886
|
try {
|
|
34764
|
-
return
|
|
34887
|
+
return readFileSync12(path, "utf8");
|
|
34765
34888
|
} catch {
|
|
34766
34889
|
return "";
|
|
34767
34890
|
}
|
|
@@ -34871,7 +34994,7 @@ function isOwnedInstallerCommandPath(input2) {
|
|
|
34871
34994
|
|
|
34872
34995
|
// src/cli/commands/skills.ts
|
|
34873
34996
|
import { spawn as spawn3 } from "child_process";
|
|
34874
|
-
import { existsSync as existsSync13, mkdirSync as mkdirSync10, readFileSync as
|
|
34997
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync10, readFileSync as readFileSync14, writeFileSync as writeFileSync14 } from "fs";
|
|
34875
34998
|
import { homedir as homedir8 } from "os";
|
|
34876
34999
|
import { dirname as dirname15, join as join15 } from "path";
|
|
34877
35000
|
|
|
@@ -34986,7 +35109,7 @@ import { spawn as spawn2, spawnSync } from "child_process";
|
|
|
34986
35109
|
import {
|
|
34987
35110
|
existsSync as existsSync12,
|
|
34988
35111
|
mkdirSync as mkdirSync9,
|
|
34989
|
-
readFileSync as
|
|
35112
|
+
readFileSync as readFileSync13,
|
|
34990
35113
|
unlinkSync,
|
|
34991
35114
|
writeFileSync as writeFileSync13
|
|
34992
35115
|
} from "fs";
|
|
@@ -35350,7 +35473,7 @@ function hasMarkedSkillsSyncVersion(path, version) {
|
|
|
35350
35473
|
}
|
|
35351
35474
|
function readMarkedSkillsSyncVersion(path) {
|
|
35352
35475
|
try {
|
|
35353
|
-
return existsSync12(path) ?
|
|
35476
|
+
return existsSync12(path) ? readFileSync13(path, "utf-8").trim() : "";
|
|
35354
35477
|
} catch {
|
|
35355
35478
|
return "";
|
|
35356
35479
|
}
|
|
@@ -35838,7 +35961,7 @@ function isSkillsPlanCurrent(plan, state) {
|
|
|
35838
35961
|
}
|
|
35839
35962
|
function readSkillsInstallState(path) {
|
|
35840
35963
|
try {
|
|
35841
|
-
const parsed = JSON.parse(
|
|
35964
|
+
const parsed = JSON.parse(readFileSync14(path, "utf8"));
|
|
35842
35965
|
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
35843
35966
|
} catch {
|
|
35844
35967
|
return null;
|
|
@@ -36130,7 +36253,7 @@ function phasesFromLegacyStatus(status) {
|
|
|
36130
36253
|
function readSetupState(input2) {
|
|
36131
36254
|
try {
|
|
36132
36255
|
const parsed = JSON.parse(
|
|
36133
|
-
|
|
36256
|
+
readFileSync15(
|
|
36134
36257
|
setupStatePath(input2.baseUrl, input2.scope, input2.root),
|
|
36135
36258
|
"utf8"
|
|
36136
36259
|
)
|
|
@@ -36235,7 +36358,7 @@ function asRecord3(value) {
|
|
|
36235
36358
|
}
|
|
36236
36359
|
function safeRead(path) {
|
|
36237
36360
|
try {
|
|
36238
|
-
return
|
|
36361
|
+
return readFileSync15(path, "utf8");
|
|
36239
36362
|
} catch {
|
|
36240
36363
|
return "";
|
|
36241
36364
|
}
|
|
@@ -36999,7 +37122,7 @@ Examples:
|
|
|
36999
37122
|
import {
|
|
37000
37123
|
existsSync as existsSync15,
|
|
37001
37124
|
mkdirSync as mkdirSync12,
|
|
37002
|
-
readFileSync as
|
|
37125
|
+
readFileSync as readFileSync16,
|
|
37003
37126
|
renameSync,
|
|
37004
37127
|
rmSync as rmSync5,
|
|
37005
37128
|
writeFileSync as writeFileSync16
|
|
@@ -37046,7 +37169,7 @@ function readCliUpdatePreferences(homeDir2 = homedir10()) {
|
|
|
37046
37169
|
const path = cliUpdatePreferencesPath(homeDir2);
|
|
37047
37170
|
if (!existsSync15(path)) return defaultPreferences();
|
|
37048
37171
|
try {
|
|
37049
|
-
const parsed = JSON.parse(
|
|
37172
|
+
const parsed = JSON.parse(readFileSync16(path, "utf8"));
|
|
37050
37173
|
return {
|
|
37051
37174
|
schemaVersion: UPDATE_PREFERENCES_SCHEMA_VERSION,
|
|
37052
37175
|
autoUpdateEnabled: typeof parsed.autoUpdateEnabled === "boolean" ? parsed.autoUpdateEnabled : true,
|
|
@@ -37125,7 +37248,7 @@ import {
|
|
|
37125
37248
|
existsSync as existsSync17,
|
|
37126
37249
|
mkdirSync as mkdirSync13,
|
|
37127
37250
|
realpathSync as realpathSync5,
|
|
37128
|
-
readFileSync as
|
|
37251
|
+
readFileSync as readFileSync18,
|
|
37129
37252
|
renameSync as renameSync2,
|
|
37130
37253
|
rmSync as rmSync6,
|
|
37131
37254
|
unlinkSync as unlinkSync2,
|
|
@@ -37143,7 +37266,7 @@ import {
|
|
|
37143
37266
|
|
|
37144
37267
|
// src/cli/install-integrity.ts
|
|
37145
37268
|
import { createRequire } from "module";
|
|
37146
|
-
import { existsSync as existsSync16, readFileSync as
|
|
37269
|
+
import { existsSync as existsSync16, readFileSync as readFileSync17, statSync as statSync5 } from "fs";
|
|
37147
37270
|
import { isAbsolute as isAbsolute6, join as join18, relative as relative6, resolve as resolve17 } from "path";
|
|
37148
37271
|
var SDK_SIDECAR_CRITICAL_PACKAGE_FILES = [
|
|
37149
37272
|
"dist/cli/index.mjs",
|
|
@@ -37177,7 +37300,7 @@ function resolveContainedPath(root, value) {
|
|
|
37177
37300
|
return target;
|
|
37178
37301
|
}
|
|
37179
37302
|
function parseJson(path) {
|
|
37180
|
-
return JSON.parse(
|
|
37303
|
+
return JSON.parse(readFileSync17(path, "utf8"));
|
|
37181
37304
|
}
|
|
37182
37305
|
function isFile(path) {
|
|
37183
37306
|
try {
|
|
@@ -37387,7 +37510,7 @@ function publicNpmFallbackRegistryUrl(hostUrl) {
|
|
|
37387
37510
|
}
|
|
37388
37511
|
function readOptionalText(path) {
|
|
37389
37512
|
try {
|
|
37390
|
-
return
|
|
37513
|
+
return readFileSync18(path, "utf8").trim();
|
|
37391
37514
|
} catch {
|
|
37392
37515
|
return "";
|
|
37393
37516
|
}
|
|
@@ -37590,7 +37713,7 @@ function readAutoUpdateFailure(plan) {
|
|
|
37590
37713
|
if (!path) return null;
|
|
37591
37714
|
try {
|
|
37592
37715
|
const parsed = JSON.parse(
|
|
37593
|
-
|
|
37716
|
+
readFileSync18(path, "utf8")
|
|
37594
37717
|
);
|
|
37595
37718
|
if ((parsed.kind === "npm-global" || parsed.kind === "python-sidecar") && typeof parsed.packageSpec === "string" && typeof parsed.failedAt === "string" && typeof parsed.exitCode === "number" && typeof parsed.manualCommand === "string") {
|
|
37596
37719
|
return parsed;
|
|
@@ -37676,7 +37799,7 @@ function installedPackageVersion(versionDir) {
|
|
|
37676
37799
|
"package.json"
|
|
37677
37800
|
);
|
|
37678
37801
|
try {
|
|
37679
|
-
const parsed = JSON.parse(
|
|
37802
|
+
const parsed = JSON.parse(readFileSync18(packageJsonPath, "utf8"));
|
|
37680
37803
|
return typeof parsed.version === "string" ? safeVersionSegment(parsed.version) : "";
|
|
37681
37804
|
} catch {
|
|
37682
37805
|
return "";
|
|
@@ -38936,7 +39059,7 @@ import {
|
|
|
38936
39059
|
chmodSync,
|
|
38937
39060
|
existsSync as existsSync18,
|
|
38938
39061
|
mkdtempSync,
|
|
38939
|
-
readFileSync as
|
|
39062
|
+
readFileSync as readFileSync19,
|
|
38940
39063
|
writeFileSync as writeFileSync19
|
|
38941
39064
|
} from "fs";
|
|
38942
39065
|
import { tmpdir as tmpdir5 } from "os";
|
|
@@ -41065,7 +41188,7 @@ function readJsonArgument(raw, flagName) {
|
|
|
41065
41188
|
throw new Error(`Invalid ${flagName} value: empty @file path.`);
|
|
41066
41189
|
}
|
|
41067
41190
|
try {
|
|
41068
|
-
return
|
|
41191
|
+
return readFileSync19(resolveAtFilePath(filePath), "utf8").replace(
|
|
41069
41192
|
/^\uFEFF/,
|
|
41070
41193
|
""
|
|
41071
41194
|
);
|