haansi 0.1.34 → 0.1.36
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/README.md +1 -1
- package/dist/haansi.js +219 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ Requires Node.js >= 18.0.0.
|
|
|
23
23
|
|
|
24
24
|
## Authentication
|
|
25
25
|
|
|
26
|
-
The CLI uses `hsk_` tokens for authentication. Generate a token at https://app.haansi.co/settings/tokens.
|
|
26
|
+
The CLI uses `hsk_` tokens for authentication. Generate a token at https://app.haansi.co/settings/developer/tokens.
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
29
|
haansi init
|
package/dist/haansi.js
CHANGED
|
@@ -95,7 +95,7 @@ var require_package = __commonJS({
|
|
|
95
95
|
"package.json"(exports2, module2) {
|
|
96
96
|
module2.exports = {
|
|
97
97
|
name: "haansi",
|
|
98
|
-
version: "0.1.
|
|
98
|
+
version: "0.1.36",
|
|
99
99
|
description: "Haansi CLI - Session collector and MCP server for Claude Code & OpenAI Codex",
|
|
100
100
|
bin: {
|
|
101
101
|
haansi: "./dist/haansi.js"
|
|
@@ -285,7 +285,7 @@ async function init() {
|
|
|
285
285
|
"Tip: For interactive login, run `haansi auth login` to authenticate via browser.\n"
|
|
286
286
|
);
|
|
287
287
|
console.log(
|
|
288
|
-
`You can generate an API token at https://app.haansi.co/settings/tokens
|
|
288
|
+
`You can generate an API token at https://app.haansi.co/settings/developer/tokens
|
|
289
289
|
`
|
|
290
290
|
);
|
|
291
291
|
const token = await prompt("Paste your Haansi API token: ");
|
|
@@ -1730,7 +1730,7 @@ var init_scaling_metrics = __esm({
|
|
|
1730
1730
|
EMBEDDING_BACKLOG_ROWS: spec({
|
|
1731
1731
|
name: "haansi/embeddings/backlog_rows",
|
|
1732
1732
|
unit: "Count",
|
|
1733
|
-
description: "Rows
|
|
1733
|
+
description: "Rows needing TEI inference across the shared intelligence registry and platform docs search index.",
|
|
1734
1734
|
dimensions: ["environment", "workload"],
|
|
1735
1735
|
treatMissingData: "breaching",
|
|
1736
1736
|
missingDataRationale: "This is the metric that must be able to wake a fleet from zero, so it is published by the reconciler and never by an embedding worker. A worker-published version of it would read as zero precisely when the fleet is asleep with work pending \u2014 the failure this whole phase exists to remove."
|
|
@@ -1751,6 +1751,70 @@ var init_scaling_metrics = __esm({
|
|
|
1751
1751
|
treatMissingData: "breaching",
|
|
1752
1752
|
missingDataRationale: "Reconciler-published, so absence means the queue is unobserved rather than empty. This is the signal that sizes the worker fleet; reading silence as zero would scale it away with work queued."
|
|
1753
1753
|
}),
|
|
1754
|
+
EMBEDDING_CLAIMS_FAILED: spec({
|
|
1755
|
+
name: "haansi/embeddings/claims_failed",
|
|
1756
|
+
unit: "Count",
|
|
1757
|
+
description: "Embedding claims parked after exhausting attempts \u2014 poison, not inference demand.",
|
|
1758
|
+
dimensions: ["environment"],
|
|
1759
|
+
treatMissingData: "notBreaching",
|
|
1760
|
+
missingDataRationale: "Failed claims cannot drain without repair and must remain separate from ready work; folding them into backlog would scale inference against poison."
|
|
1761
|
+
}),
|
|
1762
|
+
EMBEDDING_CLAIM_TICK_LIVENESS: spec({
|
|
1763
|
+
name: "haansi/embeddings/claim_tick_liveness",
|
|
1764
|
+
unit: "Count",
|
|
1765
|
+
description: "Emitted by every embedding-claim timer callback, including healthy idle and skipped passes.",
|
|
1766
|
+
dimensions: ["environment"],
|
|
1767
|
+
treatMissingData: "breaching",
|
|
1768
|
+
missingDataRationale: "This is the consumer heartbeat. Queue and lease state cannot prove the claim loop itself is alive, and missing telemetry must not authorize scale-in or be diagnosed as an inference shortage."
|
|
1769
|
+
}),
|
|
1770
|
+
EMBEDDING_CLAIM_TICK_SKIPPED: spec({
|
|
1771
|
+
name: "haansi/embeddings/claim_tick_skipped_already_running",
|
|
1772
|
+
unit: "Count",
|
|
1773
|
+
description: "Emitted when the embedding-claim interval fires while its prior pass is unresolved.",
|
|
1774
|
+
dimensions: ["environment"],
|
|
1775
|
+
treatMissingData: "notBreaching",
|
|
1776
|
+
missingDataRationale: "This is event-shaped: no datapoint normally means no pass was skipped. The independent heartbeat detects a dead publisher."
|
|
1777
|
+
}),
|
|
1778
|
+
EMBEDDING_CLAIM_TICK_USEFUL_COMPLETIONS: spec({
|
|
1779
|
+
name: "haansi/embeddings/claim_tick_useful_completions",
|
|
1780
|
+
unit: "Count",
|
|
1781
|
+
description: "Embedding claims durably completed by a settled pass; explicit zero means no progress.",
|
|
1782
|
+
dimensions: ["environment"],
|
|
1783
|
+
treatMissingData: "breaching",
|
|
1784
|
+
missingDataRationale: "Useful means a vector was accepted and its claim completed, not a scan, claim, retry, or TEI request. A settled pass publishes zero, so absence means progress is unobserved."
|
|
1785
|
+
}),
|
|
1786
|
+
EMBEDDING_CLAIM_TICK_USEFUL_TOKENS: spec({
|
|
1787
|
+
name: "haansi/embeddings/claim_tick_useful_tokens",
|
|
1788
|
+
unit: "Count",
|
|
1789
|
+
description: "Conservatively estimated input tokens whose vectors and claims were durably committed by a settled pass.",
|
|
1790
|
+
dimensions: ["environment"],
|
|
1791
|
+
treatMissingData: "breaching",
|
|
1792
|
+
missingDataRationale: "Published as zero on every settled pass. This is useful throughput, not request activity; absence means progress is unobserved."
|
|
1793
|
+
}),
|
|
1794
|
+
EMBEDDING_CLAIM_TICK_INFERENCE_BATCHES: spec({
|
|
1795
|
+
name: "haansi/embeddings/claim_tick_inference_batches",
|
|
1796
|
+
unit: "Count",
|
|
1797
|
+
description: "Packed TEI requests attempted by a settled embedding-claim pass, including failed requests.",
|
|
1798
|
+
dimensions: ["environment"],
|
|
1799
|
+
treatMissingData: "notBreaching",
|
|
1800
|
+
missingDataRationale: "Calibration-only measurement; the claim-tick heartbeat owns publisher loss. A future controller must treat absence as unknown rather than filling it to zero work."
|
|
1801
|
+
}),
|
|
1802
|
+
EMBEDDING_CLAIM_TICK_INFERENCE_MILLISECONDS: spec({
|
|
1803
|
+
name: "haansi/embeddings/claim_tick_inference_milliseconds",
|
|
1804
|
+
unit: "Milliseconds",
|
|
1805
|
+
description: "Wall time spent awaiting packed TEI requests in a settled embedding-claim pass.",
|
|
1806
|
+
dimensions: ["environment"],
|
|
1807
|
+
treatMissingData: "notBreaching",
|
|
1808
|
+
missingDataRationale: "Calibration-only measurement; the claim-tick heartbeat owns publisher loss. A future controller must treat absence as unknown rather than filling it to zero service time."
|
|
1809
|
+
}),
|
|
1810
|
+
EMBEDDING_CLAIM_TICK_FAILURES: spec({
|
|
1811
|
+
name: "haansi/embeddings/claim_tick_failures",
|
|
1812
|
+
unit: "Count",
|
|
1813
|
+
description: "Whole embedding-claim passes that failed before settling.",
|
|
1814
|
+
dimensions: ["environment"],
|
|
1815
|
+
treatMissingData: "notBreaching",
|
|
1816
|
+
missingDataRationale: "Event-shaped diagnostic metric. No datapoint normally means no pass failed; the claim-tick heartbeat covers publisher loss."
|
|
1817
|
+
}),
|
|
1754
1818
|
REDACTION_CLAIMS_OLDEST_READY_SECONDS: spec({
|
|
1755
1819
|
name: "haansi/redaction/claims_oldest_ready_seconds",
|
|
1756
1820
|
unit: "Seconds",
|
|
@@ -1786,6 +1850,78 @@ var init_scaling_metrics = __esm({
|
|
|
1786
1850
|
treatMissingData: "notBreaching",
|
|
1787
1851
|
missingDataRationale: "CHANGED with the backlog scaling policy, and the original rationale is recorded here because it stopped being true. It read 'worker-published, so absence means the queue is unobserved rather than empty' \u2014 correct when redaction-tick emitted this, and false since backlog-reconciler took it over: the reconciler runs independently of both the worker and the Presidio pool, so the metric no longer disappears with the tier it sizes. The consumer also changed. This drives a SCALE-OUT policy, and 'breaching' there means growing the fleet whenever the publisher hiccups \u2014 scaling on the absence of information rather than on work. Publisher failure is covered by RECONCILER_LIVENESS, which is the alarm that should fire for it; this one should not double as a detector for its own input being missing."
|
|
1788
1852
|
}),
|
|
1853
|
+
REDACTION_TICK_LIVENESS: spec({
|
|
1854
|
+
name: "haansi/redaction/tick_liveness",
|
|
1855
|
+
unit: "Count",
|
|
1856
|
+
description: "Emitted by every redaction timer callback, including healthy idle and skipped passes.",
|
|
1857
|
+
dimensions: ["environment"],
|
|
1858
|
+
treatMissingData: "breaching",
|
|
1859
|
+
missingDataRationale: "This is the consumer heartbeat, separate from queue and lease state. A ready queue with no leases cannot distinguish an idle-but-live timer from a dead task without it, and absence must never authorize inference scale-out or worker scale-in."
|
|
1860
|
+
}),
|
|
1861
|
+
REDACTION_TICK_SKIPPED: spec({
|
|
1862
|
+
name: "haansi/redaction/tick_skipped_already_running",
|
|
1863
|
+
unit: "Count",
|
|
1864
|
+
description: "Emitted when the interval fires while the previous whole redaction pass is unresolved.",
|
|
1865
|
+
dimensions: ["environment"],
|
|
1866
|
+
treatMissingData: "notBreaching",
|
|
1867
|
+
missingDataRationale: "This is event-shaped: no datapoint normally means no interval was skipped. The independent tick heartbeat detects a dead publisher."
|
|
1868
|
+
}),
|
|
1869
|
+
REDACTION_TICK_PASS_AGE_SECONDS: spec({
|
|
1870
|
+
name: "haansi/redaction/tick_pass_age_seconds",
|
|
1871
|
+
unit: "Seconds",
|
|
1872
|
+
description: "Age of the currently unresolved redaction pass, or zero between passes.",
|
|
1873
|
+
dimensions: ["environment"],
|
|
1874
|
+
treatMissingData: "notBreaching",
|
|
1875
|
+
missingDataRationale: "Only a reported age above the threshold proves a pass is stalled. Silence is normal while service-pipeline is intentionally at zero; when the service is desired, its separately gated heartbeat alarm detects a missing publisher."
|
|
1876
|
+
}),
|
|
1877
|
+
REDACTION_TICK_USEFUL_COMPLETIONS: spec({
|
|
1878
|
+
name: "haansi/redaction/tick_useful_completions",
|
|
1879
|
+
unit: "Count",
|
|
1880
|
+
description: "Claims durably completed by a redaction pass. Explicit zero distinguishes no progress from no publisher.",
|
|
1881
|
+
dimensions: ["environment"],
|
|
1882
|
+
treatMissingData: "breaching",
|
|
1883
|
+
missingDataRationale: "The consumer publishes zero on every settled pass. Absence therefore means progress is unobserved and cannot authorize a control decision."
|
|
1884
|
+
}),
|
|
1885
|
+
REDACTION_TICK_USEFUL_BYTES: spec({
|
|
1886
|
+
name: "haansi/redaction/tick_useful_bytes",
|
|
1887
|
+
unit: "Bytes",
|
|
1888
|
+
description: "Source bytes whose redacted output and owner-guarded claim completion were durably committed by a settled pass.",
|
|
1889
|
+
dimensions: ["environment"],
|
|
1890
|
+
treatMissingData: "notBreaching",
|
|
1891
|
+
missingDataRationale: "Calibration-only measurement; the redaction heartbeat owns publisher loss. A future controller must treat absence as unknown rather than filling it to zero completed bytes."
|
|
1892
|
+
}),
|
|
1893
|
+
REDACTION_TICK_ANALYZED_UNITS: spec({
|
|
1894
|
+
name: "haansi/redaction/tick_analyzed_units",
|
|
1895
|
+
unit: "Count",
|
|
1896
|
+
description: "Non-reused redaction windows submitted to Presidio by a settled pass.",
|
|
1897
|
+
dimensions: ["environment"],
|
|
1898
|
+
treatMissingData: "notBreaching",
|
|
1899
|
+
missingDataRationale: "Calibration-only measurement; the redaction heartbeat owns publisher loss. A future controller must treat absence as unknown rather than filling it to zero analyzed work."
|
|
1900
|
+
}),
|
|
1901
|
+
REDACTION_TICK_ANALYZED_BYTES: spec({
|
|
1902
|
+
name: "haansi/redaction/tick_analyzed_bytes",
|
|
1903
|
+
unit: "Bytes",
|
|
1904
|
+
description: "Bytes in non-reused redaction windows submitted to Presidio by a settled pass.",
|
|
1905
|
+
dimensions: ["environment"],
|
|
1906
|
+
treatMissingData: "notBreaching",
|
|
1907
|
+
missingDataRationale: "Calibration-only measurement; the redaction heartbeat owns publisher loss. A future controller must treat absence as unknown rather than filling it to zero analyzed bytes."
|
|
1908
|
+
}),
|
|
1909
|
+
REDACTION_TICK_PRESIDIO_MILLISECONDS: spec({
|
|
1910
|
+
name: "haansi/redaction/tick_presidio_milliseconds",
|
|
1911
|
+
unit: "Milliseconds",
|
|
1912
|
+
description: "Wall time spent awaiting Presidio for non-reused windows in a settled redaction pass.",
|
|
1913
|
+
dimensions: ["environment"],
|
|
1914
|
+
treatMissingData: "notBreaching",
|
|
1915
|
+
missingDataRationale: "Calibration-only measurement; the redaction heartbeat owns publisher loss. A future controller must treat absence as unknown rather than filling it to zero service time."
|
|
1916
|
+
}),
|
|
1917
|
+
REDACTION_TICK_FAILURES: spec({
|
|
1918
|
+
name: "haansi/redaction/tick_failures",
|
|
1919
|
+
unit: "Count",
|
|
1920
|
+
description: "Whole redaction passes that failed before settling normally.",
|
|
1921
|
+
dimensions: ["environment"],
|
|
1922
|
+
treatMissingData: "notBreaching",
|
|
1923
|
+
missingDataRationale: "Event-shaped diagnostic metric. No datapoint normally means no pass failed; heartbeat covers publisher loss."
|
|
1924
|
+
}),
|
|
1789
1925
|
REDACTION_CLAIMS_ACTIVE_LEASES: spec({
|
|
1790
1926
|
name: "haansi/redaction/claims_active_leases",
|
|
1791
1927
|
unit: "Count",
|
|
@@ -1896,18 +2032,75 @@ var init_jsonl_scalars = __esm({
|
|
|
1896
2032
|
}
|
|
1897
2033
|
});
|
|
1898
2034
|
|
|
2035
|
+
// ../../packages/@company/pii/src/interval-index.ts
|
|
2036
|
+
function buildIntervalIndex(ranges) {
|
|
2037
|
+
if (!ranges || ranges.length === 0) return EMPTY_INTERVAL_INDEX;
|
|
2038
|
+
const sorted = ranges.filter((range) => range.end > range.start).sort((a, b) => a.start - b.start || a.end - b.end);
|
|
2039
|
+
if (sorted.length === 0) return EMPTY_INTERVAL_INDEX;
|
|
2040
|
+
const starts = [];
|
|
2041
|
+
const ends = [];
|
|
2042
|
+
let currentStart = sorted[0].start;
|
|
2043
|
+
let currentEnd = sorted[0].end;
|
|
2044
|
+
for (let i = 1; i < sorted.length; i += 1) {
|
|
2045
|
+
const range = sorted[i];
|
|
2046
|
+
if (range.start < currentEnd) {
|
|
2047
|
+
if (range.end > currentEnd) currentEnd = range.end;
|
|
2048
|
+
} else {
|
|
2049
|
+
starts.push(currentStart);
|
|
2050
|
+
ends.push(currentEnd);
|
|
2051
|
+
currentStart = range.start;
|
|
2052
|
+
currentEnd = range.end;
|
|
2053
|
+
}
|
|
2054
|
+
}
|
|
2055
|
+
starts.push(currentStart);
|
|
2056
|
+
ends.push(currentEnd);
|
|
2057
|
+
return { starts, ends };
|
|
2058
|
+
}
|
|
2059
|
+
function intervalIndexOverlaps(index, start, end) {
|
|
2060
|
+
if (end <= start) return false;
|
|
2061
|
+
const { starts, ends } = index;
|
|
2062
|
+
let low = 0;
|
|
2063
|
+
let high = starts.length - 1;
|
|
2064
|
+
let candidate = -1;
|
|
2065
|
+
while (low <= high) {
|
|
2066
|
+
const middle = low + high >>> 1;
|
|
2067
|
+
if (starts[middle] < end) {
|
|
2068
|
+
candidate = middle;
|
|
2069
|
+
low = middle + 1;
|
|
2070
|
+
} else {
|
|
2071
|
+
high = middle - 1;
|
|
2072
|
+
}
|
|
2073
|
+
}
|
|
2074
|
+
return candidate >= 0 && ends[candidate] > start;
|
|
2075
|
+
}
|
|
2076
|
+
var EMPTY_INTERVAL_INDEX;
|
|
2077
|
+
var init_interval_index = __esm({
|
|
2078
|
+
"../../packages/@company/pii/src/interval-index.ts"() {
|
|
2079
|
+
"use strict";
|
|
2080
|
+
EMPTY_INTERVAL_INDEX = { starts: [], ends: [] };
|
|
2081
|
+
}
|
|
2082
|
+
});
|
|
2083
|
+
|
|
1899
2084
|
// ../../packages/@company/pii/src/spans.ts
|
|
1900
2085
|
function applyPiiSpans(text, spans, replacement = (span) => span.replacement ?? `<${span.entityType}>`) {
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
2086
|
+
if (spans.length === 0) return text;
|
|
2087
|
+
const ordered = [...spans].sort((a, b) => a.start - b.start || b.end - a.end);
|
|
2088
|
+
const pieces = [];
|
|
2089
|
+
let cursor = 0;
|
|
2090
|
+
for (const span of ordered) {
|
|
2091
|
+
if (span.end <= cursor) continue;
|
|
2092
|
+
if (span.start > cursor) pieces.push(text.slice(cursor, span.start));
|
|
2093
|
+
pieces.push(replacement(span, text.slice(span.start, span.end)));
|
|
2094
|
+
cursor = span.end;
|
|
2095
|
+
}
|
|
2096
|
+
pieces.push(text.slice(cursor));
|
|
2097
|
+
return pieces.join("");
|
|
1906
2098
|
}
|
|
1907
2099
|
var init_spans = __esm({
|
|
1908
2100
|
"../../packages/@company/pii/src/spans.ts"() {
|
|
1909
2101
|
"use strict";
|
|
1910
2102
|
init_jsonl_scalars();
|
|
2103
|
+
init_interval_index();
|
|
1911
2104
|
}
|
|
1912
2105
|
});
|
|
1913
2106
|
|
|
@@ -21133,13 +21326,14 @@ var init_client = __esm({
|
|
|
21133
21326
|
});
|
|
21134
21327
|
|
|
21135
21328
|
// ../../packages/@company/db/src/org-context.ts
|
|
21136
|
-
var observability3;
|
|
21329
|
+
var observability3, DECRYPTING_CLIENT;
|
|
21137
21330
|
var init_org_context = __esm({
|
|
21138
21331
|
"../../packages/@company/db/src/org-context.ts"() {
|
|
21139
21332
|
"use strict";
|
|
21140
21333
|
init_src4();
|
|
21141
21334
|
init_src2();
|
|
21142
21335
|
observability3 = createObservabilityService("db-org-context");
|
|
21336
|
+
DECRYPTING_CLIENT = Symbol.for("haansi.db.decryptingClient");
|
|
21143
21337
|
}
|
|
21144
21338
|
});
|
|
21145
21339
|
|
|
@@ -22747,23 +22941,20 @@ function planLocalPathRedaction(text, options = {}) {
|
|
|
22747
22941
|
}
|
|
22748
22942
|
}
|
|
22749
22943
|
if (options.protectUrlLike !== false) {
|
|
22944
|
+
const plannedIndex = buildIntervalIndex(protectedRanges);
|
|
22750
22945
|
for (const match of text.matchAll(URL_LIKE_RE)) {
|
|
22751
22946
|
if (match.index === void 0) continue;
|
|
22752
22947
|
const start = match.index;
|
|
22753
22948
|
const end = start + match[0].length;
|
|
22754
|
-
|
|
22755
|
-
(range) => start < range.end && end > range.start
|
|
22756
|
-
);
|
|
22757
|
-
if (!alreadyPlanned)
|
|
22949
|
+
if (!intervalIndexOverlaps(plannedIndex, start, end))
|
|
22758
22950
|
protectedRanges.push({ start, end, kind: "url_like" });
|
|
22759
22951
|
}
|
|
22760
22952
|
}
|
|
22761
22953
|
if (options.protectCodeShaped !== false) {
|
|
22954
|
+
const plannedIndex = buildIntervalIndex(protectedRanges);
|
|
22762
22955
|
for (const range of codeShapedProtectedRanges(text)) {
|
|
22763
|
-
|
|
22764
|
-
(
|
|
22765
|
-
);
|
|
22766
|
-
if (!clash) protectedRanges.push(range);
|
|
22956
|
+
if (!intervalIndexOverlaps(plannedIndex, range.start, range.end))
|
|
22957
|
+
protectedRanges.push(range);
|
|
22767
22958
|
}
|
|
22768
22959
|
}
|
|
22769
22960
|
return { spans, protectedRanges };
|
|
@@ -22779,6 +22970,7 @@ var POSIX_LOCAL_PATH_RE, DIFF_PREFIX_RE, URL_LIKE_RE, WINDOWS_LOCAL_PATH_RE, COD
|
|
|
22779
22970
|
var init_path_policy = __esm({
|
|
22780
22971
|
"../../packages/@company/pii/src/path-policy.ts"() {
|
|
22781
22972
|
"use strict";
|
|
22973
|
+
init_interval_index();
|
|
22782
22974
|
POSIX_LOCAL_PATH_RE = /\/(?:Users|home|private|tmp|var|etc|opt|workspace|root|mnt|Volumes)\/(?:[\p{L}\p{N}._@%+~=-]+\/)*[\p{L}\p{N}._@%+~=-]+\/?/gu;
|
|
22783
22975
|
DIFF_PREFIX_RE = /(?:^|\s)(?:---|\+\+\+)\s+([ab])(?=\/)/gmu;
|
|
22784
22976
|
URL_LIKE_RE = /(?<![\p{L}\p{N}@._-])(?:[a-z][a-z0-9+.-]{0,31}:\/\/|(?:site|url|repo|link|source|host):\s*|git@)?(?:[\p{L}\p{N}-]{1,63}\.)+(?:com|org|net|io|dev|co|ai|gov|edu|sh|app|cloud|local)(?::\d{2,5})?(?:[/:][^\s"'<>\\]*)?/giu;
|
|
@@ -22830,6 +23022,7 @@ var init_engine = __esm({
|
|
|
22830
23022
|
"../../packages/@company/pii/src/engine.ts"() {
|
|
22831
23023
|
"use strict";
|
|
22832
23024
|
init_deterministic();
|
|
23025
|
+
init_interval_index();
|
|
22833
23026
|
init_dictionary();
|
|
22834
23027
|
init_spans();
|
|
22835
23028
|
init_path_policy();
|
|
@@ -23337,6 +23530,9 @@ async function uploadSession(sessionId, content, apiUrl2, token, agentSource, gi
|
|
|
23337
23530
|
if (response.status === 429) {
|
|
23338
23531
|
err.rateLimited = true;
|
|
23339
23532
|
}
|
|
23533
|
+
if (response.status === 409 && text.includes("mining_disabled")) {
|
|
23534
|
+
err.miningDisabled = true;
|
|
23535
|
+
}
|
|
23340
23536
|
throw err;
|
|
23341
23537
|
}
|
|
23342
23538
|
}
|
|
@@ -23510,6 +23706,12 @@ async function collectLocked(options) {
|
|
|
23510
23706
|
}
|
|
23511
23707
|
);
|
|
23512
23708
|
} catch (err) {
|
|
23709
|
+
if (err?.miningDisabled) {
|
|
23710
|
+
void logger3.info(
|
|
23711
|
+
"Mining is disabled for this organization \u2014 nothing is being collected. An owner or admin can enable it in Settings \u2192 Connections \u2192 Coding Sessions."
|
|
23712
|
+
);
|
|
23713
|
+
break;
|
|
23714
|
+
}
|
|
23513
23715
|
if (err?.rateLimited) {
|
|
23514
23716
|
deferred++;
|
|
23515
23717
|
void logger3.info(`Rate limited, will retry next run: ${shortId}`);
|